diff --git a/data_object/bundle.json b/data_object/bundle.json index 26237616c8df80245469345c178c585fcf0c5c0f..5af3608a925ebc2b01c675213c26fdf9ae7409fa 100644 --- a/data_object/bundle.json +++ b/data_object/bundle.json @@ -65,7 +65,8 @@ }, "build": { "sub_component": [ - "//foundation/distributeddatamgr/data_object/interfaces/jskits:build_module" + "//foundation/distributeddatamgr/data_object/interfaces/jskits:build_module", + "//foundation/distributeddatamgr/data_object/frameworks/jskitsimpl/collaboration_edit:collaborationeditobject" ], "inner_kits": [ { @@ -79,12 +80,30 @@ ], "header_base": "//foundation/distributeddatamgr/data_object/interfaces/innerkits" } + }, + { + "name": "//foundation/distributeddatamgr/data_object/interfaces/innerkits:data_object_inner", + "visibility": [ "datamgr_service" ], + "header": { + "header_files": [ + "object_types.h", + "iobject_service.h", + "object_callback.h", + "object_radar_reporter.h" + ], + "header_base": [ + "//foundation/distributeddatamgr/data_object/interfaces/innerkits", + "//foundation/distributeddatamgr/data_object/frameworks/innerkitsimpl/include", + "//foundation/distributeddatamgr/data_object/frameworks/innerkitsimpl/include/common" + ] + } } ], "test": [ "//foundation/distributeddatamgr/data_object/frameworks/innerkitsimpl/test/unittest:unittest", "//foundation/distributeddatamgr/data_object/frameworks/jskitsimpl/test/unittest:unittest", - "//foundation/distributeddatamgr/data_object/frameworks/innerkitsimpl/test/fuzztest/objectstore_fuzzer:fuzztest" + "//foundation/distributeddatamgr/data_object/frameworks/innerkitsimpl/test/fuzztest/objectstore_fuzzer:fuzztest", + "//foundation/distributeddatamgr/data_object/frameworks/jskitsimpl/collaboration_edit/test:unittest" ] } } diff --git a/data_object/data_object.gni b/data_object/data_object.gni index eff61218bb2703636041dcee1bbc25e0721c3e40..9fb083b09ce7ec3a170ab993ab56b0cb520034c9 100644 --- a/data_object/data_object.gni +++ b/data_object/data_object.gni @@ -16,3 +16,5 @@ kvstore_path = "//foundation/distributeddatamgr/kv_store/frameworks" data_object_base_path = "//foundation/distributeddatamgr/data_object" relational_store_path = "//foundation/distributeddatamgr/relational_store" + +datamgr_service_path = "//foundation/distributeddatamgr/datamgr_service" diff --git a/data_object/frameworks/innerkitsimpl/collaboration_edit/include/db_common.h b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/db_common.h new file mode 100644 index 0000000000000000000000000000000000000000..58bb14b241beb03654fd0fffa43b7023e10741fd --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/db_common.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024 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 COLLABORATION_EDIT_DB_COMMON_H +#define COLLABORATION_EDIT_DB_COMMON_H + +#include +#include +#include +#include "unistd.h" + +#define UNUSED_FUNCTION __attribute__((unused)) +namespace OHOS::CollaborationEdit { +class DBCommon final { +public: + static int CreateDirectory(const std::string &dbPath); +}; + +static const std::string OP_LOG_DIR = "_oplog"; +static constexpr mode_t DIR_RIGHT = 0771; +static UNUSED_FUNCTION uint32_t GetUid() +{ +#ifdef WINDOWS_PLATFORM + return 0; +#else + return getuid(); +#endif +} + +static UNUSED_FUNCTION int MkDir(const std::string &filePath, mode_t dirRight = DIR_RIGHT) +{ +#ifdef WINDOWS_PLATFORM + return mkdir(filePath.c_str()); +#else + return mkdir(filePath.c_str(), dirRight); +#endif +} + +} // namespace OHOS::CollaborationEdit +#endif // COLLABORATION_EDIT_DB_COMMON_H \ No newline at end of file diff --git a/data_object/frameworks/innerkitsimpl/collaboration_edit/include/db_error.h b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/db_error.h new file mode 100644 index 0000000000000000000000000000000000000000..280acdcda663637198db855f8697418a25178e0d --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/db_error.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 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 COLLABORATION_EDIT_DB_ERROR_H +#define COLLABORATION_EDIT_DB_ERROR_H + +namespace OHOS::CollaborationEdit { +constexpr const int E_OK = 0; +} // namespace OHOS::CollaborationEdit +#endif // COLLABORATION_EDIT_DB_ERROR_H diff --git a/data_object/frameworks/innerkitsimpl/collaboration_edit/include/db_store.h b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/db_store.h new file mode 100644 index 0000000000000000000000000000000000000000..e7bc62bfe609ede058ede0b67c3803cb54ef682b --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/db_store.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 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 COLLABORATION_EDIT_DB_STORE_H +#define COLLABORATION_EDIT_DB_STORE_H + +#include "db_store_config.h" +#include "grd_type_export.h" + +namespace OHOS::CollaborationEdit { +class DBStore { +public: + DBStore(GRD_DB *db, std::string name); + ~DBStore(); + static const char *GetEquipId(void); + GRD_DB *GetDB(); + +private: + GRD_DB *db_; + std::string name_; +}; +} // namespace OHOS::CollaborationEdit +#endif // COLLABORATION_EDIT_DB_STORE_H diff --git a/data_object/frameworks/innerkitsimpl/collaboration_edit/include/db_store_config.h b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/db_store_config.h new file mode 100644 index 0000000000000000000000000000000000000000..217e22d47bef436b42b6acf7816257c0c077a069 --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/db_store_config.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 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 COLLABORATION_EDIT_DB_STORE_CONFIG_H +#define COLLABORATION_EDIT_DB_STORE_CONFIG_H + +#include + +namespace OHOS::CollaborationEdit { +class DBStoreConfig { +public: + DBStoreConfig(std::string path, std::string name); + ~DBStoreConfig(); + std::string GetName() const; + std::string GetPath() const; +private: + std::string path_; + std::string name_; +}; +} // namespace OHOS::CollaborationEdit +#endif // COLLABORATION_EDIT_DB_STORE_CONFIG_H diff --git a/data_object/frameworks/innerkitsimpl/collaboration_edit/include/db_store_manager.h b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/db_store_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..ea79dfe5be04cd1f04a81469a148bc22bce60ad6 --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/db_store_manager.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 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 COLLABORATION_EDIT_DB_STORE_MANAGER_H +#define COLLABORATION_EDIT_DB_STORE_MANAGER_H + +#include +#include + +#include "db_error.h" +#include "db_store.h" +#include "db_store_config.h" + +namespace OHOS::CollaborationEdit { +class DBStoreManager { +public: + static DBStoreManager &GetInstance(); + DBStoreManager(); + ~DBStoreManager(); + std::shared_ptr GetDBStore(const DBStoreConfig &config); + int DeleteDBStore(const DBStoreConfig &config); + +private: + std::shared_ptr OpenDBStore(const DBStoreConfig &config); + int RemoveDir(const char *dir); + std::mutex mutex_; + std::map> storeCache_; +}; +} // namespace OHOS::CollaborationEdit +#endif // COLLABORATION_EDIT_DB_STORE_MANAGER_H diff --git a/data_object/frameworks/innerkitsimpl/collaboration_edit/include/grd_api_manager.h b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/grd_api_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..e84b5a77730bec2c78b07b1c2f6fe61fc00a7cdc --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/grd_api_manager.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2024 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 GRD_API_MANAGER_H +#define GRD_API_MANAGER_H + +#include "grd_type_export.h" + +namespace OHOS::CollaborationEdit { +// 1. Database open/close library interface encapsulation +typedef int32_t (*DBOpen)(const char *dbPath, const char *configStr, uint32_t flags, GRD_DB **db); +typedef int32_t (*DBClose)(GRD_DB *db, uint32_t flags); +typedef int32_t (*RegisterEquipId)(GRD_DB *db, GrdEquipIdGetFuncT func); +// 2. Node operation interface encapsulation +typedef int32_t (*InsertElements)(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, uint32_t index, + GRD_DocNodeInfoT *nodeInfo, GRD_ElementIdT **outElementId); +typedef int32_t (*DeleteElements)(GRD_DB *db, const char *tableName, const GRD_ElementIdT *elementId, uint32_t index, + uint32_t length); +typedef int32_t (*GetElements)(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, uint32_t index, uint32_t length, + char **respXml); +typedef int32_t (*FragmentToString)(GRD_DB *db, const char *tableName, const GRD_ElementIdT *elementId, + char **replyJson); +// 3. XmlElement attribute operation interface encapsulation +typedef int32_t (*ElementSetAttr)(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, const char *attributeName, + const char *attributeValue, uint32_t flags); +typedef int32_t (*ElementRemoveAttr)(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, const char *attributeName); +typedef int32_t (*ElementGetAttrs)(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, char **allAttributes); +// 4. Text operation interface encapsulation +typedef int32_t (*TextInsert)(GRD_DB *db, GRD_XmlOpPositionT *opPos, uint32_t index, const char *content, + const char *formatStr); +typedef int32_t (*TextDelete)(GRD_DB *db, GRD_XmlOpPositionT *opPos, uint32_t index, uint32_t length); +typedef int32_t (*TextFormat)(GRD_DB *db, GRD_XmlOpPositionT *opPos, uint32_t index, uint32_t length, + const char *formatStr); +typedef int32_t (*TextGetLength)(GRD_DB *db, GRD_XmlOpPositionT *opPos, uint32_t *length); +typedef int32_t (*TextReadInStrMode)(GRD_DB *db, GRD_XmlOpPositionT *opPos, char **value); +typedef int32_t (*TextReadInDeltaMode)(GRD_DB *db, GRD_XmlOpPositionT *opPos, const char *snapshot, + const char *snapshotPrev, char **delta); +// 5. Undo/Redo operation interface encapsulation +typedef int32_t (*DocUndoManager)(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, GRD_UndoParamT *param); +typedef int32_t (*DocUndo)(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, char **modify); +typedef int32_t (*DocRedo)(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, char **modify); +typedef int32_t (*DocStopCapturing)(GRD_DB *db, GRD_XmlOpPositionT *elementAddr); +// Last. Memory free and others +typedef void (*FreeElementId)(GRD_ElementIdT *outElementId); +typedef int32_t (*FreeValue)(char *value); + +struct GRD_APIInfo { + // 1. Database open/close library interface encapsulation + DBOpen DBOpenApi = nullptr; + DBClose DBCloseApi = nullptr; + RegisterEquipId RegisterEquipIdApi = nullptr; + // 2. Node operation inter + InsertElements InsertElementsApi = nullptr; + DeleteElements DeleteElementsApi = nullptr; + GetElements GetElementsApi = nullptr; + FragmentToString FragmentToStringApi = nullptr; + // 3. XmlElement attribute operation interface encapsulation + ElementSetAttr ElementSetAttrApi = nullptr; + ElementRemoveAttr ElementRemoveAttrApi = nullptr; + ElementGetAttrs ElementGetAttrsApi = nullptr; + // 4. Text operation interface encapsulation + TextInsert TextInsertApi = nullptr; + TextDelete TextDeleteApi = nullptr; + TextFormat TextFormatApi = nullptr; + TextGetLength TextGetLengthApi = nullptr; + TextReadInStrMode TextReadInStrModeApi = nullptr; + TextReadInDeltaMode TextReadInDeltaModeApi = nullptr; + // 5. Undo/Redo operation interface encapsulation + DocUndoManager DocUndoManagerApi = nullptr; + DocUndo DocUndoApi = nullptr; + DocRedo DocRedoApi = nullptr; + DocStopCapturing DocStopCapturingApi = nullptr; + // Last. Memory free and others + FreeElementId FreeElementIdApi = nullptr; + FreeValue FreeValueApi = nullptr; +}; + +GRD_APIInfo GetApiInfoInstance(); +} // namespace NativeRdb + +#endif // GRD_API_MANAGER_H diff --git a/data_object/frameworks/innerkitsimpl/collaboration_edit/include/grd_error.h b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/grd_error.h new file mode 100644 index 0000000000000000000000000000000000000000..c2ddadc9757ece01af3a036b843ddb1b22ebc6a8 --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/grd_error.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2024 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 GRD_ERROR_H +#define GRD_ERROR_H + +#ifdef __cplusplus +extern "C" { +#endif + +// Error category +#define GRD_OK 0 + +// Error category +#define GRD_NOT_SUPPORT (-1000) +#define GRD_OVER_LIMIT (-2000) +#define GRD_INVALID_ARGS (-3000) +#define GRD_SYSTEM_ERR (-4000) +#define GRD_FAILED_FILE_OPERATION (-5000) +#define GRD_INVALID_FILE_FORMAT (-6000) +#define GRD_INSUFFICIENT_SPACE (-7000) +#define GRD_INNER_ERR (-8000) +#define GRD_RESOURCE_BUSY (-9000) +#define GRD_NO_DATA (-11000) +#define GRD_FAILED_MEMORY_ALLOCATE (-13000) +#define GRD_FAILED_MEMORY_RELEASE (-14000) +#define GRD_DATA_CONFLICT (-16000) +#define GRD_DATATYPE_MISMATCH (-17000) +#define GRD_NOT_AVAILABLE (-19000) +#define GRD_ACTIVE_TRANSACTION (-20000) +#define GRD_UNIQUE_VIOLATION (-21000) +#define GRD_DUPLICATE_TABLE (-22000) +#define GRD_UNDEFINED_TABLE (-23000) +#define GRD_INVALID_BIND_VALUE (-36000) +#define GRD_INVALID_FORMAT (-37000) +#define GRD_REBUILD_DATABASE (-38000) +#define GRD_TIME_OUT (-39000) +#define GRD_DB_INSTANCE_ABNORMAL (-40000) +#define GRD_DISK_SPACE_FULL (-41000) +#define GRD_CRC_CHECK_DISABLED (-42000) +#define GRD_PERMISSION_DENIED (-43000) +#define GRD_SYNC_PREREQUISITES_ABNORMAL (-44000) +#define GRD_DATA_CORRUPTED (-45000) +#define GRD_DB_BUSY (-46000) +#define GRD_CALC_MODE_SET_PERMISSION_DENIED (-47000) + +#define GRD_CIPHER_ERROR (-48000) +#define GRD_PASSWORD_NEED_REKEY (-48001) +#define GRD_PASSWORD_UNMATCHED (-48002) + +#define GRD_SCHEMA_CHANGED (-49000) +// not support +#define GRD_JSON_OPERATION_NOT_SUPPORT (-5001001) +#define GRD_MODEL_NOT_SUPPORT (-5001002) +#define GRD_FEATURE_NOT_SUPPORTED (-5001003) + +// Exceed limit +#define GRD_JSON_LEN_LIMIT (-5002001) +#define GRD_SUBSCRIPTION_EXCEEDED_LIMIT (-5002002) +#define GRD_SYNC_EXCEED_TASK_QUEUE_LIMIT (-5002003) +#define GRD_SHARED_OBJ_ENABLE_UNDO_EXCEED_LIMIT (-5002004) +#define GRD_TABLE_LIMIT_EXCEEDED (-5002005) + +// Invalid parameter +#define GRD_FIELD_TYPE_NOT_MATCH (-5003001) +#define GRD_LARGE_JSON_NEST (-5003002) +#define GRD_INVALID_JSON_TYPE (-5003003) +#define GRD_INVALID_CONFIG_VALUE (-5003004) +#define GRD_INVALID_OPERATOR (-5003005) +#define GRD_INVALID_PROJECTION_FIELD (-5003006) +#define GRD_INVALID_PROJECTION_VALUE (-5003007) +#define GRD_COLLECTION_NOT_EXIST (-5003008) +#define GRD_DB_NOT_EXIST (-5003009) +#define GRD_INVALID_VALUE (-5003010) +#define GRD_SHARED_OBJ_NOT_EXIST (-5003020) +#define GRD_SUBSCRIBE_NOT_EXIST (-5003021) +#define GRD_SHARED_OBJ_UNDO_MANAGER_NOT_EXIST (-5003022) +#define GRD_SHARED_OBJ_INVALID_UNDO (-5003023) +#define GRD_SHARED_OBJ_INVALID_REDO (-5003024) +#define GRD_NAME_TOO_LONG (-5003025) +#define GRD_INVALID_TABLE_DEFINITION (-5003026) +#define GRD_WRONG_STMT_OBJECT (-5003027) +#define GRD_SEMANTIC_ERROR (-5003028) +#define GRD_SYNTAX_ERROR (-5003029) + +// System err +#define GRD_JSON_LIB_HANDLE_FAILED (-5004001) +#define GRD_DIRECTORY_OPERATE_FAILED (-5004002) +#define GRD_FILE_OPERATE_FAILED (-5004003) +#define GRD_LOAD_THIRD_PARTY_LIBRARY_FAILED (-5004004) +#define GRD_THIRD_PARTY_FUNCTION_EXECUTE_FAILED (-5004005) +#define GRD_INSUFFICIENT_RESOURCES (-5004006) + +// resource busy +#define GRD_RESULTSET_BUSY (-5009001) + +// no data +#define GRD_RECORD_NOT_FOUND (-5011001) +#define GRD_FIELD_NOT_FOUND (-5011002) +#define GRD_ARRAY_INDEX_NOT_FOUND (-5011003) + +// data conflicted +#define GRD_KEY_CONFLICT (-5016001) +#define GRD_FIELD_TYPE_CONFLICT (-5016002) +#define GRD_SHARED_OBJ_CONFLICT (-5016003) +#define GRD_SUBSCRIBE_CONFLICT (-5016004) +#define GRD_EQUIP_ID_CONFLICT (-5016005) +#define GRD_SHARED_OBJ_ENABLE_UNDO_CONFLICT (-5016006) + +// data exception +#define GRD_DATA_EXCEPTION (-5017001) +#define GRD_FIELD_OVERFLOW (-5017002) +#define GRD_DIVISION_BY_ZERO (-5017003) + +// Cursor or ResultSet not available +#define GRD_RESULT_SET_NOT_AVAILABLE (-5019001) +#define GRD_SHARED_OBJ_UNDO_NOT_AVAILABLE (-5019002) +#define GRD_SHARED_OBJ_REDO_NOT_AVAILABLE (-5019003) + +// Transaction +#define GRD_TRANSACTION_ROLLBACK (-5020001) +#define GRD_NO_ACTIVE_TRANSACTION (-5020002) + +// violation +#define GRD_PRIMARY_KEY_VIOLATION (-5021001) +#define GRD_RESTRICT_VIOLATION (-5021002) +#define GRD_CONSTRAINT_CHECK_VIOLATION (-5021003) + +// duplicate +#define GRD_DUPLICATE_COLUMN (-5022001) +#define GRD_DUPLICATE_OBJECT (-5022002) + +// undefined +#define GRD_UNDEFINE_COLUMN (-5023001) +#define GRD_UNDEFINED_OBJECT (-5023002) + +// Invalid format +#define GRD_INVALID_JSON_FORMAT (-5037001) +#define GRD_INVALID_KEY_FORMAT (-5037002) +#define GRD_INVALID_COLLECTION_NAME (-5037003) +#define GRD_INVALID_EQUIP_ID (-5037004) + +// time out +#define GRD_REQUEST_TIME_OUT (-5039001) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // GRD_ERROR_H diff --git a/data_object/frameworks/innerkitsimpl/collaboration_edit/include/grd_type_export.h b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/grd_type_export.h new file mode 100644 index 0000000000000000000000000000000000000000..49f9e56a4b2f5ad7c42d7ed0fa8a0bf73df7cc64 --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/grd_type_export.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2024 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 GRD_TYPE_EXPORT_H +#define GRD_TYPE_EXPORT_H + +#include "stdint.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +#ifdef GRD_DLL_EXPORT +#define GRD_API __declspec(dllexport) +#else +#define GRD_API +#endif +#else +#define GRD_API __attribute__((visibility("default"))) +#endif + +#define GRD_SYMBOL GRD_API + +typedef struct GRD_DB GRD_DB; + +/** + * @brief Open database config. + */ +#define GRD_DB_OPEN_ONLY 0x00 // open database if exists, return error if database not exists +#define GRD_DB_OPEN_CREATE 0x01 // open database if exists, create database and open if database not exists +#define GRD_DB_OPEN_CHECK_FOR_ABNORMAL \ + 0x02 // check data in database if close abnormally last time, + // if data is corrupted, rebuild the database +#define GRD_DB_OPEN_CHECK 0x04 // check data in database when open database, if data is corrupted, rebuild the database +#define GRD_DB_OPEN_SHARED_READ_ONLY 0x08 // open database in as read-only mode when sharedModeEnable = 1 + +/** + * @brief close database config. + */ +#define GRD_DB_CLOSE 0x00 +#define GRD_DB_CLOSE_IGNORE_ERROR 0x01 + +/** + * @brief flush database config. + */ +#define GRD_DB_FLUSH_ASYNC 0x00 +#define GRD_DB_FLUSH_SYNC 0x01 + +#define GRD_DOC_ID_DISPLAY 0x01 + +/** + * @brief meaning attr is an asset. + */ +#define GRD_DOC_ASSET_FLAG 0x01 + +typedef struct Query { + const char *filter; + const char *projection; +} Query; + +typedef struct GRD_KVItem { + void *data; + uint32_t dataLen; +} GRD_KVItemT; + +typedef struct GRD_ElementId { + const char *equipId; + uint64_t incrClock; +} GRD_ElementIdT; + +typedef struct GRD_XmlOpPosition { + const char *tableName; + GRD_ElementIdT *elementId; +} GRD_XmlOpPositionT; + +typedef struct GRD_UndoParam { + uint64_t captureTimeout; +} GRD_UndoParamT; + +typedef enum GRD_EncodingCalMode { + UTF16 = 0, + UTF8, + ENCODE_BUTT, +} GRD_EncodingCalModeE; + +typedef enum GRD_DocNodeType { + GRD_TEXT_TYPE = 0, + GRD_ARRAY_TYPE, + GRD_MAP_TYPE, + GRD_XML_TEXT_TYPE, + GRD_XML_ELEMENT_TYPE, + GRD_XML_FRAGMENT_TYPE, +} GRD_DocNodeTypeE; + +typedef struct GRD_DocNodeInfo { + GRD_DocNodeTypeE type; + const char *content; +} GRD_DocNodeInfoT; + +typedef const char *(*GrdEquipIdGetFuncT)(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // GRD_TYPE_EXPORT_H diff --git a/data_object/frameworks/innerkitsimpl/collaboration_edit/include/rd_adapter.h b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/rd_adapter.h new file mode 100644 index 0000000000000000000000000000000000000000..b9b86d3648c6837626e3746fd78e16a286def896 --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/rd_adapter.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2024 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 COLLABORATION_EDIT_RD_ADAPTER_H +#define COLLABORATION_EDIT_RD_ADAPTER_H + +#include + +#include "db_store.h" +#include "grd_type_export.h" +#include "napi_errno.h" +#include "rd_utils.h" + +namespace OHOS::CollaborationEdit { +static constexpr const uint8_t NUMBER_OF_CHARS_IN_LABEL_PREFIX = 2; +const uint8_t LABEL_FRAGMENT = 5; // See kernel struct DmElementContentType +static std::map g_errMap = { + {GRD_OK, Status::SUCCESS}, + {GRD_ARRAY_INDEX_NOT_FOUND, Status::INDEX_OUT_OF_RANGE} +}; + +struct ID { + ID(const std::string deviceId, uint64_t clock) + { + this->deviceId = deviceId; + this->clock = clock; + } + std::string deviceId; + uint64_t clock; +}; + +class RdAdapter { +public: + RdAdapter(); + ~RdAdapter(); + void SetDBStore(std::shared_ptr dbStore); + std::shared_ptr GetDBStore(); + void SetTableName(std::string name); + std::string GetTableName(); + void SetID(std::optional id); + std::optional GetID(); + + std::pair> InsertNode(uint32_t index, std::string nodeName); + std::pair> InsertText(uint32_t index); + int32_t DeleteChildren(uint32_t index, uint32_t length); + std::pair GetChildren(uint32_t index, uint32_t length); + std::pair GetJsonString(); + int32_t SetAttribute(const std::string &attributeName, const std::string &attributeValue, uint32_t flags); + int32_t RemoveAttrribute(const std::string &attributeName); + std::pair GetAttributes(); + + int32_t TextInsert(uint32_t index, const std::string &content, const std::string &formatStr); + int32_t TextDelete(uint32_t index, uint32_t length); + int32_t TextFormat(uint32_t index, uint32_t length, const std::string &formatStr); + std::pair GetTextLength(); + std::pair ReadDeltaText(const std::string &snapshot, const std::string &snapshotPerv); + std::pair ReadStringText(); + + int32_t CreateUndoManager(uint64_t captureTimeout); + int32_t Undo(); + int32_t Redo(); + + int32_t TransferToNapiErrNo(int32_t originNo); + +private: + std::shared_ptr dbStore_; + std::string tableName_; + std::optional id_; +}; +} // namespace OHOS::CollaborationEdit +#endif // COLLABORATION_EDIT_RD_ADAPTER_H diff --git a/data_object/frameworks/innerkitsimpl/collaboration_edit/include/rd_utils.h b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/rd_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..d0b93e99754f4090ac3c1d87f5be7391b608532c --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/collaboration_edit/include/rd_utils.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024 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 COLLABORATION_EDIT_RD_UTILS_H +#define COLLABORATION_EDIT_RD_UTILS_H + +#include "grd_error.h" +#include "grd_type_export.h" + +namespace OHOS::CollaborationEdit { +class RdUtils { +public: + // 1. Database open/close library interface encapsulation + static int RdDbOpen(const char *dbFile, const char *configStr, uint32_t flags, GRD_DB **db); + static int RdDbClose(GRD_DB *db, uint32_t flags); + static int RdRegisterEquipId(GRD_DB *db, GrdEquipIdGetFuncT func); + // 2. Node operation inter + static int RdInsertElements(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, uint32_t index, GRD_DocNodeInfoT *nodeInfo, + GRD_ElementIdT **outElementId); + static int RdDeleteElements(GRD_DB *db, const char *tableName, const GRD_ElementIdT *elementId, uint32_t index, + uint32_t length); + static int RdGetElements(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, uint32_t index, uint32_t length, + char **respXml); + static int RdFragmentToString(GRD_DB *db, const char *fragmentName, const GRD_ElementIdT *elementId, + char **replyJson); + // 3. XmlElement attribute operation interface encapsulation + static int RdElementSetAttribute(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, const char *attributeName, + const char *attributeValue, uint32_t flags); + static int RdElementRemoveAttribute(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, const char *attributeName); + static int RdElementGetAttributes(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, char **allAttributes); + // 4. Text operation interface encapsulation + static int RdTextInsert(GRD_DB *db, GRD_XmlOpPositionT *opPos, uint32_t index, const char *content, + const char *formatStr); + static int RdTextDelete(GRD_DB *db, GRD_XmlOpPositionT *opPos, uint32_t index, uint32_t length); + static int RdTextFormat(GRD_DB *db, GRD_XmlOpPositionT *opPos, uint32_t index, uint32_t length, + const char *formatStr); + static int RdTextGetLength(GRD_DB *db, GRD_XmlOpPositionT *opPos, uint32_t *length); + static int RdTextReadInStrMode(GRD_DB *db, GRD_XmlOpPositionT *opPos, char **value); + static int RdTextReadInDeltaMode(GRD_DB *db, GRD_XmlOpPositionT *opPos, const char *snapshot, + const char *snapshotPerv, char **delta); + // 5. Undo/Redo operation interface encapsulation + static int RdDocUndoManager(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, GRD_UndoParamT *param); + static int RdDocUndo(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, char **modify); + static int RdDocRedo(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, char **modify); + static int RdDocStopCapturing(GRD_DB *db, GRD_XmlOpPositionT *elementAddr); + // Last. Memory free and others + static void RdFreeElementId(GRD_ElementIdT *outElementId); + static int RdFreeValue(char *value); +}; + +} // namepace OHOS::CollaborationEdit + +#endif // COLLABORATION_EDIT_RD_UTILS_H diff --git a/data_object/frameworks/innerkitsimpl/collaboration_edit/src/db_common.cpp b/data_object/frameworks/innerkitsimpl/collaboration_edit/src/db_common.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b31e4d6de78050b4745f0e7caae3867b8b1ac445 --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/collaboration_edit/src/db_common.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024 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 "DBCommon" + +#include "db_common.h" + +#include "acl.h" +#include "log_print.h" + +namespace OHOS::CollaborationEdit { +using namespace OHOS::DATABASE_UTILS; +constexpr int32_t SERVICE_GID = 3012; +int DBCommon::CreateDirectory(const std::string &dbPath) +{ + std::string tempPath = dbPath; + std::vector directories; + + size_t pos = tempPath.find('/'); + while (pos != std::string::npos) { + std::string dir = tempPath.substr(0, pos); + directories.push_back(dir); + tempPath = tempPath.substr(pos + 1); + pos = tempPath.find('/'); + } + directories.push_back(tempPath); + + std::string targetDir; + for (const std::string &directory : directories) { + targetDir = targetDir + "/" + directory; + if (access(targetDir.c_str(), F_OK) != 0) { + if (MkDir(targetDir)) { + LOG_ERROR("[CreateDirectory] mkdir errno[%{public}d] %{public}s", errno, targetDir.c_str()); + return -1; + } + + Acl acl(targetDir); + acl.SetDefaultUser(GetUid(), Acl::R_RIGHT | Acl::W_RIGHT); + acl.SetDefaultGroup(SERVICE_GID, Acl::R_RIGHT | Acl::W_RIGHT); + } + } + return 0; +} +} // namespace OHOS::CollaborationEdit diff --git a/data_object/frameworks/innerkitsimpl/collaboration_edit/src/db_store.cpp b/data_object/frameworks/innerkitsimpl/collaboration_edit/src/db_store.cpp new file mode 100644 index 0000000000000000000000000000000000000000..295ae672477f9b8455bed4793007121b8c5409e0 --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/collaboration_edit/src/db_store.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 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 "DBStore" + +#include "db_store.h" + +#include "log_print.h" +#include "rd_utils.h" + +namespace OHOS::CollaborationEdit { +DBStore::DBStore(GRD_DB *db, std::string name) : db_(db), name_(name) +{ + int ret = RdUtils::RdRegisterEquipId(db, reinterpret_cast(DBStore::GetEquipId)); + if (ret != GRD_OK) { + LOG_ERROR("register equip id go wrong. err: %{public}d", ret); + } +} + +DBStore::~DBStore() +{ + RdUtils::RdDbClose(db_, GRD_DB_CLOSE); +} + +const char *DBStore::GetEquipId(void) +{ + std::string *str = new std::string("A"); + return (*str).c_str(); +} + +GRD_DB *DBStore::GetDB() +{ + return db_; +} +} // namespace OHOS::CollaborationEdit diff --git a/data_object/frameworks/innerkitsimpl/collaboration_edit/src/db_store_config.cpp b/data_object/frameworks/innerkitsimpl/collaboration_edit/src/db_store_config.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95f157e410d0423eef94f3641c3b2dcc79758b04 --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/collaboration_edit/src/db_store_config.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 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 "DBStoreConfig" + +#include "db_store_config.h" + +namespace OHOS::CollaborationEdit { +DBStoreConfig::DBStoreConfig(std::string path, std::string name) : path_(path), name_(name) +{} + +DBStoreConfig::~DBStoreConfig() +{} + +std::string DBStoreConfig::GetName() const +{ + return name_; +} + +std::string DBStoreConfig::GetPath() const +{ + return path_; +} +} // namespace OHOS::CollaborationEdit diff --git a/data_object/frameworks/innerkitsimpl/collaboration_edit/src/db_store_manager.cpp b/data_object/frameworks/innerkitsimpl/collaboration_edit/src/db_store_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..104a8ea5071c5a692c8d7f6d2ba3f8191755ba24 --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/collaboration_edit/src/db_store_manager.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2024 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 "DBStoreManager" + +#include "db_store_manager.h" + +#include +#include +#include + +#include "db_common.h" +#include "log_print.h" +#include "rd_utils.h" + +namespace OHOS::CollaborationEdit { +DBStoreManager &DBStoreManager::GetInstance() +{ + static DBStoreManager manager; + return manager; +} + +DBStoreManager::DBStoreManager() +{} + +DBStoreManager::~DBStoreManager() +{ + std::lock_guard lock(mutex_); + storeCache_.clear(); +} + +std::shared_ptr DBStoreManager::GetDBStore(const DBStoreConfig &config) +{ + std::lock_guard lock(mutex_); + auto it = storeCache_.find(config.GetName()); + if (it != storeCache_.end()) { + return it->second; + } + std::shared_ptr dbStore = OpenDBStore(config); + if (dbStore != nullptr) { + storeCache_[config.GetName()] = dbStore; + } + return dbStore; +} + +std::shared_ptr DBStoreManager::OpenDBStore(const DBStoreConfig &dbConfig) +{ + std::string dbFilePath = dbConfig.GetPath(); + std::string name = dbConfig.GetName(); + LOG_DEBUG("[OpenDBStore] start"); + // create database and oplog directory if not exists + if (access(dbFilePath.c_str(), F_OK) != 0) { + int ret = DBCommon::CreateDirectory(dbFilePath); + if (ret != 0) { + LOG_ERROR("[OpenDBStore] Create base dir go wrong, ret = %{public}d", ret); + return nullptr; + } + // creating oplog dir here is to provide group permission for other processes access + std::string opLogDir = dbFilePath + "/" + name + OP_LOG_DIR; + ret = DBCommon::CreateDirectory(opLogDir); + if (ret != 0) { + LOG_ERROR("[OpenDBStore] Create oplog dir go wrong, ret = %{public}d", ret); + return nullptr; + } + } + + GRD_DB *db = nullptr; + std::string dbFile = dbFilePath + "/" + name; + std::string config = R"({"sharedModeEnable":1,"redoFlushByTrx":1})"; + int32_t errCode = RdUtils::RdDbOpen(dbFile.c_str(), config.c_str(), GRD_DB_OPEN_CREATE, &db); + if (errCode != GRD_OK || db == nullptr) { + LOG_ERROR("[OpenDBStore] open db go wrong, err = %{public}d", errCode); + return nullptr; + } + LOG_INFO("[OpenDBStore] open db successfully"); + std::shared_ptr dbStore = std::make_shared(db, name); + return dbStore; +} + +int DBStoreManager::DeleteDBStore(const DBStoreConfig &config) +{ + std::lock_guard lock(mutex_); + std::string dbPath = config.GetPath(); + if (dbPath.empty()) { + LOG_ERROR("[DeleteDBStore] empty path"); + return -1; + } + auto it = storeCache_.find(config.GetName()); + if (it != storeCache_.end()) { + std::shared_ptr dbStorePtr = it->second; + int32_t errCode = RdUtils::RdDbClose(dbStorePtr->GetDB(), GRD_DB_CLOSE); + if (errCode != GRD_OK) { + LOG_ERROR("[DeleteDBStore] db close go wrong, err = %{public}d", errCode); + return -1; + } + } + int ret = RemoveDir(dbPath.c_str()); + if (ret != 0) { + LOG_ERROR("[DeleteDBStore] remove dir go wrong"); + return ret; + } + LOG_INFO("[DeleteDBStore] delete db successfully"); + storeCache_.erase(config.GetName()); + return 0; +} + +int DBStoreManager::RemoveDir(const char *dir) +{ + if (access(dir, F_OK) != 0) { + return 0; + } + + struct stat dirStat; + if (stat(dir, &dirStat) < 0) { + LOG_ERROR("[RemoveDir] get dir stat go wrong"); + return -1; + } + + char dirName[PATH_MAX]; + DIR *dirPtr = nullptr; + struct dirent *dr = nullptr; + if (S_ISREG(dirStat.st_mode)) { // normal file + remove(dir); + } else if (S_ISDIR(dirStat.st_mode)) { + dirPtr = opendir(dir); + while ((dr = readdir(dirPtr)) != nullptr) { + // ignore . and .. + if ((strcmp(".", dr->d_name) == 0) || (strcmp("..", dr->d_name) == 0)) { + continue; + } + if (sprintf_s(dirName, PATH_MAX, "%s/%s", dir, dr->d_name) <= 0) { + LOG_ERROR("[RemoveDir] dirName too long."); + closedir(dirPtr); + return -1; + } + RemoveDir(dirName); + } + closedir(dirPtr); + rmdir(dir); // remove empty dir + } else { + LOG_ERROR("[RemoveDir] unknown file type, st mode %{public}d", dirStat.st_mode); + } + return 0; +} +} // namespace OHOS::CollaborationEdit diff --git a/data_object/frameworks/innerkitsimpl/collaboration_edit/src/grd_api_manager.cpp b/data_object/frameworks/innerkitsimpl/collaboration_edit/src/grd_api_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1e1a7446cfbafab116de2273071002a06d69e6cb --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/collaboration_edit/src/grd_api_manager.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2024 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 "grd_api_manager.h" + +#ifndef _WIN32 +#include +#endif + +#ifndef _WIN32 +static void *g_library = nullptr; +#endif + +namespace OHOS::CollaborationEdit { +void GRD_DBApiInitEnhance(GRD_APIInfo &GRD_DBApiInfo) +{ +#ifndef _WIN32 + // 1. Database open/close library interface encapsulation + GRD_DBApiInfo.DBOpenApi = (DBOpen)dlsym(g_library, "GRD_DBOpen"); + GRD_DBApiInfo.DBCloseApi = (DBClose)dlsym(g_library, "GRD_DBClose"); + GRD_DBApiInfo.RegisterEquipIdApi = (RegisterEquipId)dlsym(g_library, "GRD_RegisterEquipId"); + // 2. Node operation interface encapsulation + GRD_DBApiInfo.InsertElementsApi = (InsertElements)dlsym(g_library, "GRD_XmlFragmentInsert"); + GRD_DBApiInfo.DeleteElementsApi = (DeleteElements)dlsym(g_library, "GRD_XmlFragmentDelete"); + GRD_DBApiInfo.GetElementsApi = (GetElements)dlsym(g_library, "GRD_XmlFragmentGet"); + GRD_DBApiInfo.FragmentToStringApi = (FragmentToString)dlsym(g_library, "GRD_XmlFragmentToString"); + // 3. XmlElement attribute operation interface encapsulation + GRD_DBApiInfo.ElementSetAttrApi = (ElementSetAttr)dlsym(g_library, "GRD_XmlElementSetAttribute"); + GRD_DBApiInfo.ElementRemoveAttrApi = (ElementRemoveAttr)dlsym(g_library, "GRD_XmlElementRemoveAttribute"); + GRD_DBApiInfo.ElementGetAttrsApi = (ElementGetAttrs)dlsym(g_library, "GRD_XmlElementGetAttributes"); + // 4. Text operation interface encapsulation + GRD_DBApiInfo.TextInsertApi = (TextInsert)dlsym(g_library, "GRD_TextInsert"); + GRD_DBApiInfo.TextDeleteApi = (TextDelete)dlsym(g_library, "GRD_TextDelete"); + GRD_DBApiInfo.TextFormatApi = (TextFormat)dlsym(g_library, "GRD_TextAssignFormats"); + GRD_DBApiInfo.TextGetLengthApi = (TextGetLength)dlsym(g_library, "GRD_TextGetLength"); + GRD_DBApiInfo.TextReadInStrModeApi = (TextReadInStrMode)dlsym(g_library, "GRD_TextReadInStrMode"); + GRD_DBApiInfo.TextReadInDeltaModeApi = (TextReadInDeltaMode)dlsym(g_library, "GRD_TextReadInDeltaMode"); + // 5. Undo/Redo operation interface encapsulation + GRD_DBApiInfo.DocUndoManagerApi = (DocUndoManager)dlsym(g_library, "GRD_DocUndoManager"); + GRD_DBApiInfo.DocUndoApi = (DocUndo)dlsym(g_library, "GRD_DocUndo"); + GRD_DBApiInfo.DocRedoApi = (DocRedo)dlsym(g_library, "GRD_DocRedo"); + GRD_DBApiInfo.DocStopCapturingApi = (DocStopCapturing)dlsym(g_library, "GRD_DocStopCapturing"); + // Last. Memory free and others + GRD_DBApiInfo.FreeElementIdApi = (FreeElementId)dlsym(g_library, "GRD_XmlFreeElementId"); + GRD_DBApiInfo.FreeValueApi = (FreeValue)dlsym(g_library, "GRD_DocFree"); +#endif +} + +GRD_APIInfo GetApiInfoInstance() +{ + GRD_APIInfo GRD_TempApiStruct; +#ifndef _WIN32 + g_library = dlopen("libarkdata_db_core.z.so", RTLD_LAZY); + if (g_library) { + GRD_DBApiInitEnhance(GRD_TempApiStruct); + } +#endif + return GRD_TempApiStruct; +} +} // namespace OHOS::CollaborationEdit diff --git a/data_object/frameworks/innerkitsimpl/collaboration_edit/src/rd_adapter.cpp b/data_object/frameworks/innerkitsimpl/collaboration_edit/src/rd_adapter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b53431cc129a69fc9729068a456c2bfd69de0c4a --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/collaboration_edit/src/rd_adapter.cpp @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2024 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 "RdAdapter" + +#include "rd_adapter.h" + +#include "log_print.h" + +namespace OHOS::CollaborationEdit { +RdAdapter::RdAdapter() +{} + +RdAdapter::~RdAdapter() +{} + +void RdAdapter::SetDBStore(std::shared_ptr dbStore) +{ + this->dbStore_ = dbStore; +} + +std::shared_ptr RdAdapter::GetDBStore() +{ + return this->dbStore_; +} + +void RdAdapter::SetTableName(std::string name) +{ + this->tableName_ = name; +} + +std::string RdAdapter::GetTableName() +{ + return this->tableName_; +} + +void RdAdapter::SetID(std::optional id) +{ + this->id_ = id; +} + +std::optional RdAdapter::GetID() +{ + return this->id_; +} + +std::pair> RdAdapter::InsertNode(uint32_t index, std::string nodeName) +{ + GRD_ElementIdT *elementId = nullptr; + GRD_ElementIdT tempId; + if (this->id_.has_value()) { + tempId.equipId = this->id_.value().deviceId.c_str(); + tempId.incrClock = this->id_.value().clock; + elementId = &tempId; + } + GRD_XmlOpPositionT position = { + .tableName = this->tableName_.c_str(), + .elementId = elementId, + }; + GRD_DocNodeInfo nodeInfo = { + .type = GRD_XML_ELEMENT_TYPE, + .content = nodeName.c_str(), + }; + + GRD_ElementIdT *outElementId = nullptr; + int32_t errCode = RdUtils::RdInsertElements(this->dbStore_->GetDB(), &position, index, &nodeInfo, &outElementId); + if (errCode != GRD_OK || outElementId == nullptr) { + LOG_ERROR("InsertElements go wrong, errCode = %{public}d", errCode); + return std::make_pair(TransferToNapiErrNo(errCode), std::nullopt); + } + ID id(std::string(outElementId->equipId), outElementId->incrClock); + RdUtils::RdFreeElementId(outElementId); + return std::make_pair(errCode, id); +} + +std::pair> RdAdapter::InsertText(uint32_t index) +{ + GRD_ElementIdT *elementId = nullptr; + GRD_ElementIdT tempId; + if (this->id_.has_value()) { + tempId.equipId = this->id_.value().deviceId.c_str(); + tempId.incrClock = this->id_.value().clock; + elementId = &tempId; + } + GRD_XmlOpPositionT position = { + .tableName = this->tableName_.c_str(), + .elementId = elementId, + }; + GRD_DocNodeInfo nodeInfo = { + .type = GRD_XML_TEXT_TYPE, + .content = nullptr, + }; + + GRD_ElementIdT *outElementId = nullptr; + int32_t errCode = RdUtils::RdInsertElements(this->dbStore_->GetDB(), &position, index, &nodeInfo, &outElementId); + if (errCode != GRD_OK || outElementId == nullptr) { + LOG_ERROR("InsertElements go wrong, errCode = %{public}d", errCode); + return std::make_pair(TransferToNapiErrNo(errCode), std::nullopt); + } + ID id(std::string(outElementId->equipId), outElementId->incrClock); + RdUtils::RdFreeElementId(outElementId); + return std::make_pair(errCode, id); +} + +int32_t RdAdapter::DeleteChildren(uint32_t index, uint32_t length) +{ + GRD_ElementIdT *elementId = nullptr; + GRD_ElementIdT tempId; + if (this->id_.has_value()) { + tempId.equipId = this->id_.value().deviceId.c_str(); + tempId.incrClock = this->id_.value().clock; + elementId = &tempId; + } + + int32_t errCode = RdUtils::RdDeleteElements(this->dbStore_->GetDB(), this->tableName_.c_str(), elementId, index, + length); + if (errCode != GRD_OK) { + LOG_ERROR("DeleteElements go wrong, errCode = %{public}d", errCode); + } + return TransferToNapiErrNo(errCode); +} + +std::pair RdAdapter::GetChildren(uint32_t index, uint32_t length) +{ + GRD_ElementIdT *elementId = nullptr; + GRD_ElementIdT tempId; + if (this->id_.has_value()) { + tempId.equipId = this->id_.value().deviceId.c_str(); + tempId.incrClock = this->id_.value().clock; + elementId = &tempId; + } + GRD_XmlOpPositionT position = { + .tableName = this->tableName_.c_str(), + .elementId = elementId, + }; + + char *respXml = nullptr; + int32_t errCode = RdUtils::RdGetElements(this->dbStore_->GetDB(), &position, index, length, &respXml); + if (errCode != GRD_OK) { + LOG_ERROR("RdGetElements go wrong, errCode = %{public}d", errCode); + return std::make_pair(TransferToNapiErrNo(errCode), ""); + } + std::string retString(respXml == nullptr ? "" : respXml); + (void)RdUtils::RdFreeValue(respXml); + return std::make_pair(errCode, retString); +} + +std::pair RdAdapter::GetJsonString() +{ + GRD_ElementIdT *elementId = nullptr; + GRD_ElementIdT tempId; + if (this->id_.has_value()) { + tempId.equipId = this->id_.value().deviceId.c_str(); + tempId.incrClock = this->id_.value().clock; + elementId = &tempId; + } + + char *replyJson = nullptr; + int32_t errCode = RdUtils::RdFragmentToString(this->dbStore_->GetDB(), this->tableName_.c_str(), elementId, + &replyJson); + if (errCode != GRD_OK) { + LOG_ERROR("RdFragmentToString go wrong, errCode = %{public}d", errCode); + return std::make_pair(TransferToNapiErrNo(errCode), ""); + } + std::string retString(replyJson == nullptr ? "" : replyJson); + (void)RdUtils::RdFreeValue(replyJson); + return std::make_pair(errCode, retString); +} + +int32_t RdAdapter::SetAttribute(const std::string &attributeName, const std::string &attributeValue, uint32_t flags) +{ + GRD_ElementIdT *elementId = nullptr; + GRD_ElementIdT tempId; + if (this->id_.has_value()) { + tempId.equipId = this->id_.value().deviceId.c_str(); + tempId.incrClock = this->id_.value().clock; + elementId = &tempId; + } + GRD_XmlOpPositionT position = { + .tableName = this->tableName_.c_str(), + .elementId = elementId, + }; + int32_t errCode = RdUtils::RdElementSetAttribute(this->dbStore_->GetDB(), &position, attributeName.c_str(), + attributeValue.c_str(), flags); + if (errCode != GRD_OK) { + LOG_ERROR("RdElementSetAttribute go wrong, errCode = %{public}d", errCode); + } + return TransferToNapiErrNo(errCode); +} + +int32_t RdAdapter::RemoveAttrribute(const std::string &attributeName) +{ + GRD_ElementIdT *elementId = nullptr; + GRD_ElementIdT tempId; + if (this->id_.has_value()) { + tempId.equipId = this->id_.value().deviceId.c_str(); + tempId.incrClock = this->id_.value().clock; + elementId = &tempId; + } + GRD_XmlOpPositionT position = { + .tableName = this->tableName_.c_str(), + .elementId = elementId, + }; + int32_t errCode = RdUtils::RdElementRemoveAttribute(this->dbStore_->GetDB(), &position, attributeName.c_str()); + if (errCode != GRD_OK) { + LOG_ERROR("RdElementRemoveAttribute go wrong, errCode = %{public}d", errCode); + } + return TransferToNapiErrNo(errCode); +} + +std::pair RdAdapter::GetAttributes() +{ + GRD_ElementIdT *elementId = nullptr; + GRD_ElementIdT tempId; + if (this->id_.has_value()) { + tempId.equipId = this->id_.value().deviceId.c_str(); + tempId.incrClock = this->id_.value().clock; + elementId = &tempId; + } + GRD_XmlOpPositionT position = { + .tableName = this->tableName_.c_str(), + .elementId = elementId, + }; + + char *fullAttributes = nullptr; + int32_t errCode = RdUtils::RdElementGetAttributes(this->dbStore_->GetDB(), &position, &fullAttributes); + if (errCode != GRD_OK) { + LOG_ERROR("RdElementGetAttributes go wrong, errCode = %{public}d", errCode); + return std::make_pair(TransferToNapiErrNo(errCode), ""); + } + std::string attrsString(fullAttributes == nullptr ? "" : fullAttributes); + (void)RdUtils::RdFreeValue(fullAttributes); + return std::make_pair(errCode, attrsString); +} + +int32_t RdAdapter::TextInsert(uint32_t index, const std::string &content, const std::string &formatStr) +{ + GRD_ElementIdT *elementId = nullptr; + GRD_ElementIdT tempId; + if (this->id_.has_value()) { + tempId.equipId = this->id_.value().deviceId.c_str(); + tempId.incrClock = this->id_.value().clock; + elementId = &tempId; + } + GRD_XmlOpPositionT position = { + .tableName = this->tableName_.c_str(), + .elementId = elementId, + }; + int32_t errCode = RdUtils::RdTextInsert(this->dbStore_->GetDB(), &position, index, content.c_str(), + formatStr.empty() ? nullptr : formatStr.c_str()); + if (errCode != GRD_OK) { + LOG_ERROR("RdTextInsert go wrong, errCode = %{public}d", errCode); + } + return TransferToNapiErrNo(errCode); +} + +int32_t RdAdapter::TextDelete(uint32_t index, uint32_t length) +{ + GRD_ElementIdT *elementId = nullptr; + GRD_ElementIdT tempId; + if (this->id_.has_value()) { + tempId.equipId = this->id_.value().deviceId.c_str(); + tempId.incrClock = this->id_.value().clock; + elementId = &tempId; + } + GRD_XmlOpPositionT position = { + .tableName = this->tableName_.c_str(), + .elementId = elementId, + }; + int32_t errCode = RdUtils::RdTextDelete(this->dbStore_->GetDB(), &position, index, length); + if (errCode != GRD_OK) { + LOG_ERROR("RdTextDelete go wrong, errCode = %{public}d", errCode); + } + return TransferToNapiErrNo(errCode); +} + +int32_t RdAdapter::TextFormat(uint32_t index, uint32_t length, const std::string &formatStr) +{ + GRD_ElementIdT *elementId = nullptr; + GRD_ElementIdT tempId; + if (this->id_.has_value()) { + tempId.equipId = this->id_.value().deviceId.c_str(); + tempId.incrClock = this->id_.value().clock; + elementId = &tempId; + } + GRD_XmlOpPositionT position = { + .tableName = this->tableName_.c_str(), + .elementId = elementId, + }; + int32_t errCode = RdUtils::RdTextFormat(this->dbStore_->GetDB(), &position, index, length, + formatStr.c_str()); + if (errCode != GRD_OK) { + LOG_ERROR("RdTextFormat go wrong, errCode = %{public}d", errCode); + } + return TransferToNapiErrNo(errCode); +} + +std::pair RdAdapter::GetTextLength() +{ + GRD_ElementIdT *elementId = nullptr; + GRD_ElementIdT tempId; + if (this->id_.has_value()) { + tempId.equipId = this->id_.value().deviceId.c_str(); + tempId.incrClock = this->id_.value().clock; + elementId = &tempId; + } + GRD_XmlOpPositionT position = { + .tableName = this->tableName_.c_str(), + .elementId = elementId, + }; + uint32_t textLength = 0; + int32_t errCode = RdUtils::RdTextGetLength(this->dbStore_->GetDB(), &position, &textLength); + if (errCode != GRD_OK) { + LOG_ERROR("RdTextGetLength go wrong, errCode = %{public}d", errCode); + } + return std::make_pair(TransferToNapiErrNo(errCode), textLength); +} + +std::pair RdAdapter::ReadDeltaText(const std::string &snapshot, const std::string &snapshotPrev) +{ + GRD_ElementIdT *elementId = nullptr; + GRD_ElementIdT tempId; + if (this->id_.has_value()) { + tempId.equipId = this->id_.value().deviceId.c_str(); + tempId.incrClock = this->id_.value().clock; + elementId = &tempId; + } + GRD_XmlOpPositionT position = { + .tableName = this->tableName_.c_str(), + .elementId = elementId, + }; + + char *deltaText = nullptr; + const char *snapshotPtr = snapshot.empty() ? nullptr : snapshot.c_str(); + const char *snapshotPrevPtr = snapshotPrev.empty() ? nullptr : snapshotPrev.c_str(); + int32_t errCode = RdUtils::RdTextReadInDeltaMode(this->dbStore_->GetDB(), &position, snapshotPtr, + snapshotPrevPtr, &deltaText); + if (errCode != GRD_OK) { + LOG_ERROR("RdTextReadInDeltaMode go wrong, errCode = %{public}d", errCode); + return std::make_pair(TransferToNapiErrNo(errCode), ""); + } + std::string deltaString(deltaText == nullptr ? "" : deltaText); + (void)RdUtils::RdFreeValue(deltaText); + return std::make_pair(errCode, deltaString); +} + +std::pair RdAdapter::ReadStringText() +{ + GRD_ElementIdT *elementId = nullptr; + GRD_ElementIdT tempId; + if (this->id_.has_value()) { + tempId.equipId = this->id_.value().deviceId.c_str(); + tempId.incrClock = this->id_.value().clock; + elementId = &tempId; + } + GRD_XmlOpPositionT position = { + .tableName = this->tableName_.c_str(), + .elementId = elementId, + }; + + char *text = nullptr; + int32_t errCode = RdUtils::RdTextReadInStrMode(this->dbStore_->GetDB(), &position, &text); + if (errCode != GRD_OK) { + LOG_ERROR("RdTextReadInStrMode go wrong, errCode = %{public}d", errCode); + return std::make_pair(TransferToNapiErrNo(errCode), ""); + } + std::string str(text == nullptr ? "" : text); + (void)RdUtils::RdFreeValue(text); + return std::make_pair(errCode, str); +} + +int32_t RdAdapter::CreateUndoManager(uint64_t captureTimeout) +{ + GRD_XmlOpPositionT position = { + .tableName = this->tableName_.c_str(), + .elementId = nullptr, + }; + + GRD_UndoParamT undoParam = { + .captureTimeout = captureTimeout, + }; + + int32_t errCode = RdUtils::RdDocUndoManager(this->dbStore_->GetDB(), &position, &undoParam); + if (errCode != GRD_OK) { + LOG_ERROR("RdDocUndoManager go wrong, errCode = %{public}d", errCode); + } + return TransferToNapiErrNo(errCode); +} + +int32_t RdAdapter::Undo() +{ + GRD_XmlOpPositionT position = { + .tableName = this->tableName_.c_str(), + .elementId = nullptr, + }; + + char *modify = nullptr; + int32_t errCode = RdUtils::RdDocUndo(this->GetDBStore()->GetDB(), &position, &modify); + if (errCode != GRD_OK) { + LOG_ERROR("RdDocUndo go wrong, errCode = %{public}d", errCode); + } + (void)RdUtils::RdFreeValue(modify); + return TransferToNapiErrNo(errCode); +} + +int32_t RdAdapter::Redo() +{ + GRD_XmlOpPositionT position = { + .tableName = this->tableName_.c_str(), + .elementId = nullptr, + }; + + char *modify = nullptr; + int32_t errCode = RdUtils::RdDocRedo(this->GetDBStore()->GetDB(), &position, &modify); + if (errCode != GRD_OK) { + LOG_ERROR("RdDocRedo go wrong, errCode = %{public}d", errCode); + } + (void)RdUtils::RdFreeValue(modify); + return TransferToNapiErrNo(errCode); +} + +int32_t RdAdapter::TransferToNapiErrNo(int32_t originNo) +{ + auto it = g_errMap.find(originNo); + if (it == g_errMap.end()) { + return Status::DB_ERROR; + } + return it->second; +} + +} // namespace OHOS::CollaborationEdit diff --git a/data_object/frameworks/innerkitsimpl/collaboration_edit/src/rd_utils.cpp b/data_object/frameworks/innerkitsimpl/collaboration_edit/src/rd_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..684a52f6d21b067f432b984ae12659e9bf0f3b2d --- /dev/null +++ b/data_object/frameworks/innerkitsimpl/collaboration_edit/src/rd_utils.cpp @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2024 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 "RdUtils" +#include "rd_utils.h" + +#include "grd_api_manager.h" +#include "grd_error.h" + +namespace OHOS::CollaborationEdit { + +static GRD_APIInfo GRD_ApiInfo; + +// 1. Database open/close library interface encapsulation +int RdUtils::RdDbOpen(const char *dbFile, const char *configStr, uint32_t flags, GRD_DB **db) +{ + if (GRD_ApiInfo.DBOpenApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.DBOpenApi == nullptr) { + return GRD_NOT_SUPPORT; + } + return GRD_ApiInfo.DBOpenApi(dbFile, configStr, flags, db); +} + +int RdUtils::RdDbClose(GRD_DB *db, uint32_t flags) +{ + if (GRD_ApiInfo.DBCloseApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.DBCloseApi == nullptr) { + return GRD_NOT_SUPPORT; + } + return GRD_ApiInfo.DBCloseApi(db, flags); +} + +int RdUtils::RdRegisterEquipId(GRD_DB *db, GrdEquipIdGetFuncT func) +{ + if (GRD_ApiInfo.RegisterEquipIdApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.RegisterEquipIdApi == nullptr) { + return GRD_NOT_SUPPORT; + } + return GRD_ApiInfo.RegisterEquipIdApi(db, func); +} + +// 2. Node operation interface encapsulation +int32_t RdUtils::RdInsertElements(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, uint32_t index, + GRD_DocNodeInfoT *nodeInfo, GRD_ElementIdT **outElementId) +{ + if (GRD_ApiInfo.InsertElementsApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.InsertElementsApi == nullptr) { + return GRD_NOT_SUPPORT; + } + return GRD_ApiInfo.InsertElementsApi(db, elementAddr, index, nodeInfo, outElementId); +} + +int32_t RdUtils::RdDeleteElements(GRD_DB *db, const char *tableName, const GRD_ElementIdT *elementId, uint32_t index, + uint32_t length) +{ + if (GRD_ApiInfo.DeleteElementsApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.DeleteElementsApi == nullptr) { + return GRD_NOT_SUPPORT; + } + return GRD_ApiInfo.DeleteElementsApi(db, tableName, elementId, index, length); +} + +int32_t RdUtils::RdGetElements(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, uint32_t index, uint32_t length, + char **respXml) +{ + if (GRD_ApiInfo.GetElementsApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.GetElementsApi == nullptr) { + return GRD_NOT_SUPPORT; + } + return GRD_ApiInfo.GetElementsApi(db, elementAddr, index, length, respXml); +} + +int32_t RdUtils::RdFragmentToString(GRD_DB *db, const char *tableName, const GRD_ElementIdT *elementId, + char **replyJson) +{ + if (GRD_ApiInfo.FragmentToStringApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.FragmentToStringApi == nullptr) { + return GRD_NOT_SUPPORT; + } + return GRD_ApiInfo.FragmentToStringApi(db, tableName, elementId, replyJson); +} + +// 3. XmlElement attribute operation interface encapsulation +int32_t RdUtils::RdElementSetAttribute( + GRD_DB *db, GRD_XmlOpPositionT *elementAddr, const char *attributeName, const char *attributeValue, uint32_t flags) +{ + if (GRD_ApiInfo.ElementSetAttrApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.ElementSetAttrApi == nullptr) { + return GRD_NOT_SUPPORT; + } + return GRD_ApiInfo.ElementSetAttrApi(db, elementAddr, attributeName, attributeValue, flags); +} + +int32_t RdUtils::RdElementRemoveAttribute(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, const char *attributeName) +{ + if (GRD_ApiInfo.ElementRemoveAttrApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.ElementRemoveAttrApi == nullptr) { + return GRD_NOT_SUPPORT; + } + return GRD_ApiInfo.ElementRemoveAttrApi(db, elementAddr, attributeName); +} + +int32_t RdUtils::RdElementGetAttributes(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, char **allAttributes) +{ + if (GRD_ApiInfo.ElementGetAttrsApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.ElementGetAttrsApi == nullptr) { + return GRD_NOT_SUPPORT; + } + return GRD_ApiInfo.ElementGetAttrsApi(db, elementAddr, allAttributes); +} + +// 4. Text operation interface encapsulation +int32_t RdUtils::RdTextInsert( + GRD_DB *db, GRD_XmlOpPositionT *opPos, uint32_t index, const char *content, const char *formatStr) +{ + if (GRD_ApiInfo.TextInsertApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.TextInsertApi == nullptr) { + return GRD_NOT_SUPPORT; + } + return GRD_ApiInfo.TextInsertApi(db, opPos, index, content, formatStr); +} + +int32_t RdUtils::RdTextDelete(GRD_DB *db, GRD_XmlOpPositionT *opPos, uint32_t index, uint32_t length) +{ + if (GRD_ApiInfo.TextDeleteApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.TextDeleteApi == nullptr) { + return GRD_NOT_SUPPORT; + } + return GRD_ApiInfo.TextDeleteApi(db, opPos, index, length); +} + +int32_t RdUtils::RdTextFormat( + GRD_DB *db, GRD_XmlOpPositionT *opPos, uint32_t index, uint32_t length, const char *formatStr) +{ + if (GRD_ApiInfo.TextFormatApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.TextFormatApi == nullptr) { + return GRD_NOT_SUPPORT; + } + return GRD_ApiInfo.TextFormatApi(db, opPos, index, length, formatStr); +} + +int32_t RdUtils::RdTextGetLength(GRD_DB *db, GRD_XmlOpPositionT *opPos, uint32_t *length) +{ + if (GRD_ApiInfo.TextGetLengthApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.TextGetLengthApi == nullptr) { + return GRD_NOT_SUPPORT; + } + return GRD_ApiInfo.TextGetLengthApi(db, opPos, length); +} + +int32_t RdUtils::RdTextReadInStrMode(GRD_DB *db, GRD_XmlOpPositionT *opPos, char **value) +{ + if (GRD_ApiInfo.TextReadInStrModeApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.TextReadInStrModeApi == nullptr) { + return GRD_NOT_SUPPORT; + } + return GRD_ApiInfo.TextReadInStrModeApi(db, opPos, value); +} + +int32_t RdUtils::RdTextReadInDeltaMode( + GRD_DB *db, GRD_XmlOpPositionT *opPos, const char *snapshot, const char *snapshotPerv, char **delta) +{ + if (GRD_ApiInfo.TextReadInDeltaModeApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.TextReadInDeltaModeApi == nullptr) { + return GRD_NOT_SUPPORT; + } + return GRD_ApiInfo.TextReadInDeltaModeApi(db, opPos, snapshot, snapshotPerv, delta); +} + +// 5. Undo/Redo operation interface encapsulation +int32_t RdUtils::RdDocUndoManager(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, GRD_UndoParamT *param) +{ + if (GRD_ApiInfo.DocUndoManagerApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + if (GRD_ApiInfo.DocUndoManagerApi == nullptr) { + return GRD_NOT_SUPPORT; + } + } + + return GRD_ApiInfo.DocUndoManagerApi(db, elementAddr, param); +} + +int32_t RdUtils::RdDocUndo(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, char **modify) +{ + if (GRD_ApiInfo.DocUndoApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + if (GRD_ApiInfo.DocUndoApi == nullptr) { + return GRD_NOT_SUPPORT; + } + } + + return GRD_ApiInfo.DocUndoApi(db, elementAddr, modify); +} + +int32_t RdUtils::RdDocRedo(GRD_DB *db, GRD_XmlOpPositionT *elementAddr, char **modify) +{ + if (GRD_ApiInfo.DocRedoApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + if (GRD_ApiInfo.DocRedoApi == nullptr) { + return GRD_NOT_SUPPORT; + } + } + + return GRD_ApiInfo.DocRedoApi(db, elementAddr, modify); +} + +int32_t RdUtils::RdDocStopCapturing(GRD_DB *db, GRD_XmlOpPositionT *elementAddr) +{ + if (GRD_ApiInfo.DocStopCapturingApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + if (GRD_ApiInfo.DocStopCapturingApi == nullptr) { + return GRD_NOT_SUPPORT; + } + } + + return GRD_ApiInfo.DocStopCapturingApi(db, elementAddr); +} + +// Last. Memory free and others +void RdUtils::RdFreeElementId(GRD_ElementIdT *outElementId) +{ + if (GRD_ApiInfo.FreeElementIdApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.FreeElementIdApi == nullptr) { + return; + } + GRD_ApiInfo.FreeElementIdApi(outElementId); +} + +int32_t RdUtils::RdFreeValue(char *value) +{ + if (GRD_ApiInfo.FreeValueApi == nullptr) { + GRD_ApiInfo = GetApiInfoInstance(); + } + if (GRD_ApiInfo.FreeValueApi == nullptr) { + return GRD_NOT_SUPPORT; + } + return GRD_ApiInfo.FreeValueApi(value); +} +} // namespace OHOS::CollaborationEdit diff --git a/data_object/frameworks/innerkitsimpl/include/adaptor/asset_change_timer.h b/data_object/frameworks/innerkitsimpl/include/adaptor/asset_change_timer.h index 8d02238a35caf4ab23d72a3ddbccafc48a6fb420..75772a366ab1a7c61bd0169f67ba89e0dbf43029 100644 --- a/data_object/frameworks/innerkitsimpl/include/adaptor/asset_change_timer.h +++ b/data_object/frameworks/innerkitsimpl/include/adaptor/asset_change_timer.h @@ -47,8 +47,6 @@ private: static std::mutex instanceMutex; static AssetChangeTimer *instance; - static constexpr size_t MAX_THREADS = 3; - static constexpr size_t MIN_THREADS = 0; static constexpr uint32_t WAIT_INTERVAL = 100; static constexpr char ASSET_SEPARATOR = '#'; }; diff --git a/data_object/frameworks/innerkitsimpl/include/adaptor/client_adaptor.h b/data_object/frameworks/innerkitsimpl/include/adaptor/client_adaptor.h index 94f73271911c1558c14496a1ad533d8692049546..695cf3dfdddf26d9531b154dee8980b6eacb4023 100644 --- a/data_object/frameworks/innerkitsimpl/include/adaptor/client_adaptor.h +++ b/data_object/frameworks/innerkitsimpl/include/adaptor/client_adaptor.h @@ -34,9 +34,6 @@ private: void OnRemoteDied(const wptr &remote) override; }; - static constexpr int32_t DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID = 1301; - static constexpr int32_t GET_SA_RETRY_TIMES = 3; - static constexpr int32_t RETRY_INTERVAL = 1; static std::shared_ptr distributedDataMgr_; static std::shared_ptr GetDistributedDataManager(); static std::mutex mutex_; diff --git a/data_object/frameworks/innerkitsimpl/include/adaptor/flat_object_storage_engine.h b/data_object/frameworks/innerkitsimpl/include/adaptor/flat_object_storage_engine.h index 83afb625e17bf1a5b2f301e4e5ff7eb4f313cd7c..3b7b6b3285c2bc8e163bb933ef32c840dcf6bca7 100644 --- a/data_object/frameworks/innerkitsimpl/include/adaptor/flat_object_storage_engine.h +++ b/data_object/frameworks/innerkitsimpl/include/adaptor/flat_object_storage_engine.h @@ -49,7 +49,6 @@ public: void NotifyStatus(const std::string &sessionId, const std::string &deviceId, const std::string &status); void NotifyChange(const std::string &sessionId, const std::map> &changedData); private: - constexpr static const char *DISTRIBUTED_DATASYNC = "ohos.permission.DISTRIBUTED_DATASYNC"; std::mutex operationMutex_{}; std::mutex watcherMutex_{}; std::shared_ptr storeManager_; diff --git a/data_object/frameworks/innerkitsimpl/include/adaptor/flat_object_store.h b/data_object/frameworks/innerkitsimpl/include/adaptor/flat_object_store.h index 56d26aa00660f71716a7db9a62457ede7e91dd1c..3b37fc22dbc41bbdc3ae131cc790392be40621db 100644 --- a/data_object/frameworks/innerkitsimpl/include/adaptor/flat_object_store.h +++ b/data_object/frameworks/innerkitsimpl/include/adaptor/flat_object_store.h @@ -54,7 +54,6 @@ private: int32_t RevokeSaveObject( const std::string &bundleName, const std::string &sessionId, const std::function &callback); std::mutex mutex_; - static constexpr uint32_t WAIT_TIME = 5; }; class FlatObjectStore { @@ -88,7 +87,6 @@ private: uint32_t Put(const std::string &sessionId, const std::string &key, std::vector value); uint32_t Get(const std::string &sessionId, const std::string &key, Bytes &value); - static constexpr const char* DISTRIBUTED_DATASYNC = "ohos.permission.DISTRIBUTED_DATASYNC"; std::shared_ptr storageEngine_; CacheManager *cacheManager_; std::mutex mutex_; diff --git a/data_object/frameworks/innerkitsimpl/include/common/object_radar_reporter.h b/data_object/frameworks/innerkitsimpl/include/common/object_radar_reporter.h index 8c87673de6a8bc6853f3ce3ac5644fb04403ba4a..2b4ae3b4e609acb0d2b160a6401131e85349c144 100644 --- a/data_object/frameworks/innerkitsimpl/include/common/object_radar_reporter.h +++ b/data_object/frameworks/innerkitsimpl/include/common/object_radar_reporter.h @@ -64,9 +64,6 @@ enum ErrorCode { GETKV_FAILED = OFFSET + 6, DB_NOT_INIT = OFFSET + 7, }; -constexpr char DOMAIN[] = "DISTDATAMGR"; -constexpr char EVENT_NAME[] = "DISTRIBUTED_DATA_OBJECT_BEHAVIOR"; -constexpr char ORG_PKG[] = "distributeddata"; class API_EXPORT RadarReporter { public: diff --git a/data_object/frameworks/innerkitsimpl/src/adaptor/asset_change_timer.cpp b/data_object/frameworks/innerkitsimpl/src/adaptor/asset_change_timer.cpp index 981c870e591c5033757604700fa976a1c7add994..0655c1f164d0406e7e468692ddff2e57d514af16 100644 --- a/data_object/frameworks/innerkitsimpl/src/adaptor/asset_change_timer.cpp +++ b/data_object/frameworks/innerkitsimpl/src/adaptor/asset_change_timer.cpp @@ -22,6 +22,8 @@ namespace OHOS::ObjectStore { std::mutex AssetChangeTimer::instanceMutex; AssetChangeTimer *AssetChangeTimer::instance = nullptr; +static constexpr size_t MAX_THREADS = 3; +static constexpr size_t MIN_THREADS = 0; AssetChangeTimer *AssetChangeTimer::GetInstance(FlatObjectStore *flatObjectStore) { diff --git a/data_object/frameworks/innerkitsimpl/src/adaptor/client_adaptor.cpp b/data_object/frameworks/innerkitsimpl/src/adaptor/client_adaptor.cpp index c2ebec12aa15e53a8cbef38d216ad228d36616dc..633d44ff13919150a966b38be291df7f2c9239cb 100644 --- a/data_object/frameworks/innerkitsimpl/src/adaptor/client_adaptor.cpp +++ b/data_object/frameworks/innerkitsimpl/src/adaptor/client_adaptor.cpp @@ -25,6 +25,9 @@ namespace OHOS::ObjectStore { std::shared_ptr ClientAdaptor::distributedDataMgr_ = nullptr; std::mutex ClientAdaptor::mutex_; +static constexpr int32_t DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID = 1301; +static constexpr int32_t GET_SA_RETRY_TIMES = 3; +static constexpr int32_t RETRY_INTERVAL = 1; using KvStoreCode = OHOS::DistributedObject::ObjectStoreService::KvStoreServiceInterfaceCode; @@ -108,7 +111,7 @@ uint32_t ClientAdaptor::RegisterClientDeathListener(const std::string &appId, sp LOG_ERROR("get distributed data manager failed"); return ERR_EXIST; } - + auto status = distributedDataMgr_->RegisterClientDeathObserver(appId, remoteObject); if (status != SUCCESS) { LOG_ERROR("RegisterClientDeathObserver failed"); diff --git a/data_object/frameworks/innerkitsimpl/src/adaptor/flat_object_storage_engine.cpp b/data_object/frameworks/innerkitsimpl/src/adaptor/flat_object_storage_engine.cpp index 1e43feb407bc548ae0d127659e47f5e84802e872..9509b219aabac8389e170887385679a0caab41c0 100644 --- a/data_object/frameworks/innerkitsimpl/src/adaptor/flat_object_storage_engine.cpp +++ b/data_object/frameworks/innerkitsimpl/src/adaptor/flat_object_storage_engine.cpp @@ -26,6 +26,8 @@ #include "object_radar_reporter.h" namespace OHOS::ObjectStore { +constexpr static const char *DISTRIBUTED_DATASYNC = "ohos.permission.DISTRIBUTED_DATASYNC"; + FlatObjectStorageEngine::~FlatObjectStorageEngine() { if (!isOpened_) { @@ -460,7 +462,7 @@ void FlatObjectStorageEngine::NotifyChange(const std::string &sessionId, } observerMap_[sessionId]->OnChanged(sessionId, data, false); } - + void Watcher::OnChange(const DistributedDB::KvStoreChangedData &data) { std::vector changedData; diff --git a/data_object/frameworks/innerkitsimpl/src/adaptor/flat_object_store.cpp b/data_object/frameworks/innerkitsimpl/src/adaptor/flat_object_store.cpp index a7b8f549a77ff451a3258e08249009ce22d3248e..aea237c529d2b7fea79a559fddc000eeb0e0c3f0 100644 --- a/data_object/frameworks/innerkitsimpl/src/adaptor/flat_object_store.cpp +++ b/data_object/frameworks/innerkitsimpl/src/adaptor/flat_object_store.cpp @@ -30,6 +30,9 @@ #include "string_utils.h" namespace OHOS::ObjectStore { +static constexpr uint32_t WAIT_TIME = 5; +static constexpr const char* DISTRIBUTED_DATASYNC = "ohos.permission.DISTRIBUTED_DATASYNC"; + FlatObjectStore::FlatObjectStore(const std::string &bundleName) { bundleName_ = bundleName; diff --git a/data_object/frameworks/innerkitsimpl/src/object_radar_reporter.cpp b/data_object/frameworks/innerkitsimpl/src/object_radar_reporter.cpp index 5d6db6247f070002cbc53bd4280f43489aea2b0d..e363a8fb15f4c5b57dc43018cbd0b8dad4414a69 100644 --- a/data_object/frameworks/innerkitsimpl/src/object_radar_reporter.cpp +++ b/data_object/frameworks/innerkitsimpl/src/object_radar_reporter.cpp @@ -16,7 +16,11 @@ #include "object_radar_reporter.h" namespace OHOS::ObjectStore { - using namespace ObjectStore; +using namespace ObjectStore; +constexpr char DOMAIN[] = "DISTDATAMGR"; +constexpr char EVENT_NAME[] = "DISTRIBUTED_DATA_OBJECT_BEHAVIOR"; +constexpr char ORG_PKG[] = "distributeddata"; + void RadarReporter::ReportStateFinished(std::string func, int32_t scene, int32_t stage, int32_t stageRes, int32_t state) { struct HiSysEventParam params[] = { diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/BUILD.gn b/data_object/frameworks/jskitsimpl/collaboration_edit/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..9e7291db9d161101f65d64aba98288feb47c29bf --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/BUILD.gn @@ -0,0 +1,79 @@ +# Copyright (c) 2024 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. +import("//build/ohos.gni") +import("//build/ohos/ace/ace.gni") + +config("collaboration_edit_config") { + visibility = [ ":*" ] + + cflags = [ + "-DHILOG_ENABLE", + "-fvisibility=hidden", + "-Oz", + ] + + include_dirs = [ + "include", + "../../innerkitsimpl/collaboration_edit/include", + ] +} + +ohos_shared_library("collaborationeditobject") { + branch_protector_ret = "pac_ret" + sanitize = { + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + + sources = [ + "../../innerkitsimpl/collaboration_edit/src/db_common.cpp", + "../../innerkitsimpl/collaboration_edit/src/db_store.cpp", + "../../innerkitsimpl/collaboration_edit/src/db_store_config.cpp", + "../../innerkitsimpl/collaboration_edit/src/db_store_manager.cpp", + "../../innerkitsimpl/collaboration_edit/src/grd_api_manager.cpp", + "../../innerkitsimpl/collaboration_edit/src/rd_adapter.cpp", + "../../innerkitsimpl/collaboration_edit/src/rd_utils.cpp", + "src/entry_point.cpp", + "src/napi_abstract_type.cpp", + "src/napi_collaboration_edit_object.cpp", + "src/napi_edit_unit.cpp", + "src/napi_error_utils.cpp", + "src/napi_node.cpp", + "src/napi_parser.cpp", + "src/napi_text.cpp", + "src/napi_undo_manager.cpp", + "src/napi_utils.cpp", + ] + + configs = [ ":collaboration_edit_config" ] + + deps = [] + + external_deps = [ + "ability_runtime:abilitykit_native", + "ability_runtime:app_context", + "ability_runtime:extensionkit_native", + "ability_runtime:napi_base_context", + "hilog:libhilog", + "kv_store:database_utils", + "kv_store:distributeddata_inner", + "napi:ace_napi", + ] + + subsystem_name = "distributeddatamgr" + part_name = "data_object" + relative_install_dir = "module/data" +} diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/include/log_print.h b/data_object/frameworks/jskitsimpl/collaboration_edit/include/log_print.h new file mode 100644 index 0000000000000000000000000000000000000000..e076eb29a9675f0a995d33a22498244ff59b9064 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/include/log_print.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 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 COLLABORATION_EDIT_LOG_PRINT_H +#define COLLABORATION_EDIT_LOG_PRINT_H + +#include "hilog/log.h" + +namespace OHOS::CollaborationEdit { +static inline OHOS::HiviewDFX::HiLogLabel LogLabel() +{ + return { LOG_CORE, 0xD001652, "CollaborationEditObject" }; +} +} // namespace OHOS::CollaborationEdit + +#define LOG_DEBUG(fmt, ...) \ + do { \ + auto lable = LogLabel(); \ + if (HiLogIsLoggable(lable.domain, lable.tag, LogLevel::LOG_DEBUG)) { \ + ((void)HILOG_IMPL(lable.type, LOG_DEBUG, lable.domain, lable.tag, \ + LOG_TAG "[%{public}s]: " fmt, __FUNCTION__, ##__VA_ARGS__)); \ + } \ + } while (0) + +#define LOG_INFO(fmt, ...) \ + do { \ + auto lable = LogLabel(); \ + if (HiLogIsLoggable(lable.domain, lable.tag, LogLevel::LOG_INFO)) { \ + ((void)HILOG_IMPL(lable.type, LOG_INFO, lable.domain, lable.tag, \ + LOG_TAG "[%{public}s]: " fmt, __FUNCTION__, ##__VA_ARGS__)); \ + } \ + } while (0) + +#define LOG_WARN(fmt, ...) \ + do { \ + auto lable = LogLabel(); \ + if (HiLogIsLoggable(lable.domain, lable.tag, LogLevel::LOG_WARN)) { \ + ((void)HILOG_IMPL(lable.type, LOG_WARN, lable.domain, lable.tag, \ + LOG_TAG "[%{public}s]: " fmt, __FUNCTION__, ##__VA_ARGS__)); \ + } \ + } while (0) + +#define LOG_ERROR(fmt, ...) \ + do { \ + auto lable = LogLabel(); \ + if (HiLogIsLoggable(lable.domain, lable.tag, LogLevel::LOG_ERROR)) { \ + ((void)HILOG_IMPL(lable.type, LOG_ERROR, lable.domain, lable.tag, \ + LOG_TAG "[%{public}s]: " fmt, __FUNCTION__, ##__VA_ARGS__)); \ + } \ + } while (0) + +#define LOG_FATAL(fmt, ...) \ + do { \ + auto lable = LogLabel(); \ + if (HiLogIsLoggable(lable.domain, lable.tag, LogLevel::LOG_FATAL)) { \ + ((void)HILOG_IMPL(lable.type, LOG_FATAL, lable.domain, lable.tag, \ + LOG_TAG "[%{public}s]: " fmt, __FUNCTION__, ##__VA_ARGS__)); \ + } \ + } while (0) + +#endif // COLLABORATION_EDIT_LOG_PRINT_H diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_abstract_type.h b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_abstract_type.h new file mode 100644 index 0000000000000000000000000000000000000000..4264bd4fa963a1bef8a29c69bd88d8775b258fcd --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_abstract_type.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 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 COLLABORATION_EDIT_ABSTRACT_TYPE_H +#define COLLABORATION_EDIT_ABSTRACT_TYPE_H + +#include "db_store.h" +#include "rd_adapter.h" + +namespace OHOS::CollaborationEdit { +class AbstractType { +public: + AbstractType(); + virtual ~AbstractType() {} + + void SetDBStore(std::shared_ptr dbStore); + std::shared_ptr GetDBStore(); + void SetTableName(std::string name); + std::string GetTableName(); + void SetID(std::optional id); + std::optional GetID(); + std::shared_ptr GetAdapter(); + + virtual int32_t GetLength() + { + return 0; + } + +private: + std::shared_ptr adapter_; +}; +} // namespace OHOS::CollaborationEdit +#endif // COLLABORATION_EDIT_ABSTRACT_TYPE_H diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_collaboration_edit_object.h b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_collaboration_edit_object.h new file mode 100644 index 0000000000000000000000000000000000000000..6e16a2da30e02c3880665e302341c7b6065e169b --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_collaboration_edit_object.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024 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 NAPI_COLLABORATION_EDIT_OBJECT_H +#define NAPI_COLLABORATION_EDIT_OBJECT_H + +#include "db_store.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "napi_undo_manager.h" +#include "napi_utils.h" + +namespace OHOS::CollaborationEdit { + +class CollaborationEditObject { +public: + CollaborationEditObject(std::string docName, ContextParam param); + ~CollaborationEditObject(); + static napi_value NewInstance(napi_env env, napi_callback_info info); + static napi_value Delete(napi_env env, napi_callback_info info); + void SetDBStore(std::shared_ptr dbStore); + std::shared_ptr GetDBStore(); + +private: + static napi_value Constructor(napi_env env); + static napi_value Initialize(napi_env env, napi_callback_info info); + + static napi_value GetEditUnit(napi_env env, napi_callback_info info); + static napi_value GetUndoRedoManager(napi_env env, napi_callback_info info); + static napi_value DeleteUndoRedoManager(napi_env env, napi_callback_info info); + static napi_value GetName(napi_env env, napi_callback_info info); + + std::string docName_; + std::shared_ptr param_; + std::shared_ptr dbStore_; +}; +} // namespace OHOS::CollaborationEdit +#endif // NAPI_COLLABORATION_EDIT_OBJECT_H diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_edit_unit.h b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_edit_unit.h new file mode 100644 index 0000000000000000000000000000000000000000..48ec6edb5df03ade3b94975d1bd226ed76d60207 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_edit_unit.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024 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 COLLABORATION_EDIT_EDIT_UNIT_H +#define COLLABORATION_EDIT_EDIT_UNIT_H + +#include "napi_abstract_type.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "napi_node.h" +#include "napi_utils.h" + +namespace OHOS::CollaborationEdit { +class EditUnit : public AbstractType { +public: + EditUnit(std::string name); + ~EditUnit(); + static napi_value NewInstance(napi_env env, napi_callback_info info, napi_value parent); + +private: + static napi_value Constructor(napi_env env); + static napi_value Initialize(napi_env env, napi_callback_info info); + + static napi_value InsertNodes(napi_env env, napi_callback_info info); + static napi_value Delete(napi_env env, napi_callback_info info); + static napi_value GetChildren(napi_env env, napi_callback_info info); + static napi_value GetJsonResult(napi_env env, napi_callback_info info); + static napi_value GetName(napi_env env, napi_callback_info info); + + std::string name_; +}; +} +#endif // COLLABORATION_EDIT_EDIT_UNIT_H diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_errno.h b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_errno.h new file mode 100644 index 0000000000000000000000000000000000000000..be1894837b48dc3aae2f3dd16079b1309742848e --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_errno.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 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 COLLABORATION_EDIT_NAPI_ERRNO +#define COLLABORATION_EDIT_NAPI_ERRNO + +namespace OHOS::CollaborationEdit { +constexpr const int OK = 0; // used for internal method +constexpr const int ERR = -1; +static constexpr const int EDIT_ERROR_OFFSET = 15410000; + +enum Status : int32_t { + SUCCESS = 0, + INVALID_ARGUMENT = 401, + INTERNAL_ERROR = EDIT_ERROR_OFFSET, + UNSUPPORTED_OPERATION = EDIT_ERROR_OFFSET + 1, // 15410001 + INDEX_OUT_OF_RANGE, // 15410002 + DB_ERROR, // 15410003 +}; +} // namespace OHOS::CollaborationEdit +#endif // COLLABORATION_EDIT_NAPI_ERRNO diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_error_utils.h b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_error_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..86353096cf640a4d148792cc4fb82e20c3a5e661 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_error_utils.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024 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 COLLABORATION_EDIT_NAPI_ERROR_UTILS_H +#define COLLABORATION_EDIT_NAPI_ERROR_UTILS_H + +#include + +#include "js_native_api.h" +#include "log_print.h" +#include "napi_errno.h" +#include "napi/native_common.h" + +namespace OHOS::CollaborationEdit { + +#define RETVAL_NOTHING + +/* check condition, return and logging if condition not true. */ +#define ASSERT(condition, message, retVal) \ + do { \ + if (!(condition)) { \ + LOG_ERROR("test (" #condition ") go wrong: " message); \ + return retVal; \ + } \ + } while (0) + +#define ASSERT_VOID(condition, message) \ + do { \ + if (!(condition)) { \ + LOG_ERROR("test (" #condition ") go wrong: " message); \ + return; \ + } \ + } while (0) + +#define ASSERT_THROW_BASE(env, condition, errCode, message, retVal) \ + do { \ + if (!(condition)) { \ + ThrowNapiError(env, errCode, message); \ + return retVal; \ + } \ + } while (0) + +#define ASSERT_THROW(env, condition, errCode, message) ASSERT_THROW_BASE(env, condition, errCode, message, nullptr) +#define ASSERT_THROW_VOID(env, condition, errCode, message) \ + ASSERT_THROW_BASE(env, condition, errCode, message, RETVAL_NOTHING) + +void ThrowNapiError(napi_env env, int32_t errCode, const std::string &errMessage); + +} // namespace OHOS::CollaborationEdit +#endif // COLLABORATION_EDIT_NAPI_ERROR_UTILS_H diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_node.h b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_node.h new file mode 100644 index 0000000000000000000000000000000000000000..946e8164c57c845e4f4416157f1ead30377c29a2 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_node.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024 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 COLLABORATION_EDIT_NODE_H +#define COLLABORATION_EDIT_NODE_H + +#include "napi_abstract_type.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "napi_text.h" +#include "napi_utils.h" + +namespace OHOS::CollaborationEdit { +class Node : public AbstractType { +public: + Node(std::string name); + ~Node(); + static void Init(napi_env env, napi_value exports); + static napi_value Constructor(napi_env env); + std::string InnerGetName(); + +private: + static napi_value New(napi_env env, napi_callback_info info); + + static napi_value GetName(napi_env env, napi_callback_info info); + static napi_value GetUniqueId(napi_env env, napi_callback_info info); + static napi_value InsertNodes(napi_env env, napi_callback_info info); + static napi_value Delete(napi_env env, napi_callback_info info); + static napi_value GetChildren(napi_env env, napi_callback_info info); + static napi_value GetJsonResult(napi_env env, napi_callback_info info); + + static napi_value InsertTexts(napi_env env, napi_callback_info info); + static napi_value SetAttributes(napi_env env, napi_callback_info info); + static napi_value RemoveAttributes(napi_env env, napi_callback_info info); + static napi_value GetAttributes(napi_env env, napi_callback_info info); + + std::string name_; +}; +} +#endif // COLLABORATION_EDIT_NODE_H diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_parser.h b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..c2765ae7cb4e6b3f8cf1a4bc66068f676c5f3c73 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_parser.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 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 COLLABORATION_EDIT_PARSER_H +#define COLLABORATION_EDIT_PARSER_H + +#include +#include +#include + +#include + +#include "napi_abstract_type.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" + +namespace OHOS::CollaborationEdit { +class Parser { +public: + static void Stringsplit(std::string str, const char split, std::vector &res); + static bool ConvertToUint64(std::string str, uint64_t &out); + static std::optional ConvertStrToID(std::string str); + static int ParseJsonStrToJsChildren( + napi_env env, const std::string &nodeListStr, AbstractType *parent, napi_value &out); + static int ParseFromAttrsJsonStr(napi_env env, const std::string &jsonStr, napi_value &out); + static int ParseJsFormatToStr(napi_env env, napi_value jsFormat, std::string &out); + static int ParseVariantJsValueToStr(napi_env env, napi_value input, std::string &out); +}; +} // namespace OHOS::CollaborationEdit +#endif // COLLABORATION_EDIT_PARSER_H diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_text.h b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_text.h new file mode 100644 index 0000000000000000000000000000000000000000..4f5462a5693d8f6bdf7bdee2ca2567c7b4052938 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_text.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 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 COLLABORATION_EDIT_TEXT_H +#define COLLABORATION_EDIT_TEXT_H + +#include "napi_abstract_type.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "napi_utils.h" + +namespace OHOS::CollaborationEdit { +class Text : public AbstractType { +public: + Text(); + ~Text(); + static void Init(napi_env env, napi_value exports); + static napi_value Constructor(napi_env env); + +private: + static napi_value New(napi_env env, napi_callback_info info); + + static napi_value GetUniqueId(napi_env env, napi_callback_info info); + static napi_value Insert(napi_env env, napi_callback_info info); + static napi_value Delete(napi_env env, napi_callback_info info); + static napi_value Format(napi_env env, napi_callback_info info); + static napi_value GetPlainText(napi_env env, napi_callback_info info); + static napi_value GetJsonResult(napi_env env, napi_callback_info info); +}; +} +#endif // COLLABORATION_EDIT_TEXT_H diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_undo_manager.h b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_undo_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..28c02abf27a398e3f09068fc90ea789146dd4e38 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_undo_manager.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024 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 NAPI_COLLABORATION_UNDO_MANAGER_H +#define NAPI_COLLABORATION_UNDO_MANAGER_H + +#include "db_store.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "napi_utils.h" +#include "rd_adapter.h" + +namespace OHOS::CollaborationEdit { + +class UndoManager { +public: + UndoManager(std::string tableName, int64_t captureTimeout); + ~UndoManager(); + static napi_value NewInstance(napi_env env, napi_callback_info info); + + std::string GetTableName(); + int64_t GetCaptureTimeout(); + std::shared_ptr GetAdapter(); + void SetDBStore(std::shared_ptr dbStore); + +private: + static napi_value Constructor(napi_env env); + static napi_value Initialize(napi_env env, napi_callback_info info); + + static napi_value Undo(napi_env env, napi_callback_info info); + static napi_value Redo(napi_env env, napi_callback_info info); + + std::shared_ptr adapter_; + int64_t captureTimeout_; +}; +} // namespace OHOS::CollaborationEdit +#endif // NAPI_COLLABORATION_UNDO_MANAGER_H diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_utils.h b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..b7d7b1abe1511533020527c35c5907363af9c01d --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/include/napi_utils.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2024 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 COLLABORATION_EDIT_NAPI_UTILS_H +#define COLLABORATION_EDIT_NAPI_UTILS_H + +#include +#include + +#include "ability.h" +#include "napi_base_context.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" + +namespace OHOS::CollaborationEdit { +struct ContextParam { + std::string bundleName; + std::string moduleName; + std::string baseDir; + int32_t area; + bool isSystemApp = false; + bool isStageMode = true; +}; + +class NapiUtils final { +public: + using Descriptor = std::function()>; + struct JsFeatureSpace { + const char *spaceName; + const char *nameBase64; + bool isComponent; + }; + + static napi_status GetValue(napi_env env, napi_value input, napi_value &out); + static napi_status SetValue(napi_env env, napi_value input, napi_value &out); + /* napi_value <-> bool */ + static napi_status GetValue(napi_env env, napi_value input, bool &out); + + static napi_status SetValue(napi_env env, const bool &input, napi_value &out); + + /* napi_value <-> int32_t */ + static napi_status GetValue(napi_env env, napi_value input, int32_t &out); + + static napi_status SetValue(napi_env env, const int32_t &input, napi_value &out); + + /* napi_value <-> uint32_t */ + static napi_status GetValue(napi_env env, napi_value input, uint32_t &out); + + static napi_status SetValue(napi_env env, const uint32_t &input, napi_value &out); + + /* napi_value <-> int64_t */ + static napi_status GetValue(napi_env env, napi_value input, int64_t &out); + + static napi_status SetValue(napi_env env, const int64_t &input, napi_value &out); + + /* napi_value <-> double */ + static napi_status GetValue(napi_env env, napi_value input, double &out); + + static napi_status SetValue(napi_env env, const double &input, napi_value &out); + + /* napi_value <-> std::string */ + static napi_status GetValue(napi_env env, napi_value input, std::string &out); + + static napi_status SetValue(napi_env env, const std::string &input, napi_value &out); + + /* napi_value <-> std::vector */ + static napi_status GetValue(napi_env env, napi_value input, std::vector &out); + + static napi_status SetValue(napi_env env, const std::vector &input, napi_value &out); + + /* napi_value <-> std::vector */ + static napi_status GetValue(napi_env env, napi_value input, std::vector &out); + + static napi_status SetValue(napi_env env, const std::vector &input, napi_value &out); + + /* napi_value <-> std::vector */ + static napi_status GetValue(napi_env env, napi_value input, std::vector &out); + + static napi_status SetValue(napi_env env, const std::vector &input, napi_value &out); + + /* napi_value <-> std::vector */ + static napi_status GetValue(napi_env env, napi_value input, std::vector &out); + + static napi_status SetValue(napi_env env, const std::vector &input, napi_value &out); + + /* napi_value <-> std::vector */ + static napi_status GetValue(napi_env env, napi_value input, std::vector &out); + + static napi_status SetValue(napi_env env, const std::vector &input, napi_value &out); + + /* napi_value <-> std::vector */ + static napi_status GetValue(napi_env env, napi_value input, std::vector &out); + + static napi_status SetValue(napi_env env, const std::vector &input, napi_value &out); + + /* napi_value <-> std::map */ + static napi_status GetValue(napi_env env, napi_value input, std::map &out); + + static napi_status SetValue(napi_env env, const std::map &input, napi_value &out); + + static napi_status GetCurrentAbilityParam(napi_env env, ContextParam ¶m); + + static napi_status GetValue(napi_env env, napi_value input, ContextParam ¶m); + + static bool IsNull(napi_env env, napi_value value); + + static const std::optional GetJsFeatureSpace(const std::string &name); + + /* napi_define_class wrapper */ + static napi_value DefineClass(napi_env env, const std::string &spaceName, const std::string &className, + const Descriptor &descriptor, napi_callback ctor); + + static napi_value GetClass(napi_env env, const std::string &spaceName, const std::string &className); + + template + static inline napi_status GetNamedProperty( + napi_env env, napi_value input, const std::string &prop, T &value, bool optional = false) + { + auto [status, jsValue] = GetInnerValue(env, input, prop, optional); + return (jsValue == nullptr) ? status : GetValue(env, jsValue, value); + }; + +private: + enum { + /* std::map to js::tuple */ + TUPLE_KEY = 0, + TUPLE_VALUE, + TUPLE_SIZE + }; + static std::pair GetInnerValue( + napi_env env, napi_value input, const std::string &prop, bool optional); +}; +} // namespace OHOS::CollaborationEdit +#endif // COLLABORATION_EDIT_NAPI_UTILS_H diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/src/entry_point.cpp b/data_object/frameworks/jskitsimpl/collaboration_edit/src/entry_point.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7180c862c9b7154681a39ad0a8e9d819444e9630 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/src/entry_point.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024 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 "EntryPoint" + +#include "log_print.h" +#include "napi_collaboration_edit_object.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "napi_node.h" +#include "napi_text.h" + +using namespace OHOS::CollaborationEdit; + +static napi_value Init(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("getCollaborationEditObject", CollaborationEditObject::NewInstance), + DECLARE_NAPI_FUNCTION("deleteCollaborationEditObject", CollaborationEditObject::Delete), + }; + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + Node::Init(env, exports); + Text::Init(env, exports); + return exports; +} + +static __attribute__((constructor)) void RegisterModule() +{ + static napi_module module = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "data.collaborationEditObject", + .nm_priv = ((void *)0), + .reserved = {0} + }; + napi_module_register(&module); + LOG_INFO("module register data.collaborationEditObject"); +} diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_abstract_type.cpp b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_abstract_type.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bc77bf5871d788ae0b42d297020e7de5be7119c2 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_abstract_type.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024 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 "AbstractType" + +#include "napi_abstract_type.h" + +#include "log_print.h" + +namespace OHOS::CollaborationEdit { +AbstractType::AbstractType() +{ + this->adapter_ = std::make_shared(); +} + +void AbstractType::SetDBStore(std::shared_ptr dbStore) +{ + this->adapter_->SetDBStore(dbStore); +} + +std::shared_ptr AbstractType::GetDBStore() +{ + return this->adapter_->GetDBStore(); +} + +void AbstractType::SetTableName(std::string name) +{ + this->adapter_->SetTableName(name); +} + +std::string AbstractType::GetTableName() +{ + return this->adapter_->GetTableName(); +} + +void AbstractType::SetID(std::optional id) +{ + this->adapter_->SetID(id); +} + +std::optional AbstractType::GetID() +{ + return this->adapter_->GetID(); +} + +std::shared_ptr AbstractType::GetAdapter() +{ + return this->adapter_; +} +} // namespace OHOS::CollaborationEdit diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_collaboration_edit_object.cpp b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_collaboration_edit_object.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e4f751ab72640c939571b88e72d0db278e9e8100 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_collaboration_edit_object.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2024 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 "CollaborationEditObject" + +#include "napi_collaboration_edit_object.h" + +#include "db_store_config.h" +#include "db_store_manager.h" +#include "napi_edit_unit.h" +#include "napi_error_utils.h" + +namespace OHOS::CollaborationEdit { + +CollaborationEditObject::CollaborationEditObject(std::string docName, ContextParam param) + : docName_(docName), param_(std::make_shared(std::move(param))) +{} + +CollaborationEditObject::~CollaborationEditObject() +{} + +napi_value CollaborationEditObject::Initialize(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + ContextParam context; + napi_status status = NapiUtils::GetValue(env, argv[0], context); + ASSERT_THROW_BASE(env, status == napi_ok, Status::INVALID_ARGUMENT, "read context param go wrong", self); + std::string docName; + status = NapiUtils::GetNamedProperty(env, argv[1], "name", docName); + ASSERT_THROW_BASE(env, status == napi_ok, Status::INVALID_ARGUMENT, "read docName param go wrong", self); + ASSERT_THROW_BASE(env, !docName.empty(), Status::INVALID_ARGUMENT, "Param Error: invalid name", self); + std::string dbFilePath = context.baseDir + "/" + docName; + DBStoreConfig config(dbFilePath, docName); + std::shared_ptr dbStore = DBStoreManager::GetInstance().GetDBStore(config); + if (dbStore == nullptr) { + ThrowNapiError(env, Status::INTERNAL_ERROR, "open doc go wrong"); + return self; + } + + CollaborationEditObject *editObject = new (std::nothrow) CollaborationEditObject(docName, context); + editObject->SetDBStore(dbStore); + auto finalize = [](napi_env env, void *data, void *hint) { + CollaborationEditObject *editObject = reinterpret_cast(data); + delete editObject; + }; + napi_wrap(env, self, editObject, finalize, nullptr, nullptr); + return self; +} + +napi_value CollaborationEditObject::Constructor(napi_env env) +{ + auto lambda = []() -> std::vector { + std::vector properties = { + DECLARE_NAPI_FUNCTION("getEditUnit", GetEditUnit), + DECLARE_NAPI_FUNCTION("getUndoRedoManager", GetUndoRedoManager), + DECLARE_NAPI_FUNCTION("deleteUndoRedoManager", DeleteUndoRedoManager), + DECLARE_NAPI_FUNCTION("getName", GetName), + }; + return properties; + }; + return NapiUtils::DefineClass( + env, "ohos.data.collaborationEditObject", "CollaborationEditObject", lambda, Initialize); +} + +napi_value CollaborationEditObject::NewInstance(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = {nullptr}; + napi_value editObject = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr)); + + napi_status status = napi_new_instance(env, Constructor(env), argc, argv, &editObject); + if (editObject == nullptr || status != napi_ok) { + LOG_ERROR("[NewInstance] new instance go wrong"); + } + return editObject; +} + +napi_value CollaborationEditObject::GetEditUnit(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + CollaborationEditObject *editObject = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&editObject))); + napi_value napiEditUnit = EditUnit::NewInstance(env, info, self); + EditUnit *editUnit = nullptr; + napi_status status = napi_unwrap(env, napiEditUnit, reinterpret_cast(&editUnit)); + if (status != napi_ok || editUnit == nullptr) { + LOG_ERROR("unwrap EditUnit go wrong, status = %{public}d", status); + return nullptr; + } + editUnit->SetDBStore(editObject->GetDBStore()); + return napiEditUnit; +} + +napi_value CollaborationEditObject::GetUndoRedoManager(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + CollaborationEditObject *editObject = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&editObject))); + napi_value jsUndoManager = UndoManager::NewInstance(env, info); + UndoManager *undoManager = nullptr; + napi_status status = napi_unwrap(env, jsUndoManager, reinterpret_cast(&undoManager)); + if (status != napi_ok || undoManager == nullptr) { + LOG_ERROR("unwrap UndoManager go wrong, status = %{public}d", status); + return nullptr; + } + undoManager->SetDBStore(editObject->GetDBStore()); + int32_t retCode = undoManager->GetAdapter()->CreateUndoManager(undoManager->GetCaptureTimeout()); + if (retCode != SUCCESS) { + ThrowNapiError(env, retCode, "create undo manager go wrong."); + return nullptr; + } + return jsUndoManager; +} + +napi_value CollaborationEditObject::DeleteUndoRedoManager(napi_env env, napi_callback_info info) +{ + return nullptr; +} + +napi_value CollaborationEditObject::GetName(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); + CollaborationEditObject *editObject = nullptr; + napi_status status = napi_unwrap(env, self, reinterpret_cast(&editObject)); + if (status != napi_ok) { + ThrowNapiError(env, status, "unwrap object go wrong"); + return nullptr; + } + napi_value result; + NapiUtils::SetValue(env, editObject->docName_, result); + return result; +} + +napi_value CollaborationEditObject::Delete(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + ContextParam context; + napi_status status = NapiUtils::GetValue(env, argv[0], context); + ASSERT_THROW_BASE(env, status == napi_ok, Status::INVALID_ARGUMENT, "read context param go wrong", self); + std::string docName; + status = NapiUtils::GetNamedProperty(env, argv[1], "name", docName); + ASSERT_THROW_BASE(env, status == napi_ok, Status::INVALID_ARGUMENT, "read docName param go wrong", self); + ASSERT_THROW_BASE(env, !docName.empty(), Status::INVALID_ARGUMENT, "Param Error: invalid name", self); + std::string dbFilePath = context.baseDir + "/" + docName; + DBStoreConfig config(dbFilePath, docName); + int ret = DBStoreManager::GetInstance().DeleteDBStore(config); + if (ret != 0) { + ThrowNapiError(env, Status::INTERNAL_ERROR, "remove dir go wrong"); + } + return nullptr; +} + +void CollaborationEditObject::SetDBStore(std::shared_ptr dbStore) +{ + this->dbStore_ = dbStore; +} + +std::shared_ptr CollaborationEditObject::GetDBStore() +{ + return this->dbStore_; +} +} // namespace OHOS::CollaborationEdit diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_edit_unit.cpp b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_edit_unit.cpp new file mode 100644 index 0000000000000000000000000000000000000000..38317537792598e21811beddd16ea4ca19378e7e --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_edit_unit.cpp @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2024 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 "EditUnit" + +#include "napi_edit_unit.h" + +#include "napi_collaboration_edit_object.h" +#include "napi_error_utils.h" +#include "napi_parser.h" + +namespace OHOS::CollaborationEdit { +EditUnit::EditUnit(std::string name) : AbstractType(), name_(name) +{} + +EditUnit::~EditUnit() +{} + +napi_value EditUnit::Initialize(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + std::string name; + napi_status status = NapiUtils::GetValue(env, argv[0], name); + ASSERT_THROW_BASE(env, status == napi_ok, Status::INVALID_ARGUMENT, "read name param go wrong", self); + ASSERT_THROW_BASE(env, !name.empty(), Status::INVALID_ARGUMENT, "Param Error: invalid name", self); + name = std::to_string(LABEL_FRAGMENT) + "_" + name; + EditUnit *editUnit = new (std::nothrow) EditUnit(name); + editUnit->SetTableName(name); + auto finalize = [](napi_env env, void *data, void *hint) { + EditUnit *editUnit = reinterpret_cast(data); + delete editUnit; + }; + napi_wrap(env, self, editUnit, finalize, nullptr, nullptr); + return self; +} + +napi_value EditUnit::Constructor(napi_env env) +{ + auto lambda = []() -> std::vector { + std::vector properties = { + DECLARE_NAPI_FUNCTION("insertNodes", InsertNodes), + DECLARE_NAPI_FUNCTION("delete", Delete), + DECLARE_NAPI_FUNCTION("getChildren", GetChildren), + DECLARE_NAPI_FUNCTION("getJsonResult", GetJsonResult), + DECLARE_NAPI_FUNCTION("getName", GetName), + }; + return properties; + }; + return NapiUtils::DefineClass( + env, "ohos.data.collaborationEditObject", "EditUnit", lambda, Initialize); +} + +napi_value EditUnit::NewInstance(napi_env env, napi_callback_info info, napi_value parent) +{ + size_t argc = 1; + napi_value argv[1] = {nullptr}; + napi_value editUnit = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr)); + napi_status status = napi_new_instance(env, Constructor(env), argc, argv, &editUnit); + if (editUnit == nullptr || status != napi_ok) { + LOG_ERROR("new instance go wrong"); + } + return editUnit; +} + +napi_value EditUnit::GetName(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); + EditUnit *editUnit = nullptr; + napi_status status = napi_unwrap(env, self, reinterpret_cast(&editUnit)); + if (status != napi_ok || editUnit == nullptr) { + LOG_ERROR("unwrap editUnit go wrong, status = %{public}d", status); + return nullptr; + } + std::string name = editUnit->name_; + if (name.compare(0, NUMBER_OF_CHARS_IN_LABEL_PREFIX, std::to_string(LABEL_FRAGMENT) + "_") == 0) { + name = name.substr(NUMBER_OF_CHARS_IN_LABEL_PREFIX); + } + napi_value result; + NapiUtils::SetValue(env, name, result); + return result; +} + +napi_value EditUnit::InsertNodes(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + EditUnit *editUnit = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&editUnit))); + ASSERT(editUnit != nullptr, "unwrap self go wrong.", nullptr); + int64_t index = 0; + napi_status status = NapiUtils::GetValue(env, argv[0], index); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Read index go wrong."); + ASSERT_THROW(env, index >= 0, Status::INVALID_ARGUMENT, "Param Error: Invalid index."); + bool isArray = false; + NAPI_CALL(env, napi_is_array(env, argv[1], &isArray)); + ASSERT_THROW(env, isArray, Status::INVALID_ARGUMENT, "Param Error: The nodes must be an array."); + uint32_t length = 0; + NAPI_CALL(env, napi_get_array_length(env, argv[1], &length)); + for (uint32_t i = 0; i < length; i++) { + napi_value jsNode = nullptr; + NAPI_CALL(env, napi_get_element(env, argv[1], i, &jsNode)); + Node *tempNode = nullptr; + NAPI_CALL(env, napi_unwrap(env, jsNode, reinterpret_cast(&tempNode))); + auto [retCode, id] = editUnit->GetAdapter()->InsertNode(index + i, tempNode->InnerGetName()); + if (retCode != SUCCESS || !id.has_value()) { + ThrowNapiError(env, retCode, "InsertNodes go wrong."); + return nullptr; + } + tempNode->SetID(id); + tempNode->SetTableName(editUnit->GetTableName()); + tempNode->SetDBStore(editUnit->GetDBStore()); + } + LOG_INFO("insert nodes successfully."); + return nullptr; +} + +napi_value EditUnit::Delete(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + EditUnit *editUnit = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&editUnit))); + ASSERT(editUnit != nullptr, "unwrap self go wrong.", nullptr); + int64_t index = 0; + napi_status status = NapiUtils::GetValue(env, argv[0], index); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Read index go wrong."); + ASSERT_THROW(env, index >= 0, Status::INVALID_ARGUMENT, "Param Error: Invalid index."); + int64_t length = 0; + status = NapiUtils::GetValue(env, argv[1], length); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Read length go wrong."); + ASSERT_THROW(env, length > 0, Status::INVALID_ARGUMENT, "Param Error: Invalid length."); + + int32_t retCode = editUnit->GetAdapter()->DeleteChildren(index, length); + if (retCode != SUCCESS) { + ThrowNapiError(env, retCode, "Delete Nodes go wrong."); + } + return nullptr; +} + +napi_value EditUnit::GetChildren(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + EditUnit *editUnit = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&editUnit))); + ASSERT(editUnit != nullptr, "unwrap self go wrong.", nullptr); + int64_t start = 0; + napi_status status = NapiUtils::GetValue(env, argv[0], start); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Read start index go wrong."); + ASSERT_THROW(env, start >= 0, Status::INVALID_ARGUMENT, "Param Error: Invalid start."); + int64_t end = 0; + status = NapiUtils::GetValue(env, argv[1], end); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Read end index go wrong."); + ASSERT_THROW(env, end >= 0, Status::INVALID_ARGUMENT, "Param Error: Invalid end."); + ASSERT_THROW(env, end > start, Status::INVALID_ARGUMENT, "Param Error: end should be greater than start."); + + auto [retCode, result] = editUnit->GetAdapter()->GetChildren(start, end - start); + if (retCode != SUCCESS) { + ThrowNapiError(env, retCode, "Get Children go wrong."); + return nullptr; + } + // transfer string to node array + napi_value output = nullptr; + int ret = Parser::ParseJsonStrToJsChildren(env, result, editUnit, output); + if (ret != OK) { + ThrowNapiError(env, Status::INTERNAL_ERROR, "convert result go wrong."); + return nullptr; + } + return output; +} + +napi_value EditUnit::GetJsonResult(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); + EditUnit *editUnit = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&editUnit))); + ASSERT(editUnit != nullptr, "unwrap self go wrong.", nullptr); + auto [retCode, result] = editUnit->GetAdapter()->GetJsonString(); + if (retCode != SUCCESS) { + ThrowNapiError(env, retCode, "toString go wrong."); + return nullptr; + } + napi_value output = nullptr; + napi_status status = NapiUtils::SetValue(env, result, output); + if (status != napi_ok || output == nullptr) { + ThrowNapiError(env, Status::INTERNAL_ERROR, "create output string go wrong."); + return nullptr; + } + return output; +} +} // namespace OHOS::CollaborationEdit diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_error_utils.cpp b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_error_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..80a7b471856ffe9412d230fe487072ed79fe4449 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_error_utils.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 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 "NapiErrorUtils" + +#include "napi_error_utils.h" + +namespace OHOS::CollaborationEdit { + +void ThrowNapiError(napi_env env, int32_t status, const std::string &errMessage) +{ + if (status == Status::SUCCESS) { + return; + } + LOG_ERROR("ThrowNapiError message: %{public}s", errMessage.c_str()); + std::string jsCode = std::to_string(status); + napi_throw_error(env, jsCode.c_str(), errMessage.c_str()); +} + +} // namespace OHOS::CollaborationEdit diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_node.cpp b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_node.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f9f3d33966f12f601c82cf0772e8facdf603c335 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_node.cpp @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2024 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 "Node" + +#include "napi_node.h" + +#include "napi_error_utils.h" +#include "napi_parser.h" + +namespace OHOS::CollaborationEdit { +static __thread napi_ref g_node_cons_ref = nullptr; + +Node::Node(std::string name) : AbstractType(), name_(name) +{} + +Node::~Node() +{} + +void Node::Init(napi_env env, napi_value exports) +{ + napi_value cons = Node::Constructor(env); + NAPI_CALL_RETURN_VOID(env, napi_create_reference(env, cons, 1, &g_node_cons_ref)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, exports, "Node", cons)); + LOG_DEBUG("Node::Init end."); +} + +napi_value Node::Constructor(napi_env env) +{ + napi_property_descriptor descriptors[] = { + DECLARE_NAPI_FUNCTION("getId", GetUniqueId), + DECLARE_NAPI_FUNCTION("getName", GetName), + DECLARE_NAPI_FUNCTION("insertNodes", InsertNodes), + DECLARE_NAPI_FUNCTION("delete", Delete), + DECLARE_NAPI_FUNCTION("getChildren", GetChildren), + DECLARE_NAPI_FUNCTION("getJsonResult", GetJsonResult), + DECLARE_NAPI_FUNCTION("insertTexts", InsertTexts), + DECLARE_NAPI_FUNCTION("setAttributes", SetAttributes), + DECLARE_NAPI_FUNCTION("removeAttributes", RemoveAttributes), + DECLARE_NAPI_FUNCTION("getAttributes", GetAttributes), + }; + napi_value cons = nullptr; + NAPI_CALL(env, napi_define_class(env, "Node", NAPI_AUTO_LENGTH, New, nullptr, + sizeof(descriptors) / sizeof(napi_property_descriptor), descriptors, &cons)); + return cons; +} + +napi_value Node::New(napi_env env, napi_callback_info info) +{ + napi_value newTarget = nullptr; + NAPI_CALL(env, napi_get_new_target(env, info, &newTarget)); + + size_t argc = 1; + napi_value argv[1] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + + // create instance by 'new Node(name)' + if (newTarget != nullptr) { + napi_valuetype valueType = napi_undefined; + NAPI_CALL(env, napi_typeof(env, argv[0], &valueType)); + if (valueType != napi_string) { + ThrowNapiError(env, Status::INVALID_ARGUMENT, "Param error. The name must be a string"); + return nullptr; + } + std::string name = ""; + NapiUtils::GetValue(env, argv[0], name); + Node *node = new (std::nothrow) Node(name); + auto finalize = [](napi_env env, void *data, void *hint) { + Node *node = reinterpret_cast(data); + delete node; + }; + napi_wrap(env, self, node, finalize, nullptr, nullptr); + return self; + } + + // create instance by 'Node(name)' + napi_value cons = nullptr; + NAPI_CALL(env, napi_get_reference_value(env, g_node_cons_ref, &cons)); + napi_value output = nullptr; + NAPI_CALL(env, napi_new_instance(env, cons, argc, argv, &output)); + return output; +} + +std::string Node::InnerGetName() +{ + return this->name_; +} + +napi_value Node::GetName(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); + Node *thisNode = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&thisNode))); + ASSERT_THROW(env, thisNode != nullptr, Status::INTERNAL_ERROR, "unwrap self is null"); + napi_value result; + NapiUtils::SetValue(env, thisNode->name_, result); + return result; +} + +napi_value Node::GetUniqueId(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); + Node *thisNode = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&thisNode))); + ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr); + ASSERT_THROW(env, thisNode->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id"); + ID id = thisNode->GetID().value(); + napi_value result; + NAPI_CALL(env, napi_create_object(env, &result)); + napi_value jsDeviceId; + NapiUtils::SetValue(env, id.deviceId, jsDeviceId); + NAPI_CALL(env, napi_set_named_property(env, result, "id", jsDeviceId)); + napi_value jsClock; + NapiUtils::SetValue(env, static_cast(id.clock), jsClock); + NAPI_CALL(env, napi_set_named_property(env, result, "clock", jsClock)); + return result; +} + +napi_value Node::InsertNodes(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + Node *thisNode = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&thisNode))); + ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr); + ASSERT_THROW(env, thisNode->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id"); + int64_t index = 0; + napi_status status = NapiUtils::GetValue(env, argv[0], index); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Read index go wrong."); + ASSERT_THROW(env, index >= 0, Status::INVALID_ARGUMENT, "Param Error: Invalid index."); + bool isArray = false; + NAPI_CALL(env, napi_is_array(env, argv[1], &isArray)); + ASSERT_THROW(env, isArray, Status::INVALID_ARGUMENT, "Param Error: The nodes must be an array."); + uint32_t length = 0; + NAPI_CALL(env, napi_get_array_length(env, argv[1], &length)); + LOG_INFO("length = %{public}u", length); + for (uint32_t i = 0; i < length; i++) { + napi_value jsNode = nullptr; + NAPI_CALL(env, napi_get_element(env, argv[1], i, &jsNode)); + Node *tempNode = nullptr; + NAPI_CALL(env, napi_unwrap(env, jsNode, reinterpret_cast(&tempNode))); + auto [retCode, id] = thisNode->GetAdapter()->InsertNode(index + i, tempNode->InnerGetName()); + if (retCode != SUCCESS || !id.has_value()) { + ThrowNapiError(env, retCode, "InsertNodes go wrong."); + return nullptr; + } + tempNode->SetID(id); + tempNode->SetTableName(thisNode->GetTableName()); + tempNode->SetDBStore(thisNode->GetDBStore()); + } + return nullptr; +} + +napi_value Node::Delete(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + Node *thisNode = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&thisNode))); + ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr); + ASSERT_THROW(env, thisNode->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id"); + int64_t index = 0; + napi_status status = NapiUtils::GetValue(env, argv[0], index); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Read index go wrong."); + ASSERT_THROW(env, index >= 0, Status::INVALID_ARGUMENT, "Param Error: Invalid index."); + int64_t length = 0; + status = NapiUtils::GetValue(env, argv[1], length); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Read length go wrong."); + ASSERT_THROW(env, length > 0, Status::INVALID_ARGUMENT, "Param Error: Invalid length."); + + int32_t retCode = thisNode->GetAdapter()->DeleteChildren(index, length); + if (retCode != SUCCESS) { + ThrowNapiError(env, retCode, "Delete Nodes go wrong."); + } + return nullptr; +} + +napi_value Node::GetChildren(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + Node *thisNode = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&thisNode))); + ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr); + ASSERT_THROW(env, thisNode->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id"); + int64_t start = 0; + napi_status status = NapiUtils::GetValue(env, argv[0], start); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Read start index go wrong."); + ASSERT_THROW(env, start >= 0, Status::INVALID_ARGUMENT, "Param Error: Invalid start."); + int64_t end = 0; + status = NapiUtils::GetValue(env, argv[1], end); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Read end index go wrong."); + ASSERT_THROW(env, end >= 0, Status::INVALID_ARGUMENT, "Param Error: Invalid end."); + ASSERT_THROW(env, end > start, Status::INVALID_ARGUMENT, "Param Error: end should be greater than start."); + + auto [retCode, result] = thisNode->GetAdapter()->GetChildren(start, end - start); + if (retCode != SUCCESS) { + ThrowNapiError(env, retCode, "Get Children go wrong."); + return nullptr; + } + // transfer string to node array + napi_value output = nullptr; + int ret = Parser::ParseJsonStrToJsChildren(env, result, thisNode, output); + if (ret != OK) { + ThrowNapiError(env, Status::INTERNAL_ERROR, "convert result go wrong."); + return nullptr; + } + return output; +} + +napi_value Node::GetJsonResult(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); + Node *thisNode = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&thisNode))); + ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr); + ASSERT_THROW(env, thisNode->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id"); + auto [retCode, result] = thisNode->GetAdapter()->GetJsonString(); + if (retCode != SUCCESS) { + ThrowNapiError(env, retCode, "toString go wrong."); + return nullptr; + } + napi_value output = nullptr; + napi_status status = NapiUtils::SetValue(env, result, output); + if (status != napi_ok || output == nullptr) { + ThrowNapiError(env, Status::INTERNAL_ERROR, "convert result go wrong."); + return nullptr; + } + return output; +} + +napi_value Node::InsertTexts(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + Node *thisNode = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&thisNode))); + ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr); + ASSERT_THROW(env, thisNode->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id"); + int64_t index = 0; + napi_status status = NapiUtils::GetValue(env, argv[0], index); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Read index go wrong."); + ASSERT_THROW(env, index >= 0, Status::INVALID_ARGUMENT, "Param Error: Invalid index."); + bool isArray = false; + NAPI_CALL(env, napi_is_array(env, argv[1], &isArray)); + ASSERT_THROW(env, isArray, Status::INVALID_ARGUMENT, "Param Error: The nodes must be an array."); + uint32_t length = 0; + NAPI_CALL(env, napi_get_array_length(env, argv[1], &length)); + for (uint32_t i = 0; i < length; i++) { + napi_value jsText = nullptr; + NAPI_CALL(env, napi_get_element(env, argv[1], i, &jsText)); + Text *tempText = nullptr; + NAPI_CALL(env, napi_unwrap(env, jsText, reinterpret_cast(&tempText))); + auto [retCode, id] = thisNode->GetAdapter()->InsertText(index + i); + if (retCode != SUCCESS || !id.has_value()) { + ThrowNapiError(env, retCode, "InsertText go wrong."); + return nullptr; + } + tempText->SetID(id); + tempText->SetTableName(thisNode->GetTableName()); + tempText->SetDBStore(thisNode->GetDBStore()); + } + return nullptr; +} + +napi_value Node::SetAttributes(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + Node *thisNode = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&thisNode))); + ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr); + ASSERT_THROW(env, thisNode->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id"); + + // convert input argument + napi_value keys = nullptr; + napi_get_all_property_names(env, argv[0], napi_key_own_only, + static_cast(napi_key_enumerable | napi_key_skip_symbols), napi_key_numbers_to_strings, &keys); + uint32_t arrLen = 0; + napi_status status = napi_get_array_length(env, keys, &arrLen); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: Parse argument go wrong."); + for (size_t i = 0; i < arrLen; i++) { + napi_value key = nullptr; + status = napi_get_element(env, keys, i, &key); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: get element go wrong."); + std::string keyStr; + NapiUtils::GetValue(env, key, keyStr); + napi_value value = nullptr; + napi_get_property(env, argv[0], key, &value); + std::string valueStr; + int retCode = Parser::ParseVariantJsValueToStr(env, value, valueStr); + ASSERT(retCode == OK, "parse value go wrong.", nullptr); + retCode = thisNode->GetAdapter()->SetAttribute(keyStr, valueStr, 0); + ASSERT_THROW(env, retCode == SUCCESS, retCode, "Set attribute go wrong."); + } + return nullptr; +} + +napi_value Node::RemoveAttributes(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + Node *thisNode = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&thisNode))); + ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr); + bool isArray; + NAPI_CALL(env, napi_is_array(env, argv[0], &isArray)); + if (!isArray) { + ThrowNapiError(env, Status::INVALID_ARGUMENT, "Param Error: The argument must be an array."); + return nullptr; + } + uint32_t length = 0; + NAPI_CALL(env, napi_get_array_length(env, argv[0], &length)); + for (uint32_t i = 0; i < length; i++) { + napi_value jsAttributeName = nullptr; + NAPI_CALL(env, napi_get_element(env, argv[0], i, &jsAttributeName)); + std::string attributeName; + NapiUtils::GetValue(env, jsAttributeName, attributeName); + int32_t retCode = thisNode->GetAdapter()->RemoveAttrribute(attributeName); + if (retCode != SUCCESS) { + ThrowNapiError(env, retCode, "RemoveAttrribute go wrong."); + return nullptr; + } + } + return nullptr; +} + +napi_value Node::GetAttributes(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); + Node *thisNode = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&thisNode))); + ASSERT(thisNode != nullptr, "unwrap self go wrong.", nullptr); + ASSERT_THROW(env, thisNode->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id"); + + auto [retCode, result] = thisNode->GetAdapter()->GetAttributes(); + if (retCode != SUCCESS) { + ThrowNapiError(env, retCode, "GetAttributes go wrong."); + return nullptr; + } + // convert result string to record + napi_value output = nullptr; + int ret = Parser::ParseFromAttrsJsonStr(env, result, output); + if (ret != OK) { + ThrowNapiError(env, Status::INTERNAL_ERROR, "parse result go wrong."); + return nullptr; + } + return output; +} +} // namespace OHOS::CollaborationEdit diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_parser.cpp b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc6b3e2c3e7b46e7f795746b1cf3f30ff719aaf4 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_parser.cpp @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2024 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 "NapiParser" +#include "napi_parser.h" + +#include +#include +#include + +#include + +#include "napi_errno.h" +#include "napi_error_utils.h" +#include "napi_node.h" +#include "napi_utils.h" + +namespace OHOS::CollaborationEdit { +using json = nlohmann::json; + +static constexpr const uint8_t NUMBER_OF_FIELDS_IN_ID = 2; + +void Parser::Stringsplit(std::string str, const char split, std::vector &res) +{ + std::istringstream iss(str); + std::string token; + while (std::getline(iss, token, split)) { + res.push_back(token); + } +} + +bool Parser::ConvertToUint64(std::string str, uint64_t &out) +{ + auto [ptr, errCode] = std::from_chars(str.data(), str.data() + str.size(), out); + return errCode == std::errc{} && ptr == str.data() + str.size(); +} + +std::optional Parser::ConvertStrToID(std::string idStr) +{ + if (idStr.empty()) { + return std::nullopt; + } + std::vector strList; + Stringsplit(idStr, '_', strList); + if (strList.size() != NUMBER_OF_FIELDS_IN_ID) { // id returned from kernel is a string like 'id_clock' + return std::nullopt; + } + uint64_t clock = 0; + if (!ConvertToUint64(strList[1], clock)) { + return std::nullopt; + } + ID id(strList[0], clock); + return id; +} + +int ParseJsonToJsNode(napi_env env, json jsonObj, AbstractType *parent, napi_value &out) +{ + napi_value constructor = Node::Constructor(env); + ASSERT(constructor != nullptr, "node constructor is null", ERR); + std::string nodeName = jsonObj["nodeName"]; + std::string idStr = jsonObj["elementId"]; + std::optional id = Parser::ConvertStrToID(idStr); + ASSERT(id.has_value(), "incorrect id.", ERR); // ID should not be null + napi_value jsNodeName = nullptr; + napi_status status = NapiUtils::SetValue(env, nodeName, jsNodeName); + ASSERT(status == napi_ok, "wrap nodeName go wrong.", ERR); + size_t argc = 1; + napi_value argv[1] = {jsNodeName}; + napi_value jsNode; + status = napi_new_instance(env, constructor, argc, argv, &jsNode); + ASSERT(status == napi_ok, "new node instance go wrong.", ERR); + Node *tempNode = nullptr; + status = napi_unwrap(env, jsNode, reinterpret_cast(&tempNode)); + ASSERT(status == napi_ok, "unwrap jsNode go wrong.", ERR); + tempNode->SetDBStore(parent->GetDBStore()); + tempNode->SetTableName(parent->GetTableName()); + tempNode->SetID(id); + out = jsNode; + return OK; +} + +int ParseJsonToJsText(napi_env env, json jsonObj, AbstractType *parent, napi_value &out) +{ + napi_value constructor = Text::Constructor(env); + ASSERT(constructor != nullptr, "text constructor is null", ERR); + std::string idStr = jsonObj["elementId"]; + LOG_DEBUG("id is %{public}s", idStr.c_str()); + std::optional id = Parser::ConvertStrToID(idStr); + ASSERT(id.has_value(), "incorrect id.", ERR); // ID should not be null + napi_value jsText; + napi_status status = napi_new_instance(env, constructor, 0, nullptr, &jsText); + ASSERT(status == napi_ok, "new text instance go wrong.", ERR); + Node *tempText = nullptr; + status = napi_unwrap(env, jsText, reinterpret_cast(&tempText)); + ASSERT(status == napi_ok, "unwrap jsText go wrong.", ERR); + tempText->SetDBStore(parent->GetDBStore()); + tempText->SetTableName(parent->GetTableName()); + tempText->SetID(id); + out = jsText; + return OK; +} + +int Parser::ParseJsonStrToJsChildren( + napi_env env, const std::string &nodeJsonStr, AbstractType *parent, napi_value &out) +{ + ASSERT(!nodeJsonStr.empty() && json::accept(nodeJsonStr), "invalid json str", ERR); + napi_status status = napi_create_array(env, &out); + ASSERT(status == napi_ok, "create array go wrong!", ERR); + json jsonArray = json::parse(nodeJsonStr); + ASSERT(jsonArray.is_array(), "result is not json array.", ERR); + int i = 0; + for (const auto &jsonObj : jsonArray) { + if (!jsonObj.contains("type")) { + continue; + } + std::string type = jsonObj["type"]; + napi_value jsNode; + if (type.compare("XML_ELEMENT") == 0) { + int ret = ParseJsonToJsNode(env, jsonObj, parent, jsNode); + ASSERT(ret == OK, "Parse json to node go wrong.", ERR); + } else if (type.compare("XML_TEXT") == 0) { + int ret = ParseJsonToJsText(env, jsonObj, parent, jsNode); + ASSERT(ret == OK, "Parse json to text go wrong.", ERR); + } else { + LOG_ERROR("Unsupported type. type = %{public}s", type.c_str()); + continue; + } + status = napi_set_element(env, out, i, jsNode); + ASSERT(status == napi_ok, "set element go wrong.", ERR); + i++; + } + return OK; +} + +int Parser::ParseFromAttrsJsonStr(napi_env env, const std::string &jsonStr, napi_value &out) +{ + ASSERT(!jsonStr.empty() && json::accept(jsonStr), "invalid json str", ERR); + napi_status status = napi_create_object(env, &out); + ASSERT(status == napi_ok, "create object go wrong!", ERR); + json jsonObject = json::parse(jsonStr); + napi_value jsAttr = nullptr; + for (json::iterator iter = jsonObject.begin(); iter != jsonObject.end(); ++iter) { + std::string key = iter.key(); + json value = iter.value(); + if (value.is_string()) { + NapiUtils::SetValue(env, value.get(), jsAttr); + } else if (value.is_number_integer()) { + NapiUtils::SetValue(env, value.get(), jsAttr); + } else if (value.is_boolean()) { + NapiUtils::SetValue(env, value.get(), jsAttr); + } else { + LOG_ERROR("Unsupported value type"); + continue; + } + status = napi_set_named_property(env, out, key.c_str(), jsAttr); + } + return OK; +} + +int Parser::ParseJsFormatToStr(napi_env env, napi_value jsFormat, std::string &out) +{ + napi_value keys = nullptr; + napi_get_all_property_names(env, jsFormat, napi_key_own_only, + static_cast(napi_key_enumerable | napi_key_skip_symbols), napi_key_numbers_to_strings, &keys); + uint32_t arrLen = 0; + napi_status status = napi_get_array_length(env, keys, &arrLen); + ASSERT(status == napi_ok, "get keys array length go wrong.", ERR); + json resJson; + for (size_t i = 0; i < arrLen; i++) { + napi_value key = nullptr; + status = napi_get_element(env, keys, i, &key); + ASSERT(status == napi_ok, "get key element go wrong.", ERR); + std::string keyStr; + NapiUtils::GetValue(env, key, keyStr); + napi_value jsValue = nullptr; + napi_get_property(env, jsFormat, key, &jsValue); + std::string value; + int ret = ParseVariantJsValueToStr(env, jsValue, value); + ASSERT(ret == OK, "parse value go wrong.", ERR); + resJson[keyStr] = value; + } + out = resJson.dump(); + return OK; +} + +int Parser::ParseVariantJsValueToStr(napi_env env, napi_value input, std::string &out) +{ + napi_valuetype valueType; + napi_status status = napi_typeof(env, input, &valueType); + ASSERT(status == napi_ok, "get type of input go wrong.", ERR); + ASSERT(valueType != napi_undefined, "cannot be undefined.", ERR); + switch (valueType) { + case napi_number: { + int64_t intValue; + status = NapiUtils::GetValue(env, input, intValue); + if (status == napi_ok) { + out = std::to_string(intValue); + break; + } + double doubleValue; + status = NapiUtils::GetValue(env, input, doubleValue); + ASSERT(status == napi_ok, "Neither int or double", ERR); + out = std::to_string(doubleValue); + break; + } + case napi_string: { + std::string strValue; + status = NapiUtils::GetValue(env, input, strValue); + ASSERT(status == napi_ok, "convert to str go wrong.", ERR); + out = strValue; + break; + } + case napi_boolean: { + bool bValue; + status = NapiUtils::GetValue(env, input, bValue); + ASSERT(status == napi_ok, "convert to bool go wrong.", ERR); + out = bValue ? "true" : "false"; + break; + } + default: { + LOG_ERROR("unsupported format type: %{public}d", valueType); + return ERR; + } + } + return OK; +} + +} // namespace OHOS::CollaborationEdit diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_text.cpp b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_text.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b15640e55a1f9a166e950f1f2cbc13830f0926c6 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_text.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2024 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 "Text" + +#include "napi_text.h" + +#include "napi_error_utils.h" +#include "napi_parser.h" + +namespace OHOS::CollaborationEdit { +static __thread napi_ref g_text_cons_ref = nullptr; + +Text::Text() : AbstractType() +{} + +Text::~Text() +{} + +void Text::Init(napi_env env, napi_value exports) +{ + napi_value cons = Text::Constructor(env); + NAPI_CALL_RETURN_VOID(env, napi_create_reference(env, cons, 1, &g_text_cons_ref)); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, exports, "Text", cons)); + LOG_DEBUG("Text::Init end."); +} + +napi_value Text::Constructor(napi_env env) +{ + napi_property_descriptor descriptors[] = { + DECLARE_NAPI_FUNCTION("getId", GetUniqueId), + DECLARE_NAPI_FUNCTION("insert", Insert), + DECLARE_NAPI_FUNCTION("delete", Delete), + DECLARE_NAPI_FUNCTION("format", Format), + DECLARE_NAPI_FUNCTION("getPlainText", GetPlainText), + DECLARE_NAPI_FUNCTION("getJsonResult", GetJsonResult), + }; + napi_value cons = nullptr; + NAPI_CALL(env, napi_define_class(env, "Text", NAPI_AUTO_LENGTH, New, nullptr, + sizeof(descriptors) / sizeof(napi_property_descriptor), descriptors, &cons)); + return cons; +} + +napi_value Text::New(napi_env env, napi_callback_info info) +{ + napi_value newTarget = nullptr; + NAPI_CALL(env, napi_get_new_target(env, info, &newTarget)); + + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); + + // create instance by 'new Node(name)' + if (newTarget != nullptr) { + Text *text = new (std::nothrow) Text(); + auto finalize = [](napi_env env, void *data, void *hint) { + Text *text = reinterpret_cast(data); + delete text; + }; + napi_wrap(env, self, text, finalize, nullptr, nullptr); + return self; + } + + // create instance by 'Node(name)' + napi_value cons = nullptr; + NAPI_CALL(env, napi_get_reference_value(env, g_text_cons_ref, &cons)); + napi_value output = nullptr; + NAPI_CALL(env, napi_new_instance(env, cons, 0, nullptr, &output)); + return output; +} + +napi_value Text::GetUniqueId(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); + Text *text = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&text))); + ASSERT(text != nullptr, "unwrap self go wrong.", nullptr); + ASSERT_THROW(env, text->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id"); + if (!text->GetID().has_value()) { + ThrowNapiError(env, Status::INVALID_ARGUMENT, "empty id"); + return nullptr; + } + ID id = text->GetID().value(); + napi_value result; + NAPI_CALL(env, napi_create_object(env, &result)); + napi_value jsDeviceId; + NapiUtils::SetValue(env, id.deviceId, jsDeviceId); + NAPI_CALL(env, napi_set_named_property(env, result, "deviceId", jsDeviceId)); + napi_value jsClock; + NapiUtils::SetValue(env, static_cast(id.clock), jsClock); + NAPI_CALL(env, napi_set_named_property(env, result, "clock", jsClock)); + return result; +} + +napi_value Text::Insert(napi_env env, napi_callback_info info) +{ + size_t argc = 3; + napi_value argv[3] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + Text *text = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&text))); + ASSERT(text != nullptr, "unwrap self go wrong.", nullptr); + ASSERT_THROW(env, text->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id"); + int64_t index; + napi_status status = NapiUtils::GetValue(env, argv[0], index); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: read index go wrong"); + ASSERT_THROW(env, index >= 0, Status::INVALID_ARGUMENT, "Param Error: Invalid index"); + std::string content; + status = NapiUtils::GetValue(env, argv[1], content); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: read content go wrong"); + napi_valuetype valueType; + // argv[2] represents the third parameter + NAPI_CALL(env, napi_typeof(env, argv[2], &valueType)); + std::string formatStr; + if (valueType != napi_undefined) { + int ret = Parser::ParseJsFormatToStr(env, argv[2], formatStr); + ASSERT_THROW(env, ret == OK, Status::INVALID_ARGUMENT, "convert format go wrong"); + } + int32_t retCode = text->GetAdapter()->TextInsert(index, content, formatStr); + if (retCode != SUCCESS) { + ThrowNapiError(env, retCode, "TextInsert go wrong."); + } + return nullptr; +} + +napi_value Text::Delete(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + Text *text = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&text))); + ASSERT(text != nullptr, "unwrap self go wrong.", nullptr); + ASSERT_THROW(env, text->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id"); + int64_t index; + napi_status status = NapiUtils::GetValue(env, argv[0], index); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: read index go wrong"); + ASSERT_THROW(env, index >= 0, Status::INVALID_ARGUMENT, "Param Error: Invalid index"); + int64_t length = 0; + status = NapiUtils::GetValue(env, argv[1], length); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: read length go wrong"); + ASSERT_THROW(env, length > 0, Status::INVALID_ARGUMENT, "Param Error: Invalid length"); + int32_t retCode = text->GetAdapter()->TextDelete(index, length); + if (retCode != SUCCESS) { + ThrowNapiError(env, retCode, "TextDelete go wrong."); + } + return nullptr; +} + +napi_value Text::Format(napi_env env, napi_callback_info info) +{ + size_t argc = 3; + napi_value argv[3] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + Text *text = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&text))); + ASSERT(text != nullptr, "unwrap self go wrong.", nullptr); + ASSERT_THROW(env, text->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id"); + int64_t index; + napi_status status = NapiUtils::GetValue(env, argv[0], index); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: read index go wrong"); + ASSERT_THROW(env, index >= 0, Status::INVALID_ARGUMENT, "Param Error: Invalid index"); + int64_t length = 0; + status = NapiUtils::GetValue(env, argv[1], length); + ASSERT_THROW(env, status == napi_ok, Status::INVALID_ARGUMENT, "Param Error: read length go wrong"); + ASSERT_THROW(env, length > 0, Status::INVALID_ARGUMENT, "Param Error: Invalid length"); + napi_valuetype valueType; + // argv[2] represents the third parameter + NAPI_CALL(env, napi_typeof(env, argv[2], &valueType)); + std::string formatStr; + if (valueType != napi_undefined) { + // argv[2] represents the third parameter + (void)Parser::ParseJsFormatToStr(env, argv[2], formatStr); + } + int32_t retCode = text->GetAdapter()->TextFormat(index, length, formatStr); + if (retCode != SUCCESS) { + ThrowNapiError(env, retCode, "TextFormat go wrong."); + } + return nullptr; +} + +napi_value Text::GetPlainText(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); + Text *text = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&text))); + ASSERT(text != nullptr, "unwrap self go wrong.", nullptr); + ASSERT_THROW(env, text->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id"); + auto [retCode, result] = text->GetAdapter()->ReadStringText(); + if (retCode != SUCCESS) { + ThrowNapiError(env, retCode, "ReadStringText go wrong."); + return nullptr; + } + napi_value output = nullptr; + NapiUtils::SetValue(env, result, output); + return output; +} + +napi_value Text::GetJsonResult(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); + Text *text = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&text))); + ASSERT(text != nullptr, "unwrap self go wrong.", nullptr); + ASSERT_THROW(env, text->GetID().has_value(), Status::UNSUPPORTED_OPERATION, "empty id"); + auto [retCode, result] = text->GetAdapter()->ReadDeltaText("", ""); + if (retCode != SUCCESS) { + ThrowNapiError(env, retCode, "ReadDeltaText go wrong."); + return nullptr; + } + napi_value output = nullptr; + NapiUtils::SetValue(env, result, output); + return output; +} +} // namespace OHOS::CollaborationEdit diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_undo_manager.cpp b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_undo_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..103878eba79d54d97a9483a883931ea98d0cbf54 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_undo_manager.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2024 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 "UndoManager" + +#include "napi_undo_manager.h" + +#include "napi_error_utils.h" + +namespace OHOS::CollaborationEdit { + +UndoManager::UndoManager(std::string tableName, int64_t captureTimeout) : captureTimeout_(captureTimeout) +{ + this->adapter_ = std::make_shared(); + this->adapter_->SetTableName(tableName); +} + +UndoManager::~UndoManager() +{} + +napi_value UndoManager::Initialize(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = {nullptr}; + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + std::string tableName; + napi_status status = NapiUtils::GetValue(env, argv[0], tableName); + if (status != napi_ok) { + ThrowNapiError(env, Status::INVALID_ARGUMENT, "read tableName go wrong"); + return self; + } + int64_t captureTimeout = 0; + status = NapiUtils::GetNamedProperty(env, argv[1], "captureTimeout", captureTimeout); + if (status != napi_ok) { + ThrowNapiError(env, Status::INVALID_ARGUMENT, "read captureTimeout param go wrong"); + return self; + } + ASSERT_THROW_BASE(env, status == napi_ok, Status::INVALID_ARGUMENT, "read captureTimeout param go wrong", self); + ASSERT_THROW_BASE(env, captureTimeout >= 0, Status::INVALID_ARGUMENT, + "Param Error: captureTimeout cannot be negative.", self); + tableName = std::to_string(LABEL_FRAGMENT) + "_" + tableName; + UndoManager *undoManager = new (std::nothrow) UndoManager(tableName, captureTimeout); + auto finalize = [](napi_env env, void *data, void *hint) { + UndoManager *undoManager = reinterpret_cast(data); + delete undoManager; + }; + napi_wrap(env, self, undoManager, finalize, nullptr, nullptr); + return self; +} + +napi_value UndoManager::Constructor(napi_env env) +{ + auto lambda = []() -> std::vector { + std::vector properties = { + DECLARE_NAPI_FUNCTION("undo", Undo), + DECLARE_NAPI_FUNCTION("redo", Redo), + }; + return properties; + }; + return NapiUtils::DefineClass( + env, "ohos.data.collaborationEditObject", "UndoManager", lambda, Initialize); +} + +napi_value UndoManager::NewInstance(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value argv[2] = {nullptr}; + napi_value undoManager = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr)); + + napi_status status = napi_new_instance(env, Constructor(env), argc, argv, &undoManager); + if (undoManager == nullptr || status != napi_ok) { + LOG_ERROR("[NewInstance] new instance go wrong"); + } + return undoManager; +} + +napi_value UndoManager::Undo(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); + UndoManager *manager = nullptr; + napi_status status = napi_unwrap(env, self, reinterpret_cast(&manager)); + if (status != napi_ok || manager == nullptr) { + ThrowNapiError(env, Status::INVALID_ARGUMENT, "unwrap node go wrong"); + return nullptr; + } + int32_t retCode = manager->GetAdapter()->Undo(); + if (retCode != 0) { + ThrowNapiError(env, Status::DB_ERROR, "undo go wrong."); + } + return nullptr; +} + +napi_value UndoManager::Redo(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); + UndoManager *manager = nullptr; + napi_status status = napi_unwrap(env, self, reinterpret_cast(&manager)); + if (status != napi_ok || manager == nullptr) { + ThrowNapiError(env, Status::INVALID_ARGUMENT, "unwrap self go wrong"); + return nullptr; + } + int32_t retCode = manager->GetAdapter()->Redo(); + if (retCode != 0) { + ThrowNapiError(env, Status::DB_ERROR, "redo go wrong."); + } + return nullptr; +} + +std::string UndoManager::GetTableName() +{ + return this->adapter_->GetTableName(); +} + +int64_t UndoManager::GetCaptureTimeout() +{ + return this->captureTimeout_; +} + +std::shared_ptr UndoManager::GetAdapter() +{ + return this->adapter_; +} + +void UndoManager::SetDBStore(std::shared_ptr dbStore) +{ + this->adapter_->SetDBStore(dbStore); +} + +} // namespace OHOS::CollaborationEdit diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_utils.cpp b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c3e7d3f7a696f7e417aa65622943a8641f59c2d9 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/src/napi_utils.cpp @@ -0,0 +1,655 @@ +/* + * Copyright (c) 2024 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 "NapiUtils" + +#include "napi_utils.h" + +#include "napi_error_utils.h" + +namespace OHOS::CollaborationEdit { +constexpr int32_t STR_MAX_LENGTH = 4096; +constexpr size_t STR_TAIL_LENGTH = 1; + +// second param is the base64 code of data.collaborationEditObject +static constexpr NapiUtils::JsFeatureSpace FEATURE_NAME_SPACES[] = { + {"ohos.data.collaborationEditObject", "ZGF0YS5jb2xsYWJvcmF0aW9uRWRpdE9iamVjdA==", true}, +}; + +const std::optional NapiUtils::GetJsFeatureSpace(const std::string &name) +{ + auto jsFeature = JsFeatureSpace{name.data(), "", false}; + auto iter = std::lower_bound(FEATURE_NAME_SPACES, + FEATURE_NAME_SPACES + sizeof(FEATURE_NAME_SPACES) / sizeof(FEATURE_NAME_SPACES[0]), + jsFeature, + [](const JsFeatureSpace &JsFeatureSpace1, const JsFeatureSpace &JsFeatureSpace2) { + return strcmp(JsFeatureSpace1.spaceName, JsFeatureSpace2.spaceName) < 0; + }); + if (iter < FEATURE_NAME_SPACES + sizeof(FEATURE_NAME_SPACES) / sizeof(FEATURE_NAME_SPACES[0]) && + strcmp(iter->spaceName, name.data()) == 0) { + return *iter; + } + return std::nullopt; +} + +napi_status NapiUtils::GetValue(napi_env env, napi_value input, napi_value &out) +{ + out = input; + return napi_ok; +} + +napi_status NapiUtils::SetValue(napi_env env, napi_value input, napi_value &out) +{ + out = input; + return napi_ok; +} + +/* napi_value <-> bool */ +napi_status NapiUtils::GetValue(napi_env env, napi_value input, bool &out) +{ + return napi_get_value_bool(env, input, &out); +} + +napi_status NapiUtils::SetValue(napi_env env, const bool &input, napi_value &out) +{ + return napi_get_boolean(env, input, &out); +} + +/* napi_value <-> int32_t */ +napi_status NapiUtils::GetValue(napi_env env, napi_value input, int32_t &out) +{ + return napi_get_value_int32(env, input, &out); +} + +napi_status NapiUtils::SetValue(napi_env env, const int32_t &input, napi_value &out) +{ + return napi_create_int32(env, input, &out); +} + +/* napi_value <-> uint32_t */ +napi_status NapiUtils::GetValue(napi_env env, napi_value input, uint32_t &out) +{ + return napi_get_value_uint32(env, input, &out); +} + +napi_status NapiUtils::SetValue(napi_env env, const uint32_t &input, napi_value &out) +{ + return napi_create_uint32(env, input, &out); +} + +/* napi_value <-> int64_t */ +napi_status NapiUtils::GetValue(napi_env env, napi_value input, int64_t &out) +{ + return napi_get_value_int64(env, input, &out); +} + +napi_status NapiUtils::SetValue(napi_env env, const int64_t &input, napi_value &out) +{ + return napi_create_int64(env, input, &out); +} + +/* napi_value <-> double */ +napi_status NapiUtils::GetValue(napi_env env, napi_value input, double &out) +{ + return napi_get_value_double(env, input, &out); +} + +napi_status NapiUtils::SetValue(napi_env env, const double &input, napi_value &out) +{ + return napi_create_double(env, input, &out); +} + +/* napi_value <-> std::string */ +napi_status NapiUtils::GetValue(napi_env env, napi_value input, std::string &out) +{ + napi_valuetype type = napi_undefined; + napi_status ret = napi_typeof(env, input, &type); + ASSERT((ret == napi_ok) && (type == napi_string), "invalid type", napi_invalid_arg); + + size_t maxLen = STR_MAX_LENGTH; + ret = napi_get_value_string_utf8(env, input, NULL, 0, &maxLen); + if (maxLen <= 0) { + return ret; + } + LOG_DEBUG("napi_value -> std::string get length %{public}d", (int)maxLen); + char *buf = new (std::nothrow) char[maxLen + STR_TAIL_LENGTH]; + if (buf != nullptr) { + size_t len = 0; + ret = napi_get_value_string_utf8(env, input, buf, maxLen + STR_TAIL_LENGTH, &len); + if (ret == napi_ok) { + buf[len] = 0; + out = std::string(buf); + } + delete[] buf; + } else { + ret = napi_generic_failure; + } + return ret; +} + +napi_status NapiUtils::SetValue(napi_env env, const std::string &input, napi_value &out) +{ + return napi_create_string_utf8(env, input.c_str(), input.size(), &out); +} + +/* napi_value <-> std::vector */ +napi_status NapiUtils::GetValue(napi_env env, napi_value input, std::vector &out) +{ + out.clear(); + LOG_DEBUG("napi_value -> std::vector "); + napi_typedarray_type type = napi_biguint64_array; + napi_value buffer = nullptr; + void *data = nullptr; + size_t length = 0; + size_t offset = 0; + napi_status statusMsg = napi_get_typedarray_info(env, input, &type, &length, &data, &buffer, &offset); + LOG_DEBUG("array type=%{public}d length=%{public}d offset=%{public}d", (int)type, (int)length, (int)offset); + ASSERT(statusMsg == napi_ok, "napi_get_typedarray_info go wrong!", napi_invalid_arg); + ASSERT(type == napi_uint8_array, "is not Uint8Array!", napi_invalid_arg); + ASSERT((length > 0) && (data != nullptr), "invalid data!", napi_invalid_arg); + out.assign((uint8_t *)data, ((uint8_t *)data) + length); + return statusMsg; +} + +napi_status NapiUtils::SetValue(napi_env env, const std::vector &input, napi_value &out) +{ + LOG_DEBUG("napi_value <- std::vector "); + ASSERT(input.size() > 0, "invalid std::vector", napi_invalid_arg); + void *data = nullptr; + napi_value buffer = nullptr; + napi_status statusMsg = napi_create_arraybuffer(env, input.size(), &data, &buffer); + ASSERT((statusMsg == napi_ok), "create array buffer go wrong!", statusMsg); + + if (memcpy_s(data, input.size(), input.data(), input.size()) != EOK) { + LOG_ERROR("napi_value <- std::vector: memcpy_s go wrong, vector size:%{public}zd", input.size()); + return napi_invalid_arg; + } + statusMsg = napi_create_typedarray(env, napi_uint8_array, input.size(), buffer, 0, &out); + ASSERT((statusMsg == napi_ok), "napi_value <- std::vector invalid value", statusMsg); + return statusMsg; +} + +template +void TypedArray2Vector(uint8_t *dataPtr, size_t length, napi_typedarray_type type, std::vector &out) +{ + auto convert = [&out](auto *dataPtr, size_t elements) { + for (size_t index = 0; index < elements; index++) { + out.push_back(static_cast(dataPtr[index])); + } + }; + + switch (type) { + case napi_int8_array: + convert(reinterpret_cast(dataPtr), length); + break; + case napi_uint8_array: + convert(dataPtr, length); + break; + case napi_uint8_clamped_array: + convert(dataPtr, length); + break; + case napi_int16_array: + convert(reinterpret_cast(dataPtr), length / sizeof(int16_t)); + break; + case napi_uint16_array: + convert(reinterpret_cast(dataPtr), length / sizeof(uint16_t)); + break; + case napi_int32_array: + convert(reinterpret_cast(dataPtr), length / sizeof(int32_t)); + break; + case napi_uint32_array: + convert(reinterpret_cast(dataPtr), length / sizeof(uint32_t)); + break; + case napi_float32_array: + convert(reinterpret_cast(dataPtr), length / sizeof(float)); + break; + case napi_float64_array: + convert(reinterpret_cast(dataPtr), length / sizeof(double)); + break; + case napi_bigint64_array: + convert(reinterpret_cast(dataPtr), length / sizeof(int64_t)); + break; + case napi_biguint64_array: + convert(reinterpret_cast(dataPtr), length / sizeof(uint64_t)); + break; + default: + ASSERT_VOID(false, "[FATAL] invalid napi_typedarray_type!"); + } +} + +/* napi_value <-> std::vector */ +napi_status NapiUtils::GetValue(napi_env env, napi_value input, std::vector &out) +{ + out.clear(); + LOG_DEBUG("napi_value -> std::vector "); + napi_typedarray_type type = napi_biguint64_array; + napi_value buffer = nullptr; + uint8_t *data = nullptr; + size_t length = 0; + size_t offset = 0; + napi_status status = + napi_get_typedarray_info(env, input, &type, &length, reinterpret_cast(&data), &buffer, &offset); + LOG_DEBUG("array type=%{public}d length=%{public}d offset=%{public}d", (int)type, (int)length, (int)offset); + ASSERT(status == napi_ok, "napi_get_typedarray_info go wrong!", napi_invalid_arg); + ASSERT(type <= napi_int32_array, "is not int32 supported typed array!", napi_invalid_arg); + ASSERT((length > 0) && (data != nullptr), "invalid data!", napi_invalid_arg); + TypedArray2Vector(data, length, type, out); + return status; +} + +napi_status NapiUtils::SetValue(napi_env env, const std::vector &input, napi_value &out) +{ + LOG_DEBUG("napi_value <- std::vector "); + size_t bytes = input.size() * sizeof(int32_t); + ASSERT(bytes > 0, "invalid std::vector", napi_invalid_arg); + void *data = nullptr; + napi_value buffer = nullptr; + napi_status status = napi_create_arraybuffer(env, bytes, &data, &buffer); + ASSERT((status == napi_ok), "invalid buffer", status); + + if (memcpy_s(data, bytes, input.data(), bytes) != EOK) { + LOG_ERROR("napi_value <- std::vector: memcpy_s go wrong, vector size:%{public}zd", input.size()); + return napi_invalid_arg; + } + status = napi_create_typedarray(env, napi_int32_array, input.size(), buffer, 0, &out); + ASSERT((status == napi_ok), "invalid buffer", status); + return status; +} + +/* napi_value <-> std::vector */ +napi_status NapiUtils::GetValue(napi_env env, napi_value input, std::vector &out) +{ + out.clear(); + LOG_DEBUG("napi_value -> std::vector "); + napi_typedarray_type type = napi_biguint64_array; + napi_value buffer = nullptr; + uint8_t *data = nullptr; + size_t length = 0; + size_t offset = 0; + napi_status status = + napi_get_typedarray_info(env, input, &type, &length, reinterpret_cast(&data), &buffer, &offset); + LOG_DEBUG("napi_get_typedarray_info type=%{public}d", (int)type); + ASSERT(status == napi_ok, "napi_get_typedarray_info go wrong!", napi_invalid_arg); + ASSERT((type <= napi_uint16_array) || (type == napi_uint32_array), "invalid type!", napi_invalid_arg); + ASSERT((length > 0) && (data != nullptr), "invalid data!", napi_invalid_arg); + TypedArray2Vector(data, length, type, out); + return status; +} + +napi_status NapiUtils::SetValue(napi_env env, const std::vector &input, napi_value &out) +{ + LOG_DEBUG("napi_value <- std::vector "); + size_t bytes = input.size() * sizeof(uint32_t); + ASSERT(bytes > 0, "invalid std::vector", napi_invalid_arg); + void *data = nullptr; + napi_value buffer = nullptr; + napi_status status = napi_create_arraybuffer(env, bytes, &data, &buffer); + ASSERT((status == napi_ok), "invalid buffer", status); + + if (memcpy_s(data, bytes, input.data(), bytes) != EOK) { + LOG_ERROR("napi_value <- std::vector: memcpy_s go wrong, vector size:%{public}zd", input.size()); + return napi_invalid_arg; + } + status = napi_create_typedarray(env, napi_uint32_array, input.size(), buffer, 0, &out); + ASSERT((status == napi_ok), "invalid buffer", status); + return status; +} + +/* napi_value <-> std::vector */ +napi_status NapiUtils::GetValue(napi_env env, napi_value input, std::vector &out) +{ + out.clear(); + LOG_DEBUG("napi_value -> std::vector "); + napi_typedarray_type type = napi_biguint64_array; + napi_value buffer = nullptr; + uint8_t *data = nullptr; + size_t length = 0; + size_t offset = 0; + napi_status status = + napi_get_typedarray_info(env, input, &type, &length, reinterpret_cast(&data), &buffer, &offset); + LOG_DEBUG("array type=%{public}d length=%{public}d offset=%{public}d", (int)type, (int)length, (int)offset); + ASSERT(status == napi_ok, "napi_get_typedarray_info go wrong!", napi_invalid_arg); + ASSERT((type <= napi_uint32_array) || (type == napi_bigint64_array), "invalid type!", napi_invalid_arg); + ASSERT((length > 0) && (data != nullptr), "invalid data!", napi_invalid_arg); + TypedArray2Vector(data, length, type, out); + return status; +} + +napi_status NapiUtils::SetValue(napi_env env, const std::vector &input, napi_value &out) +{ + LOG_DEBUG("napi_value <- std::vector "); + size_t bytes = input.size() * sizeof(int64_t); + ASSERT(bytes > 0, "invalid std::vector", napi_invalid_arg); + void *data = nullptr; + napi_value buffer = nullptr; + napi_status status = napi_create_arraybuffer(env, bytes, &data, &buffer); + ASSERT((status == napi_ok), "invalid buffer", status); + + if (memcpy_s(data, bytes, input.data(), bytes) != EOK) { + LOG_ERROR("napi_value <- std::vector: memcpy_s go wrong, vector size:%{public}zd", input.size()); + return napi_invalid_arg; + } + status = napi_create_typedarray(env, napi_bigint64_array, input.size(), buffer, 0, &out); + ASSERT((status == napi_ok), "invalid buffer", status); + return status; +} + +/* napi_value <-> std::vector */ +napi_status NapiUtils::GetValue(napi_env env, napi_value input, std::vector &out) +{ + out.clear(); + bool isTypedArray = false; + napi_status status = napi_is_typedarray(env, input, &isTypedArray); + LOG_DEBUG("napi_value -> std::vector input %{public}s a TypedArray", isTypedArray ? "is" : "is not"); + ASSERT((status == napi_ok), "napi_is_typedarray go wrong!", status); + if (isTypedArray) { + LOG_DEBUG("napi_value -> std::vector "); + napi_typedarray_type type = napi_biguint64_array; + napi_value buffer = nullptr; + uint8_t *data = nullptr; + size_t length = 0; + size_t offset = 0; + status = + napi_get_typedarray_info(env, input, &type, &length, reinterpret_cast(&data), &buffer, &offset); + LOG_DEBUG("napi_get_typedarray_info status=%{public}d type=%{public}d", status, (int)type); + ASSERT(status == napi_ok, "napi_get_typedarray_info go wrong!", napi_invalid_arg); + ASSERT((length > 0) && (data != nullptr), "invalid data!", napi_invalid_arg); + TypedArray2Vector(data, length, type, out); + } else { + bool isArray = false; + status = napi_is_array(env, input, &isArray); + LOG_DEBUG("napi_value -> std::vector input %{public}s an Array", isArray ? "is" : "is not"); + ASSERT((status == napi_ok) && isArray, "invalid data!", napi_invalid_arg); + uint32_t length = 0; + status = napi_get_array_length(env, input, &length); + ASSERT((status == napi_ok) && (length > 0), "invalid data!", napi_invalid_arg); + for (uint32_t i = 0; i < length; ++i) { + napi_value item = nullptr; + status = napi_get_element(env, input, i, &item); + ASSERT((item != nullptr) && (status == napi_ok), "no element", napi_invalid_arg); + double vi = 0.0; + status = napi_get_value_double(env, item, &vi); + ASSERT(status == napi_ok, "element not a double", napi_invalid_arg); + out.push_back(vi); + } + } + return status; +} + +napi_status NapiUtils::SetValue(napi_env env, const std::vector &input, napi_value &out) +{ + LOG_DEBUG("napi_value <- std::vector "); + (void)(env); + (void)(input); + (void)(out); + ASSERT(false, "std::vector to napi_value, unsupported!", napi_invalid_arg); + return napi_invalid_arg; +} + +/* napi_value <-> std::vector */ +napi_status NapiUtils::GetValue(napi_env env, napi_value input, std::vector &out) +{ + LOG_DEBUG("napi_value -> std::vector"); + out.clear(); + bool isArray = false; + napi_is_array(env, input, &isArray); + ASSERT(isArray, "not an array", napi_invalid_arg); + + uint32_t length = 0; + napi_status statusMsg = napi_get_array_length(env, input, &length); + ASSERT((statusMsg == napi_ok) && (length > 0), "get_array go wrong!", napi_invalid_arg); + for (uint32_t i = 0; i < length; ++i) { + napi_value item = nullptr; + statusMsg = napi_get_element(env, input, i, &item); + ASSERT((item != nullptr) && (statusMsg == napi_ok), "no element", napi_invalid_arg); + std::string value; + statusMsg = GetValue(env, item, value); + ASSERT(statusMsg == napi_ok, "not a string", napi_invalid_arg); + out.push_back(value); + } + return statusMsg; +} + +napi_status NapiUtils::SetValue(napi_env env, const std::vector &input, napi_value &out) +{ + LOG_DEBUG("napi_value <- std::vector"); + napi_status status = napi_create_array_with_length(env, input.size(), &out); + ASSERT(status == napi_ok, "create array go wrong!", status); + int index = 0; + for (auto &item : input) { + napi_value element = nullptr; + SetValue(env, item, element); + status = napi_set_element(env, out, index++, element); + ASSERT((status == napi_ok), "napi_set_element go wrong!", status); + } + return status; +} + +/* napi_value <-> std::map */ +napi_status NapiUtils::GetValue(napi_env env, napi_value input, std::map &out) +{ + LOG_DEBUG("napi_value -> std::map "); + (void)(env); + (void)(input); + (void)(out); + ASSERT(false, "std::map from napi_value, unsupported!", napi_invalid_arg); + return napi_invalid_arg; +} + +napi_status NapiUtils::SetValue(napi_env environment, const std::map &input, napi_value &out) +{ + LOG_DEBUG("napi_value <- std::map "); + napi_status status = napi_create_array_with_length(environment, input.size(), &out); + ASSERT((status == napi_ok), "invalid object", status); + int index = 0; + for (const auto &[key, value] : input) { + napi_value element = nullptr; + napi_create_array_with_length(environment, TUPLE_SIZE, &element); + napi_value jsKey = nullptr; + napi_create_string_utf8(environment, key.c_str(), key.size(), &jsKey); + napi_set_element(environment, element, TUPLE_KEY, jsKey); + napi_value jsValue = nullptr; + napi_create_int32(environment, static_cast(value), &jsValue); + napi_set_element(environment, element, TUPLE_VALUE, jsValue); + napi_set_element(environment, out, index++, element); + } + return status; +} + +napi_status NapiUtils::GetCurrentAbilityParam(napi_env env, ContextParam ¶m) +{ + auto ability = AbilityRuntime::GetCurrentAbility(env); + if (ability == nullptr) { + LOG_ERROR("GetCurrentAbility go wrong"); + return napi_invalid_arg; + } + + auto context = ability->GetAbilityContext(); + if (context == nullptr) { + LOG_ERROR("GetAbilityContext go wrong"); + return napi_invalid_arg; + } + param.area = context->GetArea(); + param.baseDir = context->GetDatabaseDir(); + param.bundleName = context->GetBundleName(); + auto abilityInfo = context->GetAbilityInfo(); + if (abilityInfo != nullptr) { + param.moduleName = abilityInfo->moduleName; + } + return napi_ok; +} + +napi_status NapiUtils::GetValue(napi_env env, napi_value input, ContextParam ¶m) +{ + if (input == nullptr) { + LOG_INFO("get ContextParam, input is null"); + param.isStageMode = false; + return GetCurrentAbilityParam(env, param); + } + napi_status status = GetNamedProperty(env, input, "stageMode", param.isStageMode); + ASSERT(status == napi_ok, "get stageMode param go wrong", napi_invalid_arg); + if (!param.isStageMode) { + LOG_WARN("isStageMode false -> fa stage"); + return GetCurrentAbilityParam(env, param); + } + LOG_DEBUG("stage mode branch"); + status = GetNamedProperty(env, input, "databaseDir", param.baseDir); + ASSERT(status == napi_ok, "get databaseDir go wrong", napi_invalid_arg); + status = GetNamedProperty(env, input, "area", param.area, true); + ASSERT(status == napi_ok, "get area go wrong", napi_invalid_arg); + + napi_value hapInfo = nullptr; + GetNamedProperty(env, input, "currentHapModuleInfo", hapInfo); + if (hapInfo != nullptr) { + status = GetNamedProperty(env, hapInfo, "name", param.moduleName); + ASSERT(status == napi_ok, "get currentHapModuleInfo.name go wrong", napi_invalid_arg); + } + + napi_value appInfo = nullptr; + GetNamedProperty(env, input, "applicationInfo", hapInfo); + if (appInfo != nullptr) { + status = GetNamedProperty(env, appInfo, "name", param.bundleName); + ASSERT(status == napi_ok, "get applicationInfo.name go wrong", napi_invalid_arg); + status = GetNamedProperty(env, appInfo, "systemApp", param.isSystemApp, true); + ASSERT(status == napi_ok, "get applicationInfo.systemApp go wrong", napi_invalid_arg); + } + return napi_ok; +} + +napi_value NapiUtils::DefineClass(napi_env environment, const std::string &spaceName, const std::string &className, + const Descriptor &descriptor, napi_callback ctor) +{ + auto featureSpace = GetJsFeatureSpace(spaceName); + if (!featureSpace.has_value() || !featureSpace->isComponent) { + LOG_INFO("featureSpace has no feature space name"); + return nullptr; + } + if (GetClass(environment, spaceName, className)) { + return GetClass(environment, spaceName, className); + } + auto rootPropName = std::string(featureSpace->nameBase64); + napi_value root = nullptr; + bool hasRoot = false; + napi_value global = nullptr; + napi_get_global(environment, &global); + napi_has_named_property(environment, global, rootPropName.c_str(), &hasRoot); + if (hasRoot) { + napi_get_named_property(environment, global, rootPropName.c_str(), &root); + } else { + napi_create_object(environment, &root); + napi_set_named_property(environment, global, rootPropName.c_str(), root); + } + + std::string propName = "constructor_of_" + className; + napi_value constructor = nullptr; + bool hasProp = false; + napi_has_named_property(environment, root, propName.c_str(), &hasProp); + if (hasProp) { + napi_get_named_property(environment, root, propName.c_str(), &constructor); + if (constructor != nullptr) { + LOG_DEBUG("got data.distributedCollab.%{public}s as constructor", propName.c_str()); + return constructor; + } + hasProp = false; // no constructor. + } + + auto properties = descriptor(); + NAPI_CALL(environment, + napi_define_class(environment, + className.c_str(), + className.size(), + ctor, + nullptr, + properties.size(), + properties.data(), + &constructor)); + NAPI_ASSERT(environment, constructor != nullptr, "napi_define_class go wrong!"); + + if (!hasProp) { + napi_set_named_property(environment, root, propName.c_str(), constructor); + LOG_DEBUG("save constructor to data.distributedCollab.%{public}s", propName.c_str()); + } + return constructor; +} + +napi_value NapiUtils::GetClass(napi_env env, const std::string &spaceName, const std::string &className) +{ + auto featureSpace = GetJsFeatureSpace(spaceName); + if (!featureSpace.has_value()) { + LOG_DEBUG("featureSpace has no feature space name"); + return nullptr; + } + auto rootPropName = std::string(featureSpace->nameBase64); + napi_value root = nullptr; + napi_value global = nullptr; + napi_get_global(env, &global); + bool hasRoot; + napi_has_named_property(env, global, rootPropName.c_str(), &hasRoot); + if (!hasRoot) { + LOG_DEBUG("GetClass has no root"); + return nullptr; + } + napi_get_named_property(env, global, rootPropName.c_str(), &root); + std::string propName = "constructor_of_" + className; + bool hasProperty = false; + napi_value constructor = nullptr; + napi_has_named_property(env, root, propName.c_str(), &hasProperty); + if (!hasProperty) { + LOG_DEBUG("GetClass has no constructor_of_className %{public}s", className.c_str()); + return nullptr; + } + napi_get_named_property(env, root, propName.c_str(), &constructor); + if (constructor != nullptr) { + LOG_DEBUG("got data.distributedCollab.%{public}s as constructor", propName.c_str()); + return constructor; + } + hasProperty = false; // no constructor. + return constructor; +} + +bool NapiUtils::IsNull(napi_env env, napi_value value) +{ + napi_valuetype type = napi_undefined; + napi_status status = napi_typeof(env, value, &type); + if (status == napi_ok && (type == napi_undefined || type == napi_null)) { + return true; + } + return false; +} + +std::pair NapiUtils::GetInnerValue( + napi_env env, napi_value input, const std::string &prop, bool optional) +{ + bool hasProp = false; + napi_status status = napi_has_named_property(env, input, prop.c_str(), &hasProp); + if (status != napi_ok) { + return std::make_pair(napi_generic_failure, nullptr); + } + if (!hasProp) { + status = optional ? napi_ok : napi_generic_failure; + return std::make_pair(status, nullptr); + } + napi_value inner = nullptr; + status = napi_get_named_property(env, input, prop.c_str(), &inner); + if (status != napi_ok || inner == nullptr) { + return std::make_pair(napi_generic_failure, nullptr); + } + if (optional && NapiUtils::IsNull(env, inner)) { + return std::make_pair(napi_ok, nullptr); + } + return std::make_pair(napi_ok, inner); +} + +} // namespace OHOS::CollaborationEdit diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/test/BUILD.gn b/data_object/frameworks/jskitsimpl/collaboration_edit/test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..8c6395d9222c6945e299d48e4884c2c14c2d96bb --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/test/BUILD.gn @@ -0,0 +1,22 @@ +# Copyright (c) 2025 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. + +import("//build/test.gni") + +#################################group######################################### +group("unittest") { + testonly = true + deps = [] + deps += [ "unittest/src:unittest" ] +} +############################################################################### diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/config.json b/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/config.json new file mode 100644 index 0000000000000000000000000000000000000000..631703776ade9d9927a143ce222def6d2f5e0a51 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/config.json @@ -0,0 +1,63 @@ +{ + "app": { + "bundleName": "com.example.myapplication", + "vendor": "example", + "version": { + "code": 1, + "name": "1.0" + }, + "apiVersion": { + "compatible": 9, + "target": 14 + } + }, + "deviceConfig": {}, + "module": { + "package": "com.example.myapplication", + "name": ".MyApplication", + "deviceType": [ + "tablet", + "2in1", + "default", + "phone" + ], + "distro": { + "deliveryWithInstall": true, + "moduleName": "entry", + "moduleType": "entry" + }, + "abilities": [ + { + "visible": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ], + "name": "com.example.myapplication.MainAbility", + "icon": "$media:icon", + "description": "$string:mainability_description", + "label": "MyApplication", + "type": "page", + "launchType": "standard" + } + ], + "js": [ + { + "pages": [ + "pages/index/index" + ], + "name": "default", + "window": { + "designWidth": 720, + "autoDesignWidth": false + } + } + ] + } + } \ No newline at end of file diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/openharmony_sx.p7b b/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/openharmony_sx.p7b new file mode 100644 index 0000000000000000000000000000000000000000..9be1e98fa4c0c28ca997ed660112fa16b194f0f5 Binary files /dev/null and b/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/openharmony_sx.p7b differ diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/BUILD.gn b/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..8c49df4a9868120d3f495e18dbe075d96b5da7c6 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/BUILD.gn @@ -0,0 +1,29 @@ +# Copyright (C) 2025 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. + +import("//build/test.gni") + +module_output_path = "data_object/collaboration_edit" + +ohos_js_unittest("CollaborationEditJsTest") { + module_out_path = module_output_path + + hap_profile = "../config.json" + + certificate_profile = "../openharmony_sx.p7b" +} + +group("unittest") { + testonly = true + deps = [ ":CollaborationEditJsTest" ] +} diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/CollaborationEditUnit.test.js b/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/CollaborationEditUnit.test.js new file mode 100644 index 0000000000000000000000000000000000000000..3341c9888d9fb2d48c9e683d0976ee8c44be706d --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/CollaborationEditUnit.test.js @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file expect 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. + */ + +import { describe, beforeEach, afterEach, beforeAll, afterAll, it, expect } from 'deccjsunit/index' +import collaboration_edit from "@ohos.data.collaborationEditObject" +import ability_featureAbility from '@ohos.ability.featureAbility' + +const TAG = "[CollaborationEdit_JsTest]" +const DOC_CONFIG = {name: "doc_test"} +const EDIT_UNIT_NAME = "top" + +var context = ability_featureAbility.getContext() +var editObject = undefined; +var editUnit = undefined; + +describe('collaborationEditUnitTest', () => { + beforeAll(async () => { + console.log(TAG + "beforeAll"); + }) + + beforeEach(async () => { + console.log(TAG + "beforeEach"); + try { + editObject = collaboration_edit.getCollaborationEditObject(context, DOC_CONFIG); + editUnit = editObject.getEditUnit(EDIT_UNIT_NAME); + } catch (err) { + console.log(TAG + "get edit object failed. err: %s", err.message); + } + }) + + afterEach(async () => { + console.log(TAG + "afterEach"); + try { + collaboration_edit.deleteCollaborationEditObject(context, DOC_CONFIG); + console.log(TAG + "delete edit object successfully"); + } catch (err) { + console.log(TAG + "delete edit object failed. err: %s", err.message); + expect().assertFail(); + } + }) + + afterAll(async () => { + console.log(TAG + "afterAll"); + }) + + /** + * @tc.number CollaborationEdit_EditUnit_0001 + * @tc.name getEditUnit by invalid empty name + * @tc.desc + * 1. getEditUnit by empty input string + * 2. check 401 error code + */ + it("CollaborationEdit_EditUnit_0001", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_EditUnit_0001 Start*****************"); + let editUnit = undefined; + let errCode = ""; + try { + editUnit = editObject?.getEditUnit(""); + } catch (err) { + errCode = err.code; + } + expect(editUnit).assertUndefined(); + expect("401").assertEqual(errCode); + console.log(TAG + "*****************CollaborationEdit_EditUnit_0001 End*****************"); + }) + + /** + * @tc.number CollaborationEdit_EditUnit_0002 + * @tc.name EditUnit.insertNodes by null array + * @tc.desc + * 1. check EditUnit.getName + * 2. insert null node array and check 401 error code + */ + it("CollaborationEdit_EditUnit_0002", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_EditUnit_0002 Start*****************"); + expect(editUnit !== undefined).assertTrue(); + expect(EDIT_UNIT_NAME).assertEqual(editUnit?.getName()); + let errCode = ""; + try { + editUnit?.insertNodes(0, null); + } catch (err) { + console.log(TAG + "insert node failed. err: %s", err); + errCode = err.code; + } + expect("401").assertEqual(errCode); + console.log(TAG + "*****************CollaborationEdit_EditUnit_0002 End*****************"); + }) + + /** + * @tc.number CollaborationEdit_EditUnit_0003 + * @tc.name Normal test case of methods in EditUnit + * @tc.desc + * 1. construct node list + * 2. EditUnit.insertNodes + * 3. check the id of inserted nodes + * 4. EditUnit.getChildren and check result + * 5. EditUnit.getJsonResult and check result + */ + it("CollaborationEdit_EditUnit_0003", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_EditUnit_0003 Start*****************"); + expect(editUnit !== undefined).assertTrue(); + try { + let node1 = new collaboration_edit.Node("p1"); + let node2 = new collaboration_edit.Node("p2"); + editUnit?.insertNodes(0, [node1, node2]); + expect(node1.getId() !== undefined).assertTrue(); + expect(node2.getId() !== undefined).assertTrue(); + expect(node1.getId().clock).assertEqual(0); + expect(node2.getId().clock).assertEqual(1); + let nodeList = editUnit?.getChildren(0, 2); + expect(nodeList !== undefined).assertTrue(); + expect(2).assertEqual(nodeList?.length); + if (nodeList !== undefined) { + expect(nodeList[0].getId().clock).assertEqual(0); + expect(nodeList[1].getId().clock).assertEqual(1); + } + let jsonStr = editUnit?.getJsonResult(); + expect(jsonStr !== undefined).assertTrue(); + expect(jsonStr).assertEqual("{\"array\":[{\"ele\":{\"name\":\"p1\",\"attr\":{},\"children\":[]}},{\"ele\":{\"name\":\"p2\",\"attr\":{},\"children\":[]}}]}"); + } catch (err) { + console.log(TAG + "CollaborationEdit_EditUnit_0003 failed. err: %s", err); + expect().assertFail(); + } + console.log(TAG + "*****************CollaborationEdit_EditUnit_0003 End*****************"); + }) + + /** + * @tc.number CollaborationEdit_EditUnit_0004 + * @tc.name EditUnit.getChildren by invalid input + * @tc.desc + * 1. start is negative + * 2. end is negative + * 3. start is greater than end + */ + it("CollaborationEdit_EditUnit_0004", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_EditUnit_0004 Start*****************"); + expect(editUnit !== undefined).assertTrue(); + + let errCode = ""; + try { + editUnit.getChildren(-1, 2); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + + errCode = ""; + try { + editUnit.getChildren(0, -1); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + + errCode = ""; + try { + editUnit.getChildren(1, 0); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + + console.log(TAG + "*****************CollaborationEdit_EditUnit_0004 End*****************"); + }) + + /** + * @tc.number CollaborationEdit_EditUnit_0005 + * @tc.name EditUnit.delete by invalid input + * @tc.desc + * 1. index is negative + * 2. length is negative or zero + */ + it("CollaborationEdit_EditUnit_0005", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_EditUnit_0005 Start*****************"); + expect(editUnit !== undefined).assertTrue(); + + let errCode = ""; + try { + editUnit.delete(-1, 2); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + + errCode = ""; + try { + editUnit.delete(0, 0); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + + console.log(TAG + "*****************CollaborationEdit_EditUnit_0005 End*****************"); + }) + + /** + * @tc.number CollaborationEdit_EditUnit_0006 + * @tc.name EditUnit.insertNodes by invalid index + * @tc.desc + * 1. index is invalid and check 401 error code + */ + it("CollaborationEdit_EditUnit_0006", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_EditUnit_0006 Start*****************"); + expect(editUnit !== undefined).assertTrue(); + + let errCode = ""; + try { + editUnit.insertNodes(-1, []); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + console.log(TAG + "*****************CollaborationEdit_EditUnit_0006 End*****************"); + }) +}) diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/CollaborationGetEditObject.test.js b/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/CollaborationGetEditObject.test.js new file mode 100644 index 0000000000000000000000000000000000000000..f28418e1df4795d4ba872104d5b2e9d4774312d8 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/CollaborationGetEditObject.test.js @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file expect 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. + */ + +import { describe, beforeEach, afterEach, beforeAll, afterAll, it, expect } from 'deccjsunit/index' +import collaboration_edit from "@ohos.data.collaborationEditObject" +import ability_featureAbility from '@ohos.ability.featureAbility' + +const TAG = "[CollaborationEdit_JsTest]" +const DOC_CONFIG = {name: "doc_test"} + +var context = ability_featureAbility.getContext() + +describe('collaborationGetEditObjectTest', () => { + beforeAll(async () => { + console.log(TAG + "beforeAll"); + }) + + beforeEach(async () => { + console.log(TAG + "beforeEach"); + }) + + afterEach(async () => { + console.log(TAG + "afterEach"); + try { + collaboration_edit.deleteCollaborationEditObject(context, DOC_CONFIG); + console.log(TAG + "delete edit object successfully"); + } catch (err) { + console.log(TAG + "delete edit object failed. err: %s", err.message); + expect().assertFail(); + } + }) + + afterAll(async () => { + console.log(TAG + "afterAll"); + }) + + /** + * @tc.number CollaborationEdit_GetEditObject_0001 + * @tc.name Normal case of getCollaborationEditObject + * @tc.desc + * 1. get collaboration edit object correctly + * 2. delete edit object by empty name, then check 401 code + */ + it("CollaborationEdit_GetEditObject_0001", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_GetEditObject_0001 Start*****************"); + let editObject = undefined; + try { + editObject = collaboration_edit.getCollaborationEditObject(context, DOC_CONFIG); + expect(editObject !== undefined).assertTrue(); + } catch (err) { + console.log(TAG + "CollaborationEdit_GetEditObject_0001 failed."); + expect().assertFail(); + } + + let errCode = ""; + try { + collaboration_edit.deleteCollaborationEditObject(context, {name: ""}); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + console.log(TAG + "*****************CollaborationEdit_GetEditObject_0001 End*****************"); + }) + + /** + * @tc.number CollaborationEdit_GetEditObject_0002 + * @tc.name getCollaborationEditObject by null context + * @tc.desc + * 1. get collaboration edit object by null context + * 2. check 401 error code + */ + it("CollaborationEdit_GetEditObject_0002", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_GetEditObject_0002 Start*****************"); + let editObject = undefined; + let errCode = ""; + try { + editObject = collaboration_edit.getCollaborationEditObject(null, DOC_CONFIG); + } catch (err) { + errCode = err.code; + } + expect(editObject).assertUndefined(); + expect("401").assertEqual(errCode); + console.log(TAG + "*****************CollaborationEdit_GetEditObject_0002 End*****************"); + }) + + /** + * @tc.number CollaborationEdit_GetEditObject_0003 + * @tc.name getCollaborationEditObject by empty name + * @tc.desc + * 1. get collaboration edit object by empty name + * 2. check 401 error code + */ + it("CollaborationEdit_GetEditObject_0003", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_GetEditObject_0003 Start*****************"); + let editObject = undefined; + let errCode = ""; + try { + editObject = collaboration_edit.getCollaborationEditObject(context, {name: ""}); + } catch (err) { + errCode = err.code; + } + expect(editObject).assertUndefined(); + expect("401").assertEqual(errCode); + console.log(TAG + "*****************CollaborationEdit_GetEditObject_0003 End*****************"); + }) +}) diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/CollaborationNode.test.js b/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/CollaborationNode.test.js new file mode 100644 index 0000000000000000000000000000000000000000..d517b88e49312e4c93bfc5b84d507579eb2ce4ac --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/CollaborationNode.test.js @@ -0,0 +1,342 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file expect 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. + */ + +import { describe, beforeEach, afterEach, beforeAll, afterAll, it, expect } from 'deccjsunit/index' +import collaboration_edit from "@ohos.data.collaborationEditObject" +import ability_featureAbility from '@ohos.ability.featureAbility' + +const TAG = "[CollaborationEdit_JsTest]" +const DOC_CONFIG = {name: "doc_test"} +const EDIT_UNIT_NAME = "top" + +var context = ability_featureAbility.getContext() +var editObject = undefined; +var editUnit = undefined; + +describe('collaborationNodeTest', () => { + beforeAll(async () => { + console.log(TAG + "beforeAll"); + }) + + beforeEach(async () => { + console.log(TAG + "beforeEach"); + try { + editObject = collaboration_edit.getCollaborationEditObject(context, DOC_CONFIG); + editUnit = editObject.getEditUnit(EDIT_UNIT_NAME); + } catch (err) { + console.log(TAG + "get edit object failed. err: %s", err.message); + } + }) + + afterEach(async () => { + console.log(TAG + "afterEach"); + try { + collaboration_edit.deleteCollaborationEditObject(context, DOC_CONFIG); + console.log(TAG + "delete edit object failed. err: %s", err.message); + } catch (err) { + console.log(TAG + "delete edit object failed"); + expect().assertFail(); + } + }) + + afterAll(async () => { + console.log(TAG + "afterAll"); + }) + + /** + * @tc.number CollaborationEdit_Node_0001 + * @tc.name Normal case of attribute-related methods + * @tc.desc + * 1. construct a node list and insert them into edit unit + * 2. set diffrent attributes + * 3. get attributes and check result + * 4. get json result and check result + * 5. remove some attributes + * 6. again check result by getAttributes and getJsonResult + */ + it("CollaborationEdit_Node_0001", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_Node_0001 Start*****************"); + expect(editUnit !== undefined).assertTrue(); + try { + let node1 = new collaboration_edit.Node("p1"); + editUnit?.insertNodes(0, [node1]); + node1.setAttributes({"align": "left", "width": 36, "italics": true}); + let attrs = node1.getAttributes(); + expect(attrs["align"]).assertEqual("left"); + expect(attrs["width"]).assertEqual("36"); + expect(attrs["italics"]).assertEqual("true"); + let jsonStr = node1.getJsonResult(); + expect(jsonStr !== undefined).assertTrue(); + expect(jsonStr).assertEqual("{\"array\":[{\"ele\":{\"name\":\"p1\",\"attr\":{\"align\":\"left\",\"italics\":\"true\",\"width\":\"36\"},\"children\":[]}}]}"); + node1.removeAttributes(["align", "italics"]); + attrs = node1.getAttributes(); + expect(attrs["align"]).assertUndefined(); + expect(attrs["width"]).assertEqual("36"); + expect(attrs["italics"]).assertUndefined(); + jsonStr = node1.getJsonResult(); + expect(jsonStr !== undefined).assertTrue(); + expect(jsonStr).assertEqual("{\"array\":[{\"ele\":{\"name\":\"p1\",\"attr\":{\"width\":\"36\"},\"children\":[]}}]}"); + } catch (err) { + console.log(TAG + "CollaborationEdit_Node_0001 failed. err: %s", err); + expect().assertFail(); + } + console.log(TAG + "*****************CollaborationEdit_Node_0001 End*****************"); + }) + + /** + * @tc.number CollaborationEdit_Node_0002 + * @tc.name Normal case of insertTexts and delete + * @tc.desc + * 1. construct a node and insert it into edit unit + * 2. construct a text list and insert them into the node + * 3. check the unique id of the texts + * 4. getChildren and check unique id of the result list + * 5. getJsonResult and check the result + * 6. delete the first child + * 7. again check result by getChildren and getJsonResult + */ + it("CollaborationEdit_Node_0002", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_Node_0002 Start*****************"); + expect(editUnit !== undefined).assertTrue(); + try { + let node1 = new collaboration_edit.Node("p1"); + editUnit?.insertNodes(0, [node1]); + + // insert Texts + let text1 = new collaboration_edit.Text(); + let text2 = new collaboration_edit.Text(); + node1.insertTexts(0, [text1, text2]); + expect(text1.getId() !== undefined).assertTrue(); + expect(text2.getId() !== undefined).assertTrue(); + expect(text1.getId().clock).assertEqual(1); + expect(text2.getId().clock).assertEqual(2); + let nodeList = node1.getChildren(0, 2); + expect(nodeList !== undefined).assertTrue(); + expect(2).assertEqual(nodeList.length); + if (nodeList !== undefined) { + expect(nodeList[0].getId().clock).assertEqual(1); + expect(nodeList[1].getId().clock).assertEqual(2); + } + let jsonStr = node1.getJsonResult(); + expect(jsonStr !== undefined).assertTrue(); + expect(jsonStr).assertEqual("{\"array\":[{\"ele\":{\"name\":\"p1\",\"attr\":{},\"children\":[{\"text\":\"[]\"},{\"text\":\"[]\"}]}}]}"); + + // delete first child + node1.delete(0, 1); + nodeList = node1.getChildren(0, 2); // if end out of length, return all + expect(1).assertEqual(nodeList.length); + expect(nodeList[0].getId().clock).assertEqual(2); + jsonStr = node1.getJsonResult(); + expect(jsonStr).assertEqual("{\"array\":[{\"ele\":{\"name\":\"p1\",\"attr\":{},\"children\":[{\"text\":\"[]\"}]}}]}"); + } catch (err) { + console.log(TAG + "CollaborationEdit_Node_0002 failed. err: %s", err); + expect().assertFail(); + } + console.log(TAG + "*****************CollaborationEdit_Node_0002 End*****************"); + }) + + /** + * @tc.number CollaborationEdit_Node_0003 + * @tc.name Normal case of insertNode and delete + * @tc.desc + * 1. construct a node p1 and insert it into edit unit + * 2. construct a node list and insert them into the node p1 + * 3. check the unique id of the node list + * 4. getChildren and check unique id of the result list + * 5. getJsonResult and check the result + * 6. delete the second child + * 7. again check result by getChildren and getJsonResult + */ + it("CollaborationEdit_Node_0003", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_Node_0003 Start*****************"); + expect(editUnit !== undefined).assertTrue(); + try { + let node1 = new collaboration_edit.Node("p1"); + editUnit?.insertNodes(0, [node1]); + + // insert Nodes + let node2 = new collaboration_edit.Node("p2"); + let node3 = new collaboration_edit.Node("p3"); + node1?.insertNodes(0, [node2, node3]); + expect(node2.getId() !== undefined).assertTrue(); + expect(node3.getId() != undefined).assertTrue(); + expect(node2.getId().clock).assertEqual(1); + expect(node3.getId().clock).assertEqual(2); + let nodeList = node1?.getChildren(0, 2); + expect(nodeList !== undefined).assertTrue(); + expect(2).assertEqual(nodeList?.length); + if (nodeList !== undefined) { + expect(nodeList[0].getId().clock).assertEqual(1); + expect(nodeList[1].getId().clock).assertEqual(2); + } + let jsonStr = node1?.getJsonResult(); + expect(jsonStr !== undefined).assertTrue(); + expect(jsonStr).assertEqual("{\"array\":[{\"ele\":{\"name\":\"p1\",\"attr\":{},\"children\":[{\"ele\":{\"name\":\"p2\",\"attr\":{},\"children\":[]}},{\"ele\":{\"name\":\"p3\",\"attr\":{},\"children\":[]}}]}}]}"); + + // delete second child + node1.delete(1, 1); + nodeList = node1.getChildren(0, 2); // if end out of length, return all + expect(1).assertEqual(nodeList.length); + expect(nodeList[0].getId().clock).assertEqual(1); + jsonStr = node1.getJsonResult(); + expect(jsonStr).assertEqual("{\"array\":[{\"ele\":{\"name\":\"p1\",\"attr\":{},\"children\":[{\"ele\":{\"name\":\"p2\",\"attr\":{},\"children\":[]}}]}}]}"); + } catch (err) { + console.log(TAG + "CollaborationEdit_Node_0003 failed. err: %s", err); + expect().assertFail(); + } + console.log(TAG + "*****************CollaborationEdit_Node_0003 End*****************"); + }) + + /** + * @tc.number CollaborationEdit_Node_0004 + * @tc.name test getChildren by index out of range + * @tc.desc + * 1. construct a node list and insert them into edit unit + * 2. construct a text list and insert them into the node + * 3. check the unique id of the texts + * 4. getChildren if start and end are out of range + * 5. check error code + */ + it("CollaborationEdit_Node_0004", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_Node_0004 Start*****************"); + expect(editUnit !== undefined).assertTrue(); + let errCode = ""; + let nodeList = undefined; + try { + let node1 = new collaboration_edit.Node("p1"); + editUnit?.insertNodes(0, [node1]); + + // insert Texts + let text1 = new collaboration_edit.Text(); + let text2 = new collaboration_edit.Text(); + node1.insertTexts(0, [text1, text2]); + expect(text1.getId() !== undefined).assertTrue(); + expect(text2.getId() !== undefined).assertTrue(); + expect(text1.getId().clock).assertEqual(1); + expect(text2.getId().clock).assertEqual(2); + nodeList = node1.getChildren(2, 4); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("15410002"); + expect(nodeList).assertUndefined(); + console.log(TAG + "*****************CollaborationEdit_Node_0004 End*****************"); + }) + + /** + * @tc.number CollaborationEdit_Node_0005 + * @tc.name Invalid operation if node is not inserted + * @tc.desc + * 1. construct a node + * 2. call getId/setAttributes of the node + * 3. check the invalid operation error code + */ + it("CollaborationEdit_Node_0005", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_Node_0005 Start*****************"); + let node = new collaboration_edit.Node("p1"); + let errCode = ""; + let id = undefined; + try { + id = node.getId(); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("15410001"); + expect(id).assertUndefined(); + + errCode = ""; + try { + node.setAttributes({ + "align": "left" + }); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("15410001"); + console.log(TAG + "*****************CollaborationEdit_Node_0005 End*****************"); + }) + + /** + * @tc.number CollaborationEdit_Node_0006 + * @tc.name Invalid index input when call insertXXXs/delete/getChildren + * @tc.desc + * 1. insertNodes - index is negative + * 2. insertTexts - index is negative + * 3. delete - index is negative + * 4. delete - length is negative or zero + * 5. getChildren - start is negative + * 6. getChildren - start is greater than end + */ + it("CollaborationEdit_Node_0006", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_Node_0006 Start*****************"); + let node = undefined; + try { + node = new collaboration_edit.Node("p1"); + editUnit.insertNodes(0, [node]); + } catch (err) { + console.log(TAG + "CollaborationEdit_Node_0006 insertNodes failed, err: %s", err); + expect().assertFail(); + } + expect(node !== undefined).assertTrue(); + let errCode = ""; + try { + node.insertNodes(-1, []); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + + errCode = ""; + try { + node.insertTexts(-1, []); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + + errCode = ""; + try { + node.delete(-1, 1); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + + errCode = ""; + try { + node.delete(0, 0); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + + errCode = ""; + try { + node.getChildren(-1, 1); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + + errCode = ""; + try { + node.getChildren(1, 0); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + console.log(TAG + "*****************CollaborationEdit_Node_0006 End*****************"); + }) +}) diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/CollaborationText.test.js b/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/CollaborationText.test.js new file mode 100644 index 0000000000000000000000000000000000000000..69ee372478629eb1658375043f6affe0424bc70b --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/CollaborationText.test.js @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file expect 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. + */ + +import { describe, beforeEach, afterEach, beforeAll, afterAll, it, expect } from 'deccjsunit/index' +import collaboration_edit from "@ohos.data.collaborationEditObject" +import ability_featureAbility from '@ohos.ability.featureAbility' + +const TAG = "[CollaborationEdit_JsTest]" +const DOC_CONFIG = {name: "doc_test"} +const EDIT_UNIT_NAME = "top" + +var context = ability_featureAbility.getContext() +var editObject = undefined; +var editUnit = undefined; + +describe('collaborationTextTest', () => { + beforeAll(async () => { + console.log(TAG + "beforeAll"); + }) + + beforeEach(async () => { + console.log(TAG + "beforeEach"); + try { + editObject = collaboration_edit.getCollaborationEditObject(context, DOC_CONFIG); + editUnit = editObject.getEditUnit(EDIT_UNIT_NAME); + } catch (err) { + console.log(TAG + "get edit object failed. err: %s", err.message); + } + }) + + afterEach(async () => { + console.log(TAG + "afterEach"); + try { + collaboration_edit.deleteCollaborationEditObject(context, DOC_CONFIG); + console.log(TAG + "delete edit object successfully"); + } catch (err) { + console.log(TAG + "delete edit object failed. err: %s", err.message); + expect().assertFail(); + } + }) + + afterAll(async () => { + console.log(TAG + "afterAll"); + }) + + /** + * @tc.number CollaborationEdit_Text_0001 + * @tc.name Normal test case of methods in Text + * @tc.desc + * 1. construct a node and insert it into edit unit + * 2. construct a text and insert it into the node + * 3. insert strings into text + * 4. check result by getPlainText and getJsonResult + * 5. format some characters and check result by getJsonResult + * 6. delete some characters and check result by getPlainText and getJsonResult + */ + it("CollaborationEdit_Text_0001", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_Text_0001 Start*****************"); + expect(editUnit !== undefined).assertTrue(); + try { + let node = new collaboration_edit.Node("p1"); + editUnit?.insertNodes(0, [node]); + + // insert Text + let text = new collaboration_edit.Text(); + node.insertTexts(0, [text]); + expect(text.getId() !== undefined).assertTrue(); + expect(text.getId().clock).assertEqual(1); + + // insert string into text + text.insert(0, "abc"); + text.insert(3, "def", {"color":"red", "isBold":true}); + let plainText = text.getPlainText(); + expect(plainText).assertEqual("abcdef"); + let jsonStr = text.getJsonResult(); + expect(jsonStr).assertEqual("[{\"insert\":\"abc\"},{\"insert\":\"def\",\"attributes\":{\"color\":\"red\",\"isBold\":\"true\"}}]"); + + // format text + text.format(1, 2, {"font-size": 12}); + jsonStr = text.getJsonResult(); + console.log(TAG + "json str = %s", jsonStr); + expect(jsonStr).assertEqual("[{\"insert\":\"a\"},{\"insert\":\"bc\",\"attributes\":{\"font-size\":\"12\"}},{\"insert\":\"def\",\"attributes\":{\"color\":\"red\",\"isBold\":\"true\"}}]"); + + // delete + text.delete(2, 3); + plainText = text.getPlainText(); + expect(plainText).assertEqual("abf"); + jsonStr = text.getJsonResult(); + expect(jsonStr).assertEqual("[{\"insert\":\"a\"},{\"insert\":\"b\",\"attributes\":{\"font-size\":\"12\"}},{\"insert\":\"f\",\"attributes\":{\"color\":\"red\",\"isBold\":\"true\"}}]"); + } catch (err) { + console.log(TAG + "CollaborationEdit_Text_0001 failed. err: %s", err); + expect().assertFail(); + } + console.log(TAG + "*****************CollaborationEdit_Text_0001 End*****************"); + }) + + /** + * @tc.number CollaborationEdit_Text_0002 + * @tc.name Invalid operation if the text is not inserted + * @tc.desc + * 1. construct a text + * 2. call getId/insert of the text + * 3. check the invalid operation error code + */ + it("CollaborationEdit_Text_0002", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_Text_0002 Start*****************"); + let text = new collaboration_edit.Text(); + let errCode = ""; + let id = undefined; + try { + id = text.getId(); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("15410001"); + expect(id).assertUndefined(); + + errCode = ""; + try { + text.insert(0, "abc"); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("15410001"); + console.log(TAG + "*****************CollaborationEdit_Text_0002 End*****************"); + }) + + /** + * @tc.number CollaborationEdit_Text_0003 + * @tc.name Invalid index input when call insert/delete/format + * @tc.desc + * 1. construct a node and insert it into edit unit + * 2. construct a text and insert it into the node + * 3. insert string if the index is negative + * 4. delete if the index is negative + * 5. delete if the length is negative or zero + * 6. format if the index is negative + * 7. format if the length is negative or zero + */ + it("CollaborationEdit_Text_0003", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_Text_0003 Start*****************"); + let text = undefined; + try { + let node = new collaboration_edit.Node("p1"); + editUnit?.insertNodes(0, [node]); + text = new collaboration_edit.Text(); + node.insertTexts(0, [text]); + } catch (err) { + console.log(TAG + "CollaborationEdit_Text_0003 failed, err: %s", err); + expect().assertFail(); + } + let errCode = ""; + try { + text.insert(-1, "abc"); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + + errCode = ""; + try { + text.delete(-1, 1); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + + errCode = ""; + try { + text.delete(0, 0); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + + errCode = ""; + try { + text.format(-1, 1, {"color":"red"}); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + + errCode = ""; + try { + text.format(0, 0, {"color":"red"}); + } catch (err) { + errCode = err.code; + } + expect(errCode).assertEqual("401"); + console.log(TAG + "*****************CollaborationEdit_Text_0003 End*****************"); + }) +}) diff --git a/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/CollaborationUndoRedo.test.js b/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/CollaborationUndoRedo.test.js new file mode 100644 index 0000000000000000000000000000000000000000..4748c5161155adcdbac560704e4dfecd66c5a834 --- /dev/null +++ b/data_object/frameworks/jskitsimpl/collaboration_edit/test/unittest/src/CollaborationUndoRedo.test.js @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file expect 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. + */ + +import { describe, beforeEach, afterEach, beforeAll, afterAll, it, expect } from 'deccjsunit/index' +import collaboration_edit from "@ohos.data.collaborationEditObject" +import ability_featureAbility from '@ohos.ability.featureAbility' + +const TAG = "[CollaborationEdit_JsTest]" +const DOC_CONFIG = {name: "doc_test"} +const EDIT_UNIT_NAME = "top" + +var context = ability_featureAbility.getContext() +var editObject = undefined; +var editUnit = undefined; + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +describe('collaborationUndoRedoTest', () => { + beforeAll(async () => { + console.log(TAG + "beforeAll"); + }) + + beforeEach(async () => { + console.log(TAG + "beforeEach"); + try { + editObject = collaboration_edit.getCollaborationEditObject(context, DOC_CONFIG); + editUnit = editObject.getEditUnit(EDIT_UNIT_NAME); + } catch (err) { + console.log(TAG + "get edit object failed. err: %s", err.message); + } + }) + + afterEach(async () => { + console.log(TAG + "afterEach"); + try { + collaboration_edit.deleteCollaborationEditObject(context, DOC_CONFIG); + console.log(TAG + "delete edit object successfully"); + } catch (err) { + console.log(TAG + "delete edit object failed. err: %s", err.message); + expect().assertFail(); + } + }) + + afterAll(async () => { + console.log(TAG + "afterAll"); + }) + + /** + * @tc.number CollaborationEdit_UndoRedo_0001 + * @tc.name getUndoRedoManager when editUnitName is non-empty, captureTimeout is float + * @tc.desc + * 1. editUnitName is any non-empty string + * 2. captureTimeout is float + */ + it("CollaborationEdit_UndoRedo_0001", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_UndoRedo_0001 Start*****************"); + expect(editUnit !== undefined).assertTrue(); + let undoManager = undefined; + try { + // captureTimeoutéžæ•´æ•°ï¼Œå‘䏋喿•´ + undoManager = editObject?.getUndoRedoManager("notFound", {captureTimeout: 500.95}); + } catch (err) { + console.log(TAG + "getUndoRedoManager failed. err: %s", err); + } + expect(undoManager !== undefined).assertTrue(); + }) + + /** + * @tc.number CollaborationEdit_UndoRedo_0002 + * @tc.name getUndoRedoManager when captureTimeout is negative + * @tc.desc + * 1. captureTimeout is negative, then check 401 error code + */ + it("CollaborationEdit_UndoRedo_0002", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_UndoRedo_0002 Start*****************"); + expect(editUnit !== undefined).assertTrue(); + let undoManager = undefined; + let errCode = ""; + try { + undoManager = editObject?.getUndoRedoManager("top", {captureTimeout: -1}); + } catch (err) { + console.log(TAG + "getUndoRedoManager failed. err: %s", err); + errCode = err.code; + } + expect(undoManager).assertUndefined(); + expect(errCode).assertEqual("401"); + }) + + /** + * @tc.number CollaborationEdit_UndoRedo_0003 + * @tc.name Noraml case of undo/redo after setAttributes + * @tc.desc + * 1. get undoRedoManager + * 2. construct a node and insert it into edit unit + * 3. wait for 500ms + * 4. set attributes into the node, then check attributes + * 5. call undo, then check attributes undefined + * 6. call redo, then check attributes + */ + it("CollaborationEdit_UndoRedo_0003", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_UndoRedo_0003 Start*****************"); + expect(editUnit !== undefined).assertTrue(); + let undoManager = undefined; + try { + undoManager = editObject?.getUndoRedoManager("top", {captureTimeout: 500}); + expect(undoManager !== undefined).assertTrue(); + let node1 = new collaboration_edit.Node("p1"); + editUnit?.insertNodes(0, [node1]); + let nodeList = editUnit?.getChildren(0, 1); + expect(nodeList !== undefined).assertTrue(); + expect(1).assertEqual(nodeList?.length); + + // sleep for 500ms then set attributes + await sleep(500); + node1.setAttributes({"align": "left", "width": 36, "italics": true}); + let attrs = node1.getAttributes(); + expect(attrs["align"]).assertEqual("left"); + expect(attrs["width"]).assertEqual("36"); + expect(attrs["italics"]).assertEqual("true"); + + // undo + undoManager?.undo(); + attrs = node1.getAttributes(); + expect(attrs["align"]).assertUndefined(); + expect(attrs["width"]).assertUndefined(); + expect(attrs["italics"]).assertUndefined(); + + // redo + undoManager?.redo(); + attrs = node1.getAttributes(); + expect(attrs["align"]).assertEqual("left"); + expect(attrs["width"]).assertEqual("36"); + expect(attrs["italics"]).assertEqual("true"); + } catch (err) { + console.log(TAG + "CollaborationEdit_UndoRedo_0003 failed. err: %s", err); + expect().assertFail(); + } + }) + + /** + * @tc.number CollaborationEdit_UndoRedo_0004 + * @tc.name Noraml case of undo/redo after insertTexts + * @tc.desc + * 1. get undoRedoManager + * 2. construct a node and insert it into edit unit + * 3. wait for 500ms + * 4. insert texts into the node, then check clock of the text + * 5. call undo, then check result + * 6. call redo, then check clock of the texts children + */ + it("CollaborationEdit_UndoRedo_0004", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_UndoRedo_0004 Start*****************"); + expect(editUnit !== undefined).assertTrue(); + let undoManager = undefined; + try { + undoManager = editObject?.getUndoRedoManager("top", {captureTimeout: 500}); + expect(undoManager !== undefined).assertTrue(); + let node1 = new collaboration_edit.Node("p1"); + editUnit?.insertNodes(0, [node1]); + let nodeList = editUnit?.getChildren(0, 1); + expect(nodeList !== undefined).assertTrue(); + expect(1).assertEqual(nodeList?.length); + + // sleep for 500ms then insert Texts + await sleep(500); + let text1 = new collaboration_edit.Text(); + let text2 = new collaboration_edit.Text(); + node1.insertTexts(0, [text1, text2]); + nodeList = node1.getChildren(0, 2); + expect(nodeList !== undefined).assertTrue(); + expect(2).assertEqual(nodeList.length); + if (nodeList !== undefined) { + expect(nodeList[0].getId().clock).assertEqual(1); + expect(nodeList[1].getId().clock).assertEqual(2); + } + let jsonStr = node1.getJsonResult(); + expect(jsonStr !== undefined).assertTrue(); + expect(jsonStr).assertEqual("{\"array\":[{\"ele\":{\"name\":\"p1\",\"attr\":{},\"children\":[{\"text\":\"[]\"},{\"text\":\"[]\"}]}}]}"); + + // undo + undoManager?.undo(); + jsonStr = node1.getJsonResult(); + expect(jsonStr !== undefined).assertTrue(); + expect(jsonStr).assertEqual("{\"array\":[{\"ele\":{\"name\":\"p1\",\"attr\":{},\"children\":[]}}]}"); + + // redo + undoManager?.redo(); + nodeList = node1.getChildren(0, 2); + expect(nodeList !== undefined).assertTrue(); + expect(2).assertEqual(nodeList.length); + if (nodeList !== undefined) { + expect(nodeList[0].getId().clock).assertEqual(3); + expect(nodeList[1].getId().clock).assertEqual(4); + } + jsonStr = node1.getJsonResult(); + expect(jsonStr !== undefined).assertTrue(); + expect(jsonStr).assertEqual("{\"array\":[{\"ele\":{\"name\":\"p1\",\"attr\":{},\"children\":[{\"text\":\"[]\"},{\"text\":\"[]\"}]}}]}"); + } catch (err) { + console.log(TAG + "CollaborationEdit_UndoRedo_0004 failed. err: %s", err); + expect().assertFail(); + } + }) + + /** + * @tc.number CollaborationEdit_UndoRedo_0005 + * @tc.name Noraml case of undo/redo after inserting strings into text + * @tc.desc + * 1. get undoRedoManager + * 2. construct a node and insert it into edit unit + * 3. construct a text and insert it into the node + * 4. wait for 500ms + * 5. insert strings into texts and check result + * 5. call undo, then check the content of the text is empty + * 6. call redo, then check the content of the text + */ + it("CollaborationEdit_UndoRedo_0005", 0, async () => { + console.log(TAG + "*****************CollaborationEdit_UndoRedo_0005 Start*****************"); + expect(editUnit !== undefined).assertTrue(); + let undoManager = undefined; + try { + undoManager = editObject?.getUndoRedoManager("top", {captureTimeout: 500}); + expect(undoManager !== undefined).assertTrue(); + let node1 = new collaboration_edit.Node("p1"); + editUnit?.insertNodes(0, [node1]); + let nodeList = editUnit?.getChildren(0, 1); + expect(nodeList !== undefined).assertTrue(); + expect(1).assertEqual(nodeList?.length); + + // insert Texts + let text = new collaboration_edit.Text(); + node1.insertTexts(0, [text]); + + // sleep for 500ms then insert strings into text + await sleep(500); + text.insert(0, "abc"); + text.insert(3, "def", {"color": "red", "font-size":12}); + let plainText = text.getPlainText(); + expect(plainText).assertEqual("abcdef"); + let jsonStr = text.getJsonResult(); + expect(jsonStr).assertEqual("[{\"insert\":\"abc\"},{\"insert\":\"def\",\"attributes\":{\"color\":\"red\",\"font-size\":\"12\"}}]"); + + // undo + undoManager?.undo(); + plainText = text.getPlainText(); + expect(plainText).assertEqual(""); + jsonStr = text.getJsonResult(); + expect(jsonStr).assertEqual("[]"); + + // redo + undoManager?.redo(); + plainText = text.getPlainText(); + expect(plainText).assertEqual("abcdef"); + jsonStr = text.getJsonResult(); + expect(jsonStr).assertEqual("[{\"insert\":\"abc\"},{\"insert\":\"def\",\"attributes\":{\"color\":\"red\",\"font-size\":\"12\"}}]"); + + } catch (err) { + console.log(TAG + "CollaborationEdit_UndoRedo_0005 failed. err: %s", err); + expect().assertFail(); + } + }) +}) diff --git a/data_object/frameworks/jskitsimpl/include/adaptor/js_object_wrapper.h b/data_object/frameworks/jskitsimpl/include/adaptor/js_object_wrapper.h index 0f8ea760c8d82748d4df8fab04d97ba4f61ee7d4..c6acf0b9deb46d8f8f6419ad574fd1d778c56551 100644 --- a/data_object/frameworks/jskitsimpl/include/adaptor/js_object_wrapper.h +++ b/data_object/frameworks/jskitsimpl/include/adaptor/js_object_wrapper.h @@ -42,7 +42,8 @@ private: DistributedObject *object_; std::shared_ptr watcher_ = nullptr; std::shared_mutex watchMutex_{}; - std::vector undefinedProperties; + std::mutex mutex_; + std::vector undefinedProperties_; std::string objectId_; }; } // namespace OHOS::ObjectStore diff --git a/data_object/frameworks/jskitsimpl/include/common/napi_queue.h b/data_object/frameworks/jskitsimpl/include/common/napi_queue.h index 11495f7c2d8c29e0b188992e9fec5be0e76a7511..02decd5fe493fb069f266cdbaac58706528a1296 100644 --- a/data_object/frameworks/jskitsimpl/include/common/napi_queue.h +++ b/data_object/frameworks/jskitsimpl/include/common/napi_queue.h @@ -27,7 +27,7 @@ namespace OHOS::ObjectStore { using NapiCbInfoParser = std::function; using NapiAsyncExecute = std::function; using NapiAsyncComplete = std::function; -static constexpr size_t ARGC_MAX = 6; + struct ContextBase { virtual ~ContextBase(); void GetCbInfo( diff --git a/data_object/frameworks/jskitsimpl/include/common/object_error.h b/data_object/frameworks/jskitsimpl/include/common/object_error.h index 8ebe82e4deeb8843baf5208dd503a12248dd40a2..0a640e97f40e23b7176d055e7abb96b6f7c93453 100644 --- a/data_object/frameworks/jskitsimpl/include/common/object_error.h +++ b/data_object/frameworks/jskitsimpl/include/common/object_error.h @@ -20,10 +20,6 @@ namespace OHOS { namespace ObjectStore { -static const int EXCEPTION_DEVICE_NOT_SUPPORT = 801; -static const int EXCEPTION_PARAMETER_CHECK = 401; -static const int EXCEPTION_NO_PERMISSION = 201; -static const int EXCEPTION_DB_EXIST = 15400001; static const int EXCEPTION_INNER = 0; class Error { diff --git a/data_object/frameworks/jskitsimpl/include/common/uv_queue.h b/data_object/frameworks/jskitsimpl/include/common/uv_queue.h index 4823fd180988e854959aa49732b6d091bd5c73b6..8042e9551e45f8817b4d76aa7c09f2ae2936e44a 100644 --- a/data_object/frameworks/jskitsimpl/include/common/uv_queue.h +++ b/data_object/frameworks/jskitsimpl/include/common/uv_queue.h @@ -38,7 +38,7 @@ private: std::weak_ptr uvQueue_; }; - static void ExecUvWork(uv_work_t *work, int uvstatus); + static void ExecUvWork(UvEntry *uvEntry); napi_env env_; std::shared_mutex mutex_{}; diff --git a/data_object/frameworks/jskitsimpl/src/adaptor/js_object_wrapper.cpp b/data_object/frameworks/jskitsimpl/src/adaptor/js_object_wrapper.cpp index 5f3436b67b6f054d2dd2a37424d532a024b0bd2e..c024035a731146e25e3564fe9e14701ece6bc96a 100644 --- a/data_object/frameworks/jskitsimpl/src/adaptor/js_object_wrapper.cpp +++ b/data_object/frameworks/jskitsimpl/src/adaptor/js_object_wrapper.cpp @@ -67,9 +67,10 @@ void JSObjectWrapper::DeleteWatch(napi_env env, const char *type, napi_value han bool JSObjectWrapper::IsUndefined(const char *value) { + std::lock_guard lock(mutex_); std::string tmpStr = value; - auto it = std::find(undefinedProperties.begin(), undefinedProperties.end(), tmpStr); - if (it == undefinedProperties.end()) { + auto it = std::find(undefinedProperties_.begin(), undefinedProperties_.end(), tmpStr); + if (it == undefinedProperties_.end()) { return false; } return true; @@ -77,18 +78,20 @@ bool JSObjectWrapper::IsUndefined(const char *value) void JSObjectWrapper::AddUndefined(const char *value) { + std::lock_guard lock(mutex_); std::string tmpStr = value; - if (std::find(undefinedProperties.begin(), undefinedProperties.end(), tmpStr) == undefinedProperties.end()) { - undefinedProperties.push_back(tmpStr); + if (std::find(undefinedProperties_.begin(), undefinedProperties_.end(), tmpStr) == undefinedProperties_.end()) { + undefinedProperties_.push_back(tmpStr); } } void JSObjectWrapper::DeleteUndefined(const char *value) { + std::lock_guard lock(mutex_); std::string tmpStr = value; - auto it = std::find(undefinedProperties.begin(), undefinedProperties.end(), tmpStr); - if (it != undefinedProperties.end()) { - undefinedProperties.erase(it); + auto it = std::find(undefinedProperties_.begin(), undefinedProperties_.end(), tmpStr); + if (it != undefinedProperties_.end()) { + undefinedProperties_.erase(it); } } diff --git a/data_object/frameworks/jskitsimpl/src/common/napi_queue.cpp b/data_object/frameworks/jskitsimpl/src/common/napi_queue.cpp index fad2f4fdd95cb004b9adeb4ee7661f0fea72d7ca..ad34819142c74f24d65cdcd5b16cc847c9392deb 100644 --- a/data_object/frameworks/jskitsimpl/src/common/napi_queue.cpp +++ b/data_object/frameworks/jskitsimpl/src/common/napi_queue.cpp @@ -19,6 +19,8 @@ #include "logger.h" namespace OHOS::ObjectStore { +static constexpr size_t ARGC_MAX = 6; + ContextBase::~ContextBase() { LOG_DEBUG("no memory leak after callback or promise[resolved/rejected]"); diff --git a/data_object/frameworks/jskitsimpl/src/common/object_error.cpp b/data_object/frameworks/jskitsimpl/src/common/object_error.cpp index bcbbd913da41bf04b448eca1b6b61866786659d1..425763b90d6b646fa9a8545892771e758ced1433 100644 --- a/data_object/frameworks/jskitsimpl/src/common/object_error.cpp +++ b/data_object/frameworks/jskitsimpl/src/common/object_error.cpp @@ -17,6 +17,11 @@ namespace OHOS { namespace ObjectStore { +static const int EXCEPTION_DEVICE_NOT_SUPPORT = 801; +static const int EXCEPTION_PARAMETER_CHECK = 401; +static const int EXCEPTION_NO_PERMISSION = 201; +static const int EXCEPTION_DB_EXIST = 15400001; + std::string ParametersType::GetMessage() { return "Parameter error. The type of '" + name + "' must be '" + wantType + "'."; diff --git a/data_object/frameworks/jskitsimpl/src/common/uv_queue.cpp b/data_object/frameworks/jskitsimpl/src/common/uv_queue.cpp index 0298d7bade4e63d54ba651ac872c732f37431d0a..ca2b18803b81998af2fa362be913b446d7a0c954 100644 --- a/data_object/frameworks/jskitsimpl/src/common/uv_queue.cpp +++ b/data_object/frameworks/jskitsimpl/src/common/uv_queue.cpp @@ -27,9 +27,12 @@ UvQueue::~UvQueue() LOG_DEBUG("no memory leak for queue-callback"); } -void UvQueue::ExecUvWork(uv_work_t *work, int uvstatus) +void UvQueue::ExecUvWork(UvEntry *entry) { - UvEntry *entry = static_cast(work->data); + if (entry == nullptr) { + LOG_ERROR("entry is nullptr"); + return; + } auto queue = entry->uvQueue_.lock(); if (queue != nullptr) { std::unique_lock cacheLock(queue->mutex_); @@ -39,9 +42,7 @@ void UvQueue::ExecUvWork(uv_work_t *work, int uvstatus) queue->args_.clear(); } delete entry; - work->data = nullptr; - delete work; - work = nullptr; + entry = nullptr; } void UvQueue::CallFunction(Process process, void *argv) @@ -50,14 +51,8 @@ void UvQueue::CallFunction(Process process, void *argv) LOG_ERROR("nullptr"); return; } - uv_work_t *work = new (std::nothrow) uv_work_t; - if (work == nullptr) { - LOG_ERROR("no memory for uv_work_t"); - return; - } - work->data = new (std::nothrow)UvEntry { weak_from_this() }; - if (work->data == nullptr) { - delete work; + auto *uvEntry = new (std::nothrow)UvEntry { weak_from_this() }; + if (uvEntry == nullptr) { LOG_ERROR("no memory for UvEntry"); return; } @@ -74,18 +69,14 @@ void UvQueue::CallFunction(Process process, void *argv) } } - int ret = uv_queue_work( - loop_, work, [](uv_work_t *work) {}, UvQueue::ExecUvWork); - if (ret != 0) { - if (work->data != nullptr) { - UvEntry *uvEntry = static_cast(work->data); + auto task = [uvEntry]() { + UvQueue::ExecUvWork(uvEntry); + }; + if (napi_send_event(env_, task, napi_eprio_high) != 0) { + if (uvEntry != nullptr) { delete uvEntry; uvEntry = nullptr; } - if (work != nullptr) { - delete work; - work = nullptr; - } } } } // namespace OHOS::ObjectStore diff --git a/data_object/frameworks/jskitsimpl/test/unittest/src/config.json b/data_object/frameworks/jskitsimpl/test/unittest/src/config.json index 7ab092a144989baff9cd94d1629de63bac91032b..68d3d755901b88db106b2c94dc194f6fb33524a6 100644 --- a/data_object/frameworks/jskitsimpl/test/unittest/src/config.json +++ b/data_object/frameworks/jskitsimpl/test/unittest/src/config.json @@ -19,7 +19,8 @@ "tablet", "2in1", "default", - "phone" + "phone", + "wearable" ], "distro": { "deliveryWithInstall": true, diff --git a/data_object/interfaces/innerkits/BUILD.gn b/data_object/interfaces/innerkits/BUILD.gn index 5c76f81ece1a439a3589e5add5aa0f4f136a3aff..8dcded7cffe32dbcbc2cae84b2dab2545e629315 100644 --- a/data_object/interfaces/innerkits/BUILD.gn +++ b/data_object/interfaces/innerkits/BUILD.gn @@ -15,7 +15,10 @@ import("//foundation/distributeddatamgr/data_object/data_object.gni") config("objectstore_config") { visibility = [ ":*" ] - cflags = [ "-DHILOG_ENABLE" ] + cflags = [ + "-DHILOG_ENABLE", + "-Oz", + ] include_dirs = [ "../../frameworks/innerkitsimpl/include/adaptor", @@ -113,3 +116,37 @@ ohos_static_library("distributeddataobject_static") { public_configs = [ ":objectstore_public_config" ] subsystem_name = "distributeddatamgr" } + +config("object_public_config") { + visibility = [ + ":*", + "${datamgr_service_path}/services/distributeddataservice/service/object:*", + ] + + include_dirs = [ + ".", + "../../frameworks/innerkitsimpl/include", + "../../frameworks/innerkitsimpl/include/common", + "../../frameworks/innerkitsimpl/include/communicator", + ] +} + +ohos_static_library("data_object_inner") { + branch_protector_ret = "pac_ret" + sanitize = { + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + + public_configs = [ ":object_public_config" ] + + sources = [ "../../frameworks/innerkitsimpl/src/object_radar_reporter.cpp" ] + + external_deps = [ "hisysevent:libhisysevent" ] + + part_name = "data_object" + subsystem_name = "distributeddatamgr" +} diff --git a/data_object/interfaces/jskits/BUILD.gn b/data_object/interfaces/jskits/BUILD.gn index 7b4c7aafa384fd3f8090d418652ef6456ec39c00..bbca12dd3aa544eabbde32049f63cbb01f7411fa 100644 --- a/data_object/interfaces/jskits/BUILD.gn +++ b/data_object/interfaces/jskits/BUILD.gn @@ -32,7 +32,10 @@ es2abc_gen_abc("gen_distributed_data_object_abc") { config("objectstore_config") { visibility = [ ":*" ] - cflags = [ "-DHILOG_ENABLE" ] + cflags = [ + "-DHILOG_ENABLE", + "-Oz", + ] include_dirs = [ "../../frameworks/jskitsimpl/include/adaptor", diff --git a/data_object/interfaces/jskits/distributed_data_object.js b/data_object/interfaces/jskits/distributed_data_object.js index 2882265480f90f580bb74562ff1d67e2acf7d3d3..e707ebb25fc8b51013991028c569302d1b5d27bb 100644 --- a/data_object/interfaces/jskits/distributed_data_object.js +++ b/data_object/interfaces/jskits/distributed_data_object.js @@ -39,7 +39,6 @@ class Distributed { return false; } if (this.__proxy[SESSION_ID] === sessionId) { - console.info('same session has joined ' + sessionId); return true; } leaveSession(this.__sdkVersion, this.__proxy); @@ -233,7 +232,6 @@ function setAssetValue(object, key, newValue) { } function joinSession(version, obj, objectId, sessionId, context) { - console.info('start joinSession ' + sessionId); if (obj == null || sessionId == null || sessionId === '') { console.error('object is null'); return null; @@ -364,7 +362,6 @@ class DistributedV9 { } } if (this.__proxy[SESSION_ID] === sessionId) { - console.info('same session has joined ' + sessionId); if (typeof callback === 'function') { return callback(null, this.__proxy); } else { diff --git a/data_share/bundle.json b/data_share/bundle.json index 29b7d7c84e74eab0db1b5e563db84c1d412c075b..cdf403463a375b087f14510d16a07c5296800204 100644 --- a/data_share/bundle.json +++ b/data_share/bundle.json @@ -5,7 +5,7 @@ "license": "Apache License 2.0", "repository": "https://gitee.com/openharmony/distributeddatamgr_data_share", "description": "allows an application to manage its own data and share data with other applications", - "domain": "ohos", + "domain": "os", "language": "", "publishAs": "code-segment", "private": false, diff --git a/data_share/frameworks/js/napi/dataShare/include/napi_datashare_helper.h b/data_share/frameworks/js/napi/dataShare/include/napi_datashare_helper.h index fd8c8ac40c23e21512af7d60649796d27a0873e6..8ab5c2497f36ddc4e3de58f5b58bed2438599a69 100644 --- a/data_share/frameworks/js/napi/dataShare/include/napi_datashare_helper.h +++ b/data_share/frameworks/js/napi/dataShare/include/napi_datashare_helper.h @@ -67,7 +67,7 @@ private: std::shared_ptr helper, bool isNotifyDetails = false); void UnRegisteredObserver(napi_env env, const std::string& uri, std::shared_ptr helper, bool isNotifyDetails = false); - static bool GetOptions(napi_env env, napi_value jsValue, CreateOptions &options); + static bool GetOptions(napi_env env, napi_value jsValue, CreateOptions &options, Uri &uri); void SetHelper(std::shared_ptr dataShareHelper); std::shared_ptr GetHelper(); std::shared_ptr datashareHelper_ = nullptr; @@ -141,6 +141,7 @@ private: }; static void Notify(const std::shared_ptr context, std::shared_ptr helper); + static void ExecuteCreator(std::shared_ptr ctxInfo); }; } // namespace DataShare } // namespace OHOS diff --git a/data_share/frameworks/js/napi/dataShare/include/napi_datashare_inner_observer.h b/data_share/frameworks/js/napi/dataShare/include/napi_datashare_inner_observer.h index 30bad02ce581233e8a2eaaab3aa093400b7d251f..1f8abe2c70c13c45b34ea4df50908029cdd9084b 100644 --- a/data_share/frameworks/js/napi/dataShare/include/napi_datashare_inner_observer.h +++ b/data_share/frameworks/js/napi/dataShare/include/napi_datashare_inner_observer.h @@ -32,8 +32,7 @@ public: void DeleteReference(); napi_ref GetCallback(); -private: - static void OnComplete(uv_work_t *work, int status); +protected: struct ObserverWorker { std::weak_ptr observer_; DataShareObserver::ChangeInfo result_; @@ -41,7 +40,7 @@ private: ObserverWorker(std::shared_ptr observerIn, DataShareObserver::ChangeInfo resultIn = {}) : observer_(observerIn), result_(resultIn) {} }; - + static void OnComplete(ObserverWorker* observerWorker); napi_env env_ = nullptr; napi_ref ref_ = nullptr; uv_loop_s *loop_ = nullptr; diff --git a/data_share/frameworks/js/napi/dataShare/src/napi_datashare_helper.cpp b/data_share/frameworks/js/napi/dataShare/src/napi_datashare_helper.cpp index 52947282ad858e9e6193492dd118cad7d3a4dc79..884da5ff5dc7b9643049e0f7d0efd97693df99f3 100644 --- a/data_share/frameworks/js/napi/dataShare/src/napi_datashare_helper.cpp +++ b/data_share/frameworks/js/napi/dataShare/src/napi_datashare_helper.cpp @@ -31,7 +31,7 @@ using namespace OHOS::AppExecFwk; namespace OHOS { namespace DataShare { static constexpr int MAX_ARGC = 6; -static __thread napi_ref constructor_ = nullptr; +static thread_local napi_ref constructor_ = nullptr; static bool GetSilentUri(napi_env env, napi_value jsValue, std::string &uri) { napi_valuetype valuetype = napi_undefined; @@ -57,14 +57,9 @@ static bool GetUri(napi_env env, napi_value jsValue, std::string &uri) return true; } -bool NapiDataShareHelper::GetOptions(napi_env env, napi_value jsValue, CreateOptions &options) +static bool GetIsProxy(napi_env env, napi_value jsValue, CreateOptions &options) { napi_valuetype type = napi_undefined; - napi_typeof(env, jsValue, &type); - if (type != napi_object) { - LOG_ERROR("CreateOptions is not object"); - return false; - } napi_value isProxyJs = nullptr; napi_status status = napi_get_named_property(env, jsValue, "isProxy", &isProxyJs); if (status != napi_ok) { @@ -81,10 +76,74 @@ bool NapiDataShareHelper::GetOptions(napi_env env, napi_value jsValue, CreateOpt LOG_ERROR("napi_get_value_bool failed %{public}d", status); return false; } - options.enabled_ = true; return true; } +static bool GetWaitTime(napi_env env, napi_value jsValue, CreateOptions &options) +{ + napi_valuetype type = napi_undefined; + napi_value waitTimeJs; + napi_status status = napi_get_named_property(env, jsValue, "waitTime", &waitTimeJs); + if (status != napi_ok) { + LOG_ERROR("napi_get_named_property (waitTime) failed %{public}d", status); + return false; + } + napi_typeof(env, waitTimeJs, &type); + if (type == napi_undefined || type == napi_null) { + return true; + } + if (type != napi_number) { + LOG_ERROR("CreateOptions.waitTime is not number or undefined or null"); + return false; + } + status = napi_get_value_int32(env, waitTimeJs, &options.waitTime_); + if (status != napi_ok) { + LOG_ERROR("napi_get_value_int32 failed %{public}d", status); + return false; + } + return true; +} + +bool NapiDataShareHelper::GetOptions(napi_env env, napi_value jsValue, CreateOptions &options, Uri &uri) +{ + napi_valuetype type = napi_undefined; + napi_typeof(env, jsValue, &type); + if (uri.GetScheme() == "datashareproxy") { + if (type != napi_object) { + LOG_ERROR("CreateOptions is not object"); + return false; + } + if (!GetIsProxy(env, jsValue, options)) { + return false; + } + options.enabled_ = true; + } else { + if (type == napi_undefined || type == napi_null) { + return true; + } + if (type != napi_object) { + LOG_ERROR("CreateOptions is not object or undefined or null"); + return false; + } + } + if (!GetWaitTime(env, jsValue, options)) { + return false; + } + return true; +} + +void NapiDataShareHelper::ExecuteCreator(std::shared_ptr ctxInfo) +{ + if (ctxInfo->options.enabled_) { + ctxInfo->options.token_ = ctxInfo->contextS->GetToken(); + ctxInfo->dataShareHelper = DataShareHelper::Creator(ctxInfo->strUri, ctxInfo->options, "", + ctxInfo->options.waitTime_); + } else { + ctxInfo->dataShareHelper = DataShareHelper::Creator(ctxInfo->contextS->GetToken(), ctxInfo->strUri, "", + ctxInfo->options.waitTime_); + } +} + napi_value NapiDataShareHelper::Napi_CreateDataShareHelper(napi_env env, napi_callback_info info) { auto ctxInfo = std::make_shared(); @@ -97,11 +156,12 @@ napi_value NapiDataShareHelper::Napi_CreateDataShareHelper(napi_env env, napi_ca NAPI_ASSERT_CALL_ERRCODE(env, GetUri(env, argv[1], ctxInfo->strUri), ctxInfo->error = std::make_shared("uri", "string"), napi_invalid_arg); Uri uri(ctxInfo->strUri); - if (uri.GetScheme() == "datashareproxy") { - NAPI_ASSERT_CALL_ERRCODE(env, argc == 3 || argc == 4, - ctxInfo->error = std::make_shared("3 or 4"), napi_invalid_arg); - NAPI_ASSERT_CALL_ERRCODE(env, GetOptions(env, argv[2], ctxInfo->options), + if (argc != 2) { + NAPI_ASSERT_CALL_ERRCODE(env, GetOptions(env, argv[2], ctxInfo->options, uri), ctxInfo->error = std::make_shared("option", "CreateOption"), napi_invalid_arg); + } else { + NAPI_ASSERT_CALL_ERRCODE(env, uri.GetScheme() != "datashareproxy", + ctxInfo->error = std::make_shared("3 or 4"), napi_invalid_arg); } napi_value helperProxy = nullptr; napi_status status = napi_new_instance(env, GetConstructor(env), argc, argv, &helperProxy); @@ -127,12 +187,7 @@ napi_value NapiDataShareHelper::Napi_CreateDataShareHelper(napi_env env, napi_ca return status; }; auto exec = [ctxInfo](AsyncCall::Context *ctx) { - if (ctxInfo->options.enabled_) { - ctxInfo->options.token_ = ctxInfo->contextS->GetToken(); - ctxInfo->dataShareHelper = DataShareHelper::Creator(ctxInfo->strUri, ctxInfo->options); - } else { - ctxInfo->dataShareHelper = DataShareHelper::Creator(ctxInfo->contextS->GetToken(), ctxInfo->strUri); - } + ExecuteCreator(ctxInfo); }; ctxInfo->SetAction(std::move(input), std::move(output)); AsyncCall asyncCall(env, info, ctxInfo); diff --git a/data_share/frameworks/js/napi/dataShare/src/napi_datashare_inner_observer.cpp b/data_share/frameworks/js/napi/dataShare/src/napi_datashare_inner_observer.cpp index c89c2535422c7a334adf8e3361963fac8000c739..3b02fd5c4ebdfabb883945e6e63ec8e4d0194582 100644 --- a/data_share/frameworks/js/napi/dataShare/src/napi_datashare_inner_observer.cpp +++ b/data_share/frameworks/js/napi/dataShare/src/napi_datashare_inner_observer.cpp @@ -31,20 +31,20 @@ NAPIInnerObserver::NAPIInnerObserver(napi_env env, napi_value callback) napi_get_uv_event_loop(env, &loop_); } -void NAPIInnerObserver::OnComplete(uv_work_t *work, int status) +void NAPIInnerObserver::OnComplete(ObserverWorker* observerWorker) { - LOG_DEBUG("uv_queue_work start"); - std::shared_ptr innerWorker(reinterpret_cast(work->data)); - auto observer = innerWorker->observer_.lock(); + LOG_DEBUG("napi_send_event start"); + auto observer = observerWorker->observer_.lock(); if (observer == nullptr || observer->ref_ == nullptr) { - delete work; LOG_ERROR("innerWorker->observer_->ref_ is nullptr"); + delete observerWorker; return; } napi_handle_scope scope = nullptr; napi_open_handle_scope(observer->env_, &scope); if (scope == nullptr) { - delete work; + LOG_ERROR("scope is nullptr"); + delete observerWorker; return; } napi_value callback = nullptr; @@ -53,15 +53,16 @@ void NAPIInnerObserver::OnComplete(uv_work_t *work, int status) napi_get_reference_value(observer->env_, observer->ref_, &callback); napi_get_global(observer->env_, &global); napi_get_undefined(observer->env_, &args[0]); - if (innerWorker->isNotifyDetails_) { - args[1] = DataShareJSUtils::Convert2JSValue(observer->env_, innerWorker->result_); + if (observerWorker->isNotifyDetails_) { + args[1] = DataShareJSUtils::Convert2JSValue(observer->env_, observerWorker->result_); } napi_status callStatus = napi_call_function(observer->env_, global, callback, 2, args, nullptr); napi_close_handle_scope(observer->env_, scope); if (callStatus != napi_ok) { LOG_ERROR("napi_call_function failed status : %{public}d", callStatus); } - delete work; + LOG_DEBUG("napi_call_function succeed status : %{public}d", callStatus); + delete observerWorker; } void NAPIInnerObserver::OnChange(const DataShareObserver::ChangeInfo& changeInfo, bool isNotifyDetails) @@ -73,29 +74,21 @@ void NAPIInnerObserver::OnChange(const DataShareObserver::ChangeInfo& changeInfo LOG_ERROR("ref_ is nullptr"); return; } - - uv_work_t* work = new (std::nothrow) uv_work_t(); - if (work == nullptr) { - LOG_ERROR("Failed to create uv work"); - return; - } - - ObserverWorker* observerWorker = nullptr; - observerWorker = new (std::nothrow) ObserverWorker(shared_from_this(), changeInfo); + ObserverWorker* observerWorker = new (std::nothrow) ObserverWorker(shared_from_this(), changeInfo); if (observerWorker == nullptr) { - delete work; LOG_ERROR("Failed to create observerWorker"); return; } observerWorker->isNotifyDetails_ = isNotifyDetails; - work->data = observerWorker; - int ret = uv_queue_work_with_qos(loop_, work, [](uv_work_t *work) {}, - NAPIInnerObserver::OnComplete, uv_qos_user_initiated); + auto task = [observerWorker]() { + NAPIInnerObserver::OnComplete(observerWorker); + }; + int ret = napi_send_event(env_, task, napi_eprio_immediate); if (ret != 0) { - LOG_ERROR("uv_queue_work failed"); + LOG_ERROR("napi_send_event failed: %{public}d", ret); delete observerWorker; - delete work; } + LOG_INFO("NAPIInnerObserver datashare callback end, times %{public}" PRIu64 ".", time); } void NAPIInnerObserver::DeleteReference() diff --git a/data_share/frameworks/js/napi/observer/include/napi_observer.h b/data_share/frameworks/js/napi/observer/include/napi_observer.h index 56554fec825e6f5cc05c5f8ac665609df60724df..18bede72282e3b7f2954c46e120170200ff49f02 100644 --- a/data_share/frameworks/js/napi/observer/include/napi_observer.h +++ b/data_share/frameworks/js/napi/observer/include/napi_observer.h @@ -33,7 +33,12 @@ public: virtual bool operator!=(const NapiObserver &rhs) const; NapiObserver& operator=(NapiObserver &&rhs) = default; protected: - static void CallbackFunc(uv_work_t *work, int status); + struct ObserverWorker { + std::weak_ptr observer_; + std::function getParam; + explicit ObserverWorker(std::shared_ptr observerIn) : observer_(observerIn) {} + }; + static void CallbackFunc(ObserverWorker *observerWorker); napi_env env_ = nullptr; napi_ref ref_ = nullptr; uv_loop_s *loop_ = nullptr; @@ -50,12 +55,6 @@ public: NapiPublishedObserver(napi_env env, napi_value callback) : NapiObserver(env, callback) {}; void OnChange(PublishedDataChangeNode &changeNode); }; - -struct ObserverWorker { - std::weak_ptr observer_; - std::function getParam; - explicit ObserverWorker(std::shared_ptr observerIn) : observer_(observerIn) {} -}; } // namespace DataShare } // namespace OHOS #endif //NAPI_RDB_OBSERVER_H diff --git a/data_share/frameworks/js/napi/observer/src/napi_observer.cpp b/data_share/frameworks/js/napi/observer/src/napi_observer.cpp index d21d16edab1caf34c9ad881b8d152bc150a13b7c..484583c30fa211974d20aa21f02c0bcd581c12b9 100644 --- a/data_share/frameworks/js/napi/observer/src/napi_observer.cpp +++ b/data_share/frameworks/js/napi/observer/src/napi_observer.cpp @@ -26,20 +26,20 @@ NapiObserver::NapiObserver(napi_env env, napi_value callback) : env_(env) napi_get_uv_event_loop(env, &loop_); } -void NapiObserver::CallbackFunc(uv_work_t *work, int status) +void NapiObserver::CallbackFunc(ObserverWorker *observerWorker) { - LOG_DEBUG("RdbObsCallbackFunc start"); - std::shared_ptr innerWorker(reinterpret_cast(work->data)); - std::shared_ptr observer = innerWorker->observer_.lock(); + LOG_DEBUG("ObsCallbackFunc start"); + std::shared_ptr observer = observerWorker->observer_.lock(); if (observer == nullptr || observer->ref_ == nullptr) { - delete work; LOG_ERROR("rdbObserver->ref_ is nullptr"); + delete observerWorker; return; } napi_handle_scope scope = nullptr; napi_open_handle_scope(observer->env_, &scope); if (scope == nullptr) { - delete work; + LOG_ERROR("scope is nullptr"); + delete observerWorker; return; } napi_value callback = nullptr; @@ -49,13 +49,14 @@ void NapiObserver::CallbackFunc(uv_work_t *work, int status) napi_get_reference_value(observer->env_, observer->ref_, &callback); napi_get_global(observer->env_, &global); napi_get_undefined(observer->env_, ¶m[0]); - param[1] = innerWorker->getParam(observer->env_); + param[1] = observerWorker->getParam(observer->env_); napi_status callStatus = napi_call_function(observer->env_, global, callback, 2, param, &result); napi_close_handle_scope(observer->env_, scope); if (callStatus != napi_ok) { LOG_ERROR("napi_call_function failed status : %{public}d", callStatus); } - delete work; + LOG_DEBUG("napi_call_function succeed status : %{public}d", callStatus); + delete observerWorker; } NapiObserver::~NapiObserver() @@ -104,20 +105,15 @@ void NapiRdbObserver::OnChange(const RdbChangeNode &changeNode) return DataShareJSUtils::Convert2JSValue(env, changeNode); }; - uv_work_t *work = new (std::nothrow) uv_work_t(); - if (work == nullptr) { - delete observerWorker; - LOG_ERROR("Failed to create uv work"); - return; - } - work->data = observerWorker; - int ret = uv_queue_work( - loop_, work, [](uv_work_t *work) {}, CallbackFunc); + auto task = [observerWorker]() { + NapiObserver::CallbackFunc(observerWorker); + }; + int ret = napi_send_event(env_, task, napi_eprio_immediate); if (ret != 0) { - LOG_ERROR("uv_queue_work failed"); + LOG_ERROR("napi_send_event failed: %{public}d", ret); delete observerWorker; - delete work; } + LOG_DEBUG("NapiRdbObserver onchange End: %{public}d", ret); } void NapiPublishedObserver::OnChange(PublishedDataChangeNode &changeNode) @@ -137,20 +133,15 @@ void NapiPublishedObserver::OnChange(PublishedDataChangeNode &changeNode) return DataShareJSUtils::Convert2JSValue(env, *node); }; - uv_work_t *work = new (std::nothrow) uv_work_t(); - if (work == nullptr) { - delete observerWorker; - LOG_ERROR("Failed to create uv work"); - return; - } - work->data = observerWorker; - int ret = uv_queue_work( - loop_, work, [](uv_work_t *work) {}, CallbackFunc); + auto task = [observerWorker]() { + NapiObserver::CallbackFunc(observerWorker); + }; + int ret = napi_send_event(env_, task, napi_eprio_immediate); if (ret != 0) { - LOG_ERROR("uv_queue_work failed"); + LOG_ERROR("napi_send_event failed: %{public}d", ret); delete observerWorker; - delete work; } + LOG_DEBUG("NapiRdbObserver onchange End: %{public}d", ret); } } // namespace DataShare } // namespace OHOS diff --git a/data_share/frameworks/native/common/include/datashare_itypes_utils.h b/data_share/frameworks/native/common/include/datashare_itypes_utils.h index 7dd6895ef227952e069fc4e6b1102d1dd35f81b4..61c566dd7e80c767e2670999e50cfcc1a8e72be2 100644 --- a/data_share/frameworks/native/common/include/datashare_itypes_utils.h +++ b/data_share/frameworks/native/common/include/datashare_itypes_utils.h @@ -145,5 +145,19 @@ bool Marshalling(const ExecResultSet &execResultSet, MessageParcel &parcel); template<> bool Unmarshalling(ExecResultSet &execResultSet, MessageParcel &parcel); + +/** + * @brief The following four functions are used for serializing and deserializing objects + * to and from shared memory during Query and BatchInsert operations, + * which has a 128M upper limit. The upper limit of other method is 200k. + * Other methods remain unchanged. + */ +bool MarshalPredicates(const Predicates &predicates, MessageParcel &parcel); + +bool UnmarshalPredicates(Predicates &predicates, MessageParcel &parcel); + +bool MarshalValuesBucketVec(const std::vector &values, MessageParcel &parcel); + +bool UnmarshalValuesBucketVec(std::vector &values, MessageParcel &parcel); } #endif diff --git a/data_share/frameworks/native/common/include/datashare_uri_utils.h b/data_share/frameworks/native/common/include/datashare_uri_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..b381bdb51705af5184a2a91152fb5f8bd3499737 --- /dev/null +++ b/data_share/frameworks/native/common/include/datashare_uri_utils.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 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 DATASHARE_URI_UTILS_H +#define DATASHARE_URI_UTILS_H + +#include +#include +#include + +namespace OHOS::DataShare { +class DataShareURIUtils { +public: + static std::string FormatUri(const std::string &uri); + static std::map GetQueryParams(const std::string& uri); + static std::pair Strtoul(const std::string &str); + static std::pair GetUserFromUri(const std::string &uri); + +private: + static constexpr const char USER_PARAM[] = "user"; + static constexpr const int BASE_TEN = 10; +}; + +} // namespace OHOS::DataShare +#endif // DATASHARE_URI_UTILS_H \ No newline at end of file diff --git a/data_share/frameworks/native/common/include/distributeddata_data_share_ipc_interface_code.h b/data_share/frameworks/native/common/include/distributeddata_data_share_ipc_interface_code.h index a2189936a095ce97a52319907dfecbfcbbfc3e8a..83f03e388fd1f46564d25e4038daaf2ff6a0667b 100644 --- a/data_share/frameworks/native/common/include/distributeddata_data_share_ipc_interface_code.h +++ b/data_share/frameworks/native/common/include/distributeddata_data_share_ipc_interface_code.h @@ -41,6 +41,7 @@ enum class IDataShareInterfaceCode { CMD_INSERT_EX, CMD_UPDATE_EX, CMD_DELETE_EX, + CMD_USER_DEFINE_FUNC }; enum class ISharedResultInterfaceCode { diff --git a/data_share/frameworks/native/common/include/idatashare.h b/data_share/frameworks/native/common/include/idatashare.h index 24ba2bc5816fb4c3064fc8454750f57854829eb2..a5300a02631767f075031219e94dd3a3bb71c024 100644 --- a/data_share/frameworks/native/common/include/idatashare.h +++ b/data_share/frameworks/native/common/include/idatashare.h @@ -59,6 +59,7 @@ public: virtual int ExecuteBatch(const std::vector &statements, ExecResultSet &result) = 0; + // Remain bool because applications have used these two (register and unregister) methods. virtual bool RegisterObserver(const Uri &uri, const sptr &dataObserver) = 0; virtual bool UnregisterObserver(const Uri &uri, const sptr &dataObserver) = 0; @@ -77,6 +78,8 @@ public: const Uri &uri, const DataSharePredicates &predicates, const DataShareValuesBucket &value) = 0; virtual std::pair DeleteEx(const Uri &uri, const DataSharePredicates &predicates) = 0; + + virtual int32_t UserDefineFunc(MessageParcel &data, MessageParcel &reply, MessageOption &option) = 0; }; } // namespace DataShare } // namespace OHOS diff --git a/data_share/frameworks/native/common/src/datashare_itypes_utils.cpp b/data_share/frameworks/native/common/src/datashare_itypes_utils.cpp index 7f66083ea7d4ce6bd85049c27c0815600fbb7bba..8c76985b5333f873e9101e36d8cd3c6114f1b6f7 100644 --- a/data_share/frameworks/native/common/src/datashare_itypes_utils.cpp +++ b/data_share/frameworks/native/common/src/datashare_itypes_utils.cpp @@ -14,10 +14,18 @@ */ #include "datashare_itypes_utils.h" + +#include +#include +#include #include "datashare_log.h" namespace OHOS::ITypesUtil { using namespace OHOS::DataShare; + +// Maximum value of IPC shared memory +static const size_t MAX_IPC_SIZE = 128 * 1024 * 1024; + template<> bool Marshalling(const Predicates &predicates, MessageParcel &parcel) { @@ -287,4 +295,683 @@ bool Unmarshalling(ExecResultSet &execResultSet, MessageParcel &parcel) execResultSet.errorCode = static_cast(errorCode); return ITypesUtil::Unmarshal(parcel, execResultSet.results); } -} // namespace OHOS::ITypesUtil + +template +bool MarshalBasicTypeToBuffer(std::ostringstream &oss, const T &value) +{ + oss.write(reinterpret_cast(&value), sizeof(value)); + return oss.good(); +} + +template +bool MarshalBasicTypeVecToBuffer(std::ostringstream &oss, const std::vector &values) +{ + size_t valSize = values.size(); + if (!MarshalBasicTypeToBuffer(oss, valSize)) { + return false; + } + if (valSize > 0) + oss.write(reinterpret_cast(values.data()), valSize * sizeof(T)); + return oss.good(); +} + +bool MarshalStringToBuffer(std::ostringstream &oss, const std::string &value) +{ + // write string length + size_t len = value.length(); + if (!MarshalBasicTypeToBuffer(oss, len)) { + return false; + } + // write string data + if (len > 0) { + oss.write(value.data(), len); + } + return oss.good(); +} + +bool MarshalStringVecToBuffer(std::ostringstream &oss, const std::vector &values) +{ + // write vector size + size_t len = values.size(); + if (!MarshalBasicTypeToBuffer(oss, len)) { + return false; + } + for (const auto &it : values) { + if (!MarshalStringToBuffer(oss, it)) { + return false; + } + } + return oss.good(); +} + +bool MarshalSingleTypeToBuffer(std::ostringstream &oss, const SingleValue::Type &value) +{ + // write typeId + uint8_t typeId = value.index(); + if (!MarshalBasicTypeToBuffer(oss, typeId)) { + return false; + } + switch (typeId) { + case static_cast(DataSharePredicatesObjectType::TYPE_NULL): { + return oss.good(); + } + case static_cast(DataSharePredicatesObjectType::TYPE_INT): { + int val = std::get(value); + if (!MarshalBasicTypeToBuffer(oss, val)) { return false; } + break; + } + case static_cast(DataSharePredicatesObjectType::TYPE_DOUBLE): { + double val = std::get(value); + if (!MarshalBasicTypeToBuffer(oss, val)) { return false; } + break; + } + case static_cast(DataSharePredicatesObjectType::TYPE_STRING): { + std::string val = std::get(value); + if (!MarshalStringToBuffer(oss, val)) { return false; } + break; + } + case static_cast(DataSharePredicatesObjectType::TYPE_BOOL): { + bool val = std::get(value); + if (!MarshalBasicTypeToBuffer(oss, val)) { return false; } + break; + } + case static_cast(DataSharePredicatesObjectType::TYPE_LONG): { + int64_t val = std::get(value); + if (!MarshalBasicTypeToBuffer(oss, val)) { return false; } + break; + } + default: + LOG_ERROR("MarshalSingleTypeToBuffer: unknown typeId"); + return false; + } + return oss.good(); +} + +bool MarshalSingleTypeVecToBuffer(std::ostringstream &oss, const std::vector &values) +{ + // write vector size + size_t len = values.size(); + if (!MarshalBasicTypeToBuffer(oss, len)) { + return false; + } + for (const auto &it : values) { + if (!MarshalSingleTypeToBuffer(oss, it)) { + return false; + } + } + return oss.good(); +} + +bool MarshalMultiTypeToBuffer(std::ostringstream &oss, const MutliValue::Type &value) +{ + uint8_t typeId = value.index(); + if (!MarshalBasicTypeToBuffer(oss, typeId)) { + return false; + } + // add offset of TYPE_NULL + typeId += static_cast(DataSharePredicatesObjectsType::TYPE_NULL); + switch (typeId) { + case static_cast(DataSharePredicatesObjectsType::TYPE_NULL): { + return oss.good(); + } + case static_cast(DataSharePredicatesObjectsType::TYPE_INT_VECTOR): { + std::vector val = std::get>(value); + if (!MarshalBasicTypeVecToBuffer(oss, val)) { return false; } + break; + } + case static_cast(DataSharePredicatesObjectsType::TYPE_DOUBLE_VECTOR): { + std::vector val = std::get>(value); + if (!MarshalBasicTypeVecToBuffer(oss, val)) { return false; } + break; + } + case static_cast(DataSharePredicatesObjectsType::TYPE_LONG_VECTOR): { + std::vector val = std::get>(value); + if (!MarshalBasicTypeVecToBuffer(oss, val)) { return false; } + break; + } + case static_cast(DataSharePredicatesObjectsType::TYPE_STRING_VECTOR): { + auto val = std::get>(value); + if (!MarshalStringVecToBuffer(oss, val)) { return false; } + break; + } + default: + LOG_ERROR("MarshalMultiTypeToBuffer: unknown typeId"); + return false; + } + return oss.good(); +} + +bool MarshalMultiTypeVecToBuffer(std::ostringstream &oss, const std::vector &values) +{ + size_t len = values.size(); + if (!MarshalBasicTypeToBuffer(oss, len)) { + return false; + } + for (const auto &it : values) { + if (!MarshalMultiTypeToBuffer(oss, it)) { + return false; + } + } + return oss.good(); +} + +bool MarshalOperationItemToBuffer(std::ostringstream &oss, const OperationItem &value) +{ + int32_t operation = value.operation; + std::vector singleParams = value.singleParams; + std::vector multiParams = value.multiParams; + + // Serialize operation + if (!MarshalBasicTypeToBuffer(oss, operation)) { + return false; + } + // Serialize singleParams + if (!MarshalSingleTypeVecToBuffer(oss, singleParams)) { + return false; + } + // Serialize multiParams + if (!MarshalMultiTypeVecToBuffer(oss, multiParams)) { + return false; + } + return oss.good(); +} + +bool MarshalOperationItemVecToBuffer(std::ostringstream &oss, const std::vector &values) +{ + size_t len = values.size(); + if (!MarshalBasicTypeToBuffer(oss, len)) { + return false; + } + for (const auto &it : values) { + if (!MarshalOperationItemToBuffer(oss, it)) { + return false; + } + } + return oss.good(); +} + +bool MarshalPredicatesToBuffer(std::ostringstream &oss, const DataSharePredicates &predicates) +{ + // Extract all members of predicates + const std::vector &operations = predicates.GetOperationList(); + std::string whereClause = predicates.GetWhereClause(); + std::vector whereArgs = predicates.GetWhereArgs(); + std::string order = predicates.GetOrder(); + short mode = predicates.GetSettingMode(); + + // Serialize operations + if (!MarshalOperationItemVecToBuffer(oss, operations)) { + return false; + } + // Serialize whereClause + if (!MarshalStringToBuffer(oss, whereClause)) { + return false; + } + // Serialize whereArgs + if (!MarshalStringVecToBuffer(oss, whereArgs)) { + return false; + } + // Serialize order + if (!MarshalStringToBuffer(oss, order)) { + return false; + } + // Serialize mode + if (!MarshalBasicTypeToBuffer(oss, mode)) { + return false; + } + return oss.good(); +} + +bool MarshalValuesBucketToBuffer(std::ostringstream &oss, const DataShareValuesBucket &bucket) +{ + for (const auto &[key, value] : bucket.valuesMap) { + // write key + if (!MarshalStringToBuffer(oss, key)) { return false; } + // write typeId + uint8_t typeId = value.index(); + if (!MarshalBasicTypeToBuffer(oss, typeId)) { return false; } + switch (typeId) { + case static_cast(DataShareValueObjectType::TYPE_NULL): { + continue; + } + case static_cast(DataShareValueObjectType::TYPE_INT): { + int64_t val = std::get(value); + if (!MarshalBasicTypeToBuffer(oss, val)) { return false; } + break; + } + case static_cast(DataShareValueObjectType::TYPE_DOUBLE): { + double val = std::get(value); + if (!MarshalBasicTypeToBuffer(oss, val)) { return false; } + break; + } + case static_cast(DataShareValueObjectType::TYPE_STRING): { + std::string val = std::get(value); + if (!MarshalStringToBuffer(oss, val)) { return false; } + break; + } + case static_cast(DataShareValueObjectType::TYPE_BOOL): { + bool val = std::get(value); + if (!MarshalBasicTypeToBuffer(oss, val)) { return false; } + break; + } + case static_cast(DataShareValueObjectType::TYPE_BLOB): { + std::vector val = std::get>(value); + if (!MarshalBasicTypeVecToBuffer(oss, val)) { return false; } + break; + } + default: + LOG_ERROR("MarshalValuesBucketToBuffer: unknown typeId"); + return false; + } + } + return oss.good(); +} + +bool MarshalValuesBucketVecToBuffer(std::ostringstream &oss, const std::vector &values) +{ + size_t size = values.size(); + if (!MarshalBasicTypeToBuffer(oss, size)) { + return false; + } + for (const auto &bucket : values) { + size_t mapSize = bucket.valuesMap.size(); + if (!MarshalBasicTypeToBuffer(oss, mapSize)) { + return false; + } + if (!MarshalValuesBucketToBuffer(oss, bucket)) { + return false; + } + } + return oss.good(); +} + +template +bool UnmarshalBasicTypeToBuffer(std::istringstream &iss, T &value) +{ + iss.read(reinterpret_cast(&value), sizeof(value)); + return iss.good(); +} + +template +bool UnmarshalBasicTypeVecToBuffer(std::istringstream &iss, std::vector &values) +{ + size_t valSize = 0; + if (!UnmarshalBasicTypeToBuffer(iss, valSize)) { + return false; + } + if (valSize > 0) { + values.resize(valSize); + iss.read(reinterpret_cast(values.data()), valSize * sizeof(T)); + } + return iss.good(); +} + +bool UnmarshalStringToBuffer(std::istringstream &iss, std::string &value) +{ + // Get string length + size_t len; + if (!UnmarshalBasicTypeToBuffer(iss, len)) { + return false; + } + // Get string content + if (len > 0) { + value.resize(len, '\0'); + iss.read(value.data(), len); + } + return iss.good(); +} + +bool UnmarshalStringVecToBuffer(std::istringstream &iss, std::vector &values) +{ + // Get vec length + size_t len; + if (!UnmarshalBasicTypeToBuffer(iss, len)) { + return false; + } + for (size_t i = 0; i < len; i++) { + std::string value; + if (!UnmarshalStringToBuffer(iss, value)) { + return false; + } + values.push_back(value); + } + return iss.good(); +} + +bool UnmarshalSingleTypeToBuffer(std::istringstream &iss, SingleValue::Type &value) +{ + // Get type of value + uint8_t typeId; + if (!UnmarshalBasicTypeToBuffer(iss, typeId)) { + return false; + } + // Deserialize according to the type + switch (typeId) { + case static_cast(DataSharePredicatesObjectType::TYPE_NULL): { + return iss.good(); + } + case static_cast(DataSharePredicatesObjectType::TYPE_INT): { + int intVal; + if (!UnmarshalBasicTypeToBuffer(iss, intVal)) { return false; } + value = intVal; + break; + } + case static_cast(DataSharePredicatesObjectType::TYPE_DOUBLE): { + double doubleVal; + if (!UnmarshalBasicTypeToBuffer(iss, doubleVal)) { return false; } + value = doubleVal; + break; + } + case static_cast(DataSharePredicatesObjectType::TYPE_STRING): { + std::string str; + if (!UnmarshalStringToBuffer(iss, str)) { return false; } + value = str; + break; + } + case static_cast(DataSharePredicatesObjectType::TYPE_BOOL): { + bool val; + if (!UnmarshalBasicTypeToBuffer(iss, val)) { return false; } + value = val; + break; + } + case static_cast(DataSharePredicatesObjectType::TYPE_LONG): { + int64_t longVal; + if (!UnmarshalBasicTypeToBuffer(iss, longVal)) { return false; } + value = longVal; + break; + } + default: + LOG_ERROR("UnmarshalSingleTypeToBuffer: unknown typeId"); + return false; + } + return iss.good(); +} + +bool UnmarshalSingleTypeVecToBuffer(std::istringstream &iss, std::vector &values) +{ + // Get vec length + size_t len; + if (!UnmarshalBasicTypeToBuffer(iss, len)) { + return false; + } + for (size_t i = 0; i < len; i++) { + SingleValue::Type value; + if (!UnmarshalSingleTypeToBuffer(iss, value)) { + return false; + } + values.push_back(value); + } + return iss.good(); +} + +bool UnmarshalMultiTypeToBuffer(std::istringstream &iss, MutliValue::Type &value) +{ + // Get type of value + uint8_t typeId; + if (!UnmarshalBasicTypeToBuffer(iss, typeId)) { + return false; + } + // add offset of TYPE_NULL + typeId += static_cast(DataSharePredicatesObjectsType::TYPE_NULL); + switch (typeId) { + case static_cast(DataSharePredicatesObjectsType::TYPE_NULL): { + return iss.good(); + } + case static_cast(DataSharePredicatesObjectsType::TYPE_INT_VECTOR): { + std::vector intVector; + if (!UnmarshalBasicTypeVecToBuffer(iss, intVector)) { return false; } + value = intVector; + break; + } + case static_cast(DataSharePredicatesObjectsType::TYPE_LONG_VECTOR): { + std::vector longVector; + if (!UnmarshalBasicTypeVecToBuffer(iss, longVector)) { return false; } + value = longVector; + break; + } + case static_cast(DataSharePredicatesObjectsType::TYPE_DOUBLE_VECTOR): { + std::vector doubleVector; + if (!UnmarshalBasicTypeVecToBuffer(iss, doubleVector)) { return false; } + value = doubleVector; + break; + } + case static_cast(DataSharePredicatesObjectsType::TYPE_STRING_VECTOR): { + std::vector strVector; + if (!UnmarshalStringVecToBuffer(iss, strVector)) { return false; } + value = strVector; + break; + } + default: + LOG_ERROR("UnmarshalMultiTypeToBuffer: unknown typeId"); + return false; + } + return iss.good(); +} + +bool UnmarshalMultiTypeVecToBuffer(std::istringstream &iss, std::vector &values) +{ + size_t len; + if (!UnmarshalBasicTypeToBuffer(iss, len)) { + return false; + } + for (size_t i = 0; i < len; i++) { + MutliValue::Type typ; + if (!UnmarshalMultiTypeToBuffer(iss, typ)) { + return false; + } + values.push_back(typ); + } + return iss.good(); +} + +bool UnmarshalOperationItemToBuffer(std::istringstream &iss, OperationItem &value) +{ + // Deserialize operation + if (!UnmarshalBasicTypeToBuffer(iss, value.operation)) { + return false; + } + // Deserialize singleParams + if (!UnmarshalSingleTypeVecToBuffer(iss, value.singleParams)) { + return false; + } + // Deserialize multiParams + if (!UnmarshalMultiTypeVecToBuffer(iss, value.multiParams)) { + return false; + } + + return iss.good(); +} + +bool UnmarshalOperationItemVecToBuffer(std::istringstream &iss, std::vector &values) +{ + size_t len; + if (!UnmarshalBasicTypeToBuffer(iss, len)) { + return false; + } + for (size_t i = 0; i < len; i++) { + OperationItem item; + if (!UnmarshalOperationItemToBuffer(iss, item)) { + return false; + } + values.push_back(item); + } + return iss.good(); +} + +bool UnmarshalPredicatesToBuffer(std::istringstream &iss, DataSharePredicates &predicates) +{ + std::vector operations = {}; + std::string whereClause = ""; + std::vector whereArgs = {}; + std::string order = ""; + short mode = 0; + + // Deserialize operations + if (!UnmarshalOperationItemVecToBuffer(iss, operations)) { + return false; + } + // Deserialize whereClause + if (!UnmarshalStringToBuffer(iss, whereClause)) { + return false; + } + // Deserialize whereArgs + if (!UnmarshalStringVecToBuffer(iss, whereArgs)) { + return false; + } + // Deserialize order + if (!UnmarshalStringToBuffer(iss, order)) { + return false; + } + // Deserialize mode + if (!UnmarshalBasicTypeToBuffer(iss, mode)) { + return false; + } + + predicates.SetOperationList(operations); + predicates.SetWhereClause(whereClause); + predicates.SetWhereArgs(whereArgs); + predicates.SetOrder(order); + predicates.SetSettingMode(mode); + + return iss.good(); +} + +bool UnmarshalValuesMapToBuffer(std::istringstream &iss, + std::map &valuesMap) +{ + std::string key; + UnmarshalStringToBuffer(iss, key); + uint8_t typeId; + UnmarshalBasicTypeToBuffer(iss, typeId); + DataShareValueObject::Type value; + switch (typeId) { + case static_cast(DataShareValueObjectType::TYPE_NULL): { return iss.good(); } + case static_cast(DataShareValueObjectType::TYPE_INT): { + int64_t val; + UnmarshalBasicTypeToBuffer(iss, val); + value = val; + break; + } + case static_cast(DataShareValueObjectType::TYPE_DOUBLE): { + double val; + UnmarshalBasicTypeToBuffer(iss, val); + value = val; + break; + } + case static_cast(DataShareValueObjectType::TYPE_STRING): { + std::string val; + UnmarshalStringToBuffer(iss, val); + value = val; + break; + } + case static_cast(DataShareValueObjectType::TYPE_BOOL): { + bool val; + UnmarshalBasicTypeToBuffer(iss, val); + value = val; + break; + } + case static_cast(DataShareValueObjectType::TYPE_BLOB): { + std::vector val; + UnmarshalBasicTypeVecToBuffer(iss, val); + value = val; + break; + } + default: + LOG_ERROR("UnmarshalValuesMapToBuffer: unknown typeId"); + return false; + } + valuesMap.insert(std::make_pair(key, value)); + return iss.good(); +} + +bool UnmarshalValuesBucketVecToBuffer(std::istringstream &iss, std::vector &values) +{ + size_t size; + if (!UnmarshalBasicTypeToBuffer(iss, size)) { return false; } + for (size_t i = 0; i < size; i++) { + size_t mapSize; + if (!UnmarshalBasicTypeToBuffer(iss, mapSize)) { return false; } + std::map valuesMap; + for (size_t j = 0; j < mapSize; j++) { + if (!UnmarshalValuesMapToBuffer(iss, valuesMap)) { + return false; + } + } + DataShareValuesBucket value(valuesMap); + values.push_back(value); + } + return iss.good(); +} + +bool MarshalPredicates(const Predicates &predicates, MessageParcel &parcel) +{ + std::ostringstream oss; + if (!MarshalPredicatesToBuffer(oss, predicates)) { + LOG_ERROR("MarshalPredicatesToBuffer failed."); + return false; + } + std::string str = oss.str(); + size_t size = str.length(); + if (size > MAX_IPC_SIZE) { + LOG_ERROR("Size of predicates is too large."); + return false; + } + if (!parcel.WriteInt32(size)) { + LOG_ERROR("Write size failed."); + return false; + } + return parcel.WriteRawData(reinterpret_cast(str.data()), size); +} + +bool UnmarshalPredicates(Predicates &predicates, MessageParcel &parcel) +{ + size_t length = parcel.ReadInt32(); + if (length < 1) { + LOG_ERROR("Length of predicates is invalid."); + return false; + } + const char *buffer = reinterpret_cast(parcel.ReadRawData((size_t)length)); + if (buffer == nullptr) { + LOG_ERROR("ReadRawData failed."); + return false; + } + std::istringstream iss(std::string(buffer, length)); + return UnmarshalPredicatesToBuffer(iss, predicates); +} + +bool MarshalValuesBucketVec(const std::vector &values, MessageParcel &parcel) +{ + std::ostringstream oss; + if (!MarshalValuesBucketVecToBuffer(oss, values)) { + LOG_ERROR("MarshalValuesBucketVecToBuffer failed."); + return false; + } + std::string str = oss.str(); + size_t size = str.length(); + if (size > MAX_IPC_SIZE) { + LOG_ERROR("Size of ValuesBucketVec is too large."); + return false; + } + if (!parcel.WriteInt32(size)) { + LOG_ERROR("Write size failed."); + return false; + } + return parcel.WriteRawData(reinterpret_cast(str.data()), size); +} + +bool UnmarshalValuesBucketVec(std::vector &values, MessageParcel &parcel) +{ + size_t length = parcel.ReadInt32(); + if (length < 1) { + LOG_ERROR("Length of ValuesBucketVec is invalid."); + return false; + } + const char *buffer = reinterpret_cast(parcel.ReadRawData((size_t)length)); + if (buffer == nullptr) { + LOG_ERROR("ReadRawData failed."); + return false; + } + std::istringstream iss(std::string(buffer, length)); + return UnmarshalValuesBucketVecToBuffer(iss, values); +} +} // namespace OHOS::ITypesUtil \ No newline at end of file diff --git a/data_share/frameworks/native/common/src/datashare_uri_utils.cpp b/data_share/frameworks/native/common/src/datashare_uri_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..557c2504ff090ade89c8cf3a074de243b4278c20 --- /dev/null +++ b/data_share/frameworks/native/common/src/datashare_uri_utils.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024 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 "URIUtils" + +#include "datashare_uri_utils.h" + +#include + +#include "log_print.h" +#include "string_ex.h" +#include "uri.h" + +namespace OHOS::DataShare { +std::string DataShareURIUtils::FormatUri(const std::string &uri) +{ + auto pos = uri.find_last_of('?'); + if (pos == std::string::npos) { + return uri; + } + + return uri.substr(0, pos); +} + +std::pair DataShareURIUtils::Strtoul(const std::string &str) +{ + unsigned long data = 0; + if (str.empty()) { + return std::make_pair(false, data); + } + char* end = nullptr; + errno = 0; + data = strtoul(str.c_str(), &end, BASE_TEN); + if (errno == ERANGE || end == nullptr || end == str || *end != '\0') { + return std::make_pair(false, data); + } + return std::make_pair(true, data); +} + +std::map DataShareURIUtils::GetQueryParams(const std::string& uri) +{ + size_t queryStartPos = uri.find('?'); + if (queryStartPos == std::string::npos) { + return {}; + } + std::map params; + std::string queryParams = uri.substr(queryStartPos + 1); + size_t startPos = 0; + while (startPos < queryParams.size()) { + size_t delimiterIndex = queryParams.find('&', startPos); + if (delimiterIndex == std::string::npos) { + delimiterIndex = queryParams.size(); + } + size_t equalIndex = queryParams.find('=', startPos); + if (equalIndex == std::string::npos || equalIndex > delimiterIndex) { + startPos = delimiterIndex + 1; + continue; + } + std::string key = queryParams.substr(startPos, equalIndex - startPos); + std::string value = queryParams.substr(equalIndex + 1, delimiterIndex - equalIndex - 1); + params[key] = value; + startPos = delimiterIndex + 1; + } + return params; +} + +std::pair DataShareURIUtils::GetUserFromUri(const std::string &uri) +{ + auto queryParams = GetQueryParams(uri); + if (queryParams[USER_PARAM].empty()) { + // -1 is placeholder for visit provider's user + return std::make_pair(true, -1); + } + auto [success, data] = Strtoul(queryParams[USER_PARAM]); + if (!success) { + return std::make_pair(false, -1); + } + if (data < 0 || data > INT32_MAX) { + return std::make_pair(false, -1); + } + return std::make_pair(true, data); +} +} // namespace OHOS::DataShare \ No newline at end of file diff --git a/data_share/frameworks/native/consumer/controller/common/general_controller.h b/data_share/frameworks/native/consumer/controller/common/general_controller.h index 3a1f6fd7a3ce8a1c28fe757994c6d8eb7d8feb00..6a554b17bd02a9673aa05126d9904d3500046bc3 100644 --- a/data_share/frameworks/native/consumer/controller/common/general_controller.h +++ b/data_share/frameworks/native/consumer/controller/common/general_controller.h @@ -45,9 +45,9 @@ public: virtual std::shared_ptr Query(const Uri &uri, const DataSharePredicates &predicates, std::vector &columns, DatashareBusinessError &businessError) = 0; - virtual void RegisterObserver(const Uri &uri, const sptr &dataObserver) = 0; + virtual int RegisterObserver(const Uri &uri, const sptr &dataObserver) = 0; - virtual void UnregisterObserver(const Uri &uri, const sptr &dataObserver) = 0; + virtual int UnregisterObserver(const Uri &uri, const sptr &dataObserver) = 0; virtual void NotifyChange(const Uri &uri) = 0; diff --git a/data_share/frameworks/native/consumer/controller/provider/include/ext_special_controller.h b/data_share/frameworks/native/consumer/controller/provider/include/ext_special_controller.h index 81745c223dc16ff158b0bf01da2cc3ab5cf7a1d7..547a9186e5dd3dc73cb38c5ea3e1da3b3e99e812 100644 --- a/data_share/frameworks/native/consumer/controller/provider/include/ext_special_controller.h +++ b/data_share/frameworks/native/consumer/controller/provider/include/ext_special_controller.h @@ -49,6 +49,7 @@ public: std::vector GetFileTypes(const Uri &uri, const std::string &mimeTypeFilter); + int32_t UserDefineFunc(MessageParcel &data, MessageParcel &reply, MessageOption &option); private: std::shared_ptr connection_ = nullptr; sptr token_ = {}; diff --git a/data_share/frameworks/native/consumer/controller/provider/include/general_controller_provider_impl.h b/data_share/frameworks/native/consumer/controller/provider/include/general_controller_provider_impl.h index e6c5c93166aa3974612df14e8772ddce097b4170..04031a892308626498eaeee3e051899606002ee0 100644 --- a/data_share/frameworks/native/consumer/controller/provider/include/general_controller_provider_impl.h +++ b/data_share/frameworks/native/consumer/controller/provider/include/general_controller_provider_impl.h @@ -41,9 +41,9 @@ public: std::shared_ptr Query(const Uri &uri, const DataSharePredicates &predicates, std::vector &columns, DatashareBusinessError &businessError) override; - void RegisterObserver(const Uri &uri, const sptr &dataObserver) override; + int RegisterObserver(const Uri &uri, const sptr &dataObserver) override; - void UnregisterObserver(const Uri &uri, const sptr &dataObserver) override; + int UnregisterObserver(const Uri &uri, const sptr &dataObserver) override; void NotifyChange(const Uri &uri) override; diff --git a/data_share/frameworks/native/consumer/controller/provider/src/ext_special_controller.cpp b/data_share/frameworks/native/consumer/controller/provider/src/ext_special_controller.cpp index 8228fcedafe106363f8f9ffb739e3b5e965eec85..97781b3b04f231fb7681d9382cd320b7727dfac0 100644 --- a/data_share/frameworks/native/consumer/controller/provider/src/ext_special_controller.cpp +++ b/data_share/frameworks/native/consumer/controller/provider/src/ext_special_controller.cpp @@ -170,8 +170,24 @@ std::vector ExtSpecialController::GetFileTypes(const Uri &uri, cons return proxy->GetFileTypes(uri, mimeTypeFilter); } -ExtSpecialController::ExtSpecialController(std::shared_ptr connection, const Uri &uri, - const sptr &token) +int32_t ExtSpecialController::UserDefineFunc( + MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + auto connection = connection_; + if (connection == nullptr) { + LOG_ERROR("connection is nullptr"); + return INVALID_VALUE; + } + auto proxy = connection->GetDataShareProxy(uri_, token_); + if (proxy == nullptr) { + LOG_ERROR("proxy is nullptr"); + return INVALID_VALUE; + } + return proxy->UserDefineFunc(data, reply, option); +} + +ExtSpecialController::ExtSpecialController( + std::shared_ptr connection, const Uri &uri, const sptr &token) : connection_(connection), token_(token), uri_(uri) { } diff --git a/data_share/frameworks/native/consumer/controller/provider/src/general_controller_provider_impl.cpp b/data_share/frameworks/native/consumer/controller/provider/src/general_controller_provider_impl.cpp index 6c3420f4c2ef8fd2ab522f29a5217b35445d423e..fa19b05c03b75dc83ccaae4e6546bd8614fd734d 100644 --- a/data_share/frameworks/native/consumer/controller/provider/src/general_controller_provider_impl.cpp +++ b/data_share/frameworks/native/consumer/controller/provider/src/general_controller_provider_impl.cpp @@ -130,40 +130,42 @@ std::shared_ptr GeneralControllerProviderImpl::Query(const U return proxy->Query(uri, predicates, columns, businessError); } -void GeneralControllerProviderImpl::RegisterObserver(const Uri &uri, +int GeneralControllerProviderImpl::RegisterObserver(const Uri &uri, const sptr &dataObserver) { auto connection = connection_; if (connection == nullptr) { LOG_ERROR("connection is nullptr"); - return; + return E_PROVIDER_CONN_NULL; } auto proxy = connection->GetDataShareProxy(uri_, token_); if (proxy == nullptr) { LOG_ERROR("proxy is nullptr"); - return; + return E_PROVIDER_NOT_CONNECTED; } - bool ret = proxy->RegisterObserver(uri, dataObserver); + int ret = proxy->RegisterObserver(uri, dataObserver); LOG_INFO("Register non-silent observer ret: %{public}d, uri: %{public}s", ret, DataShareStringUtils::Anonymous(uri.ToString()).c_str()); + return ret; } -void GeneralControllerProviderImpl::UnregisterObserver(const Uri &uri, +int GeneralControllerProviderImpl::UnregisterObserver(const Uri &uri, const sptr &dataObserver) { auto connection = connection_; if (connection == nullptr) { LOG_ERROR("connection is nullptr"); - return; + return E_PROVIDER_CONN_NULL; } auto proxy = connection->GetDataShareProxy(uri_, token_); if (proxy == nullptr) { LOG_ERROR("proxy is nullptr"); - return; + return E_PROVIDER_NOT_CONNECTED; } - bool ret = proxy->UnregisterObserver(uri, dataObserver); + int ret = proxy->UnregisterObserver(uri, dataObserver); LOG_INFO("Unregister non-silent observer ret: %{public}d, uri: %{public}s", ret, DataShareStringUtils::Anonymous(uri.ToString()).c_str()); + return ret; } void GeneralControllerProviderImpl::NotifyChange(const Uri &uri) diff --git a/data_share/frameworks/native/consumer/controller/service/include/general_controller_service_impl.h b/data_share/frameworks/native/consumer/controller/service/include/general_controller_service_impl.h index a6d26e32f0786aba483df28569e433bfe77f2295..d4e9a9186e2f1b74a4799ac07f6cc3badea2e58f 100644 --- a/data_share/frameworks/native/consumer/controller/service/include/general_controller_service_impl.h +++ b/data_share/frameworks/native/consumer/controller/service/include/general_controller_service_impl.h @@ -44,9 +44,9 @@ public: std::shared_ptr Query(const Uri &uri, const DataSharePredicates &predicates, std::vector &columns, DatashareBusinessError &businessError) override; - void RegisterObserver(const Uri &uri, const sptr &dataObserver) override; + int RegisterObserver(const Uri &uri, const sptr &dataObserver) override; - void UnregisterObserver(const Uri &uri, const sptr &dataObserver) override; + int UnregisterObserver(const Uri &uri, const sptr &dataObserver) override; void NotifyChange(const Uri &uri) override; diff --git a/data_share/frameworks/native/consumer/controller/service/src/general_controller_service_impl.cpp b/data_share/frameworks/native/consumer/controller/service/src/general_controller_service_impl.cpp index fa26bc1a58a6e2812be3b9e60797462ccb8a0c73..5b3a7064b25288cf6884efb843706cdb3ba8af61 100644 --- a/data_share/frameworks/native/consumer/controller/service/src/general_controller_service_impl.cpp +++ b/data_share/frameworks/native/consumer/controller/service/src/general_controller_service_impl.cpp @@ -158,36 +158,38 @@ std::shared_ptr GeneralControllerServiceImpl::Query(const Ur return resultSet; } -void GeneralControllerServiceImpl::RegisterObserver(const Uri &uri, +int GeneralControllerServiceImpl::RegisterObserver(const Uri &uri, const sptr &dataObserver) { auto manager = DataShareManagerImpl::GetInstance(); if (manager == nullptr) { LOG_ERROR("Manager is nullptr"); - return; + return E_DATA_SHARE_NOT_READY; } manager->SetCallCount(__FUNCTION__, uri.ToString()); auto obsMgrClient = OHOS::AAFwk::DataObsMgrClient::GetInstance(); if (obsMgrClient == nullptr) { LOG_ERROR("get DataObsMgrClient failed"); - return; + return E_DATA_OBS_NOT_READY; } ErrCode ret = obsMgrClient->RegisterObserver(uri, dataObserver); LOG_INFO("Register silent observer ret: %{public}d, uri: %{public}s", ret, DataShareStringUtils::Anonymous(uri.ToString()).c_str()); + return ret; } -void GeneralControllerServiceImpl::UnregisterObserver(const Uri &uri, +int GeneralControllerServiceImpl::UnregisterObserver(const Uri &uri, const sptr &dataObserver) { auto obsMgrClient = OHOS::AAFwk::DataObsMgrClient::GetInstance(); if (obsMgrClient == nullptr) { LOG_ERROR("get DataObsMgrClient failed"); - return; + return E_DATA_OBS_NOT_READY; } ErrCode ret = obsMgrClient->UnregisterObserver(uri, dataObserver); LOG_INFO("Unregister silent observer ret: %{public}d, uri: %{public}s", ret, DataShareStringUtils::Anonymous(uri.ToString()).c_str()); + return ret; } void GeneralControllerServiceImpl::NotifyChange(const Uri &uri) diff --git a/data_share/frameworks/native/consumer/include/datashare_helper_impl.h b/data_share/frameworks/native/consumer/include/datashare_helper_impl.h index d71e4c1ccc30e3c5da88c175813d0561ed8568fa..6ab631ba44816179069154039e38fdee814289a0 100644 --- a/data_share/frameworks/native/consumer/include/datashare_helper_impl.h +++ b/data_share/frameworks/native/consumer/include/datashare_helper_impl.h @@ -58,9 +58,9 @@ public: int ExecuteBatch(const std::vector &statements, ExecResultSet &result) override; - void RegisterObserver(const Uri &uri, const sptr &dataObserver) override; + int RegisterObserver(const Uri &uri, const sptr &dataObserver) override; - void UnregisterObserver(const Uri &uri, const sptr &dataObserver) override; + int UnregisterObserver(const Uri &uri, const sptr &dataObserver) override; void NotifyChange(const Uri &uri) override; @@ -105,6 +105,9 @@ public: std::pair DeleteEx(Uri &uri, const DataSharePredicates &predicates) override; + int32_t UserDefineFunc( + MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + private: std::shared_ptr extSpCtl_ = nullptr; std::shared_ptr generalCtl_ = nullptr; diff --git a/data_share/frameworks/native/consumer/include/datashare_proxy.h b/data_share/frameworks/native/consumer/include/datashare_proxy.h index 7c5fad2af42ca21aa675e45d36832d73c929df97..0a696e1a18bc5afc22ac06ee26706cf2838ecff4 100644 --- a/data_share/frameworks/native/consumer/include/datashare_proxy.h +++ b/data_share/frameworks/native/consumer/include/datashare_proxy.h @@ -72,6 +72,9 @@ public: virtual std::pair DeleteEx(const Uri &uri, const DataSharePredicates &predicates) override; + virtual int32_t UserDefineFunc( + MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + private: bool CheckSize(const UpdateOperations &operations); static inline BrokerDelegator delegator_; diff --git a/data_share/frameworks/native/consumer/src/datashare_connection.cpp b/data_share/frameworks/native/consumer/src/datashare_connection.cpp index 84f2953365951dd9ced043705044ffd584dd6adc..a6080c1ea6bfe472239a67785249b52c9e1106de 100644 --- a/data_share/frameworks/native/consumer/src/datashare_connection.cpp +++ b/data_share/frameworks/native/consumer/src/datashare_connection.cpp @@ -185,17 +185,8 @@ std::shared_ptr DataShareConnection::ConnectDataShareExtAbility( if (condition_.condition.wait_for(condLock, std::chrono::seconds(waitTime_), [this] { return dataShareProxy_ != nullptr; })) { LOG_DEBUG("connect ability ended successfully uri:%{public}s", DataShareStringUtils::Change(reqUri).c_str()); - RADAR_REPORT(__FUNCTION__, RadarReporter::CREATE_DATASHARE_HELPER, - RadarReporter::CONNECT_EXT, RadarReporter::SUCCESS, - RadarReporter::LOCAL_SESS_NAME, Str16ToStr8(token->GetObjectDescriptor()), - RadarReporter::PEER_SESS_NAME, DataShareStringUtils::Change(reqUri)); } else { LOG_WARN("connect timeout uri:%{public}s", DataShareStringUtils::Change(reqUri).c_str()); - RADAR_REPORT(__FUNCTION__, RadarReporter::CREATE_DATASHARE_HELPER, - RadarReporter::CONNECT_EXT, RadarReporter::FAILED, - RadarReporter::ERROR_CODE, RadarReporter::EXT_CONNECT_TIMEOUT_ERROR, - RadarReporter::LOCAL_SESS_NAME, Str16ToStr8(token->GetObjectDescriptor()), - RadarReporter::PEER_SESS_NAME, DataShareStringUtils::Change(reqUri)); } return GetDataShareProxy(); } @@ -218,17 +209,8 @@ void DataShareConnection::DisconnectDataShareExtAbility() ErrCode ret = Disconnect(); LOG_INFO("disconnect uri:%{public}s, ret = %{public}d", DataShareStringUtils::Change(uri).c_str(), ret); if (ret == E_OK) { - RADAR_REPORT(__FUNCTION__, RadarReporter::CREATE_DATASHARE_HELPER, - RadarReporter::DIS_CONNECT_EXT, RadarReporter::SUCCESS, - RadarReporter::LOCAL_SESS_NAME, Str16ToStr8(token_->GetObjectDescriptor()), - RadarReporter::PEER_SESS_NAME, DataShareStringUtils::Change(uri)); return; } - RADAR_REPORT(__FUNCTION__, RadarReporter::CREATE_DATASHARE_HELPER, - RadarReporter::DIS_CONNECT_EXT, RadarReporter::FAILED, - RadarReporter::ERROR_CODE, RadarReporter::EXT_DIS_CONNECT_ERROR, - RadarReporter::LOCAL_SESS_NAME, Str16ToStr8(token_->GetObjectDescriptor()), - RadarReporter::PEER_SESS_NAME, DataShareStringUtils::Change(uri)); } DataShareConnection::~DataShareConnection() diff --git a/data_share/frameworks/native/consumer/src/datashare_helper.cpp b/data_share/frameworks/native/consumer/src/datashare_helper.cpp index 8db2dcba7da710d1c6ec0235d1e8870f35bd34cf..c2a71b2e3fd8e9b550d407a03cde2208b0d10ac7 100644 --- a/data_share/frameworks/native/consumer/src/datashare_helper.cpp +++ b/data_share/frameworks/native/consumer/src/datashare_helper.cpp @@ -403,5 +403,9 @@ std::pair DataShareHelper::UpdateEx(Uri &uri, const DataShareP return std::make_pair(0, 0); } +int32_t DataShareHelper::UserDefineFunc(MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + return 0; +} } // namespace DataShare } // namespace OHOS \ No newline at end of file diff --git a/data_share/frameworks/native/consumer/src/datashare_helper_impl.cpp b/data_share/frameworks/native/consumer/src/datashare_helper_impl.cpp index bbf76e1250fe242ce00ade91699b761d6d411d2b..167cf08c004cab85a7552cdbe8bdfb4140fead9b 100644 --- a/data_share/frameworks/native/consumer/src/datashare_helper_impl.cpp +++ b/data_share/frameworks/native/consumer/src/datashare_helper_impl.cpp @@ -239,38 +239,38 @@ int DataShareHelperImpl::ExecuteBatch(const std::vector &sta return extSpCtl->ExecuteBatch(statements, result); } -void DataShareHelperImpl::RegisterObserver(const Uri &uri, const sptr &dataObserver) +int DataShareHelperImpl::RegisterObserver(const Uri &uri, const sptr &dataObserver) { RadarReporter::RadarReport report(RadarReporter::OBSERVER_MANAGER, RadarReporter::REGISTER_OBSERVER, __FUNCTION__); if (dataObserver == nullptr) { LOG_ERROR("dataObserver is nullptr"); report.SetError(RadarReporter::EMPTY_OBSERVER_ERROR); - return; + return E_NULL_OBSERVER; } auto generalCtl = generalCtl_; if (generalCtl == nullptr) { LOG_ERROR("generalCtl is nullptr"); report.SetError(RadarReporter::DATA_SHARE_DIED_ERROR); - return; + return E_HELPER_DIED; } return generalCtl->RegisterObserver(uri, dataObserver); } -void DataShareHelperImpl::UnregisterObserver(const Uri &uri, const sptr &dataObserver) +int DataShareHelperImpl::UnregisterObserver(const Uri &uri, const sptr &dataObserver) { RadarReporter::RadarReport report(RadarReporter::OBSERVER_MANAGER, RadarReporter::UNREGISTER_OBSERVER, __FUNCTION__); if (dataObserver == nullptr) { LOG_ERROR("dataObserver is nullptr"); report.SetError(RadarReporter::EMPTY_OBSERVER_ERROR); - return; + return E_NULL_OBSERVER; } auto generalCtl = generalCtl_; if (generalCtl == nullptr) { LOG_ERROR("generalCtl is nullptr"); report.SetError(RadarReporter::DATA_SHARE_DIED_ERROR); - return; + return E_HELPER_DIED; } return generalCtl->UnregisterObserver(uri, dataObserver); } @@ -463,5 +463,17 @@ std::vector DataShareHelperImpl::DisablePubSubs(const std::vect } return publishedDataCtl->DisableSubscribePublishedData(this, uris, subscriberId); } + +int32_t DataShareHelperImpl::UserDefineFunc( + MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + DISTRIBUTED_DATA_HITRACE(std::string(LOG_TAG) + "::" + std::string(__FUNCTION__)); + auto extSpCtl = extSpCtl_; + if (extSpCtl == nullptr) { + LOG_ERROR("providerSpCtl is nullptr"); + return DATA_SHARE_ERROR; + } + return extSpCtl->UserDefineFunc(data, reply, option); +} } // namespace DataShare } // namespace OHOS \ No newline at end of file diff --git a/data_share/frameworks/native/consumer/src/datashare_proxy.cpp b/data_share/frameworks/native/consumer/src/datashare_proxy.cpp index 11f9c7a9bda7fd17eba09c25f1b8f3ee80f5955a..8ce36b324ed609bd9b79dd43dd96efdf4be8ab33 100644 --- a/data_share/frameworks/native/consumer/src/datashare_proxy.cpp +++ b/data_share/frameworks/native/consumer/src/datashare_proxy.cpp @@ -387,8 +387,12 @@ std::shared_ptr DataShareProxy::Query(const Uri &uri, const LOG_ERROR("WriteInterfaceToken failed"); return nullptr; } - if (!ITypesUtil::Marshal(data, uri, predicates, columns)) { - LOG_ERROR("fail to Marshalling"); + if (!ITypesUtil::Marshal(data, uri, columns)) { + LOG_ERROR("Marshalling uri and columns to data failed"); + return nullptr; + } + if (!ITypesUtil::MarshalPredicates(predicates, data)) { + LOG_ERROR("Marshalling predicates to shared-memory failed"); return nullptr; } MessageParcel reply; @@ -448,11 +452,14 @@ int DataShareProxy::BatchInsert(const Uri &uri, const std::vectorSendRequest( @@ -636,5 +643,17 @@ bool DataShareProxy::CheckSize(const UpdateOperations &operations) } return true; } +int32_t DataShareProxy::UserDefineFunc( + MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + int32_t errCode = -1; + int32_t err = Remote()->SendRequest( + static_cast(IDataShareInterfaceCode::CMD_USER_DEFINE_FUNC), data, reply, option); + if (err != E_OK) { + LOG_ERROR("UserDefineFunc fail to SendRequest. err: %{public}d", err); + return err == PERMISSION_ERR ? PERMISSION_ERR_CODE : errCode; + } + return err; +} } // namespace DataShare } // namespace OHOS diff --git a/data_share/frameworks/native/provider/include/datashare_stub.h b/data_share/frameworks/native/provider/include/datashare_stub.h index 6bd397537fa8eeed4246bb49e20dbb7516895dec..5e91786a0e306c26eb7180d45b122d064075fd9f 100644 --- a/data_share/frameworks/native/provider/include/datashare_stub.h +++ b/data_share/frameworks/native/provider/include/datashare_stub.h @@ -52,6 +52,7 @@ private: ErrCode CmdInsertEx(MessageParcel &data, MessageParcel &reply); ErrCode CmdUpdateEx(MessageParcel &data, MessageParcel &reply); ErrCode CmdDeleteEx(MessageParcel &data, MessageParcel &reply); + ErrCode CmdUserDefineFunc(MessageParcel &data, MessageParcel &reply, MessageOption &option); virtual int ExecuteBatch(const std::vector &statements, ExecResultSet &result) override; virtual int InsertExt(const Uri &uri, const DataShareValuesBucket &value, std::string &result) override; @@ -60,6 +61,8 @@ private: virtual std::pair UpdateEx(const Uri &uri, const DataSharePredicates &predicates, const DataShareValuesBucket &value) override; virtual std::pair DeleteEx(const Uri &uri, const DataSharePredicates &predicates) override; + virtual int32_t UserDefineFunc( + MessageParcel &data, MessageParcel &reply, MessageOption &option) override; using RequestFuncType = int (DataShareStub::*)(MessageParcel &data, MessageParcel &reply); std::map stubFuncMap_; diff --git a/data_share/frameworks/native/provider/include/datashare_uv_queue.h b/data_share/frameworks/native/provider/include/datashare_uv_queue.h index b122a1586cad46a1f17468edad0f5218a479a692..dff6a09aafda90b439c0cd7078a872d16216ddb2 100644 --- a/data_share/frameworks/native/provider/include/datashare_uv_queue.h +++ b/data_share/frameworks/native/provider/include/datashare_uv_queue.h @@ -41,7 +41,7 @@ public: void CheckFuncAndExec(NapiBoolFunc retFunc); private: - struct UvEntry { + struct TaskEntry { napi_env env; NapiVoidFunc func; bool done; @@ -50,9 +50,7 @@ private: std::atomic_int32_t count; }; - static void LambdaForWork(uv_work_t* work, int uvstatus); - - static void Purge(uv_work_t* work); + static void LambdaForWork(TaskEntry* taskEntry); napi_env env_ = nullptr; uv_loop_s* loop_ = nullptr; diff --git a/data_share/frameworks/native/provider/src/datashare_stub.cpp b/data_share/frameworks/native/provider/src/datashare_stub.cpp index 0ebf16736af26ac1acd56295082a18eb67885700..2f1466dcfe021f5f9fa5a67679fe54143fab25e8 100644 --- a/data_share/frameworks/native/provider/src/datashare_stub.cpp +++ b/data_share/frameworks/native/provider/src/datashare_stub.cpp @@ -77,9 +77,17 @@ int DataShareStub::OnRemoteRequest(uint32_t code, MessageParcel& data, MessagePa } const auto &itFunc = stubFuncMap_.find(code); + auto start = std::chrono::steady_clock::now(); + int32_t ret = 0; + bool isCodeValid = false; if (itFunc != stubFuncMap_.end()) { - auto start = std::chrono::steady_clock::now(); - auto ret = (this->*(itFunc->second))(data, reply); + isCodeValid = true; + ret = (this->*(itFunc->second))(data, reply); + } else if (code == static_cast(IDataShareInterfaceCode::CMD_USER_DEFINE_FUNC)) { + isCodeValid = true; + ret = CmdUserDefineFunc(data, reply, option); + } + if (isCodeValid) { auto finish = std::chrono::steady_clock::now(); auto duration = std::chrono::duration_cast(finish - start); if (duration >= TIME_THRESHOLD) { @@ -90,7 +98,6 @@ int DataShareStub::OnRemoteRequest(uint32_t code, MessageParcel& data, MessagePa } return ret; } - LOG_DEBUG("remote request unhandled: %{public}d", code); return IPCObjectStub::OnRemoteRequest(code, data, reply, option); } @@ -325,8 +332,12 @@ ErrCode DataShareStub::CmdQuery(MessageParcel &data, MessageParcel &reply) Uri uri(""); DataSharePredicates predicates; std::vector columns; - if (!ITypesUtil::Unmarshal(data, uri, predicates, columns)) { - LOG_ERROR("Unmarshalling predicates is nullptr"); + if (!ITypesUtil::Unmarshal(data, uri, columns)) { + LOG_ERROR("Unmarshalling uri and columns to data failed"); + return ERR_INVALID_VALUE; + } + if (!ITypesUtil::UnmarshalPredicates(predicates, data)) { + LOG_ERROR("Unmarshalling predicates to shared-memory failed"); return ERR_INVALID_VALUE; } DatashareBusinessError businessError; @@ -356,15 +367,24 @@ ErrCode DataShareStub::CmdGetType(MessageParcel &data, MessageParcel &reply) return E_OK; } +ErrCode DataShareStub::CmdUserDefineFunc(MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + UserDefineFunc(data, reply, option); + return E_OK; +} + ErrCode DataShareStub::CmdBatchInsert(MessageParcel &data, MessageParcel &reply) { Uri uri(""); std::vector values; - if (!ITypesUtil::Unmarshal(data, uri, values)) { - LOG_ERROR("Unmarshalling predicates is nullptr"); + if (!ITypesUtil::Unmarshal(data, uri)) { + LOG_ERROR("Unmarshalling uri from data failed"); + return ERR_INVALID_VALUE; + } + if (!ITypesUtil::UnmarshalValuesBucketVec(values, data)) { + LOG_ERROR("Unmarshalling DataShareValuesBucket from shared-memory failed"); return ERR_INVALID_VALUE; } - int ret = BatchInsert(uri, values); if (ret == DEFAULT_NUMBER) { LOG_ERROR("BatchInsert inner error"); @@ -540,5 +560,11 @@ std::pair DataShareStub::DeleteEx(const Uri &uri, const DataSh return std::make_pair(0, 0); } +int32_t DataShareStub::UserDefineFunc( + MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + LOG_ERROR("UserDefineFunc excuted."); + return 0; +} } // namespace DataShare } // namespace OHOS \ No newline at end of file diff --git a/data_share/frameworks/native/provider/src/datashare_uv_queue.cpp b/data_share/frameworks/native/provider/src/datashare_uv_queue.cpp index 307d8810cf93e6fce160e0a39e74e1dc41e99c77..638125c3a5a232a5094471867a82d13b06e6f711 100644 --- a/data_share/frameworks/native/provider/src/datashare_uv_queue.cpp +++ b/data_share/frameworks/native/provider/src/datashare_uv_queue.cpp @@ -30,87 +30,53 @@ DataShareUvQueue::DataShareUvQueue(napi_env env) napi_get_uv_event_loop(env, &loop_); } -void DataShareUvQueue::LambdaForWork(uv_work_t *work, int uvstatus) +void DataShareUvQueue::LambdaForWork(TaskEntry* taskEntry) { - if (UV_ECANCELED == uvstatus || work == nullptr || work->data == nullptr) { - LOG_ERROR("invalid work or work->data."); - DataShareUvQueue::Purge(work); + if (taskEntry == nullptr) { + LOG_ERROR("invalid taskEntry."); return; } - auto *entry = static_cast(work->data); { - std::unique_lock lock(entry->mutex); - if (entry->func) { - entry->func(); + std::unique_lock lock(taskEntry->mutex); + if (taskEntry->func) { + taskEntry->func(); } - entry->done = true; - entry->condition.notify_all(); + taskEntry->done = true; + taskEntry->condition.notify_all(); + } + if (taskEntry->count.fetch_sub(1) == 1) { + delete taskEntry; + taskEntry = nullptr; } - DataShareUvQueue::Purge(work); } void DataShareUvQueue::SyncCall(NapiVoidFunc func, NapiBoolFunc retFunc) { - uv_work_t* work = new (std::nothrow) uv_work_t; - if (work == nullptr) { - LOG_ERROR("invalid work."); - return; - } - work->data = new UvEntry {env_, std::move(func), false, {}, {}, std::atomic(1)}; - if (work->data == nullptr) { - delete work; - LOG_ERROR("invalid uvEntry."); - return; - } - - auto *uvEntry = static_cast(work->data); + auto *taskEntry = new TaskEntry {env_, std::move(func), false, {}, {}, std::atomic(1)}; { - std::unique_lock lock(uvEntry->mutex); - uvEntry->count.fetch_add(1); - auto status = uv_queue_work( - loop_, work, [](uv_work_t *work) {}, LambdaForWork); - if (status != napi_ok) { - LOG_ERROR("queue work failed"); - DataShareUvQueue::Purge(work); + std::unique_lock lock(taskEntry->mutex); + taskEntry->count.fetch_add(1); + auto task = [taskEntry]() { + DataShareUvQueue::LambdaForWork(taskEntry); + }; + if (napi_status::napi_ok != napi_send_event(env_, task, napi_eprio_immediate)) { + LOG_ERROR("napi_send_event task failed"); + delete taskEntry; + taskEntry = nullptr; return; } - if (uvEntry->condition.wait_for(lock, std::chrono::seconds(WAIT_TIME), [uvEntry] { return uvEntry->done; })) { + if (taskEntry->condition.wait_for(lock, std::chrono::seconds(WAIT_TIME), + [taskEntry] { return taskEntry->done; })) { auto time = static_cast(duration_cast( system_clock::now().time_since_epoch()).count()); LOG_INFO("function ended successfully. times %{public}" PRIu64 ".", time); } - if (!uvEntry->done && uv_cancel((uv_req_t*)work) != napi_ok) { - LOG_ERROR("uv_cancel failed."); - } } - CheckFuncAndExec(retFunc); - DataShareUvQueue::Purge(work); -} - -void DataShareUvQueue::Purge(uv_work_t* work) -{ - if (work == nullptr) { - LOG_ERROR("invalid work"); - return; + if (taskEntry->count.fetch_sub(1) == 1) { + delete taskEntry; + taskEntry = nullptr; } - if (work->data == nullptr) { - LOG_ERROR("invalid work->data"); - delete work; - return; - } - - auto *entry = static_cast(work->data); - auto count = entry->count.fetch_sub(1); - if (count != 1) { - return; - } - - delete entry; - entry = nullptr; - - delete work; - work = nullptr; } void DataShareUvQueue::CheckFuncAndExec(NapiBoolFunc retFunc) diff --git a/data_share/frameworks/native/proxy/include/published_data_subscriber_manager.h b/data_share/frameworks/native/proxy/include/published_data_subscriber_manager.h index c6e420cf6a5c83d748947bc4a764005bc06191da..5a80df06a87f71f0b17d2860e03f520ae2e4c61a 100644 --- a/data_share/frameworks/native/proxy/include/published_data_subscriber_manager.h +++ b/data_share/frameworks/native/proxy/include/published_data_subscriber_manager.h @@ -96,8 +96,6 @@ private: void Emit(const std::vector &keys, const std::shared_ptr &observer); void EmitOnEnable(std::map> &obsMap); PublishedDataSubscriberManager(); - bool Init(); - void Destroy(); sptr serviceCallback_; ConcurrentMap lastChangeNodeMap_; }; diff --git a/data_share/frameworks/native/proxy/include/rdb_subscriber_manager.h b/data_share/frameworks/native/proxy/include/rdb_subscriber_manager.h index 46f28ac8769a3a8463b9fa72ba90a7ab275391e1..814e1248002777cdb82baa17fe13fa68cdf4b0fa 100644 --- a/data_share/frameworks/native/proxy/include/rdb_subscriber_manager.h +++ b/data_share/frameworks/native/proxy/include/rdb_subscriber_manager.h @@ -96,8 +96,6 @@ private: void Emit(const std::vector &keys, const std::shared_ptr &observer); void EmitOnEnable(std::map> &obsMap); RdbSubscriberManager(); - bool Init(); - void Destroy(); sptr serviceCallback_; std::map lastChangeNodeMap_; }; diff --git a/data_share/frameworks/native/proxy/src/ams_mgr_proxy.cpp b/data_share/frameworks/native/proxy/src/ams_mgr_proxy.cpp index 0ae950daa5dad90c07b4975750c1b5e9c1b63c47..35af165325061b5b44690424ba6f6656de90881d 100644 --- a/data_share/frameworks/native/proxy/src/ams_mgr_proxy.cpp +++ b/data_share/frameworks/native/proxy/src/ams_mgr_proxy.cpp @@ -21,6 +21,8 @@ #include "iservice_registry.h" #include "system_ability_definition.h" #include "want.h" +#include "datashare_uri_utils.h" +#include "datashare_errno.h" namespace OHOS::DataShare { std::mutex AmsMgrProxy::pmutex_; @@ -61,11 +63,16 @@ __attribute__ ((no_sanitize("cfi"))) int AmsMgrProxy::Connect( const std::string &uri, const sptr &connect, const sptr &callerToken) { AAFwk::Want want; - want.SetUri(uri); + auto [success, userId] = DataShareURIUtils::GetUserFromUri(uri); + if (!success) { + return E_INVALID_USER_ID; + } + want.SetUri(DataShareURIUtils::FormatUri(uri)); std::lock_guard lock(mutex_); if (ConnectSA()) { LOG_INFO("connect start, uri = %{public}s", DataShareStringUtils::Change(uri).c_str()); - return proxy_->ConnectAbilityCommon(want, connect, callerToken, AppExecFwk::ExtensionAbilityType::DATASHARE); + return proxy_->ConnectAbilityCommon(want, connect, callerToken, AppExecFwk::ExtensionAbilityType::DATASHARE, + userId); } return -1; } diff --git a/data_share/frameworks/native/proxy/src/data_share_manager_impl.cpp b/data_share/frameworks/native/proxy/src/data_share_manager_impl.cpp index df392164097bf685a14fbfd883d79e0ad8514721..1cb704af6532ebf4fc21916909b64df38699d64f 100644 --- a/data_share/frameworks/native/proxy/src/data_share_manager_impl.cpp +++ b/data_share/frameworks/native/proxy/src/data_share_manager_impl.cpp @@ -93,9 +93,6 @@ sptr DataShareManagerImpl::GetDataShareServiceProxy() } if (dataMgrService_ == nullptr) { LOG_ERROR("Get distributed data manager failed!"); - RADAR_REPORT(__FUNCTION__, RadarReporter::CREATE_DATASHARE_HELPER, - RadarReporter::DISTRIBUTEDDATA_START, RadarReporter::FAILED, - RadarReporter::ERROR_CODE, RadarReporter::DISTRIBUTEDDATA_NOT_START); return nullptr; } auto remote = dataMgrService_->GetFeatureInterface("data_share"); diff --git a/data_share/frameworks/native/proxy/src/data_share_service_proxy.cpp b/data_share/frameworks/native/proxy/src/data_share_service_proxy.cpp index eec0efbcba9a1c44918fb8bb5690dd5510c39ebb..15f5950cf756706a9e3df91cae88ce3d83f37236 100644 --- a/data_share/frameworks/native/proxy/src/data_share_service_proxy.cpp +++ b/data_share/frameworks/native/proxy/src/data_share_service_proxy.cpp @@ -200,10 +200,16 @@ int DataShareServiceProxy::AddQueryTemplate(const std::string &uri, int64_t subs LOG_ERROR("Write descriptor failed!"); return DATA_SHARE_ERROR; } - std::string updateSqlPrefix = "update"; - if (!tpl.update_.empty() && tpl.update_.compare(0, updateSqlPrefix.size(), updateSqlPrefix) != 0) { - LOG_ERROR("Parameter update only support update SQL"); - return DATA_SHARE_ERROR; + if (!tpl.update_.empty()) { + std::string updateSqlPrefix = "UPDATE"; + std::string checkPrefix = tpl.update_.substr(0, updateSqlPrefix.size()); + std::for_each(std::begin(checkPrefix), std::end(checkPrefix), [](auto &c) { + c = std::toupper(c); + }); + if (checkPrefix != updateSqlPrefix) { + LOG_ERROR("Parameter update only support update SQL, Parameter: %{public}s", checkPrefix.c_str()); + return DATA_SHARE_ERROR; + } } if (!ITypesUtil::Marshal(data, uri, subscriberId, tpl.update_, tpl.predicates_, tpl.scheduler_)) { LOG_ERROR("Write to message parcel failed!"); diff --git a/data_share/frameworks/native/proxy/src/published_data_subscriber_manager.cpp b/data_share/frameworks/native/proxy/src/published_data_subscriber_manager.cpp index 8314395271e46d6f10e36e793fa13ffaf357d1a4..80ee18c4aec7c52d0f56a1e088a47988956da56b 100644 --- a/data_share/frameworks/native/proxy/src/published_data_subscriber_manager.cpp +++ b/data_share/frameworks/native/proxy/src/published_data_subscriber_manager.cpp @@ -50,7 +50,6 @@ std::vector PublishedDataSubscriberManager::AddObservers(void * return; } - Init(); auto subResults = proxy->SubscribePublishedData(firstAddUris, subscriberId, serviceCallback_); std::vector failedKeys; for (auto &subResult : subResults) { @@ -63,7 +62,6 @@ std::vector PublishedDataSubscriberManager::AddObservers(void * if (failedKeys.size() > 0) { BaseCallbacks::DelObservers(failedKeys, subscriber); } - Destroy(); }); } @@ -86,7 +84,6 @@ std::vector PublishedDataSubscriberManager::DelObservers(void * auto results = proxy->UnSubscribePublishedData(uris, subscriberId); opResult.insert(opResult.end(), results.begin(), results.end()); } - Destroy(); }); } @@ -117,7 +114,6 @@ std::vector PublishedDataSubscriberManager::DelObservers(void * } auto unsubResult = proxy->UnSubscribePublishedData(lastDelUris, subscriberId); opResult.insert(opResult.end(), unsubResult.begin(), unsubResult.end()); - Destroy(); }); } @@ -287,28 +283,6 @@ void PublishedDataSubscriberManager::EmitOnEnable(std::mapClearCallback(); - } - LOG_INFO("no valid subscriber, delete callback"); - serviceCallback_ = nullptr; - } -} - PublishedDataSubscriberManager &PublishedDataSubscriberManager::GetInstance() { static PublishedDataSubscriberManager manager; @@ -317,7 +291,9 @@ PublishedDataSubscriberManager &PublishedDataSubscriberManager::GetInstance() PublishedDataSubscriberManager::PublishedDataSubscriberManager() { - serviceCallback_ = nullptr; + serviceCallback_ = new PublishedDataObserverStub([this](PublishedDataChangeNode &changeNode) { + Emit(changeNode); + }); } PublishedDataObserver::PublishedDataObserver(const PublishedDataCallback &callback) : callback_(callback) {} diff --git a/data_share/frameworks/native/proxy/src/rdb_subscriber_manager.cpp b/data_share/frameworks/native/proxy/src/rdb_subscriber_manager.cpp index 4c7ed30c891409c5e03627ff8b8922c05ba2e576..7c079890c2c2a25578cc68c12c8ee18a64f0da69 100644 --- a/data_share/frameworks/native/proxy/src/rdb_subscriber_manager.cpp +++ b/data_share/frameworks/native/proxy/src/rdb_subscriber_manager.cpp @@ -31,7 +31,9 @@ RdbSubscriberManager &RdbSubscriberManager::GetInstance() RdbSubscriberManager::RdbSubscriberManager() { - serviceCallback_ = nullptr; + serviceCallback_ = new RdbObserverStub([this](const RdbChangeNode &changeNode) { + Emit(changeNode); + }); } std::vector RdbSubscriberManager::AddObservers(void *subscriber, @@ -61,7 +63,6 @@ std::vector RdbSubscriberManager::AddObservers(void *subscriber return; } - Init(); auto subResults = proxy->SubscribeRdbData(firstAddUris, templateId, serviceCallback_); std::vector failedKeys; for (auto &subResult : subResults) { @@ -74,7 +75,6 @@ std::vector RdbSubscriberManager::AddObservers(void *subscriber if (!failedKeys.empty()) { BaseCallbacks::DelObservers(failedKeys, subscriber); } - Destroy(); }); } @@ -105,7 +105,6 @@ std::vector RdbSubscriberManager::DelObservers(void *subscriber } auto unsubResult = proxy->UnSubscribeRdbData(lastDelUris, templateId); opResult.insert(opResult.end(), unsubResult.begin(), unsubResult.end()); - Destroy(); }); } @@ -124,7 +123,6 @@ std::vector RdbSubscriberManager::DelObservers(void *subscriber auto unsubResult = proxy->UnSubscribeRdbData(std::vector(1, key.uri_), key.templateId_); opResult.insert(opResult.end(), unsubResult.begin(), unsubResult.end()); } - Destroy(); }); } @@ -255,28 +253,6 @@ void RdbSubscriberManager::EmitOnEnable(std::mapClearCallback(); - } - LOG_INFO("no valid subscriber, delete callback"); - serviceCallback_ = nullptr; - } -} - RdbObserver::RdbObserver(const RdbCallback &callback) : callback_(callback) {} void RdbObserver::OnChange(const RdbChangeNode &changeNode) diff --git a/data_share/interfaces/inner_api/BUILD.gn b/data_share/interfaces/inner_api/BUILD.gn index bb9b3dcef9173b1d4aa74ab49d956fa12cb62b3e..7452123b0f222ca23501f917c040ed860cf3f026 100644 --- a/data_share/interfaces/inner_api/BUILD.gn +++ b/data_share/interfaces/inner_api/BUILD.gn @@ -50,6 +50,7 @@ config("datashare_public_config") { datashare_consumer_sources = [ "${datashare_common_native_path}/src/call_reporter.cpp", "${datashare_common_native_path}/src/datashare_string_utils.cpp", + "${datashare_common_native_path}/src/datashare_uri_utils.cpp", "${datashare_native_consumer_path}/controller/provider/src/ext_special_controller.cpp", "${datashare_native_consumer_path}/controller/provider/src/general_controller_provider_impl.cpp", "${datashare_native_consumer_path}/controller/service/src/general_controller_service_impl.cpp", @@ -259,6 +260,8 @@ ohos_shared_library("datashare_ext_ability_module") { "c_utils:utils", "common_event_service:cesfwk_innerkits", "hilog:libhilog", + "ipc:ipc_napi", + "ipc:ipc_single", "napi:ace_napi", ] diff --git a/data_share/interfaces/inner_api/common/include/datashare_errno.h b/data_share/interfaces/inner_api/common/include/datashare_errno.h index 0b175bcb93c16ba4e2998f910366e436eeb4b4d1..9703c73dcc59be3a869aa0a5ca396776402c86d4 100644 --- a/data_share/interfaces/inner_api/common/include/datashare_errno.h +++ b/data_share/interfaces/inner_api/common/include/datashare_errno.h @@ -158,6 +158,36 @@ constexpr int E_RESULTSET_BUSY = (E_BASE + 61); * @brief The error code for invalid appIndex error. */ constexpr int E_APPINDEX_INVALID = (E_BASE + 62); + +/** +* @brief The error code for nullptr observer. +*/ +constexpr int E_NULL_OBSERVER = (E_BASE + 63); + +/** +* @brief The error code for reusing helper instance released before. +*/ +constexpr int E_HELPER_DIED = (E_BASE + 64); + +/** +* @brief The error code for failure to get dataobs client. +*/ +constexpr int E_DATA_OBS_NOT_READY = (E_BASE + 65); + +/** +* @brief The error code for failure to connect the provider. +*/ +constexpr int E_PROVIDER_NOT_CONNECTED = (E_BASE + 66); + +/** +* @brief The error code for failure to null connection. +*/ +constexpr int E_PROVIDER_CONN_NULL = (E_BASE + 67); + +/** +* @brief The error code for passing invalid form of user id. +*/ +constexpr int E_INVALID_USER_ID = (E_BASE + 68); } // namespace DataShare } // namespace OHOS diff --git a/data_share/interfaces/inner_api/common/include/datashare_predicates.h b/data_share/interfaces/inner_api/common/include/datashare_predicates.h index 8426bcfc673120346d6835a79a7ce7b65b2d031f..69350d5d69a43f87ba4814a21c2381754692e68b 100644 --- a/data_share/interfaces/inner_api/common/include/datashare_predicates.h +++ b/data_share/interfaces/inner_api/common/include/datashare_predicates.h @@ -457,6 +457,21 @@ public: return operations_; } + /** + * @brief Used in the deserialization function to assign values to operations, + * Directly assignsing values to operations with Different usage from private methods. + * reference to the SetWhereClause, SetWhereArgs, SetOrder. + */ + int SetOperationList(std::vector operations) + { + if ((settingMode_ != PREDICATES_METHOD) && (!operations.empty())) { + this->operations_ = operations; + settingMode_ = QUERY_LANGUAGE; + return E_OK; + } + return E_ERROR; + } + /** * @brief The GetWhereClause of the predicate. */ diff --git a/data_share/interfaces/inner_api/common/include/datashare_predicates_object.h b/data_share/interfaces/inner_api/common/include/datashare_predicates_object.h index 15fdbf857d3780764b14e4e53545355c5d71350f..b12bc9d3f28a4b52653f996d6df8f8a70799f074 100644 --- a/data_share/interfaces/inner_api/common/include/datashare_predicates_object.h +++ b/data_share/interfaces/inner_api/common/include/datashare_predicates_object.h @@ -52,9 +52,9 @@ class SingleValue { public: /** - * @brief Use Type replace variant namespace. + * @brief Use Type replace variant namespace. The index order must be consistent with the enum. */ - using Type = std::variant; + using Type = std::variant; Type value; /** diff --git a/data_share/interfaces/inner_api/common/include/datashare_predicates_objects.h b/data_share/interfaces/inner_api/common/include/datashare_predicates_objects.h index 4335157d5557c6d58dad612a4eb76f1bd1cb1f39..6ea1815c1769731da654d34f312f7716f779ff86 100644 --- a/data_share/interfaces/inner_api/common/include/datashare_predicates_objects.h +++ b/data_share/interfaces/inner_api/common/include/datashare_predicates_objects.h @@ -46,10 +46,10 @@ class MutliValue { public: /** - * @brief Use Type replace variant namespace. + * @brief Use Type replace variant namespace. The index order must be consistent with the enum. */ using Type = std::variant, std::vector, - std::vector, std::vector>; + std::vector, std::vector>; Type value; /** diff --git a/data_share/interfaces/inner_api/common/include/datashare_template.h b/data_share/interfaces/inner_api/common/include/datashare_template.h index 6f2a1fbdbf2a219d699b6ab34f1915fbf93e75b9..5706cbd41d0ce41e03a8b10d453a0adb15d58d73 100644 --- a/data_share/interfaces/inner_api/common/include/datashare_template.h +++ b/data_share/interfaces/inner_api/common/include/datashare_template.h @@ -35,6 +35,10 @@ constexpr int32_t DATA_SIZE_ASHMEM_TRANSFER_LIMIT = (10 << 10) << 10; * Specifies the name of the shared memory that RdbChangeNode will transfer. */ constexpr const char* ASHMEM_NAME = "DataShareRdbChangeNode"; +/** + * Specifies the default wait time for connecting extension + */ +static constexpr int DEFAULT_WAITTIME = 2; /** * Specifies the predicates structure of the template. @@ -101,6 +105,8 @@ struct CreateOptions { sptr token_; /** Specifies whether use options to create DataShareHelper. */ bool enabled_ = false; + /** Specifies the time to wait for connecting extension. */ + int waitTime_ = DEFAULT_WAITTIME; }; struct AshmemNode { diff --git a/data_share/interfaces/inner_api/consumer/include/datashare_helper.h b/data_share/interfaces/inner_api/consumer/include/datashare_helper.h index c2450aa2baf6882b33ced33d6f81b64a61bfdba1..4a26bbe71cc0fd3358dbb261451d1d85362bbbbb 100644 --- a/data_share/interfaces/inner_api/consumer/include/datashare_helper.h +++ b/data_share/interfaces/inner_api/consumer/include/datashare_helper.h @@ -242,16 +242,22 @@ public: * * @param uri, Indicates the path of the data to operate. * @param dataObserver, Indicates the IDataAbilityObserver object. + * + * @return Returns the result. Error codes are listed in DataShare datashare_errno.h and + * DataObs dataobs_mgr_errors.h. */ - virtual void RegisterObserver(const Uri &uri, const sptr &dataObserver) = 0; + virtual int RegisterObserver(const Uri &uri, const sptr &dataObserver) = 0; /** * @brief Deregisters an observer used for DataObsMgr specified by the given Uri. * * @param uri, Indicates the path of the data to operate. * @param dataObserver, Indicates the IDataAbilityObserver object. + * + * @return Returns the result. Error codes are listed in DataShare datashare_errno.h and + * DataObs dataobs_mgr_errors.h. */ - virtual void UnregisterObserver(const Uri &uri, const sptr &dataObserver) = 0; + virtual int UnregisterObserver(const Uri &uri, const sptr &dataObserver) = 0; /** * @brief Notifies the registered observers of a change to the data resource specified by Uri. @@ -456,6 +462,19 @@ public: */ virtual std::pair DeleteEx(Uri &uri, const DataSharePredicates &predicates); + /** + * @brief UserDefineFunc supports user-defined serialization of data and deserialization of reply. + * It directly passes IPC parameters without any processing. + * Through this interface, users can implement their own business logic. + * + * @param data Data sent from the consumer to the provider + * @param reply Data returned from the provider to the consumer, including errCode + * @param option The options of IPC call + * + * @return Returns int32_t, the errCode of IPC call. + */ + virtual int32_t UserDefineFunc(MessageParcel &data, MessageParcel &reply, MessageOption &option); + private: static std::shared_ptr CreateServiceHelper(const std::string &extUri = "", const std::string &bundleName = ""); diff --git a/data_share/test/js/data_share/unittest/config.json b/data_share/test/js/data_share/unittest/config.json index 865615d255b08fd479e18891941ef167326e4561..6e089ad3f58a0ddcec9313a18977c8ad5e45a511 100644 --- a/data_share/test/js/data_share/unittest/config.json +++ b/data_share/test/js/data_share/unittest/config.json @@ -19,7 +19,8 @@ "tablet", "2in1", "default", - "phone" + "phone", + "wearable" ], "distro": { "deliveryWithInstall": true, diff --git a/data_share/test/native/BUILD.gn b/data_share/test/native/BUILD.gn index c578b827d53a545f43f75121fb7dd9d1486368cf..d0f24cd319bdb3997ee831be3508a4d463b432f9 100644 --- a/data_share/test/native/BUILD.gn +++ b/data_share/test/native/BUILD.gn @@ -21,13 +21,16 @@ group("unittest") { deps += [ ":AbnormalBranchTest", ":ControllerTest", + ":DataShareHelperImplTest", ":ErrorCodeTest", ":JoinTest", ":NativeDataShareTest", ":PermissionTest", ":ProxyDatasTest", + ":SharedBlockTest", ":SlientAccessTest", ":SlientSwitchTest", + ":URIUtilsTest", ":ValueProxyTest", "resource/datashare_ext_bundle:datashare_ext", "resource/datashareproxy_bundle/proxydatas_with_permission:proxydatas_with_permission", @@ -376,6 +379,7 @@ ohos_unittest("AbnormalBranchTest") { "${foundation_path}/communication/ipc/interfaces/innerkits/ipc_core/include", "//foundation/distributeddatamgr/data_share/frameworks/native/proxy/include/", "//foundation/distributeddatamgr/data_share/frameworks/native/common/include/", + "${datashare_native_proxy_path}/include", ] sources = [ "./unittest/mediadatashare_test/src/abnormal_branch_test.cpp" ] @@ -391,6 +395,7 @@ ohos_unittest("AbnormalBranchTest") { "ability_runtime:ability_manager", "ability_runtime:abilitykit_native", "ability_runtime:dataobs_manager", + "ability_runtime:extension_manager", "access_token:libaccesstoken_sdk", "access_token:libnativetoken", "access_token:libtoken_setproc", @@ -403,6 +408,12 @@ ohos_unittest("AbnormalBranchTest") { "safwk:system_ability_fwk", "samgr:samgr_proxy", ] + + cflags = [ + "-fvisibility=hidden", + "-Dprivate=public", + "-Dprotected=public", + ] } ohos_unittest("ValueProxyTest") { @@ -422,3 +433,118 @@ ohos_unittest("ValueProxyTest") { "kv_store:distributeddata_inner", ] } + +ohos_unittest("URIUtilsTest") { + module_out_path = "data_share/native_datashare" + + include_dirs = [ "${datashare_base_path}/frameworks/native/common/include/" ] + + sources = [ "./unittest/mediadatashare_test/src/uri_utils_test.cpp" ] + + deps = [ + "${datashare_innerapi_path}:datashare_consumer_static", + "${datashare_innerapi_path}/common:datashare_common_static", + ] + + external_deps = [ + "ability_base:zuri", + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_single", + "kv_store:distributeddata_inner", + ] +} + +ohos_unittest("DataShareHelperImplTest") { + module_out_path = "data_share/native_datashare" + + include_dirs = [ + "${datashare_native_consumer_path}/include", + "${datashare_common_native_path}/include", + "${datashare_innerapi_path}/consumer/include", + "${datashare_innerapi_path}/common/include", + "${datashare_innerapi_path}/provider/include", + "${datashare_native_consumer_path}/controller/provider/include", + "${datashare_native_consumer_path}/controller/common", + "${datashare_native_consumer_path}/controller/service/include", + "${datashare_native_proxy_path}/include", + ] + + sources = [ + "${datashare_common_native_path}/src/call_reporter.cpp", + "${datashare_common_native_path}/src/datashare_abs_result_set.cpp", + "${datashare_common_native_path}/src/datashare_itypes_utils.cpp", + "${datashare_common_native_path}/src/datashare_result_set.cpp", + "${datashare_common_native_path}/src/datashare_string_utils.cpp", + "${datashare_common_native_path}/src/datashare_template.cpp", + "${datashare_common_native_path}/src/datashare_uri_utils.cpp", + "${datashare_common_native_path}/src/ikvstore_data_service.cpp", + "${datashare_common_native_path}/src/ishared_result_set.cpp", + "${datashare_common_native_path}/src/ishared_result_set_proxy.cpp", + "${datashare_native_consumer_path}/controller/provider/src/ext_special_controller.cpp", + "${datashare_native_consumer_path}/controller/service/src/general_controller_service_impl.cpp", + "${datashare_native_consumer_path}/controller/service/src/persistent_data_controller.cpp", + "${datashare_native_consumer_path}/controller/service/src/published_data_controller.cpp", + "${datashare_native_consumer_path}/src/datashare_connection.cpp", + "${datashare_native_consumer_path}/src/datashare_helper.cpp", + "${datashare_native_consumer_path}/src/datashare_helper_impl.cpp", + "${datashare_native_consumer_path}/src/datashare_proxy.cpp", + "${datashare_native_proxy_path}/src/ams_mgr_proxy.cpp", + "${datashare_native_proxy_path}/src/data_proxy_observer_stub.cpp", + "${datashare_native_proxy_path}/src/data_share_manager_impl.cpp", + "${datashare_native_proxy_path}/src/data_share_service_proxy.cpp", + "${datashare_native_proxy_path}/src/idata_share_client_death_observer.cpp", + "${datashare_native_proxy_path}/src/published_data_subscriber_manager.cpp", + "${datashare_native_proxy_path}/src/rdb_subscriber_manager.cpp", + "./unittest/mediadatashare_test/src/datashare_helper_impl_test.cpp", + ] + + external_deps = [ + "ability_base:want", + "ability_base:zuri", + "ability_runtime:ability_manager", + "ability_runtime:app_context", + "ability_runtime:dataobs_manager", + "ability_runtime:extension_manager", + "c_utils:utils", + "common_event_service:cesfwk_innerkits", + "googletest:gmock_main", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", + "ipc:ipc_single", + "ipc:rpc", + "samgr:samgr_proxy", + ] + + public_external_deps = [ "kv_store:distributeddata_inner" ] + + cflags = [ + "-fvisibility=hidden", + "-Dprivate=public", + "-Dprotected=public", + ] +} + +ohos_unittest("SharedBlockTest") { + module_out_path = "data_share/native_datashare" + + include_dirs = [ "${datashare_common_native_path}/include" ] + + sources = [ "./unittest/mediadatashare_test/src/shared_block_test.cpp" ] + + deps = [ "${datashare_innerapi_path}/common:datashare_common_static" ] + + external_deps = [ + "c_utils:utils", + "googletest:gmock_main", + "hilog:libhilog", + ] + + cflags = [ + "-fvisibility=hidden", + "-Dprivate=public", + "-Dprotected=public", + ] +} diff --git a/data_share/test/native/resource/datashare_ext_bundle/entry/src/main/module.json b/data_share/test/native/resource/datashare_ext_bundle/entry/src/main/module.json index 65a338ea1e9a85273069d9d61d145f6e6084bcde..cbaf5d9d6fc129cb1d4dc54b4ec1350f662d4fbc 100644 --- a/data_share/test/native/resource/datashare_ext_bundle/entry/src/main/module.json +++ b/data_share/test/native/resource/datashare_ext_bundle/entry/src/main/module.json @@ -7,7 +7,8 @@ "mainElement": "MainAbility", "deviceTypes": [ "default", - "tablet" + "tablet", + "wearable" ], "deliveryWithInstall": true, "installationFree": false, diff --git a/data_share/test/native/resource/datashareproxy_bundle/proxydatas_with_permission/entry/src/main/module.json b/data_share/test/native/resource/datashareproxy_bundle/proxydatas_with_permission/entry/src/main/module.json index 06919a470c69656f9c3f99256c6aa2e569e4a62e..dd11522e3908fedeb26f77a5e76cde6e3743bf08 100644 --- a/data_share/test/native/resource/datashareproxy_bundle/proxydatas_with_permission/entry/src/main/module.json +++ b/data_share/test/native/resource/datashareproxy_bundle/proxydatas_with_permission/entry/src/main/module.json @@ -7,7 +7,8 @@ "mainElement": "MainAbility", "deviceTypes": [ "default", - "tablet" + "tablet", + "wearable" ], "deliveryWithInstall": true, "installationFree": false, diff --git a/data_share/test/native/resource/errorcode_ext_bundle/entry/src/main/module.json b/data_share/test/native/resource/errorcode_ext_bundle/entry/src/main/module.json index 3f44ca1fd4637b0a422ea6439c227e1f86019a5d..f91e235a3055d0a600c355a3d02f4ba6fb2710dd 100644 --- a/data_share/test/native/resource/errorcode_ext_bundle/entry/src/main/module.json +++ b/data_share/test/native/resource/errorcode_ext_bundle/entry/src/main/module.json @@ -7,7 +7,8 @@ "mainElement": "MainAbility", "deviceTypes": [ "default", - "tablet" + "tablet", + "wearable" ], "deliveryWithInstall": true, "installationFree": false, diff --git a/data_share/test/native/unittest/datashareproxy_test/proxydatas_with_permission_test.cpp b/data_share/test/native/unittest/datashareproxy_test/proxydatas_with_permission_test.cpp index 4ef42d23eef1df47b6228d1d715e3447def57ce4..1a5de881546d380707d18efb2af3c690d81d8c8c 100644 --- a/data_share/test/native/unittest/datashareproxy_test/proxydatas_with_permission_test.cpp +++ b/data_share/test/native/unittest/datashareproxy_test/proxydatas_with_permission_test.cpp @@ -196,6 +196,116 @@ HWTEST_F(ProxyDatasTest, ProxyDatasTest_Template_Test_002, TestSize.Level0) LOG_INFO("ProxyDatasTest_Template_Test_002::End"); } +/** +* @tc.name: ProxyDatasTest_Template_Test_003 +* @tc.desc: test Template update function +* @tc.type: FUNC +* @tc.require: +*/ +HWTEST_F(ProxyDatasTest, ProxyDatasTest_Template_Test_003, TestSize.Level0) +{ + LOG_INFO("ProxyDatasTest_Template_Test_003::Start"); + auto helper = dataShareHelper; + PredicateTemplateNode node1("p1", "select name0 as name from TBL00"); + std::vector nodes; + nodes.emplace_back(node1); + Template tpl(nodes, "select name0 as name from TBL00"); + tpl.update_ = "update TBL00 set name0 = 'updatetest' where name0 = 'name00'"; + auto result = helper->AddQueryTemplate(DATA_SHARE_PROXY_URI, SUBSCRIBER_ID, tpl); + EXPECT_EQ(result, 0); + + std::vector uris; + uris.emplace_back(DATA_SHARE_PROXY_URI); + TemplateId tplId; + tplId.subscriberId_ = SUBSCRIBER_ID; + tplId.bundleName_ = "ohos.datashareproxyclienttest.demo"; + std::string data1; + std::vector results1 = + helper->SubscribeRdbData(uris, tplId, [&data1](const RdbChangeNode &changeNode) { + data1 = changeNode.data_[0]; + }); + for (auto const &operationResult : results1) { + EXPECT_EQ(operationResult.errCode_, 0); + } + + Uri uri(DATA_SHARE_PROXY_URI); + DataShare::DataShareValuesBucket valuesBucket; + std::string name0 = "name00"; + valuesBucket.Put(TBL_NAME0, name0); + int retVal = helper->Insert(uri, valuesBucket); + EXPECT_GT(retVal, 0); + + DataShare::DataSharePredicates predicates; + predicates.EqualTo(TBL_NAME0, "updatetest"); + std::vector columns; + auto resultSet = helper->Query(uri, predicates, columns); + EXPECT_NE(resultSet, nullptr); + int queryResult = 0; + resultSet->GetRowCount(queryResult); + EXPECT_EQ(queryResult, 1); + + std::vector results2 = helper->UnsubscribeRdbData(uris, tplId); + EXPECT_EQ(results2.size(), uris.size()); + for (auto const &operationResult : results2) { + EXPECT_EQ(operationResult.errCode_, 0); + } + LOG_INFO("ProxyDatasTest_Template_Test_003::End"); +} + +/** +* @tc.name: ProxyDatasTest_Template_Test_004 +* @tc.desc: test add template with parameter update function +* @tc.type: FUNC +* @tc.require: +*/ +HWTEST_F(ProxyDatasTest, ProxyDatasTest_Template_Test_004, TestSize.Level0) +{ + LOG_INFO("ProxyDatasTest_Template_Test_004::Start"); + auto helper = dataShareHelper; + PredicateTemplateNode node1("p1", "select name0 as name from TBL00"); + PredicateTemplateNode node2("p2", "select name1 as name from TBL00"); + std::vector nodes; + nodes.emplace_back(node1); + nodes.emplace_back(node2); + Template tpl(nodes, "select name1 as name from TBL00"); + + auto result = helper->AddQueryTemplate(DATA_SHARE_PROXY_URI, SUBSCRIBER_ID, tpl); + EXPECT_EQ(result, 0); + result = helper->DelQueryTemplate(DATA_SHARE_PROXY_URI, SUBSCRIBER_ID); + EXPECT_EQ(result, 0); + + Template tpl2("update TBL00 set name0 = 'update'", nodes, "select name1 as name from TBL00"); + result = helper->AddQueryTemplate(DATA_SHARE_PROXY_URI, SUBSCRIBER_ID, tpl2); + EXPECT_EQ(result, 0); + result = helper->DelQueryTemplate(DATA_SHARE_PROXY_URI, SUBSCRIBER_ID); + EXPECT_EQ(result, 0); + LOG_INFO("ProxyDatasTest_Template_Test_004::End"); +} + +/** +* @tc.name: ProxyDatasTest_Template_Test_005 +* @tc.desc: test add template with wrong parameter update function +* @tc.type: FUNC +* @tc.require: +*/ +HWTEST_F(ProxyDatasTest, ProxyDatasTest_Template_Test_005, TestSize.Level0) +{ + LOG_INFO("ProxyDatasTest_Template_Test_005::Start"); + auto helper = dataShareHelper; + PredicateTemplateNode node1("p1", "select name0 as name from TBL00"); + PredicateTemplateNode node2("p2", "select name1 as name from TBL00"); + std::vector nodes; + nodes.emplace_back(node1); + nodes.emplace_back(node2); + Template tpl2("insert into TBL00 (name0) values ('test')", nodes, "select name1 as name from TBL00"); + + auto result = helper->AddQueryTemplate(DATA_SHARE_PROXY_URI, SUBSCRIBER_ID, tpl2); + EXPECT_EQ(result, -1); + result = helper->DelQueryTemplate(DATA_SHARE_PROXY_URI, SUBSCRIBER_ID); + EXPECT_EQ(result, 0); + LOG_INFO("ProxyDatasTest_Template_Test_005::End"); +} + HWTEST_F(ProxyDatasTest, ProxyDatasTest_Publish_Test_001, TestSize.Level0) { LOG_INFO("ProxyDatasTest_Publish_Test_001::Start"); diff --git a/datamgr_service/bundle.json b/datamgr_service/bundle.json index b24e8c386e84b89f208f3999b4b1c43d23a5dccb..3283ee04de55d39a283a2f73205c82c6465817f0 100644 --- a/datamgr_service/bundle.json +++ b/datamgr_service/bundle.json @@ -3,7 +3,7 @@ "version": "3.2.0", "description": "Distributed data manager that provides the capability to store data in the databases of different devices", "homePage": "https://gitee.com/openharmony", - "license": "Apache V2", + "license": "Apache-2.0", "repository": "https://gitee.com/openharmony/distributeddatamgr_datamgr_service", "domain": "os", "language": "", @@ -40,7 +40,12 @@ "syscap": [], "features": [ "datamgr_service_config", - "datamgr_service_udmf" + "datamgr_service_udmf", + "datamgr_service_cloud", + "datamgr_service_rdb", + "datamgr_service_kvdb", + "datamgr_service_object", + "datamgr_service_data_share" ], "adapted_system_type": [ "standard" @@ -87,7 +92,9 @@ "file_api", "openssl", "json", - "dmsfwk" + "dmsfwk", + "data_object", + "window_manager" ], "third_party": [ "libuv", @@ -159,6 +166,16 @@ ], "header_base": "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/framework/include" } + }, + { + "name": "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/dfx:distributeddata_dfx_fault_static", + "header": { + "header_files": [ + "dfx_types.h", + "reporter.h" + ], + "header_base": "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/include/dfx" + } } ], "test": [ diff --git a/datamgr_service/conf/config.json b/datamgr_service/conf/config.json index d369e370784e84e9f253fd25f8f6534b8da9ee72..7790030db65da35b8e4fd151507b64838700b601 100644 --- a/datamgr_service/conf/config.json +++ b/datamgr_service/conf/config.json @@ -16,12 +16,6 @@ }, { "lib": "libopencloudextension.z.so" - }, - { - "lib": "libudmf_server.z.so" - }, - { - "lib": "libdata_share_service.z.so" } ], "bundleChecker": { diff --git a/datamgr_service/datamgr_service.gni b/datamgr_service/datamgr_service.gni index 64b9838f03462c07ce69c21e7083063328cd039b..da3e7a494d5e4474f2f5e30387cab6d3a8465cfd 100644 --- a/datamgr_service/datamgr_service.gni +++ b/datamgr_service/datamgr_service.gni @@ -55,4 +55,14 @@ declare_args() { datamgr_service_config = true datamgr_service_udmf = false + + datamgr_service_cloud = true + + datamgr_service_rdb = true + + datamgr_service_kvdb = true + + datamgr_service_object = true + + datamgr_service_data_share = true } diff --git a/datamgr_service/hisysevent.yaml b/datamgr_service/hisysevent.yaml index daba8439e4ebde010512cf18fda59d089653d055..2c894f5631c4f6ba559d5e4994de2f47fbc633c6 100644 --- a/datamgr_service/hisysevent.yaml +++ b/datamgr_service/hisysevent.yaml @@ -113,4 +113,15 @@ OPEN_DATABASE_FAILED: __BASE: {type: FAULT, level: CRITICAL, desc: The database open failed} APP_ID: {type: STRING, desc: app id } STORE_ID: {type: STRING, desc: store id } - ERROR_CODE: {type: STRING, desc: error code} \ No newline at end of file + ERROR_CODE: {type: STRING, desc: error code} + +ARKDATA_CLOUD_SYNC_FAULT: + __BASE: {type: FAULT, level: CRITICAL, desc: The event is cloud sync fault} + FAULT_TIME: {type: INT64, desc: time of fault happened } + FAULT_TYPE: {type: STRING, desc: type of cloud sync fault } + BUNDLE_NAME: {type: STRING, desc: bundle name } + MODULE_NAME: {type: STRING, desc: module name } + STORE_NAME: {type: STRING, desc: store name } + BUSINESS_TYPE: {type: STRING, desc: business type } + ERROR_CODE: {type: INT32, desc: error code } + APPENDIX: {type: STRING, desc: such as uid/tokenid } \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/adapter/account/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/account/BUILD.gn index 2bc40d6e4c1560edd1bd02d6e24868b246ae9bdb..85697b11bb8a77ac94f247ab311261b84b487ac6 100644 --- a/datamgr_service/services/distributeddataservice/adapter/account/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/account/BUILD.gn @@ -13,7 +13,7 @@ import("//build/ohos.gni") import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") -ohos_static_library("distributeddata_account_static") { +ohos_source_set("distributeddata_account") { branch_protector_ret = "pac_ret" sanitize = { cfi = true @@ -31,9 +31,8 @@ ohos_static_library("distributeddata_account_static") { "../include/permission", "../include/utils", "./src", - "${kv_store_common_path}", - "${kv_store_path}/interfaces/innerkits/distributeddata/include", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/framework/include", + "${data_service_path}/framework/include", + "${data_service_path}/framework/include/account", ] cflags_cc = [ "-fvisibility=hidden" ] @@ -47,6 +46,7 @@ ohos_static_library("distributeddata_account_static") { "c_utils:utils", "common_event_service:cesfwk_innerkits", "hilog:libhilog", + "kv_store:datamgr_common", ] if (os_account_part_is_enabled) { diff --git a/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_default_impl.cpp b/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_default_impl.cpp index 444d7b29986cdc7e7d99098cdd69d7464038aa6b..ddcb50026b7bc5fef52c51d1c9bf480feaf72d3a 100644 --- a/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_default_impl.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_default_impl.cpp @@ -15,12 +15,13 @@ #define LOG_TAG "AccountDelegateDefaultImpl" #include "account_delegate_default_impl.h" + #include "log_print.h" namespace OHOS { -namespace DistributedKv { +namespace DistributedData { namespace { - constexpr const char *DEFAULT_OHOS_ACCOUNT_UID = ""; // default UID +constexpr const char *DEFAULT_OHOS_ACCOUNT_UID = ""; // default UID } __attribute__((used)) static bool g_isInit = AccountDelegateDefaultImpl::Init(); @@ -62,6 +63,12 @@ bool AccountDelegateDefaultImpl::IsVerified(int userId) return true; } +bool AccountDelegateDefaultImpl::IsDeactivating(int userId) +{ + ZLOGD("no account part."); + return false; +} + void AccountDelegateDefaultImpl::SubscribeAccountEvent() { ZLOGD("no account part."); @@ -89,5 +96,5 @@ bool AccountDelegateDefaultImpl::Init() std::call_once(onceFlag, [&]() { AccountDelegate::RegisterAccountInstance(&defaultAccountDelegate); }); return true; } -} // namespace DistributedKv -} // namespace OHOS \ No newline at end of file +} // namespace DistributedData +} // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_default_impl.h b/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_default_impl.h index 04ebda1d6e45fd6e1de5073019b2fad5c0bde08b..6d2b5408e9da85e16ec2ef80b6f71b9913f9ec4b 100644 --- a/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_default_impl.h +++ b/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_default_impl.h @@ -18,7 +18,7 @@ #include "account_delegate_impl.h" namespace OHOS { -namespace DistributedKv { +namespace DistributedData { class AccountDelegateDefaultImpl final : public AccountDelegateImpl { public: std::string GetCurrentAccountId() const override; @@ -27,6 +27,7 @@ public: bool QueryForegroundUsers(std::vector &users) override; bool IsLoginAccount() override; bool IsVerified(int userId) override; + bool IsDeactivating(int userId) override; void SubscribeAccountEvent() override; void UnsubscribeAccountEvent() override; void BindExecutor(std::shared_ptr executors) override; @@ -35,6 +36,6 @@ public: private: ~AccountDelegateDefaultImpl(); }; -} // namespace DistributedKv -} // namespace OHOS +} // namespace DistributedData +} // namespace OHOS #endif // DISTRIBUTEDDATAMGR_ACCOUNT_DELEGATE_DEFAULT_IMPL_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_impl.cpp b/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_impl.cpp index 9916508a896e446a4bc67785d478dd38dfcb5e24..76509d87174dccc91d348efdaa0ba96e4d14de6e 100644 --- a/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_impl.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_impl.cpp @@ -13,104 +13,76 @@ * limitations under the License. */ -#define LOG_TAG "EVENT_HANDLER" +#define LOG_TAG "AccountDelegateImpl" #include "account_delegate_impl.h" + #include #include +#include "error/general_error.h" + namespace OHOS { -namespace DistributedKv { -using namespace OHOS::EventFwk; -using namespace OHOS::AAFwk; +namespace DistributedData { using namespace OHOS::DistributedData; -EventSubscriber::EventSubscriber(const CommonEventSubscribeInfo &info) : CommonEventSubscriber(info) {} -static inline const std::map STATUS = { - { CommonEventSupport::COMMON_EVENT_USER_REMOVED, AccountStatus::DEVICE_ACCOUNT_DELETE }, - { CommonEventSupport::COMMON_EVENT_USER_SWITCHED, AccountStatus::DEVICE_ACCOUNT_SWITCHED }, - { CommonEventSupport::COMMON_EVENT_USER_UNLOCKED, AccountStatus::DEVICE_ACCOUNT_UNLOCKED }, - { CommonEventSupport::COMMON_EVENT_USER_STOPPING, AccountStatus::DEVICE_ACCOUNT_STOPPING }, - { CommonEventSupport::COMMON_EVENT_USER_STOPPED, AccountStatus::DEVICE_ACCOUNT_STOPPED } }; - -void EventSubscriber::OnReceiveEvent(const CommonEventData &event) -{ - const auto want = event.GetWant(); - AccountEventInfo accountEventInfo{}; - std::string action = want.GetAction(); - ZLOGI("Want Action is %{public}s", action.c_str()); - - auto it = STATUS.find(action); - if (it == STATUS.end()) { - return; - } - accountEventInfo.userId = std::to_string(event.GetCode()); - accountEventInfo.status = it->second; - eventCallback_(accountEventInfo); -} - -void EventSubscriber::SetEventCallback(EventCallback callback) -{ - eventCallback_ = callback; -} - AccountDelegateImpl::~AccountDelegateImpl() { observerMap_.Clear(); } -void AccountDelegateImpl::NotifyAccountChanged(const AccountEventInfo &accountEventInfo) +void AccountDelegateImpl::NotifyAccountChanged(const AccountEventInfo &accountEventInfo, int32_t timeout) { - observerMap_.ForEach([&accountEventInfo] (const auto& key, auto& val) { + observerMap_.ForEach([&accountEventInfo, timeout](const auto &key, auto &val) { if (val->GetLevel() == AccountDelegate::Observer::LevelType::HIGH) { - val->OnAccountChanged(accountEventInfo); + val->OnAccountChanged(accountEventInfo, timeout); } return false; }); - observerMap_.ForEach([&accountEventInfo] (const auto& key, auto& val) { + observerMap_.ForEach([&accountEventInfo, timeout](const auto &key, auto &val) { if (val->GetLevel() == AccountDelegate::Observer::LevelType::LOW) { - val->OnAccountChanged(accountEventInfo); + val->OnAccountChanged(accountEventInfo, timeout); } return false; }); } -Status AccountDelegateImpl::Subscribe(std::shared_ptr observer) +int32_t AccountDelegateImpl::Subscribe(std::shared_ptr observer) { ZLOGD("start"); if (observer == nullptr || observer->Name().empty()) { - return Status::INVALID_ARGUMENT; + return GeneralError::E_INVALID_ARGS; } if (observerMap_.Contains(observer->Name())) { - return Status::INVALID_ARGUMENT; + return GeneralError::E_INVALID_ARGS; } auto ret = observerMap_.Insert(observer->Name(), observer); if (ret) { ZLOGD("end"); - return Status::SUCCESS; + return GeneralError::E_OK; } ZLOGE("fail"); - return Status::ERROR; + return GeneralError::E_ERROR; } -Status AccountDelegateImpl::Unsubscribe(std::shared_ptr observer) +int32_t AccountDelegateImpl::Unsubscribe(std::shared_ptr observer) { ZLOGD("start"); if (observer == nullptr || observer->Name().empty()) { - return Status::INVALID_ARGUMENT; + return GeneralError::E_INVALID_ARGS; } if (!observerMap_.Contains(observer->Name())) { - return Status::INVALID_ARGUMENT; + return GeneralError::E_INVALID_ARGS; } auto ret = observerMap_.Erase(observer->Name()); if (ret) { ZLOGD("end"); - return Status::SUCCESS; + return GeneralError::E_OK; } ZLOGD("fail"); - return Status::ERROR; + return GeneralError::E_ERROR; } bool AccountDelegateImpl::RegisterHashFunc(HashFunc hash) @@ -126,5 +98,5 @@ std::string AccountDelegateImpl::DoHash(const void *data, size_t size, bool isUp } return hash_(data, size, isUpper); } -} // namespace DistributedKv -} // namespace OHOS +} // namespace DistributedData +} // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_impl.h b/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_impl.h index f3f500d3dbf1ce2e6b6583264c92f25464e3d4d5..e8fc5d5c3b1129d34fac04a1199621253cffef0a 100644 --- a/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_impl.h +++ b/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_impl.h @@ -16,44 +16,30 @@ #ifndef DISTRIBUTEDDATAMGR_ACCOUNT_DELEGATE_IMPL_H #define DISTRIBUTEDDATAMGR_ACCOUNT_DELEGATE_IMPL_H -#include "account_delegate.h" -#include #include -#include "common_event_manager.h" -#include "common_event_subscriber.h" -#include "common_event_support.h" +#include + +#include "account_delegate.h" #include "concurrent_map.h" #include "log_print.h" namespace OHOS { -namespace DistributedKv { -using namespace OHOS::EventFwk; -using EventCallback = std::function; - -class EventSubscriber final : public CommonEventSubscriber { -public: - ~EventSubscriber() {} - explicit EventSubscriber(const CommonEventSubscribeInfo &info); - void SetEventCallback(EventCallback callback); - void OnReceiveEvent(const CommonEventData &event) override; -private: - EventCallback eventCallback_ {}; -}; - +namespace DistributedData { class AccountDelegateImpl : public AccountDelegate { public: ~AccountDelegateImpl(); - Status Subscribe(std::shared_ptr observer) override __attribute__((no_sanitize("cfi"))); - Status Unsubscribe(std::shared_ptr observer) override __attribute__((no_sanitize("cfi"))); - void NotifyAccountChanged(const AccountEventInfo &accountEventInfo); + int32_t Subscribe(std::shared_ptr observer) override __attribute__((no_sanitize("cfi"))); + int32_t Unsubscribe(std::shared_ptr observer) override __attribute__((no_sanitize("cfi"))); + void NotifyAccountChanged(const AccountEventInfo &accountEventInfo, int32_t timeout = 0); bool RegisterHashFunc(HashFunc hash) override; protected: std::string DoHash(const void *data, size_t size, bool isUpper) const; + private: - ConcurrentMap> observerMap_ {}; + ConcurrentMap> observerMap_{}; HashFunc hash_ = nullptr; }; -} // namespace DistributedKv -} // namespace OHOS +} // namespace DistributedData +} // namespace OHOS #endif // DISTRIBUTEDDATAMGR_ACCOUNT_DELEGATE_IMPL_H diff --git a/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_normal_impl.cpp b/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_normal_impl.cpp index 3edb00d67883d3d2c401dbcfe3601f9ed75aaf6e..7f6d37e35f252800ad33f2c463d64faa6da0819e 100644 --- a/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_normal_impl.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_normal_impl.cpp @@ -15,24 +15,73 @@ #define LOG_TAG "AccountDelegateNormalImpl" #include "account_delegate_normal_impl.h" + #include #include -#include #include #include #include + #include "accesstoken_kit.h" #include "log_print.h" #include "ohos_account_kits.h" #include "os_account_manager.h" +#include "os_account_subscribe_info.h" namespace OHOS { -namespace DistributedKv { -using namespace OHOS::EventFwk; +namespace DistributedData { using namespace OHOS::AAFwk; using namespace OHOS::DistributedData; using namespace Security::AccessToken; __attribute__((used)) static bool g_isInit = AccountDelegateNormalImpl::Init(); +static constexpr int32_t STOPPING_TIMEOUT = 5; +static inline const std::map STATUS = { + { AccountSA::REMOVED, AccountStatus::DEVICE_ACCOUNT_DELETE }, + { AccountSA::SWITCHED, AccountStatus::DEVICE_ACCOUNT_SWITCHED }, + { AccountSA::UNLOCKED, AccountStatus::DEVICE_ACCOUNT_UNLOCKED }, + { AccountSA::STOPPING, AccountStatus::DEVICE_ACCOUNT_STOPPING }, + { AccountSA::STOPPED, AccountStatus::DEVICE_ACCOUNT_STOPPED } +}; + +AccountSubscriber::AccountSubscriber(const OsAccountSubscribeInfo &info, std::shared_ptr executors) + : OsAccountSubscriber(info), executors_(executors) +{ +} + +void AccountSubscriber::OnStateChanged(const OsAccountStateData &data) +{ + ZLOGI("state change. state:%{public}d, from %{public}d to %{public}d", data.state, data.fromId, data.toId); + + auto it = STATUS.find(data.state); + if (it == STATUS.end()) { + return; + } + AccountEventInfo accountEventInfo; + accountEventInfo.userId = std::to_string(data.toId); + accountEventInfo.status = it->second; + int32_t timeout = accountEventInfo.status == AccountStatus::DEVICE_ACCOUNT_STOPPING ? STOPPING_TIMEOUT : 0; + eventCallback_(accountEventInfo, timeout); + if (data.callback == nullptr) { + return; + } + if (executors_ != nullptr) { + executors_->Execute([callback = data.callback]() { + callback->OnComplete(); + }); + } else { + data.callback->OnComplete(); + } +} + +void AccountSubscriber::SetEventCallback(EventCallback callback) +{ + eventCallback_ = callback; +} + +AccountDelegateNormalImpl::AccountDelegateNormalImpl() +{ + userDeactivating_.InsertOrAssign(0, false); +} std::string AccountDelegateNormalImpl::GetCurrentAccountId() const { @@ -68,7 +117,7 @@ int32_t AccountDelegateNormalImpl::GetUserByToken(uint32_t tokenId) const bool AccountDelegateNormalImpl::QueryUsers(std::vector &users) { - users = {0}; // default user + users = { 0 }; // default user return AccountSA::OsAccountManager::QueryActiveOsAccountIds(users) == 0; } @@ -105,31 +154,32 @@ bool AccountDelegateNormalImpl::IsVerified(int userId) void AccountDelegateNormalImpl::SubscribeAccountEvent() { ZLOGI("Subscribe account event listener start."); - if (eventSubscriber_ == nullptr) { - MatchingSkills matchingSkills; - matchingSkills.AddEvent(CommonEventSupport::COMMON_EVENT_USER_REMOVED); - matchingSkills.AddEvent(CommonEventSupport::COMMON_EVENT_USER_SWITCHED); - matchingSkills.AddEvent(CommonEventSupport::COMMON_EVENT_USER_UNLOCKED); - matchingSkills.AddEvent(CommonEventSupport::COMMON_EVENT_USER_STOPPING); - matchingSkills.AddEvent(CommonEventSupport::COMMON_EVENT_USER_STOPPED); - CommonEventSubscribeInfo info(matchingSkills); - eventSubscriber_ = std::make_shared(info); - eventSubscriber_->SetEventCallback([this](AccountEventInfo& account) { + if (AccountSubscriber_ == nullptr) { + std::set states; + states.insert(AccountSA::REMOVED); + states.insert(AccountSA::SWITCHED); + states.insert(AccountSA::UNLOCKED); + states.insert(AccountSA::STOPPING); + states.insert(AccountSA::STOPPED); + OsAccountSubscribeInfo info(states, true); + AccountSubscriber_ = std::make_shared(info, executors_); + AccountSubscriber_->SetEventCallback([this](AccountEventInfo &account, int32_t timeout) { UpdateUserStatus(account); account.harmonyAccountId = GetCurrentAccountId(); - NotifyAccountChanged(account); + NotifyAccountChanged(account, timeout); }); } executors_->Execute(GetTask(0)); } -void AccountDelegateNormalImpl::UpdateUserStatus(const AccountEventInfo& account) +void AccountDelegateNormalImpl::UpdateUserStatus(const AccountEventInfo &account) { uint32_t status = static_cast(account.status); switch (status) { case static_cast(AccountStatus::DEVICE_ACCOUNT_STOPPING): case static_cast(AccountStatus::DEVICE_ACCOUNT_DELETE): userStatus_.Erase(atoi(account.userId.c_str())); + userDeactivating_.Erase(atoi(account.userId.c_str())); break; case static_cast(AccountStatus::DEVICE_ACCOUNT_UNLOCKED): userStatus_.InsertOrAssign(atoi(account.userId.c_str()), true); @@ -145,7 +195,7 @@ void AccountDelegateNormalImpl::UpdateUserStatus(const AccountEventInfo& account ExecutorPool::Task AccountDelegateNormalImpl::GetTask(uint32_t retry) { return [this, retry] { - auto result = CommonEventManager::SubscribeCommonEvent(eventSubscriber_); + auto result = OsAccountManager::SubscribeOsAccount(AccountSubscriber_); if (result) { ZLOGI("success to register subscriber."); return; @@ -163,7 +213,7 @@ ExecutorPool::Task AccountDelegateNormalImpl::GetTask(uint32_t retry) AccountDelegateNormalImpl::~AccountDelegateNormalImpl() { ZLOGD("destruct"); - auto res = CommonEventManager::UnSubscribeCommonEvent(eventSubscriber_); + auto res = OsAccountManager::UnsubscribeOsAccount(AccountSubscriber_); if (!res) { ZLOGW("unregister account event fail res:%d", res); } @@ -171,7 +221,7 @@ AccountDelegateNormalImpl::~AccountDelegateNormalImpl() void AccountDelegateNormalImpl::UnsubscribeAccountEvent() { - auto res = CommonEventManager::UnSubscribeCommonEvent(eventSubscriber_); + auto res = OsAccountManager::UnsubscribeOsAccount(AccountSubscriber_); if (!res) { ZLOGW("unregister account event fail res:%d", res); } @@ -229,8 +279,25 @@ bool AccountDelegateNormalImpl::Init() { static AccountDelegateNormalImpl normalAccountDelegate; static std::once_flag onceFlag; - std::call_once(onceFlag, [&]() { AccountDelegate::RegisterAccountInstance(&normalAccountDelegate); }); + std::call_once(onceFlag, [&]() { + AccountDelegate::RegisterAccountInstance(&normalAccountDelegate); + }); return true; } -} // namespace DistributedKv -} // namespace OHOS \ No newline at end of file + +bool AccountDelegateNormalImpl::IsDeactivating(int userId) +{ + auto [success, res] = userDeactivating_.Find(userId); + if (success && !res) { + return res; + } + auto status = AccountSA::OsAccountManager::IsOsAccountDeactivating(userId, res); + if (status != 0) { + ZLOGE("IsOsAccountDeactivating failed: %{public}d, user:%{public}d", status, userId); + return true; + } + userDeactivating_.InsertOrAssign(userId, res); + return res; +} +} // namespace DistributedData +} // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_normal_impl.h b/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_normal_impl.h index 63c86d66243187fbc4e176f30baf4204194033e7..1fe64a145668f1fb8f125c1628a5b34bfd20d732 100644 --- a/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_normal_impl.h +++ b/datamgr_service/services/distributeddataservice/adapter/account/src/account_delegate_normal_impl.h @@ -16,22 +16,34 @@ #define DISTRIBUTEDDATAMGR_ACCOUNT_DELEGATE_NORMAL_IMPL_H #include "account_delegate_impl.h" -#include "common_event_manager.h" -#include "common_event_subscriber.h" -#include "common_event_support.h" #include "executor_pool.h" #include "log_print.h" +#include "os_account_subscriber.h" namespace OHOS { -namespace DistributedKv { +namespace DistributedData { +using namespace AccountSA; +using EventCallback = std::function; +class AccountSubscriber final : public OsAccountSubscriber { +public: + ~AccountSubscriber() {} + explicit AccountSubscriber(const OsAccountSubscribeInfo &subscribeInfo, std::shared_ptr executors); + void SetEventCallback(EventCallback callback); + void OnStateChanged(const OsAccountStateData &data) override; +private: + EventCallback eventCallback_{}; + std::shared_ptr executors_ = nullptr; +}; class AccountDelegateNormalImpl final : public AccountDelegateImpl { public: + AccountDelegateNormalImpl(); std::string GetCurrentAccountId() const override; int32_t GetUserByToken(uint32_t tokenId) const override; bool QueryUsers(std::vector &users) override; bool QueryForegroundUsers(std::vector &users) override; bool IsLoginAccount() override; bool IsVerified(int userId) override; + bool IsDeactivating(int userId) override; void SubscribeAccountEvent() override; void UnsubscribeAccountEvent() override; void BindExecutor(std::shared_ptr executors) override; @@ -43,13 +55,14 @@ private: ~AccountDelegateNormalImpl(); std::string Sha256AccountId(const std::string &plainText) const; ExecutorPool::Task GetTask(uint32_t retry); - void UpdateUserStatus(const AccountEventInfo& account); + void UpdateUserStatus(const AccountEventInfo &account); static constexpr int MAX_RETRY_TIME = 300; static constexpr int RETRY_WAIT_TIME_S = 1; - std::shared_ptr eventSubscriber_ {}; + std::shared_ptr AccountSubscriber_{}; std::shared_ptr executors_; - ConcurrentMap userStatus_ {}; + ConcurrentMap userStatus_{}; + ConcurrentMap userDeactivating_{}; }; -} // namespace DistributedKv -} // namespace OHOS +} // namespace DistributedData +} // namespace OHOS #endif // DISTRIBUTEDDATAMGR_ACCOUNT_DELEGATE_NORMAL_IMPL_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/adapter/account/test/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/account/test/BUILD.gn index 3b3df7fe0223d123b0e44b0675d0973c7e385ae6..32ea5f92ee1efda1654bd3c6f24290ffe4deff52 100644 --- a/datamgr_service/services/distributeddataservice/adapter/account/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/account/test/BUILD.gn @@ -23,12 +23,11 @@ ohos_unittest("AccountDelegateTest") { "account_delegate_test.cpp", ] include_dirs = [ - "//commonlibrary/c_utils/base/include", "${data_service_path}/framework/include/account", - "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddata/include", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/include/autils", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/include/utils", - "//foundation/distributeddatamgr/kv_store/frameworks/common", + "${data_service_path}/adapter/include/autils", + "${data_service_path}/adapter/include/utils", + "${data_service_path}/framework/include", + "${data_service_path}/adapter/account/src", ] cflags = [ @@ -36,16 +35,17 @@ ohos_unittest("AccountDelegateTest") { "-Dprotected=public", ] - deps = [ - "../:distributeddata_account_static", - "//third_party/googletest:gtest_main", - ] + deps = [ "../:distributeddata_account" ] external_deps = [ "ability_base:base", "ability_base:want", + "access_token:libaccesstoken_sdk", + "access_token:libnativetoken", + "access_token:libtoken_setproc", "bundle_framework:appexecfwk_base", "c_utils:utils", + "googletest:gtest_main", "hilog:libhilog", "ipc:ipc_core", "kv_store:distributeddata_inner", @@ -54,13 +54,6 @@ ohos_unittest("AccountDelegateTest") { "os_account:libaccountkits", "os_account:os_account_innerkits", ] - if (os_account_part_is_enabled) { - sources += [ "${data_service_path}/adapter/account/src/account_delegate_normal_impl.cpp" ] - cflags_cc = [ "-DOS_ACCOUNT_PART_IS_ENABLED" ] - external_deps += [ "access_token:libaccesstoken_sdk" ] - } else { - sources += [ "${data_service_path}/adapter/account/src/account_delegate_default_impl.cpp" ] - } defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } diff --git a/datamgr_service/services/distributeddataservice/adapter/account/test/account_delegate_test.cpp b/datamgr_service/services/distributeddataservice/adapter/account/test/account_delegate_test.cpp index 21a0c5fc011d74bfc90f342109f040cb75646600..0a2e4caa308a8886ee83a791bd2149df9e388e4f 100644 --- a/datamgr_service/services/distributeddataservice/adapter/account/test/account_delegate_test.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/account/test/account_delegate_test.cpp @@ -16,19 +16,27 @@ #define LOG_TAG "AccountDelegateTest" #include #include +#include "accesstoken_kit.h" #include "account_delegate.h" #include "account_delegate_impl.h" #include "account_delegate_normal_impl.h" +#include "error/general_error.h" #include "ipc_skeleton.h" +#include "log_print.h" +#include "nativetoken_kit.h" #include "ohos_account_kits.h" #include "os_account_manager.h" -#include "log_print.h" +#include "token_setproc.h" + namespace { +using namespace OHOS::DistributedData; using namespace OHOS::DistributedKv; using namespace testing::ext; +using namespace OHOS::Security::AccessToken; + class AccountObserver : public AccountDelegate::Observer { public: - void OnAccountChanged(const AccountEventInfo &info) override + void OnAccountChanged(const AccountEventInfo &info, int32_t timeout) override { } // must specify unique name for observer @@ -50,9 +58,35 @@ private: std::string name_ = "accountTestObserver"; }; +void GrantPermissionNative() +{ + const char *perms[4] = { + "ohos.permission.MANAGE_LOCAL_ACCOUNTS", + "ohos.permission.DISTRIBUTED_DATASYNC", + "ohos.permission.GET_LOCAL_ACCOUNTS", + "ohos.permission.INTERACT_ACROSS_LOCAL_ACCOUNTS" + }; + TokenInfoParams infoInstance = { + .dcapsNum = 0, + .permsNum = 4, + .aclsNum = 0, + .dcaps = nullptr, + .perms = perms, + .acls = nullptr, + .processName = "distributed_data_test", + .aplStr = "system_basic", + }; + uint64_t tokenId = GetAccessTokenId(&infoInstance); + SetSelfTokenID(tokenId); + AccessTokenKit::ReloadNativeTokenInfo(); +} + class AccountDelegateTest : public testing::Test { public: - static void SetUpTestCase(void) {} + static void SetUpTestCase(void) + { + GrantPermissionNative(); + } static void TearDownTestCase(void) {} void SetUp() {} void TearDown() {} @@ -61,12 +95,10 @@ protected: static const std::string DEFAULT_OHOS_ACCOUNT_UID; static const uint32_t INVALID_TOKEN_ID; static const int32_t INVALID_USER; - static const int userId; }; const std::string AccountDelegateTest::DEFAULT_OHOS_ACCOUNT_UID = "ohosAnonymousUid"; const uint32_t AccountDelegateTest::INVALID_TOKEN_ID = -1; const int32_t AccountDelegateTest::INVALID_USER = -1; -const int AccountDelegateTest::userId = 100; /** * @tc.name: Subscribe001 @@ -80,11 +112,11 @@ HWTEST_F(AccountDelegateTest, Subscribe001, TestSize.Level0) auto account = AccountDelegate::GetInstance(); EXPECT_NE(account, nullptr); auto status = account->Subscribe(nullptr); - EXPECT_EQ(status, Status::INVALID_ARGUMENT); + EXPECT_EQ(status, GeneralError::E_INVALID_ARGS); auto observer = std::make_shared(); observer->SetName(""); status = account->Subscribe(observer); - EXPECT_EQ(status, Status::INVALID_ARGUMENT); + EXPECT_EQ(status, GeneralError::E_INVALID_ARGS); } /** @@ -100,10 +132,10 @@ HWTEST_F(AccountDelegateTest, Subscribe002, TestSize.Level0) EXPECT_NE(account, nullptr); auto observer = std::make_shared(); auto status = account->Subscribe(observer); - EXPECT_EQ(status, Status::SUCCESS); + EXPECT_EQ(status, GeneralError::E_OK); observer->SetName("Subscribe002Observer"); status = account->Subscribe(observer); - EXPECT_EQ(status, Status::SUCCESS); + EXPECT_EQ(status, GeneralError::E_OK); } /** @@ -118,13 +150,13 @@ HWTEST_F(AccountDelegateTest, Subscribe003, TestSize.Level0) EXPECT_NE(account, nullptr); auto observer = std::make_shared(); auto status = account->Subscribe(observer); - EXPECT_EQ(status, Status::INVALID_ARGUMENT); + EXPECT_EQ(status, GeneralError::E_INVALID_ARGS); observer->SetName("Subscribe003Observer"); status = account->Subscribe(observer); - EXPECT_EQ(status, Status::SUCCESS); + EXPECT_EQ(status, GeneralError::E_OK); observer->SetName("Subscribe002ObserverAfter"); status = account->Subscribe(observer); - EXPECT_EQ(status, Status::SUCCESS); + EXPECT_EQ(status, GeneralError::E_OK); } /** @@ -139,14 +171,14 @@ HWTEST_F(AccountDelegateTest, Unsubscribe001, TestSize.Level0) auto account = AccountDelegate::GetInstance(); EXPECT_NE(account, nullptr); auto status = account->Unsubscribe(nullptr); - EXPECT_EQ(status, Status::INVALID_ARGUMENT); + EXPECT_EQ(status, GeneralError::E_INVALID_ARGS); auto observer = std::make_shared(); observer->SetName(""); status = account->Unsubscribe(observer); - EXPECT_EQ(status, Status::INVALID_ARGUMENT); + EXPECT_EQ(status, GeneralError::E_INVALID_ARGS); observer->SetName("Unsubscribe001Observer"); status = account->Unsubscribe(observer); - EXPECT_EQ(status, Status::INVALID_ARGUMENT); + EXPECT_EQ(status, GeneralError::E_INVALID_ARGS); } /** @@ -163,18 +195,18 @@ HWTEST_F(AccountDelegateTest, Unsubscribe002, TestSize.Level0) auto observer = std::make_shared(); account->Subscribe(observer); auto status = account->Unsubscribe(observer); - EXPECT_EQ(status, Status::SUCCESS); + EXPECT_EQ(status, GeneralError::E_OK); observer->SetName("Unsubscribe002ObserverPre"); status = account->Subscribe(observer); - EXPECT_EQ(status, Status::SUCCESS); + EXPECT_EQ(status, GeneralError::E_OK); observer->SetName("Unsubscribe002ObserverAfter"); status = account->Subscribe(observer); - EXPECT_EQ(status, Status::SUCCESS); + EXPECT_EQ(status, GeneralError::E_OK); status = account->Unsubscribe(observer); - EXPECT_EQ(status, Status::SUCCESS); + EXPECT_EQ(status, GeneralError::E_OK); observer->SetName("Unsubscribe002ObserverPre"); status = account->Unsubscribe(observer); - EXPECT_EQ(status, Status::SUCCESS); + EXPECT_EQ(status, GeneralError::E_OK); } /** @@ -227,8 +259,8 @@ HWTEST_F(AccountDelegateTest, QueryUsers, TestSize.Level0) */ HWTEST_F(AccountDelegateTest, IsVerified, TestSize.Level0) { - auto user = AccountDelegate::GetInstance()->IsVerified(userId); - EXPECT_EQ(user, true); + auto user = AccountDelegate::GetInstance()->IsVerified(INVALID_USER); + EXPECT_EQ(user, false); } /** @@ -246,7 +278,7 @@ HWTEST_F(AccountDelegateTest, UnsubscribeAccountEvent, TestSize.Level0) AccountDelegate::GetInstance()->UnsubscribeAccountEvent(); AccountDelegate::GetInstance()->BindExecutor(executor); auto status = account->Unsubscribe(observer); - EXPECT_EQ(status, Status::SUCCESS); + EXPECT_EQ(status, GeneralError::E_OK); } /** diff --git a/datamgr_service/services/distributeddataservice/adapter/broadcaster/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/broadcaster/BUILD.gn index 1f36633bfa9d85773cb0c7c30a8d03d8e05da7c9..45b8b1895286f1ab564fb24c8a5f96ebb63eebc2 100644 --- a/datamgr_service/services/distributeddataservice/adapter/broadcaster/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/broadcaster/BUILD.gn @@ -13,7 +13,7 @@ import("//build/ohos.gni") import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") -ohos_static_library("distributeddata_broadcaster_static") { +ohos_source_set("distributeddata_broadcaster") { branch_protector_ret = "pac_ret" sanitize = { cfi = true @@ -31,8 +31,6 @@ ohos_static_library("distributeddata_broadcaster_static") { "../include/broadcaster", "../include/log", "./src", - "${kv_store_path}/interfaces/innerkits/distributeddata/include", - "${kv_store_common_path}", ] cflags_cc = [ "-fvisibility=hidden" ] @@ -45,6 +43,7 @@ ohos_static_library("distributeddata_broadcaster_static") { "common_event_service:cesfwk_innerkits", "hilog:libhilog", "ipc:ipc_core", + "kv_store:datamgr_common", ] subsystem_name = "distributeddatamgr" part_name = "datamgr_service" diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/communicator/BUILD.gn index 95897b4ce917f4a9f740089112b5654c389fcc6e..ec2f3f16d876f28480609059051b4acff7d42dbf 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/BUILD.gn @@ -12,7 +12,7 @@ # limitations under the License. import("//build/ohos.gni") import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") -ohos_static_library("distributeddata_communicator_static") { +ohos_source_set("distributeddata_communicator") { branch_protector_ret = "pac_ret" sanitize = { cfi = true @@ -47,20 +47,15 @@ ohos_static_library("distributeddata_communicator_static") { "../include/log", "../include/autils", "../include/utils", - "${kv_store_common_path}", - "${kv_store_distributeddb_path}/interfaces/include", - "${kv_store_distributeddb_path}/include", - "${kv_store_distributeddb_path}/interfaces/include/relational", - "${kv_store_path}/interfaces/innerkits/distributeddata/include", - "${data_service_path}/framework/include", + "${data_service_path}/adapter/include/communicator", ] cflags_cc = [ "-fvisibility=hidden" ] deps = [ + "${data_service_path}/adapter/utils:distributeddata_utils", "${data_service_path}/framework:distributeddatasvcfwk", - "../dfx:distributeddata_dfx_static", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/utils:distributeddata_utils_static", + "../dfx:distributeddata_dfx", ] external_deps = [ @@ -69,7 +64,8 @@ ohos_static_library("distributeddata_communicator_static") { "dsoftbus:softbus_client", "hilog:libhilog", "ipc:ipc_core", - "netmanager_base:net_conn_manager_if", + "kv_store:datamgr_common", + "kv_store:distributeddb", ] subsystem_name = "distributeddatamgr" diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/src/app_pipe_handler.cpp b/datamgr_service/services/distributeddataservice/adapter/communicator/src/app_pipe_handler.cpp index 3820f25fef41ba6a9ec19acfe0022ce0fa48c9c6..022f303dbd99ac453ee228bfd1f1ad03e60a98a3 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/src/app_pipe_handler.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/src/app_pipe_handler.cpp @@ -80,5 +80,10 @@ int AppPipeHandler::RemoveSessionServer(const std::string &sessionName) const { return softbusAdapter_->RemoveSessionServerAdapter(sessionName); } + +Status AppPipeHandler::ReuseConnect(const PipeInfo &pipeInfo, const DeviceId &deviceId) +{ + return softbusAdapter_->ReuseConnect(pipeInfo, deviceId); +} } // namespace AppDistributedKv } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/src/app_pipe_handler.h b/datamgr_service/services/distributeddataservice/adapter/communicator/src/app_pipe_handler.h index 1fddf667b595c8175fb97d3c0ae580d3445bce4a..9ea3044858839b4aebfa4e24e4a52048c18db50d 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/src/app_pipe_handler.h +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/src/app_pipe_handler.h @@ -51,6 +51,8 @@ public: int CreateSessionServer(const std::string &sessionName) const; int RemoveSessionServer(const std::string &sessionName) const; + + Status ReuseConnect(const PipeInfo &pipeInfo, const DeviceId &deviceId); private: PipeInfo pipeInfo_; std::shared_ptr softbusAdapter_ {}; diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/src/app_pipe_mgr.cpp b/datamgr_service/services/distributeddataservice/adapter/communicator/src/app_pipe_mgr.cpp index 8073d0c83587911bdf4c8dc40677266683c0931e..e96fde31b7bdd56ad56a1acf4f5a3d4137c7fabc 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/src/app_pipe_mgr.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/src/app_pipe_mgr.cpp @@ -14,6 +14,7 @@ */ #include "app_pipe_mgr.h" +#include "kvstore_utils.h" #include "reporter.h" #undef LOG_TAG @@ -162,5 +163,26 @@ void AppPipeMgr::SetMessageTransFlag(const PipeInfo &pipeInfo, bool flag) } appPipeHandler->SetMessageTransFlag(pipeInfo, flag); } + +Status AppPipeMgr::ReuseConnect(const PipeInfo &pipeInfo, const DeviceId &deviceId) +{ + if (pipeInfo.pipeId.empty() || deviceId.deviceId.empty()) { + ZLOGW("Input is invalid, pipeId:%{public}s, deviceId:%{public}s", pipeInfo.pipeId.c_str(), + KvStoreUtils::ToBeAnonymous(deviceId.deviceId).c_str()); + return Status::INVALID_ARGUMENT; + } + ZLOGD("pipeInfo:%s", pipeInfo.pipeId.c_str()); + std::shared_ptr appPipeHandler; + { + std::lock_guard lock(dataBusMapMutex_); + auto it = dataBusMap_.find(pipeInfo.pipeId); + if (it == dataBusMap_.end()) { + ZLOGW("pipeInfo:%s not found", pipeInfo.pipeId.c_str()); + return Status::INVALID_ARGUMENT; + } + appPipeHandler = it->second; + } + return appPipeHandler->ReuseConnect(pipeInfo, deviceId); +} } // namespace AppDistributedKv } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/src/app_pipe_mgr.h b/datamgr_service/services/distributeddataservice/adapter/communicator/src/app_pipe_mgr.h index 1ffb565995e8607f10317aff649c539c8f0f7b82..d7c35057cf6f81450200a5b8267b388ef98cf9bf 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/src/app_pipe_mgr.h +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/src/app_pipe_mgr.h @@ -46,6 +46,8 @@ public: bool IsSameStartedOnPeer(const struct PipeInfo &pipeInfo, const struct DeviceId &peer); void SetMessageTransFlag(const PipeInfo &pipeInfo, bool flag); + + Status ReuseConnect(const PipeInfo &pipeInfo, const DeviceId &deviceId); private: std::mutex dataBusMapMutex_ {}; std::map> dataBusMap_ {}; diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/src/communication_provider_impl.cpp b/datamgr_service/services/distributeddataservice/adapter/communicator/src/communication_provider_impl.cpp index 65869012df1d6c6b6a8cd67e19b568f0b912f3a8..25cb6c74241547f7089d01f0e8e7f2105f29d52e 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/src/communication_provider_impl.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/src/communication_provider_impl.cpp @@ -84,5 +84,10 @@ int32_t CommunicationProviderImpl::ListenBroadcastMsg(const PipeInfo &pipeInfo, { return SoftBusAdapter::GetInstance()->ListenBroadcastMsg(pipeInfo, std::move(listener)); } + +Status CommunicationProviderImpl::ReuseConnect(const PipeInfo &pipeInfo, const DeviceId &deviceId) +{ + return appPipeMgr_.ReuseConnect(pipeInfo, deviceId); +} } // namespace AppDistributedKv } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/src/communication_provider_impl.h b/datamgr_service/services/distributeddataservice/adapter/communicator/src/communication_provider_impl.h index 5f13ab415ad69f25c80f6cab7d0186cacefbd5cc..1fb5a62016d87aeade237bac915e9a6afa1ad1bc 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/src/communication_provider_impl.h +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/src/communication_provider_impl.h @@ -52,6 +52,8 @@ public: int32_t ListenBroadcastMsg(const PipeInfo &pipeInfo, std::function listener) override; + Status ReuseConnect(const PipeInfo &pipeInfo, const DeviceId &deviceId) override; + protected: virtual Status Initialize(); diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/src/device_manager_adapter.cpp b/datamgr_service/services/distributeddataservice/adapter/communicator/src/device_manager_adapter.cpp index 9547e7ff056cac98bd73b15e92215fef8d7e6e79..b9b0078f6d5f718b9d66135bb3c7ea8d28d5c678 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/src/device_manager_adapter.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/src/device_manager_adapter.cpp @@ -20,31 +20,14 @@ #include "kvstore_utils.h" #include "log_print.h" -#include "net_conn_callback_stub.h" -#include "net_conn_client.h" -#include "net_handle.h" #include "serializable/serializable.h" namespace OHOS::DistributedData { using namespace OHOS::DistributedHardware; using namespace OHOS::AppDistributedKv; -using namespace OHOS::NetManagerStandard; using KvStoreUtils = OHOS::DistributedKv::KvStoreUtils; constexpr int32_t DM_OK = 0; constexpr const char *PKG_NAME = "ohos.distributeddata.service"; -static DeviceManagerAdapter::NetworkType Convert(NetManagerStandard::NetBearType bearType) -{ - switch (bearType) { - case NetManagerStandard::BEARER_WIFI: - return DeviceManagerAdapter::WIFI; - case NetManagerStandard::BEARER_CELLULAR: - return DeviceManagerAdapter::CELLULAR; - case NetManagerStandard::BEARER_ETHERNET: - return DeviceManagerAdapter::ETHERNET; - default: - return DeviceManagerAdapter::OTHER; - } -} class DataMgrDmStateCall final : public DistributedHardware::DeviceStateCallback { public: explicit DataMgrDmStateCall(DeviceManagerAdapter &dmAdapter) : dmAdapter_(dmAdapter) {} @@ -94,69 +77,6 @@ void DataMgrDmInitCall::OnRemoteDied() dmAdapter_.Init(executors_); } -class NetConnCallbackObserver : public NetConnCallbackStub { -public: - explicit NetConnCallbackObserver(DeviceManagerAdapter &dmAdapter) : dmAdapter_(dmAdapter) {} - ~NetConnCallbackObserver() override = default; - int32_t NetAvailable(sptr &netHandle) override; - int32_t NetCapabilitiesChange(sptr &netHandle, const sptr &netAllCap) override; - int32_t NetConnectionPropertiesChange(sptr &netHandle, const sptr &info) override; - int32_t NetLost(sptr &netHandle) override; - int32_t NetUnavailable() override; - int32_t NetBlockStatusChange(sptr &netHandle, bool blocked) override; - -private: - DeviceManagerAdapter &dmAdapter_; -}; - -int32_t NetConnCallbackObserver::NetAvailable(sptr &netHandle) -{ - ZLOGI("OnNetworkAvailable"); - return DistributedKv::SUCCESS; -} - -int32_t NetConnCallbackObserver::NetUnavailable() -{ - ZLOGI("OnNetworkUnavailable"); - dmAdapter_.SetNet(DeviceManagerAdapter::NONE); - return 0; -} - -int32_t NetConnCallbackObserver::NetCapabilitiesChange(sptr &netHandle, - const sptr &netAllCap) -{ - ZLOGI("OnNetCapabilitiesChange"); - if (netHandle == nullptr || netAllCap == nullptr) { - return 0; - } - if (netAllCap->netCaps_.count(NetManagerStandard::NET_CAPABILITY_VALIDATED) && !netAllCap->bearerTypes_.empty()) { - dmAdapter_.SetNet(Convert(*netAllCap->bearerTypes_.begin())); - } else { - dmAdapter_.SetNet(DeviceManagerAdapter::NONE); - } - return 0; -} - -int32_t NetConnCallbackObserver::NetConnectionPropertiesChange(sptr &netHandle, - const sptr &info) -{ - ZLOGI("OnNetConnectionPropertiesChange"); - return 0; -} - -int32_t NetConnCallbackObserver::NetLost(sptr &netHandle) -{ - ZLOGI("OnNetLost"); - dmAdapter_.SetNet(DeviceManagerAdapter::NONE); - return 0; -} - -int32_t NetConnCallbackObserver::NetBlockStatusChange(sptr &netHandle, bool blocked) -{ - ZLOGI("OnNetBlockStatusChange"); - return 0; -} - struct DeviceExtraInfo final : public Serializable { static constexpr int32_t OH_OS_TYPE = 10; @@ -208,8 +128,7 @@ std::function DeviceManagerAdapter::RegDevCallback() auto dmInitCall = std::make_shared(*this, executors_); auto resultInit = devManager.InitDeviceManager(PKG_NAME, dmInitCall); auto resultState = devManager.RegisterDevStateCallback(PKG_NAME, "", dmStateCall); - auto resultNet = RegOnNetworkChange(); - if (resultInit == DM_OK && resultState == DM_OK && resultNet) { + if (resultInit == DM_OK && resultState == DM_OK) { InitDeviceInfo(false); return; } @@ -259,6 +178,8 @@ void DeviceManagerAdapter::Online(const DmDeviceInfo &info) SaveDeviceInfo(dvInfo, DeviceChangeType::DEVICE_ONLINE); syncTask_.Insert(dvInfo.uuid, dvInfo.uuid); auto observers = GetObservers(); + ResetLocalDeviceInfo(); + for (const auto &item : observers) { // notify db if (item == nullptr) { continue; @@ -667,72 +588,6 @@ std::string DeviceManagerAdapter::CalcClientUuid(const std::string &appId, const return encryptedUuid; } -bool DeviceManagerAdapter::RegOnNetworkChange() -{ - sptr observer = new (std::nothrow) NetConnCallbackObserver(*this); - if (observer == nullptr) { - ZLOGE("new operator error.observer is nullptr"); - return false; - } - int nRet = NetConnClient::GetInstance().RegisterNetConnCallback(observer); - if (nRet != NETMANAGER_SUCCESS) { - ZLOGE("RegisterNetConnCallback failed, ret = %{public}d", nRet); - return false; - } - return true; -} - -bool DeviceManagerAdapter::IsNetworkAvailable() -{ - if (defaultNetwork_ != NONE || expireTime_ > GetTimeStamp()) { - return defaultNetwork_ != NONE; - } - return RefreshNet() != NONE; -} - -DeviceManagerAdapter::NetworkType DeviceManagerAdapter::SetNet(NetworkType netWorkType) -{ - auto oldNet = defaultNetwork_; - bool ready = oldNet == NONE && netWorkType != NONE && (GetTimeStamp() - netLostTime_) > NET_LOST_DURATION; - bool offline = oldNet != NONE && netWorkType == NONE; - if (offline) { - netLostTime_ = GetTimeStamp(); - } - defaultNetwork_ = netWorkType; - expireTime_ = GetTimeStamp() + EFFECTIVE_DURATION; - if (ready) { - OnReady(cloudDmInfo); - } - if (offline) { - Offline(cloudDmInfo); - } - return netWorkType; -} - -DeviceManagerAdapter::NetworkType DeviceManagerAdapter::GetNetworkType(bool retrieve) -{ - if (!retrieve) { - return defaultNetwork_; - } - return RefreshNet(); -} - -DeviceManagerAdapter::NetworkType DeviceManagerAdapter::RefreshNet() -{ - NetHandle handle; - auto status = NetConnClient::GetInstance().GetDefaultNet(handle); - if (status != 0 || handle.GetNetId() == 0) { - return SetNet(NONE); - } - NetAllCapabilities capabilities; - status = NetConnClient::GetInstance().GetNetCapabilities(handle, capabilities); - if (status != 0 || !capabilities.netCaps_.count(NetManagerStandard::NET_CAPABILITY_VALIDATED) || - capabilities.bearerTypes_.empty()) { - return SetNet(NONE); - } - return SetNet(Convert(*capabilities.bearerTypes_.begin())); -} - std::string DeviceManagerAdapter::GetEncryptedUuidByNetworkId(const std::string &networkId) { if (networkId.empty()) { @@ -760,24 +615,31 @@ bool DeviceManagerAdapter::IsSameAccount(const std::string &id) bool DeviceManagerAdapter::CheckAccessControl(const AccessCaller &accCaller, const AccessCallee &accCallee) { - DmAccessCaller dmAccessCaller = { .accountId = accCaller.accountId, - .pkgName = accCaller.bundleName, - .networkId = accCaller.networkId, - .userId = accCaller.userId }; - DmAccessCallee dmAccessCallee = { .accountId = accCallee.accountId, - .networkId = accCallee.networkId, + DmAccessCaller dmAccessCaller = { .accountId = accCaller.accountId, .pkgName = accCaller.bundleName, + .networkId = accCaller.networkId, .userId = accCaller.userId }; + DmAccessCallee dmAccessCallee = { .accountId = accCallee.accountId, .networkId = accCallee.networkId, .userId = accCallee.userId }; return DeviceManager::GetInstance().CheckAccessControl(dmAccessCaller, dmAccessCallee); } bool DeviceManagerAdapter::IsSameAccount(const AccessCaller &accCaller, const AccessCallee &accCallee) { - DmAccessCaller dmAccessCaller = { .accountId = accCaller.accountId, - .networkId = accCaller.networkId, + DmAccessCaller dmAccessCaller = { .accountId = accCaller.accountId, .networkId = accCaller.networkId, .userId = accCaller.userId }; - DmAccessCallee dmAccessCallee = { .accountId = accCallee.accountId, - .networkId = accCallee.networkId, + DmAccessCallee dmAccessCallee = { .accountId = accCallee.accountId, .networkId = accCallee.networkId, .userId = accCallee.userId }; return DeviceManager::GetInstance().CheckIsSameAccount(dmAccessCaller, dmAccessCallee); } + +void DeviceManagerAdapter::ResetLocalDeviceInfo() +{ + auto local = GetLocalDeviceInfo(); + DeviceInfo dvInfo; + if (deviceInfos_.Get(local.udid, dvInfo)) { + deviceInfos_.Delete(dvInfo.networkId); + } + deviceInfos_.Set(local.uuid, local); + deviceInfos_.Set(local.udid, local); + deviceInfos_.Set(local.networkId, local); +} } // namespace OHOS::DistributedData diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/src/process_communicator_impl.cpp b/datamgr_service/services/distributeddataservice/adapter/communicator/src/process_communicator_impl.cpp index b3d43e80a5802190c6a8a7ed77bd43a12536d027..07799948ce562cb3f8ec95fb82d83b790a37a70d 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/src/process_communicator_impl.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/src/process_communicator_impl.cpp @@ -29,14 +29,20 @@ ProcessCommunicatorImpl::ProcessCommunicatorImpl() { } -ProcessCommunicatorImpl::ProcessCommunicatorImpl(RouteHeadHandlerCreator handlerCreator) - : routeHeadHandlerCreator_(std::move(handlerCreator)) +ProcessCommunicatorImpl::~ProcessCommunicatorImpl() { + ZLOGE("destructor."); } -ProcessCommunicatorImpl::~ProcessCommunicatorImpl() +ProcessCommunicatorImpl *ProcessCommunicatorImpl::GetInstance() { - ZLOGE("destructor."); + static ProcessCommunicatorImpl *processCommunicatorImpl = new ProcessCommunicatorImpl(); + return processCommunicatorImpl; +} + +void ProcessCommunicatorImpl::SetRouteHeadHandlerCreator(RouteHeadHandlerCreator handlerCreator) +{ + routeHeadHandlerCreator_ = std::move(handlerCreator); } DBStatus ProcessCommunicatorImpl::Start(const std::string &processLabel) @@ -269,5 +275,11 @@ DBStatus ProcessCommunicatorImpl::CheckAndGetDataHeadInfo( ZLOGD("ok, result:%{public}zu, user:%{public}s", users.size(), users.front().c_str()); return DBStatus::OK; } + +Status ProcessCommunicatorImpl::ReuseConnect(const DeviceId &deviceId) +{ + PipeInfo pi = {thisProcessLabel_, ""}; + return CommunicationProvider::GetInstance().ReuseConnect(pi, deviceId); +} } // namespace AppDistributedKv } // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/src/softbus_adapter.h b/datamgr_service/services/distributeddataservice/adapter/communicator/src/softbus_adapter.h index c4fa5324608816a75ebf590085d1d8c579136642..08c572812639eef7555921feb2c7259d6562c21a 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/src/softbus_adapter.h +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/src/softbus_adapter.h @@ -83,6 +83,8 @@ public: void OnDeviceChanged(const AppDistributedKv::DeviceInfo &info, const AppDistributedKv::DeviceChangeType &type) const override; + + Status ReuseConnect(const PipeInfo &pipeInfo, const DeviceId &deviceId); private: using Time = std::chrono::steady_clock::time_point; using Duration = std::chrono::steady_clock::duration; @@ -93,6 +95,7 @@ private: bool CloseSession(const std::string &networkId); void GetExpireTime(std::shared_ptr &conn); std::pair OpenConnect(const std::shared_ptr &conn, const DeviceId &deviceId); + std::shared_ptr GetConnect(const PipeInfo &pipeInfo, const DeviceId &deviceId, uint32_t qosType); static constexpr const char *PKG_NAME = "distributeddata-default"; static constexpr Time INVALID_NEXT = std::chrono::steady_clock::time_point::max(); static constexpr uint32_t QOS_COUNT = 3; diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/src/softbus_adapter_standard.cpp b/datamgr_service/services/distributeddataservice/adapter/communicator/src/softbus_adapter_standard.cpp index 7246a043b49525f9c453a4015e6e53892328efe8..3b240afa8426004a76a1d23df0daff41d5001a8c 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/src/softbus_adapter_standard.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/src/softbus_adapter_standard.cpp @@ -182,22 +182,9 @@ void SoftBusAdapter::GetExpireTime(std::shared_ptr &conn) std::pair SoftBusAdapter::SendData(const PipeInfo &pipeInfo, const DeviceId &deviceId, const DataInfo &dataInfo, uint32_t length, const MessageInfo &info) { - std::shared_ptr conn; bool isOHOSType = DmAdapter::GetInstance().IsOHOSType(deviceId.deviceId); uint32_t qosType = isOHOSType ? SoftBusClient::QOS_HML : SoftBusClient::QOS_BR; - connects_.Compute(deviceId.deviceId, [&pipeInfo, &deviceId, &conn, qosType, isOHOSType](const auto &key, - std::vector> &connects) -> bool { - for (auto &connect : connects) { - if (connect->GetQoSType() == qosType) { - conn = connect; - return true; - } - } - auto connect = std::make_shared(pipeInfo, deviceId, qosType); - connects.emplace_back(connect); - conn = connect; - return true; - }); + std::shared_ptr conn = GetConnect(pipeInfo, deviceId, qosType); if (conn == nullptr) { return std::make_pair(Status::ERROR, 0); } @@ -216,6 +203,29 @@ std::pair SoftBusAdapter::SendData(const PipeInfo &pipeInfo, co return std::make_pair(status, errCode); } +std::shared_ptr SoftBusAdapter::GetConnect(const PipeInfo &pipeInfo, const DeviceId &deviceId, + uint32_t qosType) +{ + std::shared_ptr conn; + connects_.Compute(deviceId.deviceId, [&pipeInfo, &deviceId, &conn, qosType](const auto &key, + std::vector> &connects) -> bool { + for (auto &connect : connects) { + if (connect == nullptr) { + continue; + } + if (connect->GetQoSType() == qosType) { + conn = connect; + return true; + } + } + auto connect = std::make_shared(pipeInfo, deviceId, qosType); + connects.emplace_back(connect); + conn = connect; + return true; + }); + return conn; +} + std::pair SoftBusAdapter::OpenConnect(const std::shared_ptr &conn, const DeviceId &deviceId) { @@ -587,5 +597,38 @@ bool SoftBusAdapter::CloseSession(const std::string &networkId) } return ret != 0; } + +Status SoftBusAdapter::ReuseConnect(const PipeInfo &pipeInfo, const DeviceId &deviceId) +{ + bool isOHOSType = DmAdapter::GetInstance().IsOHOSType(deviceId.deviceId); + if (!isOHOSType) { + return Status::NOT_SUPPORT; + } + uint32_t qosType = SoftBusClient::QOS_HML; + std::shared_ptr conn = GetConnect(pipeInfo, deviceId, qosType); + if (conn == nullptr) { + return Status::ERROR; + } + auto status = conn->ReuseConnect(&clientListener_); + if (status != Status::SUCCESS) { + return status; + } + // Avoid being cleared by scheduled tasks + connects_.Compute(deviceId.deviceId, [&conn, qosType](const auto &key, + std::vector> &connects) -> bool { + for (auto &connect : connects) { + if (connect == nullptr) { + continue; + } + if (connect->GetQoSType() == qosType) { + return true; + } + } + connects.emplace_back(conn); + return true; + }); + StartCloseSessionTask(deviceId.deviceId); + return Status::SUCCESS; +} } // namespace AppDistributedKv } // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/src/softbus_client.cpp b/datamgr_service/services/distributeddataservice/adapter/communicator/src/softbus_client.cpp index 9dfb23b2c525ed2a7dcf6647e5b633f19f649840..f4451869fc0dd6eb479961ce84b27b9aaed1e225 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/src/softbus_client.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/src/softbus_client.cpp @@ -36,7 +36,8 @@ SoftBusClient::SoftBusClient(const PipeInfo& pipeInfo, const DeviceId& deviceId, SoftBusClient::~SoftBusClient() { - ZLOGI("Shutdown socket:%{public}d", socket_); + ZLOGI("Shutdown socket:%{public}d, deviceId:%{public}s", socket_, + KvStoreUtils::ToBeAnonymous(device_.deviceId).c_str()); if (socket_ > 0) { Shutdown(socket_); } @@ -99,20 +100,9 @@ Status SoftBusClient::OpenConnect(const ISocketListener *listener) if (isOpening_.exchange(true)) { return Status::RATE_LIMIT; } - SocketInfo socketInfo; - std::string peerName = pipe_.pipeId; - socketInfo.peerName = const_cast(peerName.c_str()); - std::string networkId = DmAdapter::GetInstance().ToNetworkID(device_.deviceId); - socketInfo.peerNetworkId = const_cast(networkId.c_str()); - std::string clientName = pipe_.pipeId; - socketInfo.name = const_cast(clientName.c_str()); - std::string pkgName = "ohos.distributeddata"; - socketInfo.pkgName = pkgName.data(); - socketInfo.dataType = DATA_TYPE_BYTES; - int32_t clientSocket = Socket(socketInfo); + int32_t clientSocket = CreateSocket(); if (clientSocket <= 0) { isOpening_.store(false); - ZLOGE("Create the client Socket:%{public}d failed, peerName:%{public}s", clientSocket, socketInfo.peerName); return Status::NETWORK_ERROR; } auto task = [type = type_, clientSocket, listener, client = shared_from_this()]() { @@ -122,7 +112,7 @@ Status SoftBusClient::OpenConnect(const ISocketListener *listener) } ZLOGI("Bind Start, device:%{public}s socket:%{public}d type:%{public}u", KvStoreUtils::ToBeAnonymous(client->device_.deviceId).c_str(), clientSocket, type); - int32_t status = client->Open(clientSocket, QOS_INFOS[type % QOS_BUTT], listener); + int32_t status = client->Open(clientSocket, type, listener); Context::GetInstance().NotifySessionReady(client->device_.deviceId, status); client->isOpening_.store(false); }; @@ -130,6 +120,25 @@ Status SoftBusClient::OpenConnect(const ISocketListener *listener) return Status::RATE_LIMIT; } +int32_t SoftBusClient::CreateSocket() const +{ + SocketInfo socketInfo; + std::string peerName = pipe_.pipeId; + socketInfo.peerName = const_cast(peerName.c_str()); + std::string networkId = DmAdapter::GetInstance().ToNetworkID(device_.deviceId); + socketInfo.peerNetworkId = const_cast(networkId.c_str()); + std::string clientName = pipe_.pipeId; + socketInfo.name = const_cast(clientName.c_str()); + std::string pkgName = "ohos.distributeddata"; + socketInfo.pkgName = pkgName.data(); + socketInfo.dataType = DATA_TYPE_BYTES; + int32_t socket = Socket(socketInfo); + if (socket <= 0) { + ZLOGE("Create the client Socket:%{public}d failed, peerName:%{public}s", socket, socketInfo.peerName); + } + return socket; +} + Status SoftBusClient::CheckStatus() { if (bindState_ == 0) { @@ -144,9 +153,9 @@ Status SoftBusClient::CheckStatus() return Status::ERROR; } -int32_t SoftBusClient::Open(int32_t socket, const QosTV qos[], const ISocketListener *listener) +int32_t SoftBusClient::Open(int32_t socket, uint32_t type, const ISocketListener *listener, bool async) { - int32_t status = ::Bind(socket, qos, QOS_COUNT, listener); + int32_t status = ::Bind(socket, QOS_INFOS[type % QOS_BUTT], QOS_COUNTS[type % QOS_BUTT], listener); ZLOGI("Bind %{public}s,session:%{public}s,socketId:%{public}d", KvStoreUtils::ToBeAnonymous(device_.deviceId).c_str(), pipe_.pipeId.c_str(), socket); @@ -156,20 +165,16 @@ int32_t SoftBusClient::Open(int32_t socket, const QosTV qos[], const ISocketList ::Shutdown(socket); return status; } - UpdateExpireTime(); + UpdateExpireTime(async); uint32_t mtu = 0; std::tie(status, mtu) = GetMtu(socket); if (status != SOFTBUS_OK) { ZLOGE("GetMtu failed, session:%{public}s, socket:%{public}d, status:%{public}d", pipe_.pipeId.c_str(), socket_, status); + ::Shutdown(socket); return status; } - { - std::lock_guard lock(mutex_); - socket_ = socket; - mtu_ = mtu; - bindState_ = status; - } + UpdateBindInfo(socket, mtu, status, async); ZLOGI("open %{public}s, session:%{public}s success, socket:%{public}d", KvStoreUtils::ToBeAnonymous(device_.deviceId).c_str(), pipe_.pipeId.c_str(), socket_); ConnectManager::GetInstance()->OnSessionOpen(DmAdapter::GetInstance().GetDeviceInfo(device_.deviceId).networkId); @@ -187,12 +192,32 @@ int32_t SoftBusClient::GetSocket() const return socket_; } -void SoftBusClient::UpdateExpireTime() +void SoftBusClient::UpdateExpireTime(bool async) { auto expireTime = CalcExpireTime(); - std::lock_guard lock(mutex_); - if (expireTime > expireTime_) { - expireTime_ = expireTime; + if (async) { + std::lock_guard lock(mutex_); + if (expireTime > expireTime_) { + expireTime_ = expireTime; + } + } else { + if (expireTime > expireTime_) { + expireTime_ = expireTime; + } + } +} + +void SoftBusClient::UpdateBindInfo(int32_t socket, uint32_t mtu, int32_t status, bool async) +{ + if (async) { + std::lock_guard lock(mutex_); + socket_ = socket; + mtu_ = mtu; + bindState_ = status; + } else { + socket_ = socket; + mtu_ = mtu; + bindState_ = status; } } @@ -205,7 +230,7 @@ std::pair SoftBusClient::GetMtu(int32_t socket) uint32_t SoftBusClient::GetQoSType() const { - return type_ % QOS_COUNT; + return type_ % QOS_BUTT; } SoftBusClient::Time SoftBusClient::CalcExpireTime() const @@ -213,4 +238,22 @@ SoftBusClient::Time SoftBusClient::CalcExpireTime() const auto delay = type_ == QOS_BR ? BR_CLOSE_DELAY : HML_CLOSE_DELAY; return std::chrono::steady_clock::now() + delay; } + +Status SoftBusClient::ReuseConnect(const ISocketListener *listener) +{ + std::lock_guard lock(mutex_); + auto checkStatus = CheckStatus(); + if (checkStatus == Status::SUCCESS) { + UpdateExpireTime(false); + return Status::SUCCESS; + } + int32_t socket = CreateSocket(); + if (socket <= 0) { + return Status::NETWORK_ERROR; + } + ZLOGI("Reuse Start, device:%{public}s session:%{public}s socket:%{public}d", + KvStoreUtils::ToBeAnonymous(device_.deviceId).c_str(), pipe_.pipeId.c_str(), socket); + int32_t status = Open(socket, QOS_REUSE, listener, false); + return status == SOFTBUS_OK ? Status::SUCCESS : Status::NETWORK_ERROR; +} } // namespace OHOS::AppDistributedKv \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/src/softbus_client.h b/datamgr_service/services/distributeddataservice/adapter/communicator/src/softbus_client.h index 6726a29ecdc82a0c5014508c3bc0cb9c3c156545..67709bf9007d755123e27b8bfc25033dae199c50 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/src/softbus_client.h +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/src/softbus_client.h @@ -30,6 +30,7 @@ public: enum QoSType { QOS_BR, QOS_HML, + QOS_REUSE, QOS_BUTT }; SoftBusClient(const PipeInfo &pipeInfo, const DeviceId &deviceId, uint32_t type = QOS_HML); @@ -47,13 +48,16 @@ public: Time GetExpireTime() const; int32_t GetSocket() const; uint32_t GetQoSType() const; - void UpdateExpireTime(); + void UpdateExpireTime(bool async = true); int32_t GetSoftBusError(); + Status ReuseConnect(const ISocketListener *listener); private: - int32_t Open(int32_t socket, const QosTV qos[], const ISocketListener *listener); + int32_t Open(int32_t socket, uint32_t type, const ISocketListener *listener, bool async = true); std::pair GetMtu(int32_t socket); Time CalcExpireTime() const; + int32_t CreateSocket() const; + void UpdateBindInfo(int32_t socket, uint32_t mtu, int32_t status, bool async = true); static constexpr int32_t INVALID_SOCKET_ID = -1; static constexpr uint32_t DEFAULT_TIMEOUT = 30 * 1000; @@ -62,6 +66,9 @@ private: static constexpr Duration HML_CLOSE_DELAY = std::chrono::seconds(3); static constexpr Duration MAX_DELAY = std::chrono::seconds(20); static constexpr uint32_t QOS_COUNT = 3; + static constexpr uint32_t BR_QOS_COUNT = 3; + static constexpr uint32_t HML_QOS_COUNT = 2; + static constexpr uint32_t REUSE_QOS_COUNT = 1; static constexpr QosTV QOS_INFOS[QOS_BUTT][QOS_COUNT] = { { // BR QOS QosTV{ .qos = QOS_TYPE_MIN_BW, .value = 0x5a5a5a5a }, @@ -69,11 +76,14 @@ private: QosTV{ .qos = QOS_TYPE_MIN_LATENCY, .value = 1600 } }, { // HML QOS - QosTV{ .qos = QOS_TYPE_MIN_BW, .value = 90 * 1024 * 1024 }, QosTV{ .qos = QOS_TYPE_MAX_LATENCY, .value = 10000 }, QosTV{ .qos = QOS_TYPE_MIN_LATENCY, .value = 2000 } + }, + { // REUSE_QOS + QosTV{ .qos = QOS_TYPE_REUSE_BE, .value = 1 } } }; + static constexpr uint32_t QOS_COUNTS[QOS_BUTT] = { BR_QOS_COUNT, HML_QOS_COUNT, REUSE_QOS_COUNT }; std::atomic_bool isOpening_ = false; mutable std::mutex mutex_; uint32_t type_ = QOS_HML; diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/test/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/communicator/test/BUILD.gn index c627bee87042b89824ebf1a65eb4a887a927907c..ecd594abf2784f499cb46d6fdb7721e8a1b044e5 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/test/BUILD.gn @@ -22,22 +22,20 @@ ohos_unittest("CommunicationProviderTest") { sources = [ "./unittest/communication_provider_impl_test.cpp" ] include_dirs = [ - "//commonlibrary/c_utils/base/include", - "//foundation/distributeddatamgr/kv_store/frameworks/common", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/include/autils", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/include/communicator", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/include/dfx", - "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddata/include", "../src", ] external_deps = [ "dsoftbus:softbus_client", "hilog:libhilog", "ipc:ipc_core", + "kv_store:distributeddata_inner", ] + deps = [ - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/communicator:distributeddata_communicator_static", - "//third_party/googletest:gtest_main", + "${data_service_path}/adapter/communicator:distributeddata_communicator", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } @@ -47,30 +45,28 @@ ohos_unittest("DeviceManagerAdapterTest") { sources = [ "unittest/device_manager_adapter_test.cpp" ] include_dirs = [ - "//commonlibrary/c_utils/base/include", - "//foundation/distributeddatamgr/kv_store/frameworks/common", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/include/autils", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/include/communicator", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/include/dfx", - "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddata/include", "../src", ] external_deps = [ "access_token:libaccesstoken_sdk", "access_token:libnativetoken", "access_token:libtoken_setproc", + "c_utils:utils", + "device_manager:devicemanagersdk", "dsoftbus:softbus_client", "hilog:libhilog", "ipc:ipc_core", + "kv_store:distributeddata_inner", ] cflags = [ "-Dprivate=public", "-Dprotected=public", ] deps = [ - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/communicator:distributeddata_communicator_static", - "//foundation/distributedhardware/device_manager/interfaces/inner_kits/native_cpp:devicemanagersdk", - "//third_party/googletest:gtest_main", + "${data_service_path}/adapter/communicator:distributeddata_communicator", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } @@ -80,29 +76,28 @@ ohos_unittest("SoftbusAdapterStandardTest") { sources = [ "unittest/softbus_adapter_standard_test.cpp" ] include_dirs = [ - "${kv_store_path}/frameworks/common", "${data_service_path}/adapter/include/autils", "${data_service_path}/adapter/include/communicator", "${data_service_path}/adapter/include/dfx", - "${kv_store_path}/interfaces/innerkits/distributeddata/include", "../src", ] external_deps = [ "access_token:libaccesstoken_sdk", "access_token:libnativetoken", "access_token:libtoken_setproc", + "c_utils:utils", + "device_manager:devicemanagersdk", "dsoftbus:softbus_client", "hilog:libhilog", "ipc:ipc_core", + "kv_store:distributeddata_inner", ] cflags = [ "-Dprivate=public", "-Dprotected=public", ] deps = [ - "${data_service_path}/adapter/communicator:distributeddata_communicator_static", - "${device_manager_path}/interfaces/inner_kits/native_cpp:devicemanagersdk", - "//third_party/googletest:gtest_main", + "${data_service_path}/adapter/communicator:distributeddata_communicator", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/BUILD.gn index 3ee6efe2e6612b7a1f2bf07d736ce21f5c7efb9b..8f9e579b781b4563e5d96d1b02a13b6152d9b68c 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/test/fuzztest/softbusadapter_fuzzer/BUILD.gn @@ -27,12 +27,6 @@ ohos_fuzztest("SoftBusAdapterFuzzTest") { "${data_service_path}/adapter/include/utils", "${data_service_path}/adapter/communicator/src", "${data_service_path}/framework/include", - "${dsoftbus_core_path}", - "${kv_store_common_path}", - "${kv_store_distributeddb_path}/interfaces/include", - "${kv_store_distributeddb_path}/include", - "${kv_store_distributeddb_path}/interfaces/include/relational", - "${kv_store_path}/interfaces/innerkits/distributeddata/include", ] fuzz_config_file = "${data_service_path}/adapter/communicator/test/fuzztest/softbusadapter_fuzzer" @@ -47,9 +41,8 @@ ohos_fuzztest("SoftBusAdapterFuzzTest") { sources = [ "softbusadapter_fuzzer.cpp" ] deps = [ - "${data_service_path}/adapter/communicator:distributeddata_communicator_static", - "${data_service_path}/adapter/dfx:distributeddata_dfx_static", - "${data_service_path}/adapter/utils:distributeddata_utils_static", + "${data_service_path}/adapter/dfx:distributeddata_dfx", + "${data_service_path}/adapter/utils:distributeddata_utils", ] external_deps = [ @@ -57,6 +50,8 @@ ohos_fuzztest("SoftBusAdapterFuzzTest") { "device_manager:devicemanagersdk", "dsoftbus:softbus_client", "hilog:libhilog", + "kv_store:distributeddata_inner", + "kv_store:distributeddb", ] } diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/test/unittest/communication_provider_impl_test.cpp b/datamgr_service/services/distributeddataservice/adapter/communicator/test/unittest/communication_provider_impl_test.cpp index 6c82c8b7653a06cbe18f5e6132205c9409edbb0f..518bb0fc8238a8e2eee88a346258ba15e5bc90b6 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/test/unittest/communication_provider_impl_test.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/test/unittest/communication_provider_impl_test.cpp @@ -98,22 +98,6 @@ HWTEST_F(CommunicationProviderImplTest, CommunicationProvider003, TestSize.Level sleep(1); // avoid thread dnet thread died, then will have pthread; } -/** -* @tc.name: CommunicationProvider004 -* @tc.desc: singleton pipe -* @tc.type: FUNC -* @tc.require: AR000CCPQ2 -* @tc.author: hongbo -*/ -HWTEST_F(CommunicationProviderImplTest, CommunicationProvider004, TestSize.Level1) -{ - ZLOGI("begin."); - auto &provider = CommunicationProvider::GetInstance(); - auto &provider1 = CommunicationProvider::GetInstance(); - EXPECT_EQ(&provider, &provider1); - sleep(1); // avoid thread dnet thread died, then will have pthread; -} - /** * @tc.name: CommunicationProvider005 * @tc.desc: parse sent data diff --git a/datamgr_service/services/distributeddataservice/adapter/dfx/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/dfx/BUILD.gn index 3b7ee1704cd37528169e4e3ea68b8fb3a3872659..b150f471182a6dda2dcf14a27b5b1607f2236384 100644 --- a/datamgr_service/services/distributeddataservice/adapter/dfx/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/dfx/BUILD.gn @@ -13,7 +13,11 @@ import("//build/ohos.gni") import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") -ohos_static_library("distributeddata_dfx_static") { +config("dfx_public_config") { + include_dirs = [ "${data_service_path}/adapter/include/dfx" ] +} + +ohos_source_set("distributeddata_dfx") { branch_protector_ret = "pac_ret" sanitize = { cfi = true @@ -24,6 +28,7 @@ ohos_static_library("distributeddata_dfx_static") { } sources = [ "src/behaviour/behaviour_reporter_impl.cpp", + "src/fault/cloud_sync_fault_impl.cpp", "src/fault/communication_fault_impl.cpp", "src/fault/database_fault_impl.cpp", "src/fault/runtime_fault_impl.cpp", @@ -43,10 +48,8 @@ ohos_static_library("distributeddata_dfx_static") { "./src/statistic", "../include/dfx", "../include/log", - "../include/autils", + "../include/utils", "../include/communicator", - "${kv_store_common_path}", - "${kv_store_path}/interfaces/inner_api/distributeddata/include", ] cflags_cc = [ "-fvisibility=hidden" ] @@ -58,9 +61,62 @@ ohos_static_library("distributeddata_dfx_static") { "hisysevent:libhisysevent", "hitrace:hitrace_meter", "hitrace:libhitracechain", + "kv_store:datamgr_common", + "openssl:libcrypto_shared", + ] + public_configs = [ ":dfx_public_config" ] + subsystem_name = "distributeddatamgr" + part_name = "datamgr_service" + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] +} + +ohos_static_library("distributeddata_dfx_fault_static") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + boundary_sanitize = true + ubsan = true + } + sources = [ + "src/behaviour/behaviour_reporter_impl.cpp", + "src/fault/cloud_sync_fault_impl.cpp", + "src/fault/communication_fault_impl.cpp", + "src/fault/database_fault_impl.cpp", + "src/fault/runtime_fault_impl.cpp", + "src/fault/service_fault_impl.cpp", + "src/hiview_adapter.cpp", + "src/reporter.cpp", + "src/statistic/api_performance_statistic_impl.cpp", + "src/statistic/database_statistic_impl.cpp", + "src/statistic/traffic_statistic_impl.cpp", + "src/statistic/visit_statistic_impl.cpp", + ] + + include_dirs = [ + "./src", + "./src/fault", + "./src/statistic", + "../include/dfx", + "../include/utils", + ] + + cflags_cc = [ "-fvisibility=hidden" ] + + deps = [ "${data_service_path}/adapter/utils:distributeddata_utils" ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", "kv_store:distributeddata_inner", "openssl:libcrypto_shared", ] + + public_configs = [ ":dfx_public_config" ] subsystem_name = "distributeddatamgr" part_name = "datamgr_service" defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] diff --git a/datamgr_service/services/distributeddataservice/adapter/dfx/src/dfx_code_constant.h b/datamgr_service/services/distributeddataservice/adapter/dfx/src/dfx_code_constant.h index cc2cba1d19716c83e325a6d6d50776be83e71c78..1ab83214187653935c2c3f347a64e3121d419df6 100644 --- a/datamgr_service/services/distributeddataservice/adapter/dfx/src/dfx_code_constant.h +++ b/datamgr_service/services/distributeddataservice/adapter/dfx/src/dfx_code_constant.h @@ -33,5 +33,6 @@ public: static inline const int DATABASE_REKEY_FAILED = 950001114; static inline const int DATABASE_BEHAVIOUR = 950001115; static inline const int UDMF_DATA_BEHAVIOR = 950001116; + static inline const int ARKDATA_CLOUD_SYNC_FAULT = 950001117; }; #endif // DISTRIBUTEDDATAMGR_DFX_CODE_CONSTANT_H diff --git a/datamgr_service/services/distributeddataservice/adapter/dfx/src/fault/cloud_sync_fault_impl.cpp b/datamgr_service/services/distributeddataservice/adapter/dfx/src/fault/cloud_sync_fault_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8eea95631e89ab2815740e19a52737eefe01939f --- /dev/null +++ b/datamgr_service/services/distributeddataservice/adapter/dfx/src/fault/cloud_sync_fault_impl.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 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 "cloud_sync_fault_impl.h" + +namespace OHOS { +namespace DistributedDataDfx { +ReportStatus CloudSyncFaultImpl::Report(const ArkDataFaultMsg &msg) +{ + HiViewAdapter::ReportArkDataFault(DfxCodeConstant::ARKDATA_CLOUD_SYNC_FAULT, msg, executors_); + return ReportStatus::SUCCESS; +} +void CloudSyncFaultImpl::SetThreadPool(std::shared_ptr executors) +{ + executors_ = executors; +} +} // namespace DistributedDataDfx +} // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/adapter/dfx/src/fault/cloud_sync_fault_impl.h b/datamgr_service/services/distributeddataservice/adapter/dfx/src/fault/cloud_sync_fault_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..e4e45bc90ab88e468c8f7c07b868afb8bcc2d295 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/adapter/dfx/src/fault/cloud_sync_fault_impl.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 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 DISTRIBUTEDDATAMGR_DATAMGR_SERVICE_CLOUD_SYNC_FAULT_IMPL_H +#define DISTRIBUTEDDATAMGR_DATAMGR_SERVICE_CLOUD_SYNC_FAULT_IMPL_H + +#include "fault_reporter.h" +#include "hiview_adapter.h" +#include "dfx_types.h" + +namespace OHOS { +namespace DistributedDataDfx { +class CloudSyncFaultImpl : public FaultReporter { +public: + virtual ~CloudSyncFaultImpl() {} + ReportStatus Report(const FaultMsg &msg) override + { + return ReportStatus::SUCCESS; + }; + ReportStatus Report(const DBFaultMsg &ms) override + { + return ReportStatus::SUCCESS; + }; + ReportStatus Report(const struct CommFaultMsg &msg) override + { + return ReportStatus::SUCCESS; + }; + ReportStatus Report(const ArkDataFaultMsg &msg) override; + void SetThreadPool(std::shared_ptr executors); + +private: + std::shared_ptr executors_; +}; +} // namespace DistributedDataDfx +} // namespace OHOS +#endif // DISTRIBUTEDDATAMGR_DATAMGR_SERVICE_CLOUD_SYNC_FAULT_IMPL_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/adapter/dfx/src/hiview_adapter.cpp b/datamgr_service/services/distributeddataservice/adapter/dfx/src/hiview_adapter.cpp index cb7f26c5d992a475e8ec89722279f7d5e406498c..01c883fa5d13945dc76c0c106f2911ddebfe5d9d 100644 --- a/datamgr_service/services/distributeddataservice/adapter/dfx/src/hiview_adapter.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/dfx/src/hiview_adapter.cpp @@ -16,9 +16,12 @@ #define LOG_TAG "HiViewAdapter" #include "hiview_adapter.h" + #include #include + #include "log_print.h" +#include "time_utils.h" namespace OHOS { namespace DistributedDataDfx { @@ -70,6 +73,7 @@ const std::map EVENT_COVERT_TABLE = { { DfxCodeConstant::DATABASE_REKEY_FAILED, "DATABASE_REKEY_FAILED" }, { DfxCodeConstant::DATABASE_BEHAVIOUR, "DATABASE_BEHAVIOUR" }, { DfxCodeConstant::UDMF_DATA_BEHAVIOR, "UDMF_DATA_BEHAVIOR" }, + { DfxCodeConstant::ARKDATA_CLOUD_SYNC_FAULT, "ARKDATA_CLOUD_SYNC_FAULT" }, }; } std::mutex HiViewAdapter::visitMutex_; @@ -89,6 +93,10 @@ std::mutex HiViewAdapter::runMutex_; void HiViewAdapter::ReportFault(int dfxCode, const FaultMsg &msg, std::shared_ptr executors) { + if (executors == nullptr) { + ZLOGW("executors is nullptr!"); + return; + } ExecutorPool::Task task([dfxCode, msg]() { struct HiSysEventParam params[] = { { .name = { *FAULT_TYPE }, @@ -121,6 +129,10 @@ void HiViewAdapter::ReportFault(int dfxCode, const FaultMsg &msg, std::shared_pt void HiViewAdapter::ReportDBFault(int dfxCode, const DBFaultMsg &msg, std::shared_ptr executors) { + if (executors == nullptr) { + ZLOGW("executors is nullptr!"); + return; + } ExecutorPool::Task task([dfxCode, msg]() { struct HiSysEventParam params[] = { { .name = { *APP_ID }, @@ -153,6 +165,10 @@ void HiViewAdapter::ReportDBFault(int dfxCode, const DBFaultMsg &msg, std::share void HiViewAdapter::ReportCommFault(int dfxCode, const CommFaultMsg &msg, std::shared_ptr executors) { + if (executors == nullptr) { + ZLOGW("executors is nullptr!"); + return; + } ExecutorPool ::Task task([dfxCode, msg]() { std::string message; for (size_t i = 0; i < msg.deviceId.size(); i++) { @@ -189,8 +205,42 @@ void HiViewAdapter::ReportCommFault(int dfxCode, const CommFaultMsg &msg, std::s executors->Execute(std::move(task)); } +void HiViewAdapter::ReportArkDataFault(int dfxCode, const ArkDataFaultMsg &msg, std::shared_ptr executors) +{ + if (executors == nullptr) { + ZLOGW("executors is nullptr!"); + return; + } + ExecutorPool::Task task([dfxCode, msg]() { + std::string occurTime = TimeUtils::GetCurSysTimeWithMs(); + std::string bundleName = msg.bundleName; + std::string moduleName = msg.moduleName; + std::string storeName = msg.storeName; + std::string businessType = msg.businessType; + std::string appendix = msg.appendixMsg; + std::string faultType = msg.faultType; + struct HiSysEventParam params[] = { + { .name = { "FAULT_TIME" }, .t = HISYSEVENT_STRING, .v = { .s = occurTime.data() }, .arraySize = 0 }, + { .name = { "FAULT_TYPE" }, .t = HISYSEVENT_STRING, .v = { .s = faultType.data() }, .arraySize = 0 }, + { .name = { "BUNDLE_NAME" }, .t = HISYSEVENT_STRING, .v = { .s = bundleName.data() }, .arraySize = 0 }, + { .name = { "MODULE_NAME" }, .t = HISYSEVENT_STRING, .v = { .s = moduleName.data() }, .arraySize = 0 }, + { .name = { "STORE_NAME" }, .t = HISYSEVENT_STRING, .v = { .s = storeName.data() }, .arraySize = 0 }, + { .name = { "BUSINESS_TYPE" }, .t = HISYSEVENT_STRING, .v = { .s = businessType.data() }, .arraySize = 0 }, + { .name = { "ERROR_CODE" }, .t = HISYSEVENT_INT32, .v = { .i32 = msg.errorType }, .arraySize = 0 }, + { .name = { "APPENDIX" }, .t = HISYSEVENT_STRING, .v = { .s = appendix.data() }, .arraySize = 0 }, + }; + OH_HiSysEvent_Write(DATAMGR_DOMAIN, CoverEventID(dfxCode).c_str(), HISYSEVENT_FAULT, params, + sizeof(params) / sizeof(params[0])); + }); + executors->Execute(std::move(task)); +} + void HiViewAdapter::ReportBehaviour(int dfxCode, const BehaviourMsg &msg, std::shared_ptr executors) { + if (executors == nullptr) { + ZLOGW("executors is nullptr!"); + return; + } ExecutorPool::Task task([dfxCode, msg]() { std::string message; message.append("Behaviour type : ").append(std::to_string(static_cast(msg.behaviourType))) @@ -226,6 +276,10 @@ void HiViewAdapter::ReportBehaviour(int dfxCode, const BehaviourMsg &msg, std::s void HiViewAdapter::ReportDatabaseStatistic(int dfxCode, const DbStat &stat, std::shared_ptr executors) { + if (executors == nullptr) { + ZLOGW("executors is nullptr!"); + return; + } ExecutorPool::Task task([dfxCode, stat]() { std::lock_guard lock(dbMutex_); if (!dbStat_.count(stat.GetKey())) { @@ -302,6 +356,10 @@ void HiViewAdapter::InvokeDbSize() void HiViewAdapter::ReportTrafficStatistic(int dfxCode, const TrafficStat &stat, std::shared_ptr executors) { + if (executors == nullptr) { + ZLOGW("executors is nullptr!"); + return; + } ExecutorPool::Task task([dfxCode, stat]() { std::lock_guard lock(trafficMutex_); auto it = trafficStat_.find(stat.GetKey()); @@ -357,6 +415,10 @@ void HiViewAdapter::InvokeTraffic() void HiViewAdapter::ReportVisitStatistic(int dfxCode, const VisitStat &stat, std::shared_ptr executors) { + if (executors == nullptr) { + ZLOGW("executors is nullptr!"); + return; + } ExecutorPool::Task task([dfxCode, stat]() { std::lock_guard lock(visitMutex_); auto it = visitStat_.find(stat.GetKey()); @@ -406,6 +468,10 @@ void HiViewAdapter::InvokeVisit() void HiViewAdapter::ReportApiPerformanceStatistic(int dfxCode, const ApiPerformanceStat &stat, std::shared_ptr executors) { + if (executors == nullptr) { + ZLOGW("executors is nullptr!"); + return; + } ExecutorPool::Task task([dfxCode, stat]() { std::lock_guard lock(apiPerformanceMutex_); auto it = apiPerformanceStat_.find(stat.GetKey()); diff --git a/datamgr_service/services/distributeddataservice/adapter/dfx/src/hiview_adapter.h b/datamgr_service/services/distributeddataservice/adapter/dfx/src/hiview_adapter.h index 9583563933d45f3b00045e1330b3dce4d0107908..a4c5f66546bbb636c72073447fcd2b14b11c56da 100644 --- a/datamgr_service/services/distributeddataservice/adapter/dfx/src/hiview_adapter.h +++ b/datamgr_service/services/distributeddataservice/adapter/dfx/src/hiview_adapter.h @@ -40,6 +40,7 @@ public: static void ReportFault(int dfxCode, const FaultMsg &msg, std::shared_ptr executors); static void ReportDBFault(int dfxCode, const DBFaultMsg &msg, std::shared_ptr executors); static void ReportCommFault(int dfxCode, const CommFaultMsg &msg, std::shared_ptr executors); + static void ReportArkDataFault(int dfxCode, const ArkDataFaultMsg &msg, std::shared_ptr executors); static void ReportVisitStatistic(int dfxCode, const VisitStat &stat, std::shared_ptr executors); static void ReportTrafficStatistic(int dfxCode, const TrafficStat &stat, std::shared_ptr executors); static void ReportDatabaseStatistic(int dfxCode, const DbStat &stat, std::shared_ptr executors); diff --git a/datamgr_service/services/distributeddataservice/adapter/dfx/src/radar_reporter.cpp b/datamgr_service/services/distributeddataservice/adapter/dfx/src/radar_reporter.cpp index 0a22c8f60eaced073e65f35d05dc9c35e68bbfcd..cec370a56ae76db2d7fd44ff80d2944ddbcf489d 100644 --- a/datamgr_service/services/distributeddataservice/adapter/dfx/src/radar_reporter.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/dfx/src/radar_reporter.cpp @@ -21,10 +21,11 @@ namespace OHOS { namespace DistributedDataDfx { using DmAdapter = OHOS::DistributedData::DeviceManagerAdapter; RadarReporter::RadarReporter(const char *eventName, int32_t scene, const char *bundleName, const char *funcName) - : eventName_(eventName), funcName_(funcName) { + eventName_ = eventName != nullptr ? eventName : ""; + funcName_ = funcName != nullptr ? funcName : ""; radarParam_.scene_ = scene; - radarParam_.bundleName_ = bundleName; + radarParam_.bundleName_ = bundleName != nullptr ? bundleName : ""; radarParam_.res_ = RES_IDLE; Report(radarParam_, funcName_, BEGIN, eventName_); } diff --git a/datamgr_service/services/distributeddataservice/adapter/dfx/src/reporter.cpp b/datamgr_service/services/distributeddataservice/adapter/dfx/src/reporter.cpp index 63102aecb51a04c8bbf5d34153f97958139739d3..35ff346f0b0f884368b711c9ba5eddaa9c206405 100644 --- a/datamgr_service/services/distributeddataservice/adapter/dfx/src/reporter.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/dfx/src/reporter.cpp @@ -18,6 +18,7 @@ #include "fault/database_fault_impl.h" #include "fault/runtime_fault_impl.h" #include "fault/service_fault_impl.h" +#include "fault/cloud_sync_fault_impl.h" #include "statistic/traffic_statistic_impl.h" #include "statistic/visit_statistic_impl.h" @@ -55,6 +56,13 @@ FaultReporter* Reporter::RuntimeFault() return &runtimeFault; } +FaultReporter* Reporter::CloudSyncFault() +{ + static CloudSyncFaultImpl cloudSyncFault; + cloudSyncFault.SetThreadPool(executors_); + return &cloudSyncFault; +} + FaultReporter* Reporter::ServiceFault() { static ServiceFaultImpl serviceFault; diff --git a/datamgr_service/services/distributeddataservice/adapter/dfx/test/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/dfx/test/BUILD.gn index f866b02e53a63f5eafa6d3970a5d63969f6d0983..e355fb9f0d9742fe32b0fc2cacca3d83fc07bf27 100644 --- a/datamgr_service/services/distributeddataservice/adapter/dfx/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/dfx/test/BUILD.gn @@ -24,13 +24,8 @@ config("module_dfx_mst_config") { "../src/fault", "../src/statistic", "../../include/log", - "../../include/autils", + "../../include/utils", "../../include/dfx", - "${kv_store_path}/interfaces/inner_api/distributeddata/include", - "//commonlibrary/c_utils/base/include", - "//utils/system/safwk/native/include", - "//third_party/openssl/include/", - "//foundation/distributeddatamgr/kv_store/frameworks/common", ] } @@ -47,10 +42,12 @@ ohos_unittest("DistributeddataDfxMSTTest") { "hisysevent:libhisysevent", "hitrace:hitrace_meter", "kv_store:distributeddata_inner", + "openssl:libcrypto_shared", ] ldflags = [ "-Wl,--exclude-libs,ALL" ] deps = [ - "../../dfx:distributeddata_dfx_static", + "${data_service_path}/adapter/utils:distributeddata_utils", + "../../dfx:distributeddata_dfx", "//third_party/googletest:gtest_main", "//third_party/openssl:libcrypto_shared", ] @@ -68,12 +65,8 @@ config("module_dfx_config") { "../src/fault", "../src/statistic", "../../include/log", - "../../include/autils", + "../../include/utils", "../../include/dfx", - "//commonlibrary/c_utils/base/include", - "//utils/system/safwk/native/include", - "//third_party/openssl/include/", - "//foundation/distributeddatamgr/kv_store/frameworks/common", ] } @@ -82,6 +75,7 @@ ohos_unittest("DistributeddataDfxUTTest") { sources = [ "../src/behaviour/behaviour_reporter_impl.cpp", + "../src/fault/cloud_sync_fault_impl.cpp", "../src/fault/communication_fault_impl.cpp", "../src/fault/database_fault_impl.cpp", "../src/fault/fault_reporter.cpp", @@ -106,9 +100,11 @@ ohos_unittest("DistributeddataDfxUTTest") { "hisysevent:libhisysevent", "hitrace:hitrace_meter", "kv_store:distributeddata_inner", + "openssl:libcrypto_shared", ] ldflags = [ "-Wl,--exclude-libs,ALL" ] deps = [ + "${data_service_path}/adapter/utils:distributeddata_utils", "//third_party/googletest:gtest_main", "//third_party/openssl:libcrypto_shared", ] diff --git a/datamgr_service/services/distributeddataservice/adapter/dfx/test/unittest/distributeddata_dfx_ut_test.cpp b/datamgr_service/services/distributeddataservice/adapter/dfx/test/unittest/distributeddata_dfx_ut_test.cpp index d79bca483a71112ad80ed708818f53c0eac93580..d1b20ccdad451597e850f0a7543797933e99a73d 100644 --- a/datamgr_service/services/distributeddataservice/adapter/dfx/test/unittest/distributeddata_dfx_ut_test.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/dfx/test/unittest/distributeddata_dfx_ut_test.cpp @@ -22,7 +22,7 @@ using namespace testing::ext; using namespace OHOS::DistributedDataDfx; -class DistributedataDfxUTTest : public testing::Test { +class DistributeddataDfxUTTest : public testing::Test { public: static void SetUpTestCase(void); @@ -33,28 +33,24 @@ public: void TearDown(); }; -void DistributedataDfxUTTest::SetUpTestCase() +void DistributeddataDfxUTTest::SetUpTestCase() { FakeHivew::Clear(); -} - -void DistributedataDfxUTTest::TearDownTestCase() -{ - FakeHivew::Clear(); -} - -void DistributedataDfxUTTest::SetUp() -{ size_t max = 12; size_t min = 5; Reporter::GetInstance()->SetThreadPool(std::make_shared(max, min)); } -void DistributedataDfxUTTest::TearDown() +void DistributeddataDfxUTTest::TearDownTestCase() { Reporter::GetInstance()->SetThreadPool(nullptr); + FakeHivew::Clear(); } +void DistributeddataDfxUTTest::SetUp() {} + +void DistributeddataDfxUTTest::TearDown() {} + /** * @tc.name: Dfx001 * @tc.desc: send data to 1 device, then check reporter message. @@ -62,7 +58,7 @@ void DistributedataDfxUTTest::TearDown() * @tc.require: AR000CQE1L SR000CQE1J * @tc.author: hongbo */ -HWTEST_F(DistributedataDfxUTTest, Dfx001, TestSize.Level0) +HWTEST_F(DistributeddataDfxUTTest, Dfx001, TestSize.Level0) { /** * @tc.steps: step1. getcommunicationFault instance @@ -104,7 +100,7 @@ HWTEST_F(DistributedataDfxUTTest, Dfx001, TestSize.Level0) * @tc.require: AR000CQE1L AR000CQE1K SR000CQE1J * @tc.author: hongbo */ -HWTEST_F(DistributedataDfxUTTest, Dfx002, TestSize.Level0) +HWTEST_F(DistributeddataDfxUTTest, Dfx002, TestSize.Level0) { FakeHivew::Clear(); /** @@ -140,7 +136,7 @@ HWTEST_F(DistributedataDfxUTTest, Dfx002, TestSize.Level0) * @tc.require: AR000CQE1O SR000CQE1J * @tc.author: hongbo */ -HWTEST_F(DistributedataDfxUTTest, Dfx003, TestSize.Level0) +HWTEST_F(DistributeddataDfxUTTest, Dfx003, TestSize.Level0) { /** * @tc.steps: step1. get database reporter instance. @@ -165,7 +161,7 @@ HWTEST_F(DistributedataDfxUTTest, Dfx003, TestSize.Level0) * @tc.require: AR000CQE1L SR000CQE1J * @tc.author: hongbo */ -HWTEST_F(DistributedataDfxUTTest, Dfx004, TestSize.Level0) +HWTEST_F(DistributeddataDfxUTTest, Dfx004, TestSize.Level0) { /** * @tc.steps: step1. Get runtime fault instance. @@ -202,7 +198,7 @@ HWTEST_F(DistributedataDfxUTTest, Dfx004, TestSize.Level0) * @tc.require: AR000CQE1P SR000CQE1J * @tc.author: hongbo */ -HWTEST_F(DistributedataDfxUTTest, Dfx005, TestSize.Level0) +HWTEST_F(DistributeddataDfxUTTest, Dfx005, TestSize.Level0) { /** * @tc.steps:step1. send data to 1 device @@ -228,7 +224,7 @@ HWTEST_F(DistributedataDfxUTTest, Dfx005, TestSize.Level0) * @tc.require: AR000CQE1N SR000CQE1J * @tc.author: hongbo */ -HWTEST_F(DistributedataDfxUTTest, Dfx006, TestSize.Level0) +HWTEST_F(DistributeddataDfxUTTest, Dfx006, TestSize.Level0) { /** * @tc.steps:step1. create call interface statistic instance @@ -258,7 +254,7 @@ HWTEST_F(DistributedataDfxUTTest, Dfx006, TestSize.Level0) * @tc.require: AR000DPVGP SR000DPVGH * @tc.author: liwei */ -HWTEST_F(DistributedataDfxUTTest, Dfx007, TestSize.Level0) +HWTEST_F(DistributeddataDfxUTTest, Dfx007, TestSize.Level0) { /** * @tc.steps:step1. create call api perforamnce statistic instance @@ -283,7 +279,7 @@ HWTEST_F(DistributedataDfxUTTest, Dfx007, TestSize.Level0) * @tc.type: send data * @tc.author: nhj */ -HWTEST_F(DistributedataDfxUTTest, Dfx008, TestSize.Level0) +HWTEST_F(DistributeddataDfxUTTest, Dfx008, TestSize.Level0) { /** * @tc.steps: step1. get database fault report instance @@ -321,7 +317,7 @@ HWTEST_F(DistributedataDfxUTTest, Dfx008, TestSize.Level0) * @tc.type: CreateKvStore test * @tc.author: nhj */ -HWTEST_F(DistributedataDfxUTTest, Dfx009, TestSize.Level0) +HWTEST_F(DistributeddataDfxUTTest, Dfx009, TestSize.Level0) { /** * @tc.steps: step1. Get runtime fault instance. @@ -357,7 +353,7 @@ HWTEST_F(DistributedataDfxUTTest, Dfx009, TestSize.Level0) * @tc.type: check database file size. * @tc.author: nhj */ -HWTEST_F(DistributedataDfxUTTest, Dfx010, TestSize.Level0) +HWTEST_F(DistributeddataDfxUTTest, Dfx010, TestSize.Level0) { /** * @tc.steps: step1. get database reporter instance. @@ -389,7 +385,7 @@ HWTEST_F(DistributedataDfxUTTest, Dfx010, TestSize.Level0) * @tc.type: Send data * @tc.author: nhj */ -HWTEST_F(DistributedataDfxUTTest, Dfx011, TestSize.Level0) +HWTEST_F(DistributeddataDfxUTTest, Dfx011, TestSize.Level0) { /** * @tc.steps: step1. get database fault report instance @@ -433,7 +429,7 @@ HWTEST_F(DistributedataDfxUTTest, Dfx011, TestSize.Level0) * @tc.type: send data * @tc.author: nhj */ -HWTEST_F(DistributedataDfxUTTest, Dfx012, TestSize.Level0) +HWTEST_F(DistributeddataDfxUTTest, Dfx012, TestSize.Level0) { /** * @tc.steps:step1. send data to 1 device @@ -462,7 +458,7 @@ HWTEST_F(DistributedataDfxUTTest, Dfx012, TestSize.Level0) * @tc.type: * @tc.author: nhj */ -HWTEST_F(DistributedataDfxUTTest, Dfx013, TestSize.Level0) +HWTEST_F(DistributeddataDfxUTTest, Dfx013, TestSize.Level0) { /** * @tc.steps:step1. create call api perforamnce statistic instance diff --git a/datamgr_service/services/distributeddataservice/adapter/include/communicator/communication_provider.h b/datamgr_service/services/distributeddataservice/adapter/include/communicator/communication_provider.h index 94cd0ed4e97324e189e7bfb7204ef3c011810b2a..07cfb231c2ea71d112c192ee5f263d7a082ed778 100644 --- a/datamgr_service/services/distributeddataservice/adapter/include/communicator/communication_provider.h +++ b/datamgr_service/services/distributeddataservice/adapter/include/communicator/communication_provider.h @@ -65,6 +65,8 @@ public: virtual Status Broadcast(const PipeInfo &pipeInfo, const LevelInfo &levelInfo) = 0; virtual int32_t ListenBroadcastMsg(const PipeInfo &pipeInfo, std::function listener) = 0; + + virtual Status ReuseConnect(const PipeInfo &pipeInfo, const DeviceId &deviceId) = 0; }; } // namespace AppDistributedKv } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/adapter/include/communicator/device_manager_adapter.h b/datamgr_service/services/distributeddataservice/adapter/include/communicator/device_manager_adapter.h index 7edbd0fd1a598c913b4eef55cf407578567dc8c9..a50783ae1d148c07b41d3a1286ddf56959fdef71 100644 --- a/datamgr_service/services/distributeddataservice/adapter/include/communicator/device_manager_adapter.h +++ b/datamgr_service/services/distributeddataservice/adapter/include/communicator/device_manager_adapter.h @@ -37,13 +37,6 @@ public: DEVICE_ONREADY, DEVICE_BUTT }; - enum NetworkType { - NONE, - CELLULAR, - WIFI, - ETHERNET, - OTHER - }; using DmDeviceInfo = OHOS::DistributedHardware::DmDeviceInfo; using DeviceInfo = OHOS::AppDistributedKv::DeviceInfo; using PipeInfo = OHOS::AppDistributedKv::PipeInfo; @@ -76,12 +69,12 @@ public: static std::vector ToUUID(std::vector devices); std::string ToNetworkID(const std::string &id); void NotifyReadyEvent(const std::string &uuid); - bool IsNetworkAvailable(); - NetworkType GetNetworkType(bool retrieve = false); int32_t GetAuthType(const std::string& id); bool IsSameAccount(const std::string &id); bool IsSameAccount(const AccessCaller &accCaller, const AccessCallee &accCallee); bool CheckAccessControl(const AccessCaller &accCaller, const AccessCallee &accCallee); + void Offline(const DmDeviceInfo &info); + void OnReady(const DmDeviceInfo &info); friend class DataMgrDmStateCall; friend class NetConnCallbackObserver; @@ -89,19 +82,15 @@ private: DeviceManagerAdapter(); ~DeviceManagerAdapter(); std::function RegDevCallback(); - bool RegOnNetworkChange(); - NetworkType SetNet(NetworkType netWorkType); - NetworkType RefreshNet(); bool GetDeviceInfo(const DmDeviceInfo &dmInfo, DeviceInfo &dvInfo); void SaveDeviceInfo(const DeviceInfo &deviceInfo, const AppDistributedKv::DeviceChangeType &type); void InitDeviceInfo(bool onlyCache = true); DeviceInfo GetLocalDeviceInfo(); DeviceInfo GetDeviceInfoFromCache(const std::string &id); void Online(const DmDeviceInfo &info); - void Offline(const DmDeviceInfo &info); void OnChanged(const DmDeviceInfo &info); - void OnReady(const DmDeviceInfo &info); std::vector GetObservers(); + void ResetLocalDeviceInfo(); static inline uint64_t GetTimeStamp() { return std::chrono::duration_cast( @@ -119,11 +108,6 @@ private: static constexpr int32_t OH_OS_TYPE = 10; ConcurrentMap syncTask_ {}; std::shared_ptr executors_; - static constexpr int32_t EFFECTIVE_DURATION = 30 * 1000; // ms - static constexpr int32_t NET_LOST_DURATION = 10 * 1000; // ms - uint64_t expireTime_ = 0; - uint64_t netLostTime_ = 0; - NetworkType defaultNetwork_ = NONE; ConcurrentMap> readyDevices_; }; } // namespace DistributedData diff --git a/datamgr_service/services/distributeddataservice/adapter/include/communicator/process_communicator_impl.h b/datamgr_service/services/distributeddataservice/adapter/include/communicator/process_communicator_impl.h index 4620c0fc4df645a87f30ea4d3fa7b66eb46fd90d..a196c69b0d427501ab360f6fb77a34917392f3e3 100644 --- a/datamgr_service/services/distributeddataservice/adapter/include/communicator/process_communicator_impl.h +++ b/datamgr_service/services/distributeddataservice/adapter/include/communicator/process_communicator_impl.h @@ -36,8 +36,8 @@ public: using RouteHeadHandlerCreator = std::function(const DistributedDB::ExtendInfo &info)>; - API_EXPORT ProcessCommunicatorImpl(); - API_EXPORT explicit ProcessCommunicatorImpl(RouteHeadHandlerCreator handlerCreator); + API_EXPORT static ProcessCommunicatorImpl *GetInstance(); + API_EXPORT void SetRouteHeadHandlerCreator(RouteHeadHandlerCreator handlerCreator); API_EXPORT ~ProcessCommunicatorImpl() override; DBStatus Start(const std::string &processLabel) override; @@ -64,10 +64,12 @@ public: API_EXPORT DBStatus CheckAndGetDataHeadInfo( const uint8_t *data, uint32_t dataLen, uint32_t &headLen, std::vector &users) override; + Status ReuseConnect(const DeviceId &deviceId); + private: void OnMessage(const DeviceInfo &info, const uint8_t *ptr, const int size, const PipeInfo &pipeInfo) const override; - + ProcessCommunicatorImpl(); std::string thisProcessLabel_; OnDeviceChange onDeviceChangeHandler_; OnDataReceive onDataReceiveHandler_; diff --git a/datamgr_service/services/distributeddataservice/adapter/include/dfx/dfx_types.h b/datamgr_service/services/distributeddataservice/adapter/include/dfx/dfx_types.h index cbc0117d044d6c3c2cbc5070c5e1f0042f28c3d7..8fd03bb76485fa80aa6a4cc61d1dcaae382d5ac3 100644 --- a/datamgr_service/services/distributeddataservice/adapter/include/dfx/dfx_types.h +++ b/datamgr_service/services/distributeddataservice/adapter/include/dfx/dfx_types.h @@ -16,8 +16,10 @@ #ifndef DISTRIBUTEDDATAMGR_DFX_TYPES_H #define DISTRIBUTEDDATAMGR_DFX_TYPES_H -#include +#include #include +#include + #include "db_meta_callback_delegate.h" namespace OHOS { @@ -25,6 +27,10 @@ namespace DistributedDataDfx { struct ModuleName { static const inline std::string DEVICE = "DEVICE"; static const inline std::string USER = "USER"; + static const inline std::string RDB_STORE = "RDB_STORE"; + static const inline std::string KV_STORE = "KV_STORE"; + static const inline std::string CLOUD_SERVER = "CLOUD_SERVER"; + static const inline std::string CLOUD_SYNC_CALLBACK = "CLOUD_SYNC_CALLBACK"; }; enum class Fault { @@ -65,6 +71,23 @@ enum class Fault { DF_DB_DAMAGE = 60, DF_DB_REKEY_FAILED = 61, DF_DB_CORRUPTED = 62, + + // Cloud Sync Fault + CSF_CLOUD_INFO = 70, + CSF_SUBSCRIBE = 71, + CSF_UNSUBSCRIBE = 72, + CSF_APP_SCHEMA = 73, + CSF_CONNECT_CLOUD_ASSET_LOADER = 74, + CSF_CONNECT_CLOUD_DB = 75, + CSF_BATCH_INSERT = 76, + CSF_BATCH_UPDATE = 77, + CSF_BATCH_DELETE = 78, + CSF_BATCH_QUERY = 79, + CSF_LOCK = 80, + CSF_SHARE = 81, + CSF_DOWNLOAD_ASSETS = 82, + CSF_GS_CREATE_DISTRIBUTED_TABLE = 83, + CSF_GS_CLOUD_SYNC = 84, }; enum class FaultType { @@ -108,6 +131,16 @@ struct CommFaultMsg { std::vector errorCode; }; +struct ArkDataFaultMsg { + std::string faultType; + std::string bundleName; + std::string moduleName; + std::string storeName; + std::string businessType; + int32_t errorType; + std::string appendixMsg; +}; + struct SecurityPermissionsMsg { std::string userId; std::string appId; diff --git a/datamgr_service/services/distributeddataservice/adapter/include/dfx/fault_reporter.h b/datamgr_service/services/distributeddataservice/adapter/include/dfx/fault_reporter.h index 180d84e2358beaf2e89bc4ac8f84dcc8fc6ab325..073863028b7761519268719d2eb75c564c57b402 100644 --- a/datamgr_service/services/distributeddataservice/adapter/include/dfx/fault_reporter.h +++ b/datamgr_service/services/distributeddataservice/adapter/include/dfx/fault_reporter.h @@ -25,6 +25,7 @@ public: KVSTORE_API virtual ReportStatus Report(const FaultMsg &msg) = 0; KVSTORE_API virtual ReportStatus Report(const CommFaultMsg &msg) = 0; KVSTORE_API virtual ReportStatus Report(const DBFaultMsg &ms) = 0; + KVSTORE_API virtual ReportStatus Report(const ArkDataFaultMsg &msg){ return ReportStatus::SUCCESS; }; KVSTORE_API virtual ~FaultReporter() {} }; } // namespace DistributedDataDfx diff --git a/datamgr_service/services/distributeddataservice/adapter/include/dfx/radar_reporter.h b/datamgr_service/services/distributeddataservice/adapter/include/dfx/radar_reporter.h index 7a60cc064c10ea002fca58f968477249b0e74e31..450bcdb8090b448e60fe2e0cbd2d641ff5d68bd3 100644 --- a/datamgr_service/services/distributeddataservice/adapter/include/dfx/radar_reporter.h +++ b/datamgr_service/services/distributeddataservice/adapter/include/dfx/radar_reporter.h @@ -71,8 +71,8 @@ struct RadarParam { int32_t stage_ = GENERAL_STAGE; uint64_t syncId_ = 0; int32_t triggerMode_ = 0; - uint64_t changeCount = 0; int32_t errCode_ = 0; + uint64_t changeCount = 0; int32_t res_ = RES_SUCCESS; }; diff --git a/datamgr_service/services/distributeddataservice/adapter/include/dfx/reporter.h b/datamgr_service/services/distributeddataservice/adapter/include/dfx/reporter.h index de60c0e848f15bdbd8484fc883f517308abf17aa..0ecf7c93b304cea985eeb4f0f22c810914d6fdf4 100644 --- a/datamgr_service/services/distributeddataservice/adapter/include/dfx/reporter.h +++ b/datamgr_service/services/distributeddataservice/adapter/include/dfx/reporter.h @@ -33,6 +33,7 @@ public: KVSTORE_API FaultReporter* RuntimeFault(); KVSTORE_API FaultReporter* DatabaseFault(); KVSTORE_API FaultReporter* CommunicationFault(); + KVSTORE_API FaultReporter* CloudSyncFault(); KVSTORE_API StatisticReporter* DatabaseStatistic(); KVSTORE_API StatisticReporter* VisitStatistic(); @@ -47,6 +48,7 @@ public: ServiceFault(); RuntimeFault(); DatabaseFault(); + CloudSyncFault(); CommunicationFault(); DatabaseStatistic(); VisitStatistic(); diff --git a/datamgr_service/services/distributeddataservice/adapter/include/screenlock/screen_lock.h b/datamgr_service/services/distributeddataservice/adapter/include/screenlock/screen_lock.h index db40555e3d797bac5d535b459933060907d7274d..375957abf5c9b2999d6786898ea6d561e65b3fc0 100644 --- a/datamgr_service/services/distributeddataservice/adapter/include/screenlock/screen_lock.h +++ b/datamgr_service/services/distributeddataservice/adapter/include/screenlock/screen_lock.h @@ -15,15 +15,47 @@ #ifndef DISTRIBUTEDDATAMGR_ADAPTER_SCREEN_LOCK_H #define DISTRIBUTEDDATAMGR_ADAPTER_SCREEN_LOCK_H -#include "visibility.h" +#include "common_event_manager.h" +#include "common_event_subscriber.h" +#include "common_event_support.h" +#include "concurrent_map.h" #include "screen/screen_manager.h" namespace OHOS { namespace DistributedData { +using namespace OHOS::EventFwk; +using EventCallback = std::function; + +class EventSubscriber final : public CommonEventSubscriber { +public: + ~EventSubscriber() {} + explicit EventSubscriber(const CommonEventSubscribeInfo &info); + void SetEventCallback(EventCallback callback); + void OnReceiveEvent(const CommonEventData &event) override; +private: + static constexpr const char *USER_ID = "userId"; + static constexpr int32_t INVALID_USER = -1; + EventCallback eventCallback_ {}; +}; + class ScreenLock : public ScreenManager { public: - API_EXPORT bool IsLocked(); + bool IsLocked(); + void Subscribe(std::shared_ptr observer) __attribute__((no_sanitize("cfi"))); + void Unsubscribe(std::shared_ptr observer) __attribute__((no_sanitize("cfi"))); + void BindExecutor(std::shared_ptr executors); + void SubscribeScreenEvent(); + void UnsubscribeScreenEvent(); + +private: + static constexpr int32_t MAX_RETRY_TIME = 300; + static constexpr int32_t RETRY_WAIT_TIME_S = 1; + void NotifyScreenUnlocked(int32_t user); + ExecutorPool::Task GetTask(uint32_t retry); + ConcurrentMap> observerMap_{}; + std::shared_ptr executors_; + std::shared_ptr eventSubscriber_{}; }; } // namespace DistributedData } // namespace OHOS -#endif //DISTRIBUTEDDATAMGR_ADAPTER_SCREEN_LOCK_H +#endif //DISTRIBUTEDDATAMGR_ADAPTER_SCREEN_LOCK_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/adapter/include/utils/kvstore_utils.h b/datamgr_service/services/distributeddataservice/adapter/include/utils/kvstore_utils.h index 69336f8336d041bea9aa0b0484907fc7fe9d07d9..d521bf31757a2448ff15fb7c3a8333a2637df60c 100644 --- a/datamgr_service/services/distributeddataservice/adapter/include/utils/kvstore_utils.h +++ b/datamgr_service/services/distributeddataservice/adapter/include/utils/kvstore_utils.h @@ -19,7 +19,6 @@ #include #include #include "visibility.h" -#include "communication_provider.h" namespace OHOS { namespace DistributedKv { diff --git a/datamgr_service/services/distributeddataservice/adapter/include/utils/time_utils.h b/datamgr_service/services/distributeddataservice/adapter/include/utils/time_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..b7ca61819aee0159eae18252a24df1a0f1d42fff --- /dev/null +++ b/datamgr_service/services/distributeddataservice/adapter/include/utils/time_utils.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 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_FRAMEWORKS_TIME_UTILS_H +#define OHOS_DISTRIBUTED_DATA_FRAMEWORKS_TIME_UTILS_H + +#include +#include +#include + +namespace OHOS { +namespace DistributedKv { +class TimeUtils { +public: + static std::string GetCurSysTimeWithMs(); + static std::string GetTimeWithMs(time_t sec, int64_t nsec); +}; + +} // namespace DistributedKv +} // namespace OHOS +#endif \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/adapter/screenlock/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/screenlock/BUILD.gn index cb30d1da49819d8bc735ede6017e23100b23ca80..ed1fd3913264cbc69ab99c4a525b120fc0793093 100644 --- a/datamgr_service/services/distributeddataservice/adapter/screenlock/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/screenlock/BUILD.gn @@ -13,7 +13,7 @@ import("//build/ohos.gni") import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") -ohos_static_library("distributeddata_screenlock_static") { +ohos_source_set("distributeddata_screenlock") { branch_protector_ret = "pac_ret" sanitize = { cfi = true @@ -32,8 +32,13 @@ ohos_static_library("distributeddata_screenlock_static") { "${data_service_path}/framework/include", ] + deps = [ "${data_service_path}/adapter/account:distributeddata_account" ] + external_deps = [ "c_utils:utils", + "common_event_service:cesfwk_innerkits", + "hilog:libhilog", + "kv_store:datamgr_common", "screenlock_mgr:screenlock_client", ] subsystem_name = "distributeddatamgr" diff --git a/datamgr_service/services/distributeddataservice/adapter/screenlock/src/screen_lock.cpp b/datamgr_service/services/distributeddataservice/adapter/screenlock/src/screen_lock.cpp index a83e2bb49fb0cada46f8fa11e5afeb5163b77dcc..7cac20cbfe4f563f221275c8f31b23ddb0b7bf8e 100644 --- a/datamgr_service/services/distributeddataservice/adapter/screenlock/src/screen_lock.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/screenlock/src/screen_lock.cpp @@ -13,9 +13,11 @@ * limitations under the License. */ -#define LOG_TAG "screen_lock" +#define LOG_TAG "ScreenLock" #include "screen_lock.h" +#include "account/account_delegate.h" +#include "log_print.h" #include "screenlock_manager.h" namespace OHOS::DistributedData { @@ -30,4 +32,107 @@ bool ScreenLock::IsLocked() } return manager->IsScreenLocked(); } + +EventSubscriber::EventSubscriber(const CommonEventSubscribeInfo &info) : CommonEventSubscriber(info) +{ +} + +void EventSubscriber::OnReceiveEvent(const CommonEventData &event) +{ + const auto want = event.GetWant(); + const auto action = want.GetAction(); + if (action != CommonEventSupport::COMMON_EVENT_SCREEN_UNLOCKED) { + return; + } + ZLOGI("Want Action is %{public}s", action.c_str()); + auto user = want.GetIntParam(USER_ID, INVALID_USER); + if (user == INVALID_USER) { + std::vector users; + AccountDelegate::GetInstance()->QueryForegroundUsers(users); + if (users.empty()) { + return; + } + user = users[0]; + } + eventCallback_(user); +} + +void EventSubscriber::SetEventCallback(EventCallback callback) +{ + eventCallback_ = callback; +} + +void ScreenLock::Subscribe(std::shared_ptr observer) +{ + if (observer == nullptr || observer->GetName().empty() || observerMap_.Contains(observer->GetName())) { + return; + } + if (!observerMap_.Insert(observer->GetName(), observer)) { + ZLOGE("fail, name is %{public}s", observer->GetName().c_str()); + } +} + +void ScreenLock::Unsubscribe(std::shared_ptr observer) +{ + if (observer == nullptr || observer->GetName().empty() || !observerMap_.Contains(observer->GetName())) { + return; + } + if (!observerMap_.Erase(observer->GetName())) { + ZLOGD("fail, name is %{public}s", observer->GetName().c_str()); + } +} + +void ScreenLock::SubscribeScreenEvent() +{ + ZLOGI("Subscribe screen event listener start."); + if (eventSubscriber_ == nullptr) { + MatchingSkills matchingSkills; + matchingSkills.AddEvent(CommonEventSupport::COMMON_EVENT_SCREEN_UNLOCKED); + CommonEventSubscribeInfo info(matchingSkills); + eventSubscriber_ = std::make_shared(info); + eventSubscriber_->SetEventCallback([this](int32_t user) { + NotifyScreenUnlocked(user); + }); + } + executors_->Execute(GetTask(0)); +} + +void ScreenLock::UnsubscribeScreenEvent() +{ + auto res = CommonEventManager::UnSubscribeCommonEvent(eventSubscriber_); + if (!res) { + ZLOGW("unregister screen event fail res:%d", res); + } +} + +void ScreenLock::NotifyScreenUnlocked(int32_t user) +{ + observerMap_.ForEach([user](const auto &key, auto &val) { + val->OnScreenUnlocked(user); + return false; + }); +} + +void ScreenLock::BindExecutor(std::shared_ptr executors) +{ + executors_ = executors; +} + +ExecutorPool::Task ScreenLock::GetTask(uint32_t retry) +{ + return [this, retry] { + auto result = CommonEventManager::SubscribeCommonEvent(eventSubscriber_); + if (result) { + ZLOGI("success to register subscriber."); + return; + } + ZLOGD("fail to register subscriber, error:%{public}d, time:%{public}d", result, retry); + + if (retry + 1 > MAX_RETRY_TIME) { + ZLOGE("fail to register subscriber!"); + return; + } + executors_->Schedule(std::chrono::seconds(RETRY_WAIT_TIME_S), GetTask(retry + 1)); + }; +} } // namespace OHOS::DistributedData \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/adapter/screenlock/test/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/screenlock/test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..8a1c3084cbfabe1634c0ecdf7ac96ab91539936c --- /dev/null +++ b/datamgr_service/services/distributeddataservice/adapter/screenlock/test/BUILD.gn @@ -0,0 +1,57 @@ +# Copyright (c) 2024 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. +import("//build/test.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") +module_output_path = "datamgr_service/distributeddatafwk" + +############################################################################### +ohos_unittest("ScreenLockTest") { + module_out_path = module_output_path + + sources = [ + "${data_service_path}/adapter/screenlock/src/screen_lock.cpp", + "${data_service_path}/framework/account/account_delegate.cpp", + "${data_service_path}/framework/screen/screen_manager.cpp", + "screen_lock_test.cpp", + ] + include_dirs = [ + "${data_service_path}/adapter/include/screenlock", + "${data_service_path}/framework/include", + "${data_service_path}/framework/include/account", + ] + cflags = [ + "-Dprivate=public", + "-Dprotected=public", + "-Werror", + ] + + external_deps = [ + "c_utils:utils", + "common_event_service:cesfwk_innerkits", + "googletest:gtest_main", + "hilog:libhilog", + "kv_store:distributeddata_inner", + "screenlock_mgr:screenlock_client", + ] + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] +} + +############################################################################### +group("unittest") { + testonly = true + + deps = [] + + deps += [ ":ScreenLockTest" ] +} +############################################################################### diff --git a/datamgr_service/services/distributeddataservice/adapter/screenlock/test/screen_lock_test.cpp b/datamgr_service/services/distributeddataservice/adapter/screenlock/test/screen_lock_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be5a5f5f1b1c174aa2bbd0ed270e72bb83a316a8 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/adapter/screenlock/test/screen_lock_test.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2024 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 "screen_lock.h" + +#include +namespace { +using namespace OHOS::DistributedData; +using namespace testing::ext; +class ScreenLockObserver : public ScreenManager::Observer { +public: + void OnScreenUnlocked(int32_t user) override + { + } + + std::string GetName() override + { + return name_; + } + + void SetName(const std::string &name) + { + name_ = name; + } + +private: + std::string name_ = "screenTestObserver"; +}; + +class ScreenLockTest : public testing::Test { +public: + static void SetUpTestCase(void) + { + } + static void TearDownTestCase(void) + { + } + void SetUp() + { + } + void TearDown() + { + } +}; + +/** +* @tc.name: Subscribe001 +* @tc.desc: invalid param +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(ScreenLockTest, Subscribe001, TestSize.Level0) +{ + auto screenLock = std::make_shared(); + screenLock->ScreenManager::Subscribe(nullptr); + screenLock->Subscribe(nullptr); + EXPECT_TRUE(screenLock->observerMap_.Empty()); + auto observer = std::make_shared(); + observer->SetName(""); + screenLock->Subscribe(observer); + EXPECT_TRUE(screenLock->observerMap_.Empty()); +} + +/** +* @tc.name: Subscribe002 +* @tc.desc: valid param +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(ScreenLockTest, Subscribe002, TestSize.Level0) +{ + auto screenLock = std::make_shared(); + auto observer = std::make_shared(); + screenLock->Subscribe(observer); + EXPECT_TRUE(screenLock->observerMap_.Contains(observer->GetName())); + screenLock->Subscribe(observer); + EXPECT_EQ(screenLock->observerMap_.Size(), 1); +} + +/** +* @tc.name: Unsubscribe001 +* @tc.desc: test normal unsubscribe +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(ScreenLockTest, Unsubscribe001, TestSize.Level0) +{ + auto screenLock = std::make_shared(); + screenLock->ScreenManager::Unsubscribe(nullptr); + auto observer = std::make_shared(); + screenLock->Subscribe(observer); + EXPECT_EQ(screenLock->observerMap_.Size(), 1); + screenLock->Unsubscribe(observer); + EXPECT_TRUE(screenLock->observerMap_.Empty()); +} + +/** +* @tc.name: SubscribeScreenEvent001 +* @tc.desc: subscribe ScreenEvent +* @tc.type: FUNC +* @tc.author: +*/ +HWTEST_F(ScreenLockTest, SubscribeScreenEvent001, TestSize.Level0) +{ + auto executor = std::make_shared(12, 5); + auto screenLock = std::make_shared(); + screenLock->BindExecutor(executor); + ASSERT_NE(screenLock->executors_, nullptr); + EXPECT_EQ(screenLock->eventSubscriber_, nullptr); + screenLock->ScreenManager::SubscribeScreenEvent(); + screenLock->SubscribeScreenEvent(); + EXPECT_NE(screenLock->eventSubscriber_, nullptr); + screenLock->ScreenManager::UnsubscribeScreenEvent(); + screenLock->UnsubscribeScreenEvent(); +} +} // namespace \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/adapter/test/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/test/BUILD.gn index f85ada83e4e6922db5824e910fc8c5e187a4b800..4ae23205977ec4a13f81c1c480a947f205feaa5e 100644 --- a/datamgr_service/services/distributeddataservice/adapter/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/test/BUILD.gn @@ -21,7 +21,7 @@ group("unittest") { "../account/test:unittest", "../communicator/test:unittest", "../dfx/test:unittest", - "../permission/test:unittest", + "../screenlock/test:unittest", ] } diff --git a/datamgr_service/services/distributeddataservice/adapter/utils/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/utils/BUILD.gn index eb32cd549203262832ddb276a2b216ad5118a873..7ae119fd22f51b150e92b44d572996f9beb5c21f 100644 --- a/datamgr_service/services/distributeddataservice/adapter/utils/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/utils/BUILD.gn @@ -13,7 +13,7 @@ import("//build/ohos.gni") import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") -ohos_static_library("distributeddata_utils_static") { +ohos_source_set("distributeddata_utils") { branch_protector_ret = "pac_ret" sanitize = { cfi = true @@ -22,7 +22,10 @@ ohos_static_library("distributeddata_utils_static") { boundary_sanitize = true ubsan = true } - sources = [ "src/kvstore_utils.cpp" ] + sources = [ + "src/kvstore_utils.cpp", + "src/time_utils.cpp", + ] cflags_cc = [ "-fvisibility=hidden" ] @@ -36,8 +39,6 @@ ohos_static_library("distributeddata_utils_static") { "../include/log", "../include/communicator", "../include/dfx", - "${kv_store_common_path}", - "${kv_store_path}/interfaces/innerkits/distributeddata/include", ] ldflags = [ "-Wl,--exclude-libs,ALL" ] diff --git a/datamgr_service/services/distributeddataservice/adapter/utils/src/time_utils.cpp b/datamgr_service/services/distributeddataservice/adapter/utils/src/time_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a5f0d9d83c08473a7f5640a88ec57b46403e6077 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/adapter/utils/src/time_utils.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025 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 "TimeUtils" + +#include "time_utils.h" + +#include +#include +#include + +namespace OHOS { +namespace DistributedKv { +constexpr int MAX_TIME_BUF_LEN = 32; +constexpr int MILLISECONDS_LEN = 3; +constexpr int NANO_TO_MILLI = 1000000; +constexpr int MILLI_PRE_SEC = 1000; + +std::string TimeUtils::GetCurSysTimeWithMs() +{ + auto now = std::chrono::system_clock::now(); + std::time_t time = std::chrono::system_clock::to_time_t(now); + std::chrono::nanoseconds nsec = std::chrono::duration_cast(now.time_since_epoch()); + return GetTimeWithMs(time, nsec.count()); +} + +std::string TimeUtils::GetTimeWithMs(time_t sec, int64_t nsec) +{ + std::stringstream oss; + char buffer[MAX_TIME_BUF_LEN] = { 0 }; + std::tm local_time; + localtime_r(&sec, &local_time); + std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &local_time); + oss << buffer << '.' << std::setfill('0') << std::setw(MILLISECONDS_LEN) << (nsec / NANO_TO_MILLI) % MILLI_PRE_SEC; + return oss.str(); +} +} // namespace DistributedKv +} // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/app/BUILD.gn b/datamgr_service/services/distributeddataservice/app/BUILD.gn index 42ad60e3f99365b87a33ebbb0d50b83bce07da0f..03daee0033fbccc93e31948e484c1e58227158a0 100644 --- a/datamgr_service/services/distributeddataservice/app/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/app/BUILD.gn @@ -43,6 +43,7 @@ config("module_private_config") { "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/include", "${data_service_path}/adapter/include/account", "${data_service_path}/adapter/include/permission", + "${data_service_path}/adapter/include/screen", "${data_service_path}/adapter/include/installer", "${data_service_path}/adapter/include/broadcaster", "${data_service_path}/adapter/include/utils", @@ -60,8 +61,8 @@ config("module_private_config") { "${data_service_path}/service/backup/include", "${data_service_path}/service/app_id_mapping/include", "${data_service_path}/service/kvdb", - "${data_service_path}/service/waterversion", "${data_service_path}/service/dumper/include", + "${data_service_path}/adapter/include/communicator", # for ipc_core interfaces. "include", @@ -74,9 +75,13 @@ config("module_private_config") { "-Werror", "-Wno-multichar", "-D_LIBCPP_HAS_COND_CLOCKWAIT", + "-Oz", ] - cflags_cc = [ "-fvisibility=hidden" ] + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] } ohos_shared_library("distributeddataservice") { @@ -90,6 +95,8 @@ ohos_shared_library("distributeddataservice") { } sources = [ "${data_service_path}/service/common/xcollie.cpp", + "src/clone/clone_backup_info.cpp", + "src/clone/secret_key_backup_data.cpp", "src/db_info_handle_impl.cpp", "src/feature_stub_impl.cpp", "src/kvstore_account_observer.cpp", @@ -97,6 +104,7 @@ ohos_shared_library("distributeddataservice") { "src/kvstore_data_service_stub.cpp", "src/kvstore_device_listener.cpp", "src/kvstore_meta_manager.cpp", + "src/kvstore_screen_observer.cpp", "src/security/security.cpp", "src/security/sensitive.cpp", "src/session_manager/route_head_handler_impl.cpp", @@ -115,12 +123,9 @@ ohos_shared_library("distributeddataservice") { configs = [ ":module_private_config" ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", - "${data_service_path}/adapter/broadcaster:distributeddata_broadcaster_static", - "${data_service_path}/adapter/utils:distributeddata_utils_static", - "${data_service_path}/app/src/checker:distributeddata_checker_static", - "${data_service_path}/app/src/flowctrl_manager:distributeddata_flowctrl_static", - "${data_service_path}/app/src/installer:distributeddata_installer_static", + "${data_service_path}/adapter/utils:distributeddata_utils", + "${data_service_path}/app/src/checker:distributeddata_checker", + "${data_service_path}/app/src/installer:distributeddata_installer", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", ] @@ -133,6 +138,7 @@ ohos_shared_library("distributeddataservice") { "bundle_framework:appexecfwk_core", "c_utils:utils", "dataclassification:data_transit_mgr", + "device_manager:devicemanagersdk", "file_api:securitylabel", "hicollie:libhicollie", "hilog:libhilog", @@ -141,7 +147,7 @@ ohos_shared_library("distributeddataservice") { "hitrace:libhitracechain", "ipc:ipc_core", "json:nlohmann_json_static", - "kv_store:distributeddata_inner", + "kv_store:datamgr_common", "kv_store:distributeddata_mgr", "kv_store:distributeddb", "memmgr:memmgrclient", diff --git a/datamgr_service/services/distributeddataservice/app/CMakeLists.txt b/datamgr_service/services/distributeddataservice/app/CMakeLists.txt index 2faa483bf5165b25c4d45889bd2badbd70407505..47ba4989c10ac1789b9c7cbe3ef0c82dd6c535b4 100644 --- a/datamgr_service/services/distributeddataservice/app/CMakeLists.txt +++ b/datamgr_service/services/distributeddataservice/app/CMakeLists.txt @@ -14,6 +14,7 @@ add_definitions(-DPROCESS_LABEL="mytest") aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src appSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src/flowctrl_manager appSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src/installer appSrc) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src/clone appSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src/security appSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src/session_manager appSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src/checker appSrc) diff --git a/datamgr_service/services/distributeddataservice/app/src/checker/BUILD.gn b/datamgr_service/services/distributeddataservice/app/src/checker/BUILD.gn index ef5c271ef977f2749f44919ae7a9def067e56972..f0fa8dd258432a3254d58b3173dd84958c6fa2d7 100644 --- a/datamgr_service/services/distributeddataservice/app/src/checker/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/app/src/checker/BUILD.gn @@ -13,7 +13,7 @@ import("//build/ohos.gni") import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") -ohos_static_library("distributeddata_checker_static") { +ohos_source_set("distributeddata_checker") { branch_protector_ret = "pac_ret" sanitize = { cfi = true @@ -27,20 +27,19 @@ ohos_static_library("distributeddata_checker_static") { "system_checker.cpp", ] - cflags_cc = [ "-fvisibility=hidden" ] - - include_dirs = [ - "${kv_store_common_path}", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/framework/include", - "${kv_store_path}/interfaces/innerkits/distributeddata/include", + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", ] + include_dirs = [ "${data_service_path}/framework/include" ] + if (build_public_version) { cflags_cc += [ "-DCONFIG_PUBLIC_VERSION" ] } ldflags = [ "-Wl,--exclude-libs,ALL" ] - deps = [ "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/utils:distributeddata_utils_static" ] - + deps = [ "${data_service_path}/adapter/utils:distributeddata_utils" ] + cflags = [ "-Oz" ] external_deps = [ "ability_base:base", "ability_base:want", @@ -50,6 +49,7 @@ ohos_static_library("distributeddata_checker_static") { "c_utils:utils", "hilog:libhilog", "ipc:ipc_core", + "kv_store:datamgr_common", "samgr:samgr_proxy", ] subsystem_name = "distributeddatamgr" diff --git a/datamgr_service/services/distributeddataservice/app/src/clone/clone_backup_info.cpp b/datamgr_service/services/distributeddataservice/app/src/clone/clone_backup_info.cpp new file mode 100644 index 0000000000000000000000000000000000000000..83bfa59c9ff06d34ecbf73e67f516d0f03ba7feb --- /dev/null +++ b/datamgr_service/services/distributeddataservice/app/src/clone/clone_backup_info.cpp @@ -0,0 +1,111 @@ +/* +* Copyright (c) 2025 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 "clone_backup_info.h" + +namespace OHOS { +namespace DistributedData { +constexpr const char* CLONE_INFO_DETAIL = "detail"; +constexpr const char* ENCRYPTION_INFO = "encryption_info"; +constexpr const char* APPLICATION_SELECTION = "application_selection"; +constexpr const char* USER_ID = "userId"; +constexpr const char* ENCRYPTION_SYMKEY = "encryption_symkey"; +constexpr const char* ENCRYPTION_ALGORITHM = "encryption_algname"; +constexpr const char* GCM_PARAMS_IV = "gcmParams_iv"; + +bool CloneEncryptionInfo::Unmarshal(const json &node) +{ + bool res = GetValue(node, ENCRYPTION_SYMKEY, symkey); + res = GetValue(node, ENCRYPTION_ALGORITHM, algName) && res; + res = GetValue(node, GCM_PARAMS_IV, iv) && res; + return res; +} + +bool CloneEncryptionInfo::Marshal(json &node) const +{ + return false; +} + +CloneEncryptionInfo::~CloneEncryptionInfo() +{ + symkey.assign(symkey.size(), 0); + algName.assign(algName.size(), 0); + iv.assign(iv.size(), 0); +} + +bool CloneBundleInfo::Unmarshal(const json &node) +{ + bool res = GetValue(node, GET_NAME(bundleName), bundleName); + res = GetValue(node, GET_NAME(accessTokenId), accessTokenId) && res; + return res; +} + +bool CloneBundleInfo::Marshal(json &node) const +{ + return false; +} + +bool CloneBackupInfo::Unmarshal(const json &node) +{ + if (!node.is_array()) { + return false; + } + std::string type; + auto size = node.size(); + for (size_t i = 0; i < size; i++) { + bool result = GetValue(node[i], GET_NAME(type), type); + if (!result || type.empty()) { + continue; + } + if (type == ENCRYPTION_INFO) { + GetValue(node[i], CLONE_INFO_DETAIL, encryptionInfo); + } else if (type == APPLICATION_SELECTION) { + GetValue(node[i], CLONE_INFO_DETAIL, bundleInfos); + } else if (type == USER_ID) { + GetValue(node[i], CLONE_INFO_DETAIL, userId); + } + } + return true; +} + +bool CloneBackupInfo::Marshal(json &node) const +{ + return false; +} + +bool CloneReplyResult::Marshal(json &node) const +{ + SetValue(node[GET_NAME(type)], type); + SetValue(node[GET_NAME(errorCode)], errorCode); + SetValue(node[GET_NAME(errorInfo)], errorInfo); + return true; +} + +bool CloneReplyResult::Unmarshal(const json &node) +{ + return false; +} + +bool CloneReplyCode::Marshal(json &node) const +{ + SetValue(node[GET_NAME(resultInfo)], resultInfo); + return true; +} + +bool CloneReplyCode::Unmarshal(const json &node) +{ + return false; +} +} // namespace DistributedData +} // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/app/src/clone/clone_backup_info.h b/datamgr_service/services/distributeddataservice/app/src/clone/clone_backup_info.h new file mode 100644 index 0000000000000000000000000000000000000000..8af4343a8bc834b4ce4be6743cef78a9d32893db --- /dev/null +++ b/datamgr_service/services/distributeddataservice/app/src/clone/clone_backup_info.h @@ -0,0 +1,60 @@ +/* +* Copyright (c) 2025 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_SERVICES_CLONE_BACKUP_INFO_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_CLONE_BACKUP_INFO_H +#include "serializable/serializable.h" +namespace OHOS { +namespace DistributedData { +struct CloneEncryptionInfo final : public Serializable { + std::string symkey; + std::string algName; + std::string iv; + API_EXPORT bool Marshal(json &node) const override; + API_EXPORT bool Unmarshal(const json &node) override; + ~CloneEncryptionInfo(); +}; + +struct CloneBundleInfo final : public Serializable { + std::string bundleName; + uint32_t accessTokenId; + API_EXPORT bool Marshal(json &node) const override; + API_EXPORT bool Unmarshal(const json &node) override; +}; + +struct CloneBackupInfo final : public Serializable { + CloneEncryptionInfo encryptionInfo; + std::vector bundleInfos; + std::string userId; + API_EXPORT bool Marshal(json &node) const override; + API_EXPORT bool Unmarshal(const json &node) override; +}; + +struct CloneReplyResult final : public Serializable { + std::string type = "ErrorInfo"; + std::string errorCode; + std::string errorInfo; + API_EXPORT bool Marshal(json &node) const override; + API_EXPORT bool Unmarshal(const json &node) override; +}; + +struct CloneReplyCode final : public Serializable { + std::vector resultInfo; + API_EXPORT bool Marshal(json &node) const override; + API_EXPORT bool Unmarshal(const json &node) override; +}; +} // namespace DistributedData +} // namespace OHOS +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_CLONE_BACKUP_INFO_H diff --git a/datamgr_service/services/distributeddataservice/app/src/clone/secret_key_backup_data.cpp b/datamgr_service/services/distributeddataservice/app/src/clone/secret_key_backup_data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95a5ada4512f9b831ae0fa75d0a9b6bed5c6129d --- /dev/null +++ b/datamgr_service/services/distributeddataservice/app/src/clone/secret_key_backup_data.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025 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 "secret_key_backup_data.h" +namespace OHOS { +namespace DistributedData { +SecretKeyBackupData::SecretKeyBackupData() +{ +} + +SecretKeyBackupData::~SecretKeyBackupData() +{ +} + +bool SecretKeyBackupData::Marshal(json &node) const +{ + SetValue(node[GET_NAME(infos)], infos); + return true; +} + +bool SecretKeyBackupData::Unmarshal(const json &node) +{ + bool ret = GetValue(node, GET_NAME(infos), infos); + return ret; +} + +SecretKeyBackupData::BackupItem::BackupItem() +{ +} + +SecretKeyBackupData::BackupItem::~BackupItem() +{ + sKey.assign(sKey.size(), 0); +} + +bool SecretKeyBackupData::BackupItem::Marshal(json &node) const +{ + SetValue(node[GET_NAME(bundleName)], bundleName); + SetValue(node[GET_NAME(dbName)], dbName); + SetValue(node[GET_NAME(instanceId)], instanceId); + SetValue(node[GET_NAME(user)], user); + SetValue(node[GET_NAME(time)], time); + SetValue(node[GET_NAME(sKey)], sKey); + SetValue(node[GET_NAME(storeType)], storeType); + return true; +} + +bool SecretKeyBackupData::BackupItem::Unmarshal(const json &node) +{ + bool ret = GetValue(node, GET_NAME(bundleName), bundleName); + ret = GetValue(node, GET_NAME(dbName), dbName) && ret; + ret = GetValue(node, GET_NAME(instanceId), instanceId) && ret; + ret = GetValue(node, GET_NAME(user), user) && ret; + ret = GetValue(node, GET_NAME(time), time) && ret; + ret = GetValue(node, GET_NAME(sKey), sKey) && ret; + ret = GetValue(node, GET_NAME(storeType), storeType) && ret; + return ret; +} + +bool SecretKeyBackupData::BackupItem::IsValid() const +{ + return !bundleName.empty() && !dbName.empty() && !time.empty() && !sKey.empty() && !user.empty(); +} +} // namespace DistributedData +} // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/app/src/clone/secret_key_backup_data.h b/datamgr_service/services/distributeddataservice/app/src/clone/secret_key_backup_data.h new file mode 100644 index 0000000000000000000000000000000000000000..5cfc2cdcbc3f9a8dcc7a111e759a40d3c0923b92 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/app/src/clone/secret_key_backup_data.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 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_SERVICES_SECRET_KEY_BACKUP_DATA_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_SECRET_KEY_BACKUP_DATA_H +#include "serializable/serializable.h" +namespace OHOS { +namespace DistributedData { +struct SecretKeyBackupData final : public Serializable { +public: + struct API_EXPORT BackupItem final : public Serializable { + std::string bundleName; + std::string dbName; + std::string user; + std::string sKey; + int32_t instanceId; + int32_t storeType; + std::vector time; + + API_EXPORT BackupItem(); + ~BackupItem(); + API_EXPORT bool Marshal(json &node) const override; + API_EXPORT bool Unmarshal(const json &node) override; + API_EXPORT bool IsValid() const; + }; + std::vector infos; + API_EXPORT SecretKeyBackupData(); + ~SecretKeyBackupData(); + API_EXPORT bool Marshal(json &node) const override; + API_EXPORT bool Unmarshal(const json &node) override; +}; +} // namespace DistributedData +} // namespace OHOS +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_SECRET_KEY_BACKUP_DATA_H diff --git a/datamgr_service/services/distributeddataservice/app/src/feature_stub_impl.cpp b/datamgr_service/services/distributeddataservice/app/src/feature_stub_impl.cpp index a690ddbe9cd44abd4c77a9e7447f0f0ab586722b..e81ed5a8991f8957d348aacda04ce76771d6bd36 100644 --- a/datamgr_service/services/distributeddataservice/app/src/feature_stub_impl.cpp +++ b/datamgr_service/services/distributeddataservice/app/src/feature_stub_impl.cpp @@ -132,4 +132,4 @@ int32_t FeatureStubImpl::OnScreenUnlocked(int32_t user) } return featureImpl_->OnScreenUnlocked(user); } -} +} \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/app/src/feature_stub_impl.h b/datamgr_service/services/distributeddataservice/app/src/feature_stub_impl.h index e9249a76b784bbba4e4d0c8e6927b259e5fb3bb0..77e90d58907c36c7c1674fd6c49e8c1da4d0b31d 100644 --- a/datamgr_service/services/distributeddataservice/app/src/feature_stub_impl.h +++ b/datamgr_service/services/distributeddataservice/app/src/feature_stub_impl.h @@ -47,4 +47,4 @@ private: std::shared_ptr featureImpl_; }; } -#endif // OHOS_DISTRIBUTED_DATA_APP_FEATURE_STUB_IMPL_H +#endif // OHOS_DISTRIBUTED_DATA_APP_FEATURE_STUB_IMPL_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/app/src/flowctrl_manager/BUILD.gn b/datamgr_service/services/distributeddataservice/app/src/flowctrl_manager/BUILD.gn index 58bb2bd7f670a4216fcb507fe2a392cabc525a6f..9508a79a165cecc29a6ad0f2d7647da77cedfe9b 100644 --- a/datamgr_service/services/distributeddataservice/app/src/flowctrl_manager/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/app/src/flowctrl_manager/BUILD.gn @@ -14,7 +14,7 @@ import("//build/ohos.gni") import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") -ohos_static_library("distributeddata_flowctrl_static") { +ohos_source_set("distributeddata_flowctrl") { branch_protector_ret = "pac_ret" sanitize = { cfi = true @@ -28,16 +28,19 @@ ohos_static_library("distributeddata_flowctrl_static") { include_dirs = [ "../../../adapter/include/account", "../../src", - "${kv_store_path}/frameworks/innerkitsimpl/distributeddatasvc/include", - "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/include", - "${kv_store_path}/interfaces/innerkits/distributeddata/include", ] - cflags_cc = [ "-fvisibility=hidden" ] + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] + + cflags = [ "-Oz" ] external_deps = [ "c_utils:utils", "json:nlohmann_json_static", + "kv_store:datamgr_common", ] subsystem_name = "distributeddatamgr" diff --git a/datamgr_service/services/distributeddataservice/app/src/installer/BUILD.gn b/datamgr_service/services/distributeddataservice/app/src/installer/BUILD.gn index a4ee8a56e19af447239bc9891d1aa410b53ec524..4dcc6a7796501a1f8e92f0dc58a60d11b1f5a6ef 100644 --- a/datamgr_service/services/distributeddataservice/app/src/installer/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/app/src/installer/BUILD.gn @@ -14,7 +14,7 @@ import("//build/ohos.gni") import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") -ohos_static_library("distributeddata_installer_static") { +ohos_source_set("distributeddata_installer") { branch_protector_ret = "pac_ret" sanitize = { cfi = true @@ -31,18 +31,21 @@ ohos_static_library("distributeddata_installer_static") { include_dirs = [ "../../../adapter/include/account", "../../src", - "${kv_store_path}/frameworks/innerkitsimpl/distributeddatasvc/include", - "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/include", - "${kv_store_path}/interfaces/innerkits/distributeddata/include", "${data_service_path}/framework/include", "${data_service_path}/service/kvdb", "${data_service_path}/service/permission/include", + "${data_service_path}/adapter/include/communicator", + "${data_service_path}/adapter/include/dfx", ] - cflags_cc = [ "-fvisibility=hidden" ] + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] + + cflags = [ "-Oz" ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", ] @@ -53,8 +56,10 @@ ohos_static_library("distributeddata_installer_static") { "c_utils:utils", "common_event_service:cesfwk_innerkits", "dataclassification:data_transit_mgr", + "device_manager:devicemanagersdk", "hilog:libhilog", "ipc:ipc_core", + "kv_store:distributeddata_mgr", "kv_store:distributeddb", "safwk:system_ability_fwk", "samgr:samgr_proxy", diff --git a/datamgr_service/services/distributeddataservice/app/src/installer/installer_impl.cpp b/datamgr_service/services/distributeddataservice/app/src/installer/installer_impl.cpp index 98de6baf3058e82e4b990cb20638342d90d2fb54..72feb1e84b4fd066b8c97f8154d1309809d9c1fa 100644 --- a/datamgr_service/services/distributeddataservice/app/src/installer/installer_impl.cpp +++ b/datamgr_service/services/distributeddataservice/app/src/installer/installer_impl.cpp @@ -87,6 +87,7 @@ void InstallEventSubscriber::OnUninstall(const std::string &bundleName, int32_t MetaDataManager::GetInstance().DelMeta(meta.GetBackupSecretKey(), true); MetaDataManager::GetInstance().DelMeta(meta.GetAutoLaunchKey(), true); MetaDataManager::GetInstance().DelMeta(meta.GetDebugInfoKey(), true); + MetaDataManager::GetInstance().DelMeta(meta.GetCloneSecretKey(), true); PermitDelegate::GetInstance().DelCache(meta.GetKey()); } } @@ -170,4 +171,4 @@ ExecutorPool::Task InstallerImpl::GetTask() executors_->Schedule(std::chrono::milliseconds(RETRY_INTERVAL), GetTask()); }; } -} // namespace OHOS::DistributedKv +} // namespace OHOS::DistributedKv \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/app/src/installer/installer_impl.h b/datamgr_service/services/distributeddataservice/app/src/installer/installer_impl.h index 683ae72999006e46b2217958bcde2b610796eecf..51441cdc92d296c08304d5e39b474b7049873930 100644 --- a/datamgr_service/services/distributeddataservice/app/src/installer/installer_impl.h +++ b/datamgr_service/services/distributeddataservice/app/src/installer/installer_impl.h @@ -58,4 +58,4 @@ private: std::shared_ptr executors_ {}; }; } // namespace OHOS::DistributedKv -#endif // DISTRIBUTEDDATAMGR_INSTALLER_IMPL_H +#endif // DISTRIBUTEDDATAMGR_INSTALLER_IMPL_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/app/src/kvstore_account_observer.cpp b/datamgr_service/services/distributeddataservice/app/src/kvstore_account_observer.cpp index 4c6f0be5b3b881d7287ec1c1a547a5864435d5bb..10fd9ed3108a52f836b44795e5eddc4a6a239dc4 100644 --- a/datamgr_service/services/distributeddataservice/app/src/kvstore_account_observer.cpp +++ b/datamgr_service/services/distributeddataservice/app/src/kvstore_account_observer.cpp @@ -16,22 +16,30 @@ #define LOG_TAG "KvStoreAccountObserver" #include "kvstore_account_observer.h" + #include + #include "kvstore_data_service.h" #include "log_print.h" +#include "xcollie.h" namespace OHOS { namespace DistributedKv { std::atomic g_kvStoreAccountEventStatus {0}; -void KvStoreAccountObserver::OnAccountChanged(const AccountEventInfo &eventInfo) +void KvStoreAccountObserver::OnAccountChanged(const AccountEventInfo &eventInfo, int32_t timeout) { - ZLOGI("account event %d, begin.", eventInfo.status); - ExecutorPool::Task task([this, eventInfo]() { - ZLOGI("account event processing in thread"); + ZLOGI("account event %{public}d, begin.", eventInfo.status); + if (timeout > 0) { + XCollie xcollie(__FUNCTION__, XCollie::XCOLLIE_LOG | XCollie::XCOLLIE_RECOVERY, timeout); kvStoreDataService_.AccountEventChanged(eventInfo); - }); - executors_->Execute(std::move(task)); - ZLOGI("account event %d, end.", eventInfo.status); + } else { + ExecutorPool::Task task([this, eventInfo]() { + ZLOGI("account event processing in thread"); + kvStoreDataService_.AccountEventChanged(eventInfo); + }); + executors_->Execute(std::move(task)); + } + ZLOGI("account event %{public}d, end.", eventInfo.status); } } // namespace DistributedKv } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/app/src/kvstore_account_observer.h b/datamgr_service/services/distributeddataservice/app/src/kvstore_account_observer.h index a0598ec0439273d82617e64826dae8c4bdc065f3..d8ea3d153caafdf98e16a4c8f5e61faf36c650b9 100644 --- a/datamgr_service/services/distributeddataservice/app/src/kvstore_account_observer.h +++ b/datamgr_service/services/distributeddataservice/app/src/kvstore_account_observer.h @@ -23,6 +23,7 @@ namespace OHOS { namespace DistributedKv { +using namespace DistributedData; // KvStore account event proc controller. extern std::atomic g_kvStoreAccountEventStatus; #define KVSTORE_ACCOUNT_EVENT_PROCESSING_CHECKER(result) \ @@ -41,7 +42,7 @@ public: } ~KvStoreAccountObserver() override = default; - void OnAccountChanged(const AccountEventInfo &eventInfo) override; + void OnAccountChanged(const AccountEventInfo &eventInfo, int32_t timeout) override; // must specify unique name for observer std::string Name() override { diff --git a/datamgr_service/services/distributeddataservice/app/src/kvstore_data_service.cpp b/datamgr_service/services/distributeddataservice/app/src/kvstore_data_service.cpp index c33d5a66ee5dc808c104630d81c5aae30f02beda..ba292c0c5de4002e5b9fada0e447c12a461483c5 100644 --- a/datamgr_service/services/distributeddataservice/app/src/kvstore_data_service.cpp +++ b/datamgr_service/services/distributeddataservice/app/src/kvstore_data_service.cpp @@ -16,11 +16,16 @@ #include "kvstore_data_service.h" #include +#include +#include #include +//#include +#include #include #include #include "accesstoken_kit.h" +#include "app_id_mapping/app_id_mapping_config_manager.h" #include "auth_delegate.h" #include "auto_launch_export.h" #include "bootstrap.h" @@ -36,8 +41,10 @@ #include "dump_helper.h" #include "eventcenter/event_center.h" #include "if_system_ability_manager.h" +#include "installer/installer.h" #include "iservice_registry.h" #include "kvstore_account_observer.h" +#include "kvstore_screen_observer.h" #include "log_print.h" #include "mem_mgr_client.h" #include "mem_mgr_proxy.h" @@ -54,15 +61,15 @@ #include "string_ex.h" #include "system_ability_definition.h" #include "task_manager.h" -#include "installer/installer.h" +#include "thread/thread_manager.h" #include "upgrade.h" #include "upgrade_manager.h" #include "user_delegate.h" #include "utils/anonymous.h" +#include "utils/base64_utils.h" #include "utils/block_integer.h" +#include "utils/constant.h" #include "utils/crypto.h" -#include "water_version_manager.h" -#include "app_id_mapping/app_id_mapping_config_manager.h" namespace OHOS::DistributedKv { using namespace std::chrono; @@ -72,34 +79,30 @@ using namespace OHOS::Security::AccessToken; using KvStoreDelegateManager = DistributedDB::KvStoreDelegateManager; using SecretKeyMeta = DistributedData::SecretKeyMetaData; using DmAdapter = DistributedData::DeviceManagerAdapter; -using DBConfig = DistributedDB::RuntimeConfig; +constexpr const char* EXTENSION_BACKUP = "backup"; +constexpr const char* EXTENSION_RESTORE = "restore"; +constexpr const char* SECRET_KEY_BACKUP_PATH = + "/data/service/el1/public/database/distributeddata/" + "secret_key_backup.conf"; REGISTER_SYSTEM_ABILITY_BY_ID(KvStoreDataService, DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID, true); constexpr char FOUNDATION_PROCESS_NAME[] = "foundation"; +constexpr int MAX_DOWNLOAD_ASSETS_COUNT = 50; +constexpr int MAX_DOWNLOAD_TASK = 5; +constexpr int KEY_SIZE = 32; +constexpr int AES_256_NONCE_SIZE = 32; KvStoreDataService::KvStoreDataService(bool runOnCreate) : SystemAbility(runOnCreate), clients_() { ZLOGI("begin."); - if (executors_ == nullptr) { - constexpr size_t MAX = 12; - constexpr size_t MIN = 5; - executors_ = std::make_shared(MAX, MIN); - DistributedDB::RuntimeConfig::SetThreadPool(std::make_shared(executors_)); - } } KvStoreDataService::KvStoreDataService(int32_t systemAbilityId, bool runOnCreate) : SystemAbility(systemAbilityId, runOnCreate), clients_() { ZLOGI("begin"); - if (executors_ == nullptr) { - constexpr size_t MAX = 12; - constexpr size_t MIN = 5; - executors_ = std::make_shared(MAX, MIN); - DistributedDB::RuntimeConfig::SetThreadPool(std::make_shared(executors_)); - } } KvStoreDataService::~KvStoreDataService() @@ -116,8 +119,11 @@ void KvStoreDataService::Initialize() KvStoreDelegateManager::SetProcessLabel(Bootstrap::GetInstance().GetProcessLabel(), "default"); #endif CommunicatorContext::GetInstance().SetThreadPool(executors_); - auto communicator = std::make_shared(RouteHeadHandlerImpl::Create); + auto communicator = std::shared_ptr( + AppDistributedKv::ProcessCommunicatorImpl::GetInstance()); + communicator->SetRouteHeadHandlerCreator(RouteHeadHandlerImpl::Create); DistributedDB::RuntimeConfig::SetDBInfoHandle(std::make_shared()); + DistributedDB::RuntimeConfig::SetAsyncDownloadAssetsConfig({ MAX_DOWNLOAD_TASK, MAX_DOWNLOAD_ASSETS_COUNT }); auto ret = KvStoreDelegateManager::SetProcessCommunicator(communicator); ZLOGI("set communicator ret:%{public}d.", static_cast(ret)); @@ -128,6 +134,8 @@ void KvStoreDataService::Initialize() KvStoreMetaManager::GetInstance().InitMetaParameter(); accountEventObserver_ = std::make_shared(*this, executors_); AccountDelegate::GetInstance()->Subscribe(accountEventObserver_); + screenEventObserver_ = std::make_shared(*this, executors_); + ScreenManager::GetInstance()->Subscribe(screenEventObserver_); deviceInnerListener_ = std::make_unique(*this); DmAdapter::GetInstance().StartWatchDeviceChange(deviceInnerListener_.get(), { "innerListener" }); CommunicatorContext::GetInstance().RegSessionListener(deviceInnerListener_.get()); @@ -138,11 +146,18 @@ void KvStoreDataService::Initialize() meta.bundleName = appIdMeta.bundleName; meta.storeId = info.storeId; meta.user = info.userId; - meta.deviceId = oriDevId; - MetaDataManager::GetInstance().LoadMeta(meta.GetKey(), meta); - return Upgrade::GetInstance().GetEncryptedUuidByMeta(meta); + meta.deviceId = DmAdapter::GetInstance().GetLocalDevice().uuid; + MetaDataManager::GetInstance().LoadMeta(meta.GetKey(), meta, true); + std::string uuid; + if (OHOS::Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(meta.tokenId) == + OHOS::Security::AccessToken::TOKEN_HAP) { + uuid = DmAdapter::GetInstance().CalcClientUuid(meta.appId, oriDevId); + } else { + uuid = DmAdapter::GetInstance().CalcClientUuid(" ", oriDevId); + } + return uuid; }; - DBConfig::SetTranslateToDeviceIdCallback(translateCall); + DistributedDB::RuntimeConfig::SetTranslateToDeviceIdCallback(translateCall); } sptr KvStoreDataService::GetFeatureInterface(const std::string &name) @@ -258,12 +273,24 @@ int KvStoreDataService::Dump(int fd, const std::vector &args) return ERROR; } +void KvStoreDataService::InitExecutor() +{ + if (executors_ == nullptr) { + executors_ = std::make_shared(ThreadManager::GetInstance().GetMaxThreadNum(), + ThreadManager::GetInstance().GetMinThreadNum()); + DistributedDB::RuntimeConfig::SetThreadPool(std::make_shared(executors_)); + } + IPCSkeleton::SetMaxWorkThreadNum(ThreadManager::GetInstance().GetIpcThreadNum()); +} + void KvStoreDataService::OnStart() { ZLOGI("distributeddata service onStart"); + LoadConfigs(); EventCenter::Defer defer; Reporter::GetInstance()->SetThreadPool(executors_); AccountDelegate::GetInstance()->BindExecutor(executors_); + ScreenManager::GetInstance()->BindExecutor(executors_); AccountDelegate::GetInstance()->RegisterHashFunc(Crypto::Sha256); DmAdapter::GetInstance().Init(executors_); AutoCache::GetInstance().Bind(executors_); @@ -275,8 +302,6 @@ void KvStoreDataService::OnStart() } ZLOGW("GetLocalDeviceId failed, retry count:%{public}d", static_cast(retry)); } - ZLOGI("Bootstrap configs and plugins."); - LoadConfigs(); Initialize(); auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); if (samgr != nullptr) { @@ -307,6 +332,9 @@ void KvStoreDataService::OnStart() void KvStoreDataService::LoadConfigs() { + ZLOGI("Bootstrap configs and plugins."); + Bootstrap::GetInstance().LoadThread(); + InitExecutor(); Bootstrap::GetInstance().LoadComponents(); Bootstrap::GetInstance().LoadDirectory(); Bootstrap::GetInstance().LoadCheckers(); @@ -323,6 +351,7 @@ void KvStoreDataService::OnAddSystemAbility(int32_t systemAbilityId, const std:: if (systemAbilityId == COMMON_EVENT_SERVICE_ID) { AccountDelegate::GetInstance()->SubscribeAccountEvent(); Installer::GetInstance().Init(this, executors_); + ScreenManager::GetInstance()->SubscribeScreenEvent(); } else if (systemAbilityId == MEMORY_MANAGER_SA_ID) { Memory::MemMgrClient::GetInstance().NotifyProcessStatus(getpid(), 1, 1, DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID); @@ -338,16 +367,307 @@ void KvStoreDataService::OnRemoveSystemAbility(int32_t systemAbilityId, const st return; } AccountDelegate::GetInstance()->UnsubscribeAccountEvent(); + ScreenManager::GetInstance()->UnsubscribeScreenEvent(); Installer::GetInstance().UnsubscribeEvent(); } +int32_t KvStoreDataService::OnExtension(const std::string &extension, MessageParcel &data, MessageParcel &reply) +{ + ZLOGI("extension is %{public}s, callingPid:%{public}d.", extension.c_str(), IPCSkeleton::GetCallingPid()); + if (extension == EXTENSION_BACKUP) { + return KvStoreDataService::OnBackup(data, reply); + } else if (extension == EXTENSION_RESTORE) { + return KvStoreDataService::OnRestore(data, reply); + } + return 0; +} + +std::string GetBackupReplyCode(int replyCode, const std::string &info = "") +{ + CloneReplyCode reply; + CloneReplyResult result; + result.errorCode = std::to_string(replyCode); + result.errorInfo = info; + reply.resultInfo.push_back(std::move(result)); + return Serializable::Marshall(reply); +} + +bool ParseBackupInfo(MessageParcel &data, CloneBackupInfo &backupInfo) +{ + std::string info = data.ReadString(); + bool success = backupInfo.Unmarshal(DistributedData::Serializable::ToJson(info)); + if (!success) { + ZLOGE("parse backup json failed."); + return false; + } + return true; +} + +bool CheckBackupInfo(CloneBackupInfo &backupInfo) +{ + if (backupInfo.bundleInfos.empty()) { + ZLOGE("bundle empty."); + return false; + } + if (backupInfo.userId.empty()) { + ZLOGE("userId invalid"); + return false; + } + return true; +} + +std::vector ConvertDecStrToVec(const std::string &inData) +{ + std::vector outData; + auto splitedToken = Constant::Split(inData, ","); + outData.reserve(splitedToken.size()); + for (auto &token : splitedToken) { + uint8_t num = atoi(token.c_str()); + outData.push_back(num); + } + return outData; +} + +bool ImportCloneKey(const std::string &keyStr, const std::string &ivStr) +{ + auto key = ConvertDecStrToVec(keyStr); + if (key.size() != KEY_SIZE) { + ZLOGE("ImportKey failed, key length not correct."); + key.assign(key.size(), 0); + return false; + } + auto iv = ConvertDecStrToVec(ivStr); + if (iv.size() != AES_256_NONCE_SIZE) { + ZLOGE("ImportKey failed, iv length not correct."); + key.assign(key.size(), 0); + iv.assign(iv.size(), 0); + return false; + } + + if (!CryptoManager::GetInstance().ImportCloneKey(key, iv)) { + ZLOGE("ImportCloneKey failed."); + key.assign(key.size(), 0); + iv.assign(iv.size(), 0); + return false; + } + key.assign(key.size(), 0); + iv.assign(iv.size(), 0); + return true; +} + +bool WriteBackupInfo(const std::string &content) +{ + FILE *fp = fopen(SECRET_KEY_BACKUP_PATH, "w"); + + if (!fp) { + ZLOGE("Secret key backup file open failed"); + return false; + } + size_t ret = fwrite(content.c_str(), 1, content.length(), fp); + if (ret != content.length()) { + ZLOGE("Save config file fwrite() failed!"); + (void)fclose(fp); + return false; + } + + (void)fflush(fp); + (void)fsync(fileno(fp)); + (void)fclose(fp); + return true; +} + +int32_t KvStoreDataService::OnBackup(MessageParcel &data, MessageParcel &reply) +{ + CloneBackupInfo backupInfo; + if (!ParseBackupInfo(data, backupInfo)) { + return -1; + } + + if (!CheckBackupInfo(backupInfo)) { + return -1; + } + + if (!ImportCloneKey(backupInfo.encryptionInfo.symkey, backupInfo.encryptionInfo.iv)) { + return -1; + } + + std::string content; + if (!GetSecretKeyBackup(backupInfo.bundleInfos, backupInfo.userId, content)) { + return -1; + }; + + if (!WriteBackupInfo(content)) { + return -1; + } + + UniqueFd fd(-1); + fd = UniqueFd(open(SECRET_KEY_BACKUP_PATH, O_RDONLY)); + std::string replyCode = GetBackupReplyCode(0); + if (!reply.WriteFileDescriptor(fd) || !reply.WriteString(replyCode)) { + close(fd.Release()); + ZLOGE("OnBackup fail: reply wirte fail, fd:%{public}d", fd.Get()); + return -1; + } + + close(fd.Release()); + return 0; +} + +std::vector ReEncryptKey(const std::string &key, SecretKeyMetaData &secretKeyMeta) +{ + if (!MetaDataManager::GetInstance().LoadMeta(key, secretKeyMeta, true)) { + ZLOGE("Secret key meta load failed."); + return {}; + }; + std::vector password; + if (!CryptoManager::GetInstance().Decrypt(secretKeyMeta.sKey, password)) { + ZLOGE("Secret key decrypt failed."); + return {}; + }; + auto reEncryptedKey = CryptoManager::GetInstance().EncryptCloneKey(password); + if (reEncryptedKey.size() == 0) { + ZLOGE("Secret key encrypt failed."); + return {}; + }; + return reEncryptedKey; +} + +bool KvStoreDataService::GetSecretKeyBackup( + const std::vector &bundleInfos, + const std::string &userId, std::string &content) +{ + SecretKeyBackupData backupInfos; + std::string deviceId = DmAdapter::GetInstance().GetLocalDevice().uuid; + for (const auto& bundleInfo : bundleInfos) { + std::string metaPrefix = StoreMetaData::GetKey({ deviceId, userId, "default", bundleInfo.bundleName }); + std::vector StoreMetas; + if (!MetaDataManager::GetInstance().LoadMeta(metaPrefix, StoreMetas, true)) { + ZLOGW("Store meta load failed, bundleName: %{public}s", bundleInfo.bundleName.c_str()); + continue; + }; + for (const auto &storeMeta : StoreMetas) { + if (!storeMeta.isEncrypt) { + continue; + }; + auto key = storeMeta.GetSecretKey(); + SecretKeyMetaData secretKeyMeta; + auto reEncryptedKey = ReEncryptKey(key, secretKeyMeta); + if (reEncryptedKey.size() == 0) { + ZLOGE("Secret key re-encrypt failed, user: %{public}s, bundleName: %{public}s, Db: " + "%{public}s, instanceId: %{public}d", userId.c_str(), + storeMeta.bundleName.c_str(), Anonymous::Change(storeMeta.storeId).c_str(), + storeMeta.instanceId); + continue; + }; + SecretKeyBackupData::BackupItem item; + item.time = secretKeyMeta.time; + item.bundleName = bundleInfo.bundleName; + item.dbName = storeMeta.storeId; + item.instanceId = storeMeta.instanceId; + item.sKey = DistributedData::Base64::Encode(reEncryptedKey); + item.storeType = secretKeyMeta.storeType; + item.user = userId; + backupInfos.infos.push_back(std::move(item)); + } + } + content = Serializable::Marshall(backupInfos); + return true; +} + +int32_t KvStoreDataService::OnRestore(MessageParcel &data, MessageParcel &reply) +{ + SecretKeyBackupData backupData; + if (!ParseSecretKeyFile(data, backupData) || backupData.infos.size() == 0) { + ZLOGE("Read backup file failed or infos is empty!"); + return ReplyForRestore(reply, -1); + } + CloneBackupInfo backupInfo; + bool ret = backupInfo.Unmarshal(DistributedData::Serializable::ToJson(data.ReadString())); + if (!ret || backupInfo.userId.empty()) { + ZLOGE("Clone info invalid or userId is empty!"); + return ReplyForRestore(reply, -1); + } + + if (!ImportCloneKey(backupInfo.encryptionInfo.symkey, backupInfo.encryptionInfo.iv)) { + return ReplyForRestore(reply, -1); + } + for (const auto &item : backupData.infos) { + if (!item.IsValid() || !RestoreSecretKey(item, backupInfo.userId)) { + ZLOGW("Restore secret key failed! bundleName:%{public}s, dbName:%{public}s, instanceId:%{public}d, " + "storeType:%{public}d, time.size:%{public}zu, sKey:%{public}s, user:%{public}s", + item.bundleName.c_str(), Anonymous::Change(item.dbName).c_str(), item.instanceId, item.storeType, + item.time.size(), Anonymous::Change(item.sKey).c_str(), item.user.c_str()); + continue; + } + } + return ReplyForRestore(reply, 0); +} + +int32_t KvStoreDataService::ReplyForRestore(MessageParcel &reply, int32_t result) +{ + std::string replyCode = GetBackupReplyCode(result); + if (!reply.WriteString(replyCode)) { + ZLOGE("Write reply failed"); + return -1; + } + return result; +} + +bool KvStoreDataService::ParseSecretKeyFile(MessageParcel &data, SecretKeyBackupData &backupData) +{ + UniqueFd fd(data.ReadFileDescriptor()); + struct stat statBuf; + if (fd.Get() < 0 || fstat(fd.Get(), &statBuf) < 0) { + ZLOGE("Parse backup secret key failed, fd:%{public}d, errno:%{public}d", fd.Get(), errno); + close(fd.Release()); + return false; + } + char buffer[statBuf.st_size + 1]; + if (read(fd.Get(), buffer, statBuf.st_size + 1) < 0) { + ZLOGE("Read backup secret key failed. errno:%{public}d", errno); + close(fd.Release()); + return false; + } + close(fd.Release()); + std::string secretKeyStr(buffer); + DistributedData::Serializable::Unmarshall(secretKeyStr, backupData); + return true; +} + +bool KvStoreDataService::RestoreSecretKey(const SecretKeyBackupData::BackupItem &item, const std::string &userId) +{ + StoreMetaData metaData; + metaData.bundleName = item.bundleName; + metaData.storeId = item.dbName; + metaData.user = item.user == "0" ? "0" : userId; + metaData.instanceId = item.instanceId; + auto sKey = DistributedData::Base64::Decode(item.sKey); + std::vector rawKey; + if (!CryptoManager::GetInstance().DecryptCloneKey(sKey, rawKey)) { + ZLOGE("Decrypt by clonekey failed."); + sKey.assign(sKey.size(), 0); + rawKey.assign(rawKey.size(), 0); + return false; + } + SecretKeyMetaData secretKey; + secretKey.storeType = item.storeType; + secretKey.sKey = CryptoManager::GetInstance().Encrypt(rawKey); + secretKey.time = { item.time.begin(), item.time.end() }; + sKey.assign(sKey.size(), 0); + rawKey.assign(rawKey.size(), 0); + if (!MetaDataManager::GetInstance().SaveMeta(metaData.GetCloneSecretKey(), secretKey, true)) { + ZLOGE("Save meta failed."); + return false; + } + return true; +} + void KvStoreDataService::StartService() { // register this to ServiceManager. ZLOGI("begin."); KvStoreMetaManager::GetInstance().InitMetaListener(); DeviceMatrix::GetInstance().Initialize(IPCSkeleton::GetCallingTokenID(), Bootstrap::GetInstance().GetMetaDBName()); - WaterVersionManager::GetInstance().Init(); LoadFeatures(); bool ret = SystemAbility::Publish(this); if (!ret) { @@ -521,6 +841,7 @@ void KvStoreDataService::AccountEventChanged(const AccountEventInfo &eventInfo) MetaDataManager::GetInstance().DelMeta(meta.GetAutoLaunchKey(), true); MetaDataManager::GetInstance().DelMeta(meta.appId, true); MetaDataManager::GetInstance().DelMeta(meta.GetDebugInfoKey(), true); + MetaDataManager::GetInstance().DelMeta(meta.GetCloneSecretKey(), true); PermitDelegate::GetInstance().DelCache(meta.GetKey()); } g_kvStoreAccountEventStatus = 0; @@ -551,8 +872,14 @@ void KvStoreDataService::NotifyAccountEvent(const AccountEventInfo &eventInfo) std::vector users; AccountDelegate::GetInstance()->QueryUsers(users); std::set userIds(users.begin(), users.end()); + userIds.insert(0); AutoCache::GetInstance().CloseStore([&userIds](const StoreMetaData &meta) { - return userIds.count(atoi(meta.user.c_str())) == 0; + if (userIds.count(atoi(meta.user.c_str())) == 0) { + ZLOGW("Illegal use of database by user %{public}s, %{public}s:%{public}s", meta.user.c_str(), + meta.bundleName.c_str(), meta.GetStoreAlias().c_str()); + return true; + } + return false; }); break; } @@ -560,6 +887,7 @@ void KvStoreDataService::NotifyAccountEvent(const AccountEventInfo &eventInfo) AutoCache::GetInstance().CloseStore([&eventInfo](const StoreMetaData &meta) { return meta.user == eventInfo.userId; }); + break; default: break; } @@ -574,7 +902,7 @@ void KvStoreDataService::InitSecurityAdapter(std::shared_ptr execu ZLOGE("security is nullptr."); return; } - + security_->InitLocalSecurity(); auto dbStatus = DistributedDB::RuntimeConfig::SetProcessSystemAPIAdapter(security_); ZLOGD("set distributed db system api adapter: %d.", static_cast(dbStatus)); @@ -1002,4 +1330,4 @@ void KvStoreDataService::DumpBundleInfo(int fd, std::map #include #include #include #include "account_delegate.h" +#include "clone/clone_backup_info.h" +#include "clone/secret_key_backup_data.h" #include "feature_stub_impl.h" #include "ikvstore_data_service.h" #include "ithread_pool.h" @@ -30,13 +33,17 @@ #include "metadata/store_meta_data.h" #include "reporter.h" #include "runtime_config.h" +#include "screen/screen_manager.h" #include "security/security.h" #include "system_ability.h" #include "executor_pool.h" #include "types.h" +#include "unique_fd.h" namespace OHOS::DistributedKv { +using namespace DistributedData; class KvStoreAccountObserver; +class KvStoreScreenObserver; class KvStoreDataService : public SystemAbility, public KvStoreDataServiceStub { DECLARE_SYSTEM_ABILITY(KvStoreDataService); using Handler = std::function> &)>; @@ -56,6 +63,8 @@ public: std::set storeIDs; }; using StoreMetaData = DistributedData::StoreMetaData; + using SecretKeyBackupData = DistributedData::SecretKeyBackupData; + using CloneBackupInfo = DistributedData::CloneBackupInfo; // record kvstore meta version for compatible, should update when modify kvstore meta structure. static constexpr uint32_t STORE_VERSION = 0x03000001; @@ -120,7 +129,14 @@ public: int32_t OnScreenUnlocked(int32_t user); -private: + int32_t OnExtension(const std::string &extension, MessageParcel &data, MessageParcel &reply) override; + int32_t OnBackup(MessageParcel &data, MessageParcel &reply); + int32_t OnRestore(MessageParcel &data, MessageParcel &reply); + static bool GetSecretKeyBackup( + const std::vector &bundleInfos, + const std::string &userId, std::string &content); + + private: void NotifyAccountEvent(const AccountEventInfo &eventInfo); class KvStoreClientDeathObserverImpl { public: @@ -165,13 +181,22 @@ private: void OnStoreMetaChanged(const std::vector &key, const std::vector &value, CHANGE_FLAG flag); Status AppExit(pid_t uid, pid_t pid, uint32_t token, const AppId &appId); - + void LoadConfigs(); + void InitExecutor(); + + bool ParseSecretKeyFile(MessageParcel &data, SecretKeyBackupData &backupData); + + bool RestoreSecretKey(const SecretKeyBackupData::BackupItem &item, const std::string &userId); + + int32_t ReplyForRestore(MessageParcel &reply, int32_t result); + static constexpr int TEN_SEC = 10; ConcurrentMap> clients_; std::shared_ptr accountEventObserver_; + std::shared_ptr screenEventObserver_; std::shared_ptr security_; ConcurrentMap> features_; @@ -188,4 +213,4 @@ private: static constexpr uint32_t INVALID_TOKEN = 0; }; } -#endif // KVSTORE_DATASERVICE_H +#endif // KVSTORE_DATASERVICE_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/app/src/kvstore_meta_manager.cpp b/datamgr_service/services/distributeddataservice/app/src/kvstore_meta_manager.cpp index 5c19c739ff9f2320e19ad697267ddaec849271a5..f7e315cabb42bfa37b7d29cdf9f3c47e0a8c01c2 100644 --- a/datamgr_service/services/distributeddataservice/app/src/kvstore_meta_manager.cpp +++ b/datamgr_service/services/distributeddataservice/app/src/kvstore_meta_manager.cpp @@ -42,10 +42,10 @@ #include "store/store_info.h" #include "utils/anonymous.h" #include "utils/block_integer.h" +#include "utils/corrupt_reporter.h" #include "utils/crypto.h" #include "utils/ref_count.h" #include "utils/converter.h" -#include "water_version_manager.h" namespace OHOS { namespace DistributedKv { @@ -239,7 +239,19 @@ KvStoreMetaManager::NbDelegate KvStoreMetaManager::GetMetaKvStore() return metaDelegate_; } - metaDelegate_ = CreateMetaKvStore(); + auto metaDbName = Bootstrap::GetInstance().GetMetaDBName(); + if (CorruptReporter::HasCorruptedFlag(metaDBDirectory_, metaDbName)) { + DistributedDB::DBStatus dbStatus = delegateManager_.DeleteKvStore(metaDbName); + if (dbStatus != DistributedDB::DBStatus::OK) { + ZLOGE("delete meta store failed! dbStatus: %{public}d", dbStatus); + } + metaDelegate_ = CreateMetaKvStore(true); + if (metaDelegate_ != nullptr) { + CorruptReporter::DeleteCorruptedFlag(metaDBDirectory_, metaDbName); + } + } else { + metaDelegate_ = CreateMetaKvStore(); + } auto fullName = GetBackupPath(); auto backup = [executors = executors_, queue = std::make_shared>(MAX_TASK_COUNT), fullName]( const auto &store) -> int32_t { @@ -257,7 +269,7 @@ KvStoreMetaManager::NbDelegate KvStoreMetaManager::GetMetaKvStore() executors->Schedule(std::chrono::hours(RETRY_INTERVAL), GetBackupTask(queue, executors, store)); return OK; }; - MetaDataManager::GetInstance().Initialize(metaDelegate_, backup); + MetaDataManager::GetInstance().Initialize(metaDelegate_, backup, metaDbName); return metaDelegate_; } @@ -275,19 +287,19 @@ ExecutorPool::Task KvStoreMetaManager::GetBackupTask( }; } -KvStoreMetaManager::NbDelegate KvStoreMetaManager::CreateMetaKvStore() +KvStoreMetaManager::NbDelegate KvStoreMetaManager::CreateMetaKvStore(bool isRestore) { DistributedDB::DBStatus dbStatusTmp = DistributedDB::DBStatus::NOT_SUPPORT; - DistributedDB::KvStoreNbDelegate::Option option; - InitDBOption(option); + auto option = InitDBOption(); DistributedDB::KvStoreNbDelegate *delegate = nullptr; - delegateManager_.GetKvStore(Bootstrap::GetInstance().GetMetaDBName(), option, - [&delegate, &dbStatusTmp](DistributedDB::DBStatus dbStatus, DistributedDB::KvStoreNbDelegate *nbDelegate) { - delegate = nbDelegate; - dbStatusTmp = dbStatus; - }); - - if (dbStatusTmp == DistributedDB::DBStatus::INVALID_PASSWD_OR_CORRUPTED_DB) { + if (!isRestore) { + delegateManager_.GetKvStore(Bootstrap::GetInstance().GetMetaDBName(), option, + [&delegate, &dbStatusTmp](DistributedDB::DBStatus dbStatus, DistributedDB::KvStoreNbDelegate *nbDelegate) { + delegate = nbDelegate; + dbStatusTmp = dbStatus; + }); + } + if (dbStatusTmp == DistributedDB::DBStatus::INVALID_PASSWD_OR_CORRUPTED_DB || isRestore) { ZLOGE("meta data corrupted!"); option.isNeedRmCorruptedDb = true; auto fullName = GetBackupPath(); @@ -303,7 +315,6 @@ KvStoreMetaManager::NbDelegate KvStoreMetaManager::CreateMetaKvStore() } }); } - if (dbStatusTmp != DistributedDB::DBStatus::OK || delegate == nullptr) { ZLOGE("GetKvStore return error status: %{public}d or delegate is nullptr", static_cast(dbStatusTmp)); return nullptr; @@ -316,11 +327,10 @@ KvStoreMetaManager::NbDelegate KvStoreMetaManager::CreateMetaKvStore() auto data = static_cast(¶m); delegate->Pragma(DistributedDB::SET_SYNC_RETRY, data); auto release = [this](DistributedDB::KvStoreNbDelegate *delegate) { - ZLOGI("release meta data kv store"); + ZLOGI("release meta data kv store"); if (delegate == nullptr) { return; } - auto result = delegateManager_.CloseKvStore(delegate); if (result != DistributedDB::DBStatus::OK) { ZLOGE("CloseMetaKvStore return error status: %{public}d", static_cast(result)); @@ -329,8 +339,9 @@ KvStoreMetaManager::NbDelegate KvStoreMetaManager::CreateMetaKvStore() return NbDelegate(delegate, release); } -void KvStoreMetaManager::InitDBOption(DistributedDB::KvStoreNbDelegate::Option &option) +DistributedDB::KvStoreNbDelegate::Option KvStoreMetaManager::InitDBOption() { + DistributedDB::KvStoreNbDelegate::Option option; option.createIfNecessary = true; option.isMemoryDb = false; option.createDirByStoreIdOnly = true; @@ -340,6 +351,7 @@ void KvStoreMetaManager::InitDBOption(DistributedDB::KvStoreNbDelegate::Option & option.isNeedCompressOnSync = true; option.compressionRate = COMPRESS_RATE; option.secOption = { DistributedDB::S1, DistributedDB::ECE }; + return option; } void KvStoreMetaManager::SetCloudSyncer() diff --git a/datamgr_service/services/distributeddataservice/app/src/kvstore_meta_manager.h b/datamgr_service/services/distributeddataservice/app/src/kvstore_meta_manager.h index 492cc1ffa619753b7083520e1a5004c762a0f1ba..87bcc7162d8ad9f84f9ac437a5cbd233ca119677 100644 --- a/datamgr_service/services/distributeddataservice/app/src/kvstore_meta_manager.h +++ b/datamgr_service/services/distributeddataservice/app/src/kvstore_meta_manager.h @@ -65,7 +65,7 @@ private: using TaskQueue = std::shared_ptr>; NbDelegate GetMetaKvStore(); - NbDelegate CreateMetaKvStore(); + NbDelegate CreateMetaKvStore(bool isRestore = false); void SetCloudSyncer(); @@ -94,7 +94,7 @@ private: ExecutorPool::Task GetTask(uint32_t retry); - void InitDBOption(DistributedDB::KvStoreNbDelegate::Option &option); + DistributedDB::KvStoreNbDelegate::Option InitDBOption(); static ExecutorPool::Task GetBackupTask( TaskQueue queue, std::shared_ptr executors, const NbDelegate store); diff --git a/datamgr_service/services/distributeddataservice/app/src/kvstore_screen_observer.cpp b/datamgr_service/services/distributeddataservice/app/src/kvstore_screen_observer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..49a693a3dec63cb0e078dac3d8d8b00ec1bc8bad --- /dev/null +++ b/datamgr_service/services/distributeddataservice/app/src/kvstore_screen_observer.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 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 "KvStoreScreenObserver" + +#include "kvstore_screen_observer.h" + +#include "kvstore_data_service.h" +#include "log_print.h" + +namespace OHOS { +namespace DistributedKv { +void KvStoreScreenObserver::OnScreenUnlocked(int32_t user) +{ + ZLOGI("user: %{public}d screen unlock begin.", user); + ExecutorPool::Task task([this, user]() { + ZLOGI("screen event processing in thread"); + kvStoreDataService_.OnScreenUnlocked(user); + }); + executors_->Execute(std::move(task)); + ZLOGI("user: %{public}d screen unlock end.", user); +} +} // namespace DistributedKv +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/client/async_obtain_data.h b/datamgr_service/services/distributeddataservice/app/src/kvstore_screen_observer.h similarity index 35% rename from udmf/framework/innerkitsimpl/client/async_obtain_data.h rename to datamgr_service/services/distributeddataservice/app/src/kvstore_screen_observer.h index 9c0f58a017f90eb27d22cdb1691473fc58dcbde1..944a5463c70124993c36ef539c7fdd22d27fa8a3 100644 --- a/udmf/framework/innerkitsimpl/client/async_obtain_data.h +++ b/datamgr_service/services/distributeddataservice/app/src/kvstore_screen_observer.h @@ -4,7 +4,7 @@ * 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 + * 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, @@ -13,49 +13,35 @@ * limitations under the License. */ -#ifndef ASYNC_OBTAIN_DATA_H -#define ASYNC_OBTAIN_DATA_H +#ifndef KVSTORE_SCREEN_OBSERVER_H +#define KVSTORE_SCREEN_OBSERVER_H #include "executor_pool.h" -#include "udmf_service.h" +#include "screen/screen_manager.h" namespace OHOS { -namespace UDMF { -using ObtainDataCallback = std::function; - -class AsyncObtainData { +namespace DistributedKv { +using namespace DistributedData; +class KvStoreDataService; +class KvStoreScreenObserver : public ScreenManager::Observer { public: - AsyncObtainData(); - ~AsyncObtainData() = default; + explicit KvStoreScreenObserver(KvStoreDataService &kvStoreDataService, std::shared_ptr executors) + : kvStoreDataService_(kvStoreDataService), executors_(executors) + { + } + ~KvStoreScreenObserver() override = default; -public: - Status InitTask(const QueryOption &query, ObtainDataCallback callback); - Status RunTask(); - void ClearTask(); + void OnScreenUnlocked(int32_t user) override; -private: - void InvokeCallback(UnifiedData &data); - void ObtainDataTask(); - void ProgressTask(); - - void UpdateProcessInfo(AsyncProcessInfo &info); - uint32_t CalProgress(); - uint32_t CalSyncProgress(); - uint32_t CalPermProgress(); + std::string GetName() override + { + return "DistributedDataService"; + } private: - bool initialized_{ false }; - ExecutorPool executor_; - ExecutorPool::TaskId progressTaskId_ = ExecutorPool::INVALID_TASK_ID; - ExecutorPool::TaskId obtainDataTaskId_ = ExecutorPool::INVALID_TASK_ID; - AsyncTaskStatus taskStatus_{ ASYNC_IDLE }; - QueryOption query_; - ObtainDataCallback callback_{ nullptr }; - uint32_t lastProgress_{ 0 }; - AsyncProcessInfo processInfo_; - std::shared_ptr serviceClient_{ nullptr }; + KvStoreDataService &kvStoreDataService_; + std::shared_ptr executors_; }; -} // namespace UDMF +} // namespace DistributedKv } // namespace OHOS - -#endif \ No newline at end of file +#endif // KVSTORE_SCREEN_OBSERVER_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/app/test/BUILD.gn b/datamgr_service/services/distributeddataservice/app/test/BUILD.gn index 5aa0b09eb4a5c4eba5746f7ba4962602731664f1..010a654667c525dcf74c8b9e29dc7423b7fb1b56 100644 --- a/datamgr_service/services/distributeddataservice/app/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/app/test/BUILD.gn @@ -36,10 +36,11 @@ config("module_private_config") { "${data_service_path}/service/common", "${data_service_path}/service/config/include", "${data_service_path}/service/crypto/include", + "${data_service_path}/service/data_share/common", "${data_service_path}/service/directory/include", "${data_service_path}/service/permission/include", "${data_service_path}/service/matrix/include", - "${data_service_path}/service/waterversion", + "${data_service_path}/app/src", "${data_service_path}/app/src/session_manager", "${data_service_path}/service/kvdb", "${device_manager_path}/interfaces/inner_kits/native_cpp/include", @@ -55,6 +56,7 @@ config("module_private_config") { "../../../../interfaces/innerkits/distributeddata", "../../service/dumper/include", "//third_party/json/single_include", + "${data_service_path}/adapter/include/communicator", ] if (datamgr_service_power) { @@ -67,12 +69,23 @@ config("module_private_config") { "-Dprotected=public", ] ldflags = [ "-Wl,--whole-archive" ] - defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] + defines = [ + "TEST_ON_DEVICE", + "OPENSSL_SUPPRESS_DEPRECATED", + ] } ohos_unittest("KvStoreDataServiceTest") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + module_out_path = module_output_path sources = [ + "${data_service_path}/app/src/clone/clone_backup_info.cpp", + "${data_service_path}/app/src/clone/secret_key_backup_data.cpp", "${data_service_path}/app/src/db_info_handle_impl.cpp", "${data_service_path}/app/src/feature_stub_impl.cpp", "${data_service_path}/app/src/kvstore_account_observer.cpp", @@ -80,6 +93,7 @@ ohos_unittest("KvStoreDataServiceTest") { "${data_service_path}/app/src/kvstore_data_service_stub.cpp", "${data_service_path}/app/src/kvstore_device_listener.cpp", "${data_service_path}/app/src/kvstore_meta_manager.cpp", + "${data_service_path}/app/src/kvstore_screen_observer.cpp", "${data_service_path}/app/src/security/security.cpp", "${data_service_path}/app/src/security/sensitive.cpp", "${data_service_path}/app/src/session_manager/route_head_handler_impl.cpp", @@ -119,12 +133,11 @@ ohos_unittest("KvStoreDataServiceTest") { } deps = [ - "${data_service_path}/adapter:distributeddata_adapter", - "${data_service_path}/adapter/broadcaster:distributeddata_broadcaster_static", - "${data_service_path}/adapter/utils:distributeddata_utils_static", - "${data_service_path}/app/src/checker:distributeddata_checker_static", - "${data_service_path}/app/src/flowctrl_manager:distributeddata_flowctrl_static", - "${data_service_path}/app/src/installer:distributeddata_installer_static", + "${data_service_path}/adapter/broadcaster:distributeddata_broadcaster", + "${data_service_path}/adapter/utils:distributeddata_utils", + "${data_service_path}/app/src/checker:distributeddata_checker", + "${data_service_path}/app/src/flowctrl_manager:distributeddata_flowctrl", + "${data_service_path}/app/src/installer:distributeddata_installer", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", "//third_party/googletest:gtest_main", @@ -175,11 +188,10 @@ ohos_unittest("SessionManagerTest") { } deps = [ + "${data_service_path}/adapter/broadcaster:distributeddata_broadcaster", + "${data_service_path}/adapter/utils:distributeddata_utils", + "${data_service_path}/app/src/checker:distributeddata_checker", "${kv_store_path}/interfaces/innerkits/distributeddatamgr:distributeddata_mgr", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter:distributeddata_adapter", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/broadcaster:distributeddata_broadcaster_static", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/utils:distributeddata_utils_static", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/app/src/checker:distributeddata_checker_static", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/framework:distributeddatasvcfwk", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/service:distributeddatasvc", "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb:distributeddb", @@ -217,9 +229,8 @@ ohos_unittest("KvStoreFlowCtrlManagerTest") { } deps = [ + "${data_service_path}/app/src/flowctrl_manager:distributeddata_flowctrl", "${kv_store_path}/interfaces/innerkits/distributeddatamgr:distributeddata_mgr", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter:distributeddata_adapter", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/app/src/flowctrl_manager:distributeddata_flowctrl_static", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/framework:distributeddatasvcfwk", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/service:distributeddatasvc", "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddata:distributeddata_inner", @@ -231,6 +242,8 @@ ohos_unittest("KvStoreFlowCtrlManagerTest") { ohos_unittest("KvStoreDataServiceClearTest") { module_out_path = module_output_path sources = [ + "${data_service_path}/app/src/clone/clone_backup_info.cpp", + "${data_service_path}/app/src/clone/secret_key_backup_data.cpp", "${data_service_path}/app/src/db_info_handle_impl.cpp", "${data_service_path}/app/src/feature_stub_impl.cpp", "${data_service_path}/app/src/kvstore_account_observer.cpp", @@ -238,6 +251,7 @@ ohos_unittest("KvStoreDataServiceClearTest") { "${data_service_path}/app/src/kvstore_data_service_stub.cpp", "${data_service_path}/app/src/kvstore_device_listener.cpp", "${data_service_path}/app/src/kvstore_meta_manager.cpp", + "${data_service_path}/app/src/kvstore_screen_observer.cpp", "${data_service_path}/app/src/security/security.cpp", "${data_service_path}/app/src/security/sensitive.cpp", "${data_service_path}/app/src/session_manager/route_head_handler_impl.cpp", @@ -287,12 +301,11 @@ ohos_unittest("KvStoreDataServiceClearTest") { } deps = [ - "${data_service_path}/adapter:distributeddata_adapter", - "${data_service_path}/adapter/broadcaster:distributeddata_broadcaster_static", - "${data_service_path}/adapter/utils:distributeddata_utils_static", - "${data_service_path}/app/src/checker:distributeddata_checker_static", - "${data_service_path}/app/src/flowctrl_manager:distributeddata_flowctrl_static", - "${data_service_path}/app/src/installer:distributeddata_installer_static", + "${data_service_path}/adapter/broadcaster:distributeddata_broadcaster", + "${data_service_path}/adapter/utils:distributeddata_utils", + "${data_service_path}/app/src/checker:distributeddata_checker", + "${data_service_path}/app/src/flowctrl_manager:distributeddata_flowctrl", + "${data_service_path}/app/src/installer:distributeddata_installer", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", "//third_party/googletest:gtest_main", @@ -301,6 +314,71 @@ ohos_unittest("KvStoreDataServiceClearTest") { part_name = "datamgr_service" } +ohos_unittest("FeatureStubImplTest") { + module_out_path = module_output_path + + include_dirs = [ + "${data_service_path}/adapter/include/permission", + "${data_service_path}/adapter/include/account", + "${data_service_path}/adapter/include", + "${data_service_path}/adapter/include/dfx", + "${data_service_path}/adapter/include/broadcaster", + "${data_service_path}/adapter/include/utils", + "${data_service_path}/framework/include", + "${data_service_path}/service/bootstrap/include", + "${data_service_path}/service/common", + "${data_service_path}/service/config/include", + "${data_service_path}/service/crypto/include", + "${data_service_path}/service/directory/include", + "${data_service_path}/service/permission/include", + "${data_service_path}/service/matrix/include", + "${data_service_path}/app/src/session_manager", + "${data_service_path}/app/src", + "${data_service_path}/service/kvdb", + ] + + sources = [ + "${data_service_path}/app/src/feature_stub_impl.cpp", + "unittest/feature_stub_impl_test.cpp", + ] + + external_deps = [ + "access_token:libaccesstoken_sdk", + "c_utils:utils", + "dataclassification:data_transit_mgr", + "device_auth:deviceauth_sdk", + "file_api:securitylabel", + "googletest:gtest_main", + "hilog:libhilog", + "hisysevent:libhisysevent", + "ipc:ipc_core", + "kv_store:distributeddata_inner", + "kv_store:distributeddata_mgr", + "kv_store:distributeddb", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + ] + + cflags = [ + "-Dprivate=public", + "-Dprotected=public", + ] + + if (datamgr_service_power) { + external_deps += [ + "battery_manager:batterysrv_client", + "power_manager:powermgr_client", + ] + } + + deps = [ + "${data_service_path}/app/src/flowctrl_manager:distributeddata_flowctrl", + "${data_service_path}/framework:distributeddatasvcfwk", + "${data_service_path}/service:distributeddatasvc", + ] + part_name = "datamgr_service" +} + ############################################################################### group("unittest") { @@ -308,6 +386,7 @@ group("unittest") { deps = [] deps += [ + ":FeatureStubImplTest", ":KvStoreDataServiceClearTest", ":KvStoreDataServiceTest", ":KvStoreFlowCtrlManagerTest", diff --git a/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/BUILD.gn index 4294628127cf9b3d28bd35cf48f3bda8979d7091..4b3b0124d94491fc0ca763cbfc84ebf52ad5fbc5 100644 --- a/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/app/test/fuzztest/dataservicestub_fuzzer/BUILD.gn @@ -26,6 +26,7 @@ ohos_fuzztest("DataServiceStubFuzzTest") { "${data_service_path}/service/bootstrap/include", "${data_service_path}/service/config/include", "${data_service_path}/service/crypto/include", + "${data_service_path}/service/data_share/common", "${data_service_path}/service/directory/include", "${data_service_path}/service/permission/include", "${data_service_path}/service/matrix/include", @@ -41,7 +42,6 @@ ohos_fuzztest("DataServiceStubFuzzTest") { "${data_service_path}/service/common", "${data_service_path}/service/dumper/include", "${data_service_path}/service/kvdb", - "${data_service_path}/service/waterversion", "${data_service_path}/adapter/include/account", "${data_service_path}/adapter/include/permission", "${data_service_path}/adapter/include/installer", @@ -51,6 +51,7 @@ ohos_fuzztest("DataServiceStubFuzzTest") { "${data_service_path}/adapter/include", "${device_manager_path}/interfaces/inner_kits/native_cpp/include", "//third_party/json/single_include", + "${data_service_path}/adapter/include/communicator", ] fuzz_config_file = @@ -64,6 +65,8 @@ ohos_fuzztest("DataServiceStubFuzzTest") { ] sources = [ + "${data_service_path}/app/src/clone/clone_backup_info.cpp", + "${data_service_path}/app/src/clone/secret_key_backup_data.cpp", "${data_service_path}/app/src/db_info_handle_impl.cpp", "${data_service_path}/app/src/feature_stub_impl.cpp", "${data_service_path}/app/src/kvstore_account_observer.cpp", @@ -71,6 +74,7 @@ ohos_fuzztest("DataServiceStubFuzzTest") { "${data_service_path}/app/src/kvstore_data_service_stub.cpp", "${data_service_path}/app/src/kvstore_device_listener.cpp", "${data_service_path}/app/src/kvstore_meta_manager.cpp", + "${data_service_path}/app/src/kvstore_screen_observer.cpp", "${data_service_path}/app/src/security/security.cpp", "${data_service_path}/app/src/security/sensitive.cpp", "${data_service_path}/app/src/session_manager/route_head_handler_impl.cpp", @@ -82,12 +86,12 @@ ohos_fuzztest("DataServiceStubFuzzTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", - "${data_service_path}/adapter/broadcaster:distributeddata_broadcaster_static", - "${data_service_path}/adapter/utils:distributeddata_utils_static", - "${data_service_path}/app/src/checker:distributeddata_checker_static", - "${data_service_path}/app/src/flowctrl_manager:distributeddata_flowctrl_static", - "${data_service_path}/app/src/installer:distributeddata_installer_static", + "${data_service_path}/adapter/account:distributeddata_account", + "${data_service_path}/adapter/broadcaster:distributeddata_broadcaster", + "${data_service_path}/adapter/utils:distributeddata_utils", + "${data_service_path}/app/src/checker:distributeddata_checker", + "${data_service_path}/app/src/flowctrl_manager:distributeddata_flowctrl", + "${data_service_path}/app/src/installer:distributeddata_installer", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", "${kv_store_distributeddb_path}:distributeddb", diff --git a/datamgr_service/services/distributeddataservice/app/test/unittest/feature_stub_impl_test.cpp b/datamgr_service/services/distributeddataservice/app/test/unittest/feature_stub_impl_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bae31a7d32306a371e1ceb4c1e5853e993a9c7b8 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/app/test/unittest/feature_stub_impl_test.cpp @@ -0,0 +1,550 @@ +/* +* Copyright (c) 2024 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 "FeatureStubImplTest" + +#include "auto_launch_export.h" +#include "bootstrap.h" +#include "error/general_error.h" +#include "executor_pool.h" +#include "feature_stub_impl.h" +#include "feature/feature_system.h" +#include "gtest/gtest.h" +#include "ipc_skeleton.h" +#include "iremote_stub.h" + +using namespace OHOS; +using namespace testing::ext; +using namespace OHOS::DistributedData; +namespace OHOS::Test { +namespace DistributedDataTest { + +class FeatureStubImplTest : public testing::Test { +public: + static void SetUpTestCase(void){}; + static void TearDownTestCase(void){}; + void SetUp(){}; + void TearDown(){}; +}; + +class MockFeature : public FeatureSystem::Feature { +public: + int OnRemoteRequest(uint32_t code, OHOS::MessageParcel& data, OHOS::MessageParcel& reply) override + { + return E_OK; + } + int32_t OnInitialize() override + { + return E_OK; + } + int32_t OnBind(const BindInfo &bindInfo) override + { + return E_OK; + } + int32_t OnAppExit(pid_t uid, pid_t pid, uint32_t tokenId, const std::string &bundleName) override + { + return E_OK; + } + int32_t OnAppUninstall(const std::string &bundleName, int32_t user, int32_t index) override + { + return E_OK; + } + int32_t OnAppUpdate(const std::string &bundleName, int32_t user, int32_t index) override + { + return E_OK; + } + int32_t OnAppInstall(const std::string &bundleName, int32_t user, int32_t index) override + { + return E_OK; + } + int32_t ResolveAutoLaunch(const std::string &identifier, DistributedDB::AutoLaunchParam ¶m) override + { + return E_OK; + } + int32_t OnUserChange(uint32_t code, const std::string &user, const std::string &account) override + { + return E_OK; + } + int32_t Online(const std::string &device) override + { + return E_OK; + } + int32_t Offline(const std::string &device) override + { + return E_OK; + } + int32_t OnReady(const std::string &device) override + { + return E_OK; + } + int32_t OnSessionReady(const std::string &device) override + { + return E_OK; + } + int32_t OnScreenUnlocked(int32_t user) override + { + return E_OK; + } +}; + +/** +* @tc.name: OnRemoteRequest001 +* @tc.desc: OnRemoteRequest function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnRemoteRequest001, TestSize.Level1) +{ + std::shared_ptr feature = nullptr; + std::shared_ptr featureStubImpl = std::make_shared(feature); + uint32_t code = 0; + MessageParcel data; + MessageParcel reply; + MessageOption option; + auto result = featureStubImpl->OnRemoteRequest(code, data, reply, option); + EXPECT_NE(result, E_OK); +} + +/** +* @tc.name: OnRemoteRequest002 +* @tc.desc: OnRemoteRequest function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnRemoteRequest002, TestSize.Level1) +{ + std::shared_ptr feature = std::make_shared(); + std::shared_ptr featureStubImpl = std::make_shared(feature); + uint32_t code = 0; + MessageParcel data; + MessageParcel reply; + MessageOption option; + auto result = featureStubImpl->OnRemoteRequest(code, data, reply, option); + EXPECT_EQ(result, E_OK); +} + +/** +* @tc.name: OnInitialize001 +* @tc.desc: OnInitialize function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnInitialize001, TestSize.Level1) +{ + std::shared_ptr feature = nullptr; + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::shared_ptr executor = std::make_shared(1, 0); + auto result = featureStubImpl->OnInitialize(executor); + EXPECT_EQ(result, -1); +} + +/** +* @tc.name: OnInitialize002 +* @tc.desc: OnInitialize function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnInitialize002, TestSize.Level1) +{ + std::shared_ptr feature = std::make_shared(); + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::shared_ptr executor = std::make_shared(1, 0); + auto result = featureStubImpl->OnInitialize(executor); + EXPECT_EQ(result, E_OK); +} + +/** +* @tc.name: OnAppExit001 +* @tc.desc: OnAppExit function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnAppExit001, TestSize.Level1) +{ + std::shared_ptr feature = nullptr; + std::shared_ptr featureStubImpl = std::make_shared(feature); + pid_t uid = 0; + pid_t pid = 0; + uint32_t tokenId = 0; + std::string bundleName = "com.ohos.test"; + std::shared_ptr executor = std::make_shared(1, 0); + auto result = featureStubImpl->OnAppExit(uid, pid, tokenId, bundleName); + EXPECT_EQ(result, -1); +} + +/** +* @tc.name: OnAppExit002 +* @tc.desc: OnAppExit function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnAppExit002, TestSize.Level1) +{ + std::shared_ptr feature = std::make_shared(); + std::shared_ptr featureStubImpl = std::make_shared(feature); + pid_t uid = 0; + pid_t pid = 0; + uint32_t tokenId = 0; + std::string bundleName = "com.ohos.test"; + std::shared_ptr executor = std::make_shared(1, 0); + auto result = featureStubImpl->OnAppExit(uid, pid, tokenId, bundleName); + EXPECT_EQ(result, E_OK); +} + +/** +* @tc.name: OnAppUninstall001 +* @tc.desc: OnAppUninstall function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnAppUninstall001, TestSize.Level1) +{ + std::shared_ptr feature = nullptr; + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::string bundleName = "com.ohos.test"; + int32_t user = 0; + int32_t index = 0; + auto result = featureStubImpl->OnAppUninstall(bundleName, user, index); + EXPECT_EQ(result, -1); +} + +/** +* @tc.name: OnAppUninstall002 +* @tc.desc: OnAppUninstall function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnAppUninstall002, TestSize.Level1) +{ + std::shared_ptr feature = std::make_shared(); + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::string bundleName = "com.ohos.test"; + int32_t user = 0; + int32_t index = 0; + auto result = featureStubImpl->OnAppUninstall(bundleName, user, index); + EXPECT_EQ(result, E_OK); +} + +/** +* @tc.name: OnAppUpdate001 +* @tc.desc: OnAppUpdate function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnAppUpdate001, TestSize.Level1) +{ + std::shared_ptr feature = nullptr; + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::string bundleName = "com.ohos.test"; + int32_t user = 0; + int32_t index = 0; + auto result = featureStubImpl->OnAppUpdate(bundleName, user, index); + EXPECT_EQ(result, -1); +} + +/** +* @tc.name: OnAppUpdate002 +* @tc.desc: OnAppUpdate function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnAppUpdate002, TestSize.Level1) +{ + std::shared_ptr feature = std::make_shared(); + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::string bundleName = "com.ohos.test"; + int32_t user = 0; + int32_t index = 0; + auto result = featureStubImpl->OnAppUpdate(bundleName, user, index); + EXPECT_EQ(result, E_OK); +} + +/** +* @tc.name: OnAppInstall001 +* @tc.desc: OnAppInstall function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnAppInstall001, TestSize.Level1) +{ + std::shared_ptr feature = nullptr; + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::string bundleName = "com.ohos.test"; + int32_t user = 0; + int32_t index = 0; + auto result = featureStubImpl->OnAppInstall(bundleName, user, index); + EXPECT_EQ(result, -1); +} + +/** +* @tc.name: OnAppInstall002 +* @tc.desc: OnAppInstall function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnAppInstall002, TestSize.Level1) +{ + std::shared_ptr feature = std::make_shared(); + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::string bundleName = "com.ohos.test"; + int32_t user = 0; + int32_t index = 0; + auto result = featureStubImpl->OnAppInstall(bundleName, user, index); + EXPECT_EQ(result, E_OK); +} + +/** +* @tc.name: ResolveAutoLaunch001 +* @tc.desc: ResolveAutoLaunch function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, ResolveAutoLaunch001, TestSize.Level1) +{ + std::shared_ptr feature = nullptr; + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::string identifier = "identifier"; + DistributedDB::AutoLaunchParam param; + auto result = featureStubImpl->ResolveAutoLaunch(identifier, param); + EXPECT_EQ(result, -1); +} + +/** +* @tc.name: ResolveAutoLaunch002 +* @tc.desc: ResolveAutoLaunch function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, ResolveAutoLaunch002, TestSize.Level1) +{ + std::shared_ptr feature = std::make_shared(); + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::string identifier = "identifier"; + DistributedDB::AutoLaunchParam param; + auto result = featureStubImpl->ResolveAutoLaunch(identifier, param); + EXPECT_EQ(result, E_OK); +} + +/** +* @tc.name: OnUserChange001 +* @tc.desc: OnUserChange function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnUserChange001, TestSize.Level1) +{ + std::shared_ptr feature = nullptr; + std::shared_ptr featureStubImpl = std::make_shared(feature); + uint32_t code = 0; + std::string user = "user"; + std::string account = "account"; + auto result = featureStubImpl->OnUserChange(code, user, account); + EXPECT_EQ(result, -1); +} + +/** +* @tc.name: OnUserChange002 +* @tc.desc: OnUserChange function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnUserChange002, TestSize.Level1) +{ + std::shared_ptr feature = std::make_shared(); + std::shared_ptr featureStubImpl = std::make_shared(feature); + uint32_t code = 0; + std::string user = "user"; + std::string account = "account"; + auto result = featureStubImpl->OnUserChange(code, user, account); + EXPECT_EQ(result, E_OK); +} + +/** +* @tc.name: Online001 +* @tc.desc: Online function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, Online001, TestSize.Level1) +{ + std::shared_ptr feature = nullptr; + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::string device = "device"; + auto result = featureStubImpl->Online(device); + EXPECT_EQ(result, -1); +} + +/** +* @tc.name: Online002 +* @tc.desc: Online function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, Online002, TestSize.Level1) +{ + std::shared_ptr feature = std::make_shared(); + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::string device = "device"; + auto result = featureStubImpl->Online(device); + EXPECT_EQ(result, E_OK); +} + +/** +* @tc.name: Offline001 +* @tc.desc: Offline function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, Offline001, TestSize.Level1) +{ + std::shared_ptr feature = nullptr; + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::string device = "device"; + auto result = featureStubImpl->Offline(device); + EXPECT_EQ(result, -1); +} + +/** +* @tc.name: Offline002 +* @tc.desc: Offline function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, Offline002, TestSize.Level1) +{ + std::shared_ptr feature = std::make_shared(); + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::string device = "device"; + auto result = featureStubImpl->Offline(device); + EXPECT_EQ(result, E_OK); +} + +/** +* @tc.name: OnReady001 +* @tc.desc: OnReady function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnReady001, TestSize.Level1) +{ + std::shared_ptr feature = nullptr; + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::string device = "device"; + auto result = featureStubImpl->OnReady(device); + EXPECT_EQ(result, -1); +} + +/** +* @tc.name: OnReady002 +* @tc.desc: OnReady function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnReady002, TestSize.Level1) +{ + std::shared_ptr feature = std::make_shared(); + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::string device = "device"; + auto result = featureStubImpl->OnReady(device); + EXPECT_EQ(result, E_OK); +} + +/** +* @tc.name: OnSessionReady001 +* @tc.desc: OnSessionReady function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnSessionReady001, TestSize.Level1) +{ + std::shared_ptr feature = nullptr; + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::string device = "device"; + auto result = featureStubImpl->OnSessionReady(device); + EXPECT_EQ(result, -1); +} + +/** +* @tc.name: OnSessionReady002 +* @tc.desc: OnSessionReady function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnSessionReady002, TestSize.Level1) +{ + std::shared_ptr feature = std::make_shared(); + std::shared_ptr featureStubImpl = std::make_shared(feature); + std::string device = "device"; + auto result = featureStubImpl->OnSessionReady(device); + EXPECT_EQ(result, E_OK); +} + +/** +* @tc.name: OnScreenUnlocked001 +* @tc.desc: OnScreenUnlocked function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnScreenUnlocked001, TestSize.Level1) +{ + std::shared_ptr feature = nullptr; + std::shared_ptr featureStubImpl = std::make_shared(feature); + int32_t user = 0; + auto result = featureStubImpl->OnScreenUnlocked(user); + EXPECT_EQ(result, -1); +} + +/** +* @tc.name: OnScreenUnlocked002 +* @tc.desc: OnScreenUnlocked function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(FeatureStubImplTest, OnScreenUnlocked002, TestSize.Level1) +{ + std::shared_ptr feature = std::make_shared(); + std::shared_ptr featureStubImpl = std::make_shared(feature); + int32_t user = 0; + auto result = featureStubImpl->OnScreenUnlocked(user); + EXPECT_EQ(result, E_OK); +} +} // namespace DistributedDataTest +} // namespace OHOS::Test \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/app/test/unittest/kvstore_data_service_test.cpp b/datamgr_service/services/distributeddataservice/app/test/unittest/kvstore_data_service_test.cpp index f9aa98e7c1f949f5069d4bd390aa2dd453e8dfcc..b6b05a974530d0bcc9751f4ed6c838cc7682cd20 100644 --- a/datamgr_service/services/distributeddataservice/app/test/unittest/kvstore_data_service_test.cpp +++ b/datamgr_service/services/distributeddataservice/app/test/unittest/kvstore_data_service_test.cpp @@ -15,8 +15,11 @@ #include "auth_delegate.h" #include "bootstrap.h" +#include "crypto_manager.h" +#include "device_manager_adapter.h" #include "executor_pool.h" #include +#include "metadata/secret_key_meta_data.h" #include "metadata/store_meta_data.h" #include #include "kvstore_client_death_observer.h" @@ -35,6 +38,26 @@ using namespace OHOS::DistributedData; using StoreMetaData = DistributedData::StoreMetaData; namespace OHOS::Test { +const std::string SECRETKEY_BACKUP_PATH = "/data/service/el1/public/database/backup_test/"; +const std::string SECRETKEY_BACKUP_FILE = SECRETKEY_BACKUP_PATH + "secret_key_backup.conf"; +const std::string NORMAL_CLONE_INFO = + "[{\"type\":\"encryption_info\",\"detail\":{\"encryption_symkey\":\"27," + "145,118,212,62,156,133,135,50,68,188,239,20,170,227,190,37,142,218," + "158,177,32,5,160,13,114,186,141,59,91,44,200\",\"encryption_algname\":" + "\"AES256\",\"gcmParams_iv\":\"97,160,201,177,46,37,129,18,112,220,107," + "106,25,231,15,15,58,85,31,83,123,216,211,2,222,49,122,72,21,251,83," + "16\"}},{\"type\":\"application_selection\",\"detail\":[{" + "\"bundleName\":\"com.example.restore_test\",\"accessTokenId\":" + "536973769}]},{\"type\":\"userId\",\"detail\":\"100\"}]"; +const std::string NORMAL_BACKUP_DATA = + "{\"infos\":[{\"bundleName\":\"com.myapp.example\",\"dbName\":" + "\"storeId\",\"instanceId\":0,\"storeType\":\"1\",\"user\":\"100\"," + "\"sKey\":\"9aJQwx3XD3EN7To2j/I9E9MCzn2+6f/bBqFjOPcY+1pRgx/" + "XI6jXedyuzEEVdwrc\",\"time\":[50,180,137,103,0,0,0,0]},{" + "\"bundleName\":\"sa1\",\"dbName\":\"storeId1\",\"instanceId\":\"0\"," + "\"dbType\":\"1\",\"user\":\"0\",\"sKey\":\"9aJQwx3XD3EN7To2j/" + "I9E9MCzn2+6f/bBqFjOPcY+1pRgx/" + "XI6jXedyuzEEVdwrc\",\"time\":[50,180,137,103,0,0,0,0]}]}"; class KvStoreDataServiceTest : public testing::Test { public: static void SetUpTestCase(void); @@ -48,10 +71,24 @@ public: }; void KvStoreDataServiceTest::SetUpTestCase(void) -{} +{ + mode_t mode = S_IRWXU | S_IRWXG | S_IXOTH; // 0771 + mkdir(SECRETKEY_BACKUP_PATH.c_str(), mode); + auto executors = std::make_shared(12, 5); + Bootstrap::GetInstance().LoadComponents(); + Bootstrap::GetInstance().LoadDirectory(); + Bootstrap::GetInstance().LoadCheckers(); + KvStoreMetaManager::GetInstance().BindExecutor(executors); + KvStoreMetaManager::GetInstance().InitMetaParameter(); + KvStoreMetaManager::GetInstance().InitMetaListener(); + DeviceManagerAdapter::GetInstance().Init(executors); +} void KvStoreDataServiceTest::TearDownTestCase(void) -{} +{ + (void)remove(SECRETKEY_BACKUP_FILE.c_str()); + (void)rmdir(SECRETKEY_BACKUP_PATH.c_str()); +} void KvStoreDataServiceTest::SetUp(void) {} @@ -79,6 +116,23 @@ void UpgradeManagerTest::SetUp(void) void UpgradeManagerTest::TearDown(void) {} +static int32_t WriteContentToFile(const std::string &path, const std::string &content) +{ + FILE *fp = fopen(path.c_str(), "w"); + if (!fp) { + return -1; + } + size_t ret = fwrite(content.c_str(), 1, content.length(), fp); + if (ret != content.length()) { + (void)fclose(fp); + return -1; + } + (void)fflush(fp); + (void)fsync(fileno(fp)); + (void)fclose(fp); + return 0; +} + /** * @tc.name: RegisterClientDeathObserver001 * @tc.desc: register client death observer @@ -631,4 +685,358 @@ HWTEST_F(UpgradeManagerTest, UpgradeManagerTest001, TestSize.Level0) instance.Init(executors); EXPECT_TRUE(instance.executors_); } + +/** +* @tc.name: OnExtensionRestore001 +* @tc.desc: restore with invalid fd +* @tc.type: FUNC +* @tc.require: +* @tc.author: yanhui +*/ +HWTEST_F(KvStoreDataServiceTest, OnExtensionRestore001, TestSize.Level0) +{ + KvStoreDataService kvStoreDataServiceTest; + MessageParcel data; + MessageParcel reply; + data.WriteFileDescriptor(-1); + EXPECT_EQ(kvStoreDataServiceTest.OnExtension("restore", data, reply), -1); +} + +/** +* @tc.name: OnExtensionRestore002 +* @tc.desc: restore with invalid json +* @tc.type: FUNC +* @tc.require: +* @tc.author: yanhui +*/ +HWTEST_F(KvStoreDataServiceTest, OnExtensionRestore002, TestSize.Level0) +{ + KvStoreDataService kvStoreDataServiceTest; + MessageParcel data; + MessageParcel reply; + EXPECT_EQ(WriteContentToFile(SECRETKEY_BACKUP_FILE, "{}"), 0); + int32_t fd = open(SECRETKEY_BACKUP_FILE.c_str(), O_RDONLY); + ASSERT_GE(fd, 0); + data.WriteFileDescriptor(fd); + std::string cloneInfoStr = "[{\"type\":\"application_selection\",\"detail\""; + data.WriteString(cloneInfoStr); + EXPECT_EQ(kvStoreDataServiceTest.OnExtension("restore", data, reply), -1); + close(fd); +} + +/** +* @tc.name: OnExtensionRestore003 +* @tc.desc: restore with empty backup content +* @tc.type: FUNC +* @tc.require: +* @tc.author: yanhui +*/ +HWTEST_F(KvStoreDataServiceTest, OnExtensionRestore003, TestSize.Level0) +{ + KvStoreDataService kvStoreDataServiceTest; + MessageParcel data; + MessageParcel reply; + EXPECT_EQ(WriteContentToFile(SECRETKEY_BACKUP_FILE, "{}"), 0); + int32_t fd = open(SECRETKEY_BACKUP_FILE.c_str(), O_RDONLY); + ASSERT_GE(fd, 0); + data.WriteFileDescriptor(fd); + data.WriteString(NORMAL_CLONE_INFO); + EXPECT_EQ(kvStoreDataServiceTest.OnExtension("restore", data, reply), -1); + close(fd); +} + +/** +* @tc.name: OnExtensionRestore004 +* @tc.desc: restore with invalid backup item +* @tc.type: FUNC +* @tc.require: +* @tc.author: yanhui +*/ +HWTEST_F(KvStoreDataServiceTest, OnExtensionRestore004, TestSize.Level0) +{ + KvStoreDataService kvStoreDataServiceTest; + MessageParcel data; + MessageParcel reply; + std::string backupData = + "{\"infos\":[{\"bundleName\":\"\",\"dbName\":" + "\"storeId\",\"instanceId\":0,\"storeType\":\"1\",\"user\":\"100\"," + "\"key\":\"9aJQwx3XD3EN7To2j/I9E9MCzn2+6f/bBqFjOPcY+1pRgx/" + "XI6jXedyuzEEVdwrc\",\"time\":[50,180,137,103,0,0,0,0]},{" + "\"bundleName\":\"sa1\",\"dbName\":\"\",\"instanceId\":\"0\"," + "\"dbType\":\"1\",\"user\":\"0\",\"key\":\"9aJQwx3XD3EN7To2j/" + "I9E9MCzn2+6f/bBqFjOPcY+1pRgx/" + "XI6jXedyuzEEVdwrc\",\"time\":[50,180,137,103,0,0,0,0]}]}"; + EXPECT_EQ(WriteContentToFile(SECRETKEY_BACKUP_FILE, backupData), 0); + int32_t fd = open(SECRETKEY_BACKUP_FILE.c_str(), O_RDONLY); + ASSERT_GE(fd, 0); + data.WriteFileDescriptor(fd); + data.WriteString(NORMAL_CLONE_INFO); + EXPECT_EQ(kvStoreDataServiceTest.OnExtension("restore", data, reply), 0); + close(fd); +} + +/** +* @tc.name: OnExtensionRestore005 +* @tc.desc: restore with empty userId +* @tc.type: FUNC +* @tc.require: +* @tc.author: yanhui +*/ +HWTEST_F(KvStoreDataServiceTest, OnExtensionRestore005, TestSize.Level0) +{ + KvStoreDataService kvStoreDataServiceTest; + MessageParcel data; + MessageParcel reply; + + std::string cloneInfoStr = + "[{\"type\":\"encryption_info\",\"detail\":{\"encryption_symkey\":\"27," + "145,118,212,62,156,133,135,50,68,188,239\",\"encryption_algname\":" + "\"AES256\",\"gcmParams_iv\":\"97,160,201,177,46,37,129,18,112,220,107," + "106,25,231,15,15,58,85,31,83,123,216,211,2,222,49,122,72,21,251,83," + "16\"}},{\"type\":\"userId\",\"detail\":\"\"}]"; + EXPECT_EQ(WriteContentToFile(SECRETKEY_BACKUP_FILE, NORMAL_BACKUP_DATA), 0); + int32_t fd = open(SECRETKEY_BACKUP_FILE.c_str(), O_RDONLY); + ASSERT_GE(fd, 0); + data.WriteFileDescriptor(fd); + data.WriteString(cloneInfoStr); + EXPECT_EQ(kvStoreDataServiceTest.OnExtension("restore", data, reply), -1); + close(fd); +} + +/** +* @tc.name: OnExtensionRestore006 +* @tc.desc: restore success +* @tc.type: FUNC +* @tc.require: +* @tc.author: yanhui +*/ +HWTEST_F(KvStoreDataServiceTest, OnExtensionRestore006, TestSize.Level0) +{ + KvStoreDataService kvStoreDataServiceTest; + MessageParcel data; + MessageParcel reply; + EXPECT_EQ(WriteContentToFile(SECRETKEY_BACKUP_FILE, NORMAL_BACKUP_DATA), 0); + int32_t fd = open(SECRETKEY_BACKUP_FILE.c_str(), O_RDONLY); + ASSERT_GE(fd, 0); + data.WriteFileDescriptor(fd); + data.WriteString(NORMAL_CLONE_INFO); + EXPECT_EQ(kvStoreDataServiceTest.OnExtension("restore", data, reply), 0); + close(fd); +} + +/** + * @tc.name: OnExtensionBackup001 + * @tc.desc: test OnExtension function backup invalid json + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(KvStoreDataServiceTest, OnExtensionBackup001, TestSize.Level0) { + KvStoreDataService kvStoreDataServiceTest; + MessageParcel data; + MessageParcel reply; + + data.WriteString("InvalidJson"); + EXPECT_EQ(kvStoreDataServiceTest.OnExtension("backup", data, reply), -1); +} + +/** + * @tc.name: OnExtensionBackup002 + * @tc.desc: test OnExtension function backup application empty + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(KvStoreDataServiceTest, OnExtensionBackup002, TestSize.Level0) { + KvStoreDataService kvStoreDataServiceTest; + MessageParcel data; + MessageParcel reply; + + std::string cloneInfoStr = + "[{\"type\": \"application_selection\",\"detail\": []}]"; + data.WriteString(cloneInfoStr); + EXPECT_EQ(kvStoreDataServiceTest.OnExtension("backup", data, reply), -1); +} + +/** + * @tc.name: OnExtensionBackup003 + * @tc.desc: test OnExtension function backup no userInfo + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(KvStoreDataServiceTest, OnExtensionBackup003, TestSize.Level0) { + KvStoreDataService kvStoreDataServiceTest; + MessageParcel data; + MessageParcel reply; + + std::string cloneInfoStr = + "[{\"type\":\"application_selection\",\"detail\":[{\"bundleName\":" + "\"com.example.restore_test\",\"accessTokenId\":536973769}]}]"; + data.WriteString(cloneInfoStr); + EXPECT_EQ(kvStoreDataServiceTest.OnExtension("backup", data, reply), -1); +} + +/** + * @tc.name: OnExtensionBackup004 + * @tc.desc: test OnExtension function backup userinfo empty + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(KvStoreDataServiceTest, OnExtensionBackup004, TestSize.Level0) { + KvStoreDataService kvStoreDataServiceTest; + MessageParcel data; + MessageParcel reply; + + std::string cloneInfoStr = + "[{\"type\":\"application_selection\",\"detail\":[{\"bundleName\":" + "\"com.example.restore_test\",\"accessTokenId\":536973769}]},{\"type\":" + "\"userId\",\"detail\":\"\"}]"; + data.WriteString(cloneInfoStr); + EXPECT_EQ(kvStoreDataServiceTest.OnExtension("backup", data, reply), -1); +} + +/** + * @tc.name: OnExtensionBackup005 + * @tc.desc: test OnExtension function backup secret key length invalid + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(KvStoreDataServiceTest, OnExtensionBackup005, TestSize.Level0) { + KvStoreDataService kvStoreDataServiceTest; + MessageParcel data; + MessageParcel reply; + + std::string cloneInfoStr = + "[{\"type\":\"encryption_info\",\"detail\":{\"encryption_symkey\":\"27," + "145,118,212,62,156,133,135,50,68\",\"encryption_algname\":" + "\"AES256\",\"gcmParams_iv\":\"97,160,201,177,46,37,129,18,112,220,107," + "106,25,231,15,15,58,85,31,83,123,216,211,2,222,49,122,72,21,251,83," + "16\"}},{\"type\":\"application_selection\",\"detail\":[{" + "\"bundleName\":\"com.example.restore_test\",\"accessTokenId\":" + "536973769}]},{\"type\":\"userId\",\"detail\":\"100\"}]"; + data.WriteString(cloneInfoStr); + EXPECT_EQ(kvStoreDataServiceTest.OnExtension("backup", data, reply), -1); +} + +/** + * @tc.name: OnExtensionBackup006 + * @tc.desc: test OnExtension function backup secret iv length invalid + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(KvStoreDataServiceTest, OnExtensionBackup006, TestSize.Level0) { + KvStoreDataService kvStoreDataServiceTest; + MessageParcel data; + MessageParcel reply; + + std::string cloneInfoStr = + "[{\"type\":\"encryption_info\",\"detail\":{\"encryption_symkey\":\"27," + "145,118,212,62,156,133,135,50,68,188,239,20,170,227,190,37,142,218," + "158,177,32,5,160,13,114,186,141,59,91,44,200\",\"encryption_algname\":" + "\"AES256\",\"gcmParams_iv\":\"97,160,201,112,220,107,106,25,231" + "16\"}},{\"type\":\"application_selection\",\"detail\":[{" + "\"bundleName\":\"com.example.restore_test\",\"accessTokenId\":" + "536973769}]},{\"type\":\"userId\",\"detail\":\"100\"}]"; + data.WriteString(cloneInfoStr); + EXPECT_EQ(kvStoreDataServiceTest.OnExtension("backup", data, reply), -1); +} + +/** + * @tc.name: OnExtensionBackup007 + * @tc.desc: test OnExtension function backup no bundle + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(KvStoreDataServiceTest, OnExtensionBackup007, TestSize.Level0) { + KvStoreDataService kvStoreDataServiceTest; + MessageParcel data; + MessageParcel reply; + + std::string cloneInfoStr = + "[{\"type\":\"encryption_info\",\"detail\":{\"encryption_symkey\":\"27," + "145,118,212,62,156,133,135,50,68,188,239,20,170,227,190,37,142,218," + "158,177,32,5,160,13,114,186,141,59,91,44,200\",\"encryption_algname\":" + "\"AES256\",\"gcmParams_iv\":\"97,160,201,177,46,37,129,18,112,220,107," + "106,25,231,15,15,58,85,31,83,123,216,211,2,222,49,122,72,21,251,83," + "16\"}},{\"type\":\"application_selection\",\"detail\":[{" + "\"bundleName\":\"notexistbundle\",\"accessTokenId\":" + "536973769}]},{\"type\":\"userId\",\"detail\":\"100\"}]"; + data.WriteString(cloneInfoStr); + EXPECT_EQ(kvStoreDataServiceTest.OnExtension("backup", data, reply), 0); + UniqueFd fd(reply.ReadFileDescriptor()); + struct stat statBuf; + EXPECT_TRUE(fstat(fd.Get(), &statBuf) == 0); + EXPECT_TRUE(statBuf.st_size > 0); + + char buffer[statBuf.st_size + 1]; + EXPECT_TRUE(read(fd.Get(), buffer, statBuf.st_size + 1) > 0); + std::string secretKeyStr(buffer); + EXPECT_TRUE(secretKeyStr == "{\"infos\":[]}"); +} + +/** + * @tc.name: OnExtensionBackup008 + * @tc.desc: test OnExtension function backup no bundle + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(KvStoreDataServiceTest, OnExtensionBackup008, TestSize.Level0) { + KvStoreDataService kvStoreDataServiceTest; + MessageParcel data; + MessageParcel reply; + StoreMetaData testMeta; + testMeta.bundleName = "com.example.restore_test"; + testMeta.storeId = "Source"; + testMeta.user = "100"; + testMeta.instanceId = 0; + testMeta.deviceId = + DeviceManagerAdapter::GetInstance().GetLocalDevice().uuid; + testMeta.isEncrypt = true; + std::vector sKey{2, 249, 221, 119, 177, 216, 217, 134, 185, 139, + 114, 38, 140, 64, 165, 35, 77, 169, 0, 226, + 226, 166, 37, 73, 181, 229, 42, 88, 108, 111, + 131, 104, 141, 43, 96, 119, 214, 34, 177, 129, + 233, 96, 98, 164, 87, 115, 187, 170}; + SecretKeyMetaData testSecret; + testSecret.sKey = CryptoManager::GetInstance().Encrypt(sKey); + testSecret.storeType = 10; + testSecret.time = std::vector{233, 39, 137, 103, 0, 0, 0, 0}; + EXPECT_EQ(MetaDataManager::GetInstance().SaveMeta(testMeta.GetKey(), + testMeta, true), + true); + EXPECT_EQ(MetaDataManager::GetInstance().SaveMeta(testMeta.GetSecretKey(), + testSecret, true), + true); + + std::string cloneInfoStr = + "[{\"type\":\"encryption_info\",\"detail\":{\"encryption_symkey\":\"27," + "145,118,212,62,156,133,135,50,68,188,239,20,170,227,190,37,142,218," + "158,177,32,5,160,13,114,186,141,59,91,44,200\",\"encryption_algname\":" + "\"AES256\",\"gcmParams_iv\":\"97,160,201,177,46,37,129,18,112,220,107," + "106,25,231,15,15,58,85,31,83,123,216,211,2,222,49,122,72,21,251,83," + "16\"}},{\"type\":\"application_selection\",\"detail\":[{" + "\"bundleName\":\"com.example.restore_test\",\"accessTokenId\":" + "536973769},{\"bundleName\":\"com.example.notexist\",\"accessTokenId\":" + "536973769}]},{\"type\":\"userId\",\"detail\":\"100\"}]"; + data.WriteString(cloneInfoStr); + EXPECT_EQ(kvStoreDataServiceTest.OnExtension("backup", data, reply), 0); + UniqueFd fd(reply.ReadFileDescriptor()); + struct stat statBuf; + EXPECT_TRUE(fstat(fd.Get(), &statBuf) == 0); + EXPECT_TRUE(statBuf.st_size > 0); + + char buffer[statBuf.st_size + 1]; + EXPECT_TRUE(read(fd.Get(), buffer, statBuf.st_size + 1) > 0); + std::string secretKeyStr(buffer); + SecretKeyBackupData backupData; + backupData.Unmarshal(DistributedData::Serializable::ToJson(secretKeyStr)); + + EXPECT_TRUE(backupData.infos.size() == 1); +} } // namespace OHOS::Test \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/framework/BUILD.gn b/datamgr_service/services/distributeddataservice/framework/BUILD.gn index 0456d7f2268788b9af25762b5158b0e00b3ae1c2..9f86825eda637113c1f69ef6fb20c5b1776a90f8 100644 --- a/datamgr_service/services/distributeddataservice/framework/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/framework/BUILD.gn @@ -98,10 +98,13 @@ ohos_shared_library("distributeddatasvcfwk") { "snapshot/bind_event.cpp", "snapshot/snapshot.cpp", "store/auto_cache.cpp", + "thread/thread_manager.cpp", "utils/anonymous.cpp", + "utils/base64_utils.cpp", "utils/block_integer.cpp", "utils/constant.cpp", "utils/converter.cpp", + "utils/corrupt_reporter.cpp", "utils/crypto.cpp", "utils/ref_count.cpp", ] @@ -120,6 +123,7 @@ ohos_shared_library("distributeddatasvcfwk") { external_deps = [ "access_token:libaccesstoken_sdk", "c_utils:utils", + "common_event_service:cesfwk_innerkits", "hilog:libhilog", "json:nlohmann_json_static", "openssl:libcrypto_shared", diff --git a/datamgr_service/services/distributeddataservice/framework/CMakeLists.txt b/datamgr_service/services/distributeddataservice/framework/CMakeLists.txt index 9166243b738ddfd32191bc8754cd8b8e242cd999..a83b5cdbf2e54e5cbdf7a1baad9fec5237a13dfc 100644 --- a/datamgr_service/services/distributeddataservice/framework/CMakeLists.txt +++ b/datamgr_service/services/distributeddataservice/framework/CMakeLists.txt @@ -26,6 +26,7 @@ aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/screen svcFwkSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/serializable svcFwkSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/snapshot svcFwkSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/store svcFwkSrc) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/thread svcFwkSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/utils svcFwkSrc) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../adapter/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../../utils_native/base/include) diff --git a/datamgr_service/services/distributeddataservice/framework/account/account_delegate.cpp b/datamgr_service/services/distributeddataservice/framework/account/account_delegate.cpp index 1734d6541b80be85e2bbb28e63018590ba27242f..2b77557d43bc96b5fbac2ab39e6c99824e6a8ada 100644 --- a/datamgr_service/services/distributeddataservice/framework/account/account_delegate.cpp +++ b/datamgr_service/services/distributeddataservice/framework/account/account_delegate.cpp @@ -16,7 +16,7 @@ #include "account_delegate.h" namespace OHOS { -namespace DistributedKv { +namespace DistributedData { AccountDelegate *AccountDelegate::instance_ = nullptr; bool AccountDelegate::RegisterAccountInstance(AccountDelegate *instance) @@ -32,5 +32,5 @@ AccountDelegate *AccountDelegate::GetInstance() { return instance_; } -} // namespace DistributedKv +} // namespace DistributedData } // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/framework/cloud/asset_loader.cpp b/datamgr_service/services/distributeddataservice/framework/cloud/asset_loader.cpp index fdaf28e3e90f6c95897ddd95969a2f89301ae4ea..eb435873ca39968c35e913f85607e980045919d4 100644 --- a/datamgr_service/services/distributeddataservice/framework/cloud/asset_loader.cpp +++ b/datamgr_service/services/distributeddataservice/framework/cloud/asset_loader.cpp @@ -33,7 +33,7 @@ int32_t AssetLoader::RemoveLocalAssets( return E_NOT_SUPPORT; } -int32_t AssetLoader::Cancel() +int32_t AssetLoader::CancelDownload() { return E_NOT_SUPPORT; } diff --git a/datamgr_service/services/distributeddataservice/framework/cloud/cloud_lock_event.cpp b/datamgr_service/services/distributeddataservice/framework/cloud/cloud_lock_event.cpp index c9d2b4eaf2ad588787af216346e9187d25cc78eb..206c03636ab1dbca2d2cc871663dcce8c21be597 100644 --- a/datamgr_service/services/distributeddataservice/framework/cloud/cloud_lock_event.cpp +++ b/datamgr_service/services/distributeddataservice/framework/cloud/cloud_lock_event.cpp @@ -17,7 +17,7 @@ namespace OHOS::DistributedData { CloudLockEvent::CloudLockEvent(int32_t evtId, StoreInfo storeInfo, Callback callback) - : CloudEvent(evtId, storeInfo), callback_(std::move(callback)) + : CloudEvent(evtId, std::move(storeInfo)), callback_(std::move(callback)) { } diff --git a/datamgr_service/services/distributeddataservice/framework/cloud/cloud_server.cpp b/datamgr_service/services/distributeddataservice/framework/cloud/cloud_server.cpp index 1488cda20d00cb5eea3c0383643168d8a017fa71..2841cf0b29aabee3ecd2b7e37b86428217946d42 100644 --- a/datamgr_service/services/distributeddataservice/framework/cloud/cloud_server.cpp +++ b/datamgr_service/services/distributeddataservice/framework/cloud/cloud_server.cpp @@ -30,9 +30,9 @@ bool CloudServer::RegisterCloudInstance(CloudServer *instance) return true; } -CloudInfo CloudServer::GetServerInfo(int32_t userId, bool needSpaceInfo) +std::pair CloudServer::GetServerInfo(int32_t userId, bool needSpaceInfo) { - return CloudInfo(); + return { 0, CloudInfo() }; } std::pair CloudServer::GetAppSchema(int32_t userId, const std::string &bundleName) diff --git a/datamgr_service/services/distributeddataservice/framework/cloud/schema_meta.cpp b/datamgr_service/services/distributeddataservice/framework/cloud/schema_meta.cpp index e0df117706ce7c26f3b65e57341c37260e2dcb0a..7ced1856be3a8f2b42b7aaf092050e76d606b2b2 100644 --- a/datamgr_service/services/distributeddataservice/framework/cloud/schema_meta.cpp +++ b/datamgr_service/services/distributeddataservice/framework/cloud/schema_meta.cpp @@ -15,6 +15,8 @@ #include "cloud/schema_meta.h" namespace OHOS::DistributedData { +static constexpr const char *KEY_PREFIX = "DistributedSchema"; +static constexpr const char *KEY_SEPARATOR = "###"; bool SchemaMeta::Marshal(Serializable::json &node) const { SetValue(node[GET_NAME(metaVersion)], metaVersion); @@ -32,6 +34,7 @@ bool SchemaMeta::Unmarshal(const Serializable::json &node) GetValue(node, GET_NAME(version), version); GetValue(node, GET_NAME(bundleName), bundleName); GetValue(node, GET_NAME(databases), databases); + GetValue(node, GET_NAME(dbSchema), databases); return true; } @@ -48,11 +51,35 @@ std::vector Database::GetTableNames() const return tableNames; } +std::string Database::GetKey() const +{ + return GetKey({user, "default", bundleName, name}); +} + +std::string Database::GetKey(const std::initializer_list &fields) +{ + std::string prefix = KEY_PREFIX; + for (const auto &field : fields) { + prefix.append(KEY_SEPARATOR).append(field); + } + return prefix; +} + +std::string Database::GetPrefix(const std::initializer_list &fields) +{ + return GetKey(fields).append(KEY_SEPARATOR); +} + bool Database::Marshal(Serializable::json &node) const { SetValue(node[GET_NAME(name)], name); SetValue(node[GET_NAME(alias)], alias); SetValue(node[GET_NAME(tables)], tables); + SetValue(node[GET_NAME(version)], version); + SetValue(node[GET_NAME(bundleName)], bundleName); + SetValue(node[GET_NAME(user)], user); + SetValue(node[GET_NAME(deviceId)], deviceId); + SetValue(node[GET_NAME(autoSyncType)], autoSyncType); return true; } @@ -61,6 +88,12 @@ bool Database::Unmarshal(const Serializable::json &node) GetValue(node, GET_NAME(name), name); GetValue(node, GET_NAME(alias), alias); GetValue(node, GET_NAME(tables), tables); + GetValue(node, GET_NAME(dbName), name); + GetValue(node, GET_NAME(autoSyncType), autoSyncType); + GetValue(node, GET_NAME(user), user); + GetValue(node, GET_NAME(deviceId), deviceId); + GetValue(node, GET_NAME(version), version); + GetValue(node, GET_NAME(bundleName), bundleName); return true; } @@ -70,6 +103,8 @@ bool Table::Marshal(Serializable::json &node) const SetValue(node[GET_NAME(sharedTableName)], sharedTableName); SetValue(node[GET_NAME(alias)], alias); SetValue(node[GET_NAME(fields)], fields); + SetValue(node[GET_NAME(deviceSyncFields)], deviceSyncFields); + SetValue(node[GET_NAME(cloudSyncFields)], cloudSyncFields); return true; } @@ -79,6 +114,9 @@ bool Table::Unmarshal(const Serializable::json &node) GetValue(node, GET_NAME(sharedTableName), sharedTableName); GetValue(node, GET_NAME(alias), alias); GetValue(node, GET_NAME(fields), fields); + GetValue(node, GET_NAME(tableName), name); + GetValue(node, GET_NAME(deviceSyncFields), deviceSyncFields); + GetValue(node, GET_NAME(cloudSyncFields), cloudSyncFields); return true; } @@ -99,6 +137,8 @@ bool Field::Unmarshal(const Serializable::json &node) GetValue(node, GET_NAME(type), type); GetValue(node, GET_NAME(primary), primary); GetValue(node, GET_NAME(nullable), nullable); + GetValue(node, GET_NAME(columnName), colName); + GetValue(node, GET_NAME(notNull), nullable); return true; } diff --git a/datamgr_service/services/distributeddataservice/framework/directory/directory_manager.cpp b/datamgr_service/services/distributeddataservice/framework/directory/directory_manager.cpp index ce5cf4529f0a0129f5ded2b72b65675e3d37090d..4cc56b21c2b817ddd111cb99f573556e1370c4fa 100644 --- a/datamgr_service/services/distributeddataservice/framework/directory/directory_manager.cpp +++ b/datamgr_service/services/distributeddataservice/framework/directory/directory_manager.cpp @@ -158,7 +158,7 @@ std::string DirectoryManager::GetArea(const StoreMetaData &metaData) const std::string DirectoryManager::GetUserId(const StoreMetaData &metaData) const { auto type = AccessTokenKit::GetTokenTypeFlag(metaData.tokenId); - if (type == TOKEN_NATIVE || type == TOKEN_SHELL) { + if ((type == TOKEN_NATIVE || type == TOKEN_SHELL) && (metaData.user == StoreMetaData::ROOT_USER)) { return "public"; } return metaData.user; diff --git a/datamgr_service/services/distributeddataservice/framework/include/account/account_delegate.h b/datamgr_service/services/distributeddataservice/framework/include/account/account_delegate.h index 2f32674d089892b9c01d58f8bd4f763b7c27372d..92584aac8500fdb86710a8a372935ec528627a10 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/account/account_delegate.h +++ b/datamgr_service/services/distributeddataservice/framework/include/account/account_delegate.h @@ -24,7 +24,7 @@ #include "visibility.h" namespace OHOS { -namespace DistributedKv { +namespace DistributedData { enum class AccountStatus { HARMONY_ACCOUNT_LOGIN = 0, // the openHarmony account is logged in HARMONY_ACCOUNT_LOGOUT, // the openHarmony account is logged out @@ -51,7 +51,7 @@ public: LOW, }; API_EXPORT virtual ~Observer() = default; - API_EXPORT virtual void OnAccountChanged(const AccountEventInfo &eventInfo) = 0; + API_EXPORT virtual void OnAccountChanged(const AccountEventInfo &eventInfo, int32_t timeout = 0) = 0; // must specify unique name for observer API_EXPORT virtual std::string Name() = 0; @@ -59,8 +59,8 @@ public: }; using HashFunc = std::string (*)(const void *data, size_t size, bool isUpper); API_EXPORT virtual ~AccountDelegate() = default; - API_EXPORT virtual Status Subscribe(std::shared_ptr observer) = 0; - API_EXPORT virtual Status Unsubscribe(std::shared_ptr observer) = 0; + API_EXPORT virtual int32_t Subscribe(std::shared_ptr observer) = 0; + API_EXPORT virtual int32_t Unsubscribe(std::shared_ptr observer) = 0; API_EXPORT virtual std::string GetCurrentAccountId() const = 0; API_EXPORT virtual int32_t GetUserByToken(uint32_t tokenId) const = 0; API_EXPORT virtual void SubscribeAccountEvent() = 0; @@ -71,6 +71,7 @@ public: API_EXPORT virtual bool QueryForegroundUserId(int &foregroundUserId) = 0; API_EXPORT virtual bool IsVerified(int userId) = 0; API_EXPORT virtual bool RegisterHashFunc(HashFunc hash) = 0; + API_EXPORT virtual bool IsDeactivating(int userId) = 0; API_EXPORT virtual void BindExecutor(std::shared_ptr executors) = 0; API_EXPORT virtual std::string GetUnencryptedAccountId(int32_t userId = 0) const = 0; API_EXPORT static AccountDelegate *GetInstance(); diff --git a/datamgr_service/services/distributeddataservice/framework/include/cloud/asset_loader.h b/datamgr_service/services/distributeddataservice/framework/include/cloud/asset_loader.h index 80126aa769d0c6cf530b09c093d046ff6ad93b81..a7caf47b6d7683fa0c7491132c49e7be6aa04116 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/cloud/asset_loader.h +++ b/datamgr_service/services/distributeddataservice/framework/include/cloud/asset_loader.h @@ -28,7 +28,7 @@ public: virtual void Download(const std::string &tableName, std::vector &assetsRecords); virtual int32_t RemoveLocalAssets( const std::string &tableName, const std::string &gid, const Value &prefix, VBucket &assets); - virtual int32_t Cancel(); + virtual int32_t CancelDownload(); }; } // namespace OHOS::DistributedData #endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_ASSET_LOADER_H diff --git a/datamgr_service/services/distributeddataservice/framework/include/cloud/cloud_server.h b/datamgr_service/services/distributeddataservice/framework/include/cloud/cloud_server.h index daaecf8daf5dd4b03ea6253e93d72d4189d367d3..9cb060c81f0b941b0356242c364dcf0d477df30a 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/cloud/cloud_server.h +++ b/datamgr_service/services/distributeddataservice/framework/include/cloud/cloud_server.h @@ -29,7 +29,7 @@ public: API_EXPORT static CloudServer *GetInstance(); API_EXPORT static bool RegisterCloudInstance(CloudServer *instance); - virtual CloudInfo GetServerInfo(int32_t userId, bool needSpaceInfo = true); + virtual std::pair GetServerInfo(int32_t userId, bool needSpaceInfo = true); virtual std::pair GetAppSchema(int32_t userId, const std::string &bundleName); virtual int32_t Subscribe(int32_t userId, const std::map> &dbs); virtual int32_t Unsubscribe(int32_t userId, const std::map> &dbs); diff --git a/datamgr_service/services/distributeddataservice/framework/include/cloud/schema_meta.h b/datamgr_service/services/distributeddataservice/framework/include/cloud/schema_meta.h index 7e5fd6404ca40cef272e94c7824a7fdd7800a7d8..bfa6f14f334d9c124b9995349d912494aa1d9e03 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/cloud/schema_meta.h +++ b/datamgr_service/services/distributeddataservice/framework/include/cloud/schema_meta.h @@ -32,6 +32,8 @@ struct API_EXPORT Table final : public Serializable { std::string sharedTableName; std::string alias; std::vector fields; + std::vector deviceSyncFields = {}; + std::vector cloudSyncFields = {}; bool Marshal(json &node) const override; bool Unmarshal(const json &node) override; }; @@ -41,6 +43,14 @@ struct API_EXPORT Database final : public Serializable { std::string alias; std::vector tables; std::vector GetTableNames() const; + uint32_t autoSyncType = 0; + std::string user = ""; + std::string deviceId = ""; + uint32_t version = 0; + std::string bundleName = ""; + API_EXPORT std::string GetKey() const; + API_EXPORT static std::string GetKey(const std::initializer_list &fields); + API_EXPORT static std::string GetPrefix(const std::initializer_list &fields); bool Marshal(json &node) const override; bool Unmarshal(const json &node) override; }; @@ -83,5 +93,14 @@ public: bool IsValid() const; Database GetDataBase(const std::string &storeId); }; + +// Table mode of device data sync time +enum AutoSyncType { + IS_NOT_AUTO_SYNC = 0, + SYNC_ON_CHANGE = 1, // datachange sync + SYNC_ON_READY, // onready sync + SYNC_ON_CHANGE_READY //datachange and onready sync +}; + } // namespace OHOS::DistributedData #endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_SCHEMA_META_H diff --git a/datamgr_service/services/distributeddataservice/framework/include/commonevent/data_change_event.h b/datamgr_service/services/distributeddataservice/framework/include/commonevent/data_change_event.h index d66482886b232bf3715f5073b8347b9a4b5f2b84..0c74b688bac9bacdf6db93b5568534f9595fab73 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/commonevent/data_change_event.h +++ b/datamgr_service/services/distributeddataservice/framework/include/commonevent/data_change_event.h @@ -23,6 +23,7 @@ class API_EXPORT DataChangeEvent : public CloudEvent { public: struct TableChangeProperties { bool isTrackedDataChange = false; + bool isP2pSyncDataChange = false; }; using TableProperties = std::map; struct EventInfo { diff --git a/datamgr_service/services/distributeddataservice/framework/include/error/general_error.h b/datamgr_service/services/distributeddataservice/framework/include/error/general_error.h index f798cecfceb7cb07164ccbcb8b90f63fa41117bc..1359397feceb7d5c34fa92e40d11dddbf572b899 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/error/general_error.h +++ b/datamgr_service/services/distributeddataservice/framework/include/error/general_error.h @@ -28,6 +28,8 @@ enum GeneralError : int32_t { E_BUSY, E_INVALID_ARGS, E_NOT_INIT, + E_DK_NOT_INIT, + E_NOT_LOGIN, E_NOT_SUPPORT, E_ALREADY_CONSUMED, E_ALREADY_CLOSED, @@ -52,6 +54,14 @@ enum GeneralError : int32_t { E_OVER_MAX_LIMITS, E_SECURITY_LEVEL_ERROR, E_FILE_NOT_EXIST, + E_SCREEN_LOCKED, + E_USER_DEACTIVATING, + E_GET_CLOUD_USER_INFO, + E_GET_BRIEF_INFO, + E_GET_APP_SCHEMA, + E_CONNECT_ASSET_LOADER, + E_CONNECT_CLOUD_DB, + E_SKIP_ASSET, E_BUTT, }; } diff --git a/datamgr_service/services/distributeddataservice/framework/include/metadata/meta_data_manager.h b/datamgr_service/services/distributeddataservice/framework/include/metadata/meta_data_manager.h index 433af7b7e61138a3499985d2fc2f87f610f0f8bd..91d1d244c658202de625d773a768ee4e0ff31dba 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/metadata/meta_data_manager.h +++ b/datamgr_service/services/distributeddataservice/framework/include/metadata/meta_data_manager.h @@ -52,7 +52,7 @@ public: using Bytes = std::vector; using OnComplete = std::function &)>; API_EXPORT static MetaDataManager &GetInstance(); - API_EXPORT void Initialize(std::shared_ptr metaStore, const Backup &backup); + API_EXPORT void Initialize(std::shared_ptr metaStore, const Backup &backup, const std::string storeId); API_EXPORT void SetSyncer(const Syncer &syncer); API_EXPORT void SetCloudSyncer(const CloudSyncer &cloudSyncer); API_EXPORT bool SaveMeta(const std::string &key, const Serializable &value, bool isLocal = false); @@ -94,6 +94,7 @@ private: Backup backup_; Syncer syncer_; CloudSyncer cloudSyncer_; + std::string storeId_; }; } // namespace OHOS::DistributedData #endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_METADATA_META_DATA_MANAGER_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/framework/include/metadata/secret_key_meta_data.h b/datamgr_service/services/distributeddataservice/framework/include/metadata/secret_key_meta_data.h index 281a7a77ab21b19ef14fbaf6ba8c43d384124f91..a97b04e36a78bae59ab5c53fd18eac148a39bcc8 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/metadata/secret_key_meta_data.h +++ b/datamgr_service/services/distributeddataservice/framework/include/metadata/secret_key_meta_data.h @@ -31,9 +31,11 @@ struct API_EXPORT SecretKeyMetaData final : public Serializable { API_EXPORT static std::string GetBackupKey(const std::initializer_list &fields); API_EXPORT static std::string GetPrefix(const std::initializer_list &fields); API_EXPORT static std::string GetBackupPrefix(const std::initializer_list &fields); + API_EXPORT static std::string GetCloneKey(const std::initializer_list &fields); private: static constexpr const char *KEY_PREFIX = "SecretKey"; static constexpr const char *BACKUP_KEY_PREFIX = "BackupSecretKey"; + static constexpr const char *CLONE_KEY_PREFIX = "Clone"; }; } // namespace DistributedData } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/framework/include/metadata/store_meta_data.h b/datamgr_service/services/distributeddataservice/framework/include/metadata/store_meta_data.h index 007fd6ab06b524ccbfe13bf34619682fc88ba01d..e80e14b4d762f704b60000382e184763b625e0cd 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/metadata/store_meta_data.h +++ b/datamgr_service/services/distributeddataservice/framework/include/metadata/store_meta_data.h @@ -59,6 +59,7 @@ struct API_EXPORT StoreMetaData final : public Serializable { std::string user = ""; std::string account = ""; int32_t authType = 0; + bool asyncDownloadAsset = false; enum StoreType { STORE_KV_BEGIN = 0, @@ -89,6 +90,7 @@ struct API_EXPORT StoreMetaData final : public Serializable { API_EXPORT StoreInfo GetStoreInfo() const; API_EXPORT static std::string GetKey(const std::initializer_list &fields); API_EXPORT static std::string GetPrefix(const std::initializer_list &fields); + API_EXPORT std::string GetCloneSecretKey() const; }; } // namespace OHOS::DistributedData #endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_METADATA_STORE_META_DATA_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/framework/include/screen/screen_manager.h b/datamgr_service/services/distributeddataservice/framework/include/screen/screen_manager.h index cbf7c8666ed2fe73674f5e5039b4ae1805b14908..c670a5584af9d4c6bc51f939a5ebd6b6cf6537a8 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/screen/screen_manager.h +++ b/datamgr_service/services/distributeddataservice/framework/include/screen/screen_manager.h @@ -17,17 +17,30 @@ #include #include + +#include "executor_pool.h" #include "visibility.h" namespace OHOS { namespace DistributedData { class ScreenManager { public: + class Observer { + public: + virtual ~Observer() = default; + virtual void OnScreenUnlocked(int32_t user) = 0; + virtual std::string GetName() = 0; + }; API_EXPORT static std::shared_ptr GetInstance(); API_EXPORT static bool RegisterInstance(std::shared_ptr instance); ScreenManager() = default; virtual ~ScreenManager() = default; virtual bool IsLocked(); + virtual void Subscribe(std::shared_ptr observer); + virtual void Unsubscribe(std::shared_ptr observer); + virtual void BindExecutor(std::shared_ptr executors); + virtual void SubscribeScreenEvent(); + virtual void UnsubscribeScreenEvent(); private: static std::mutex mutex_; @@ -35,4 +48,4 @@ private: }; } // namespace DistributedData } // namespace OHOS -#endif //DISTRIBUTEDDATAMGR_FRAMEWORK_SCREEN_LOCK_H +#endif //DISTRIBUTEDDATAMGR_FRAMEWORK_SCREEN_LOCK_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/framework/include/store/auto_cache.h b/datamgr_service/services/distributeddataservice/framework/include/store/auto_cache.h index 9eb51570ff2cfba076a2b12d8c074ff34009d3b1..cc9e6c79bd0df00fbc529d533774369e1f9d9ffa 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/store/auto_cache.h +++ b/datamgr_service/services/distributeddataservice/framework/include/store/auto_cache.h @@ -50,6 +50,8 @@ public: API_EXPORT Store GetStore(const StoreMetaData &meta, const Watchers &watchers); + API_EXPORT std::pair GetDBStore(const StoreMetaData &meta, const Watchers &watchers); + API_EXPORT Stores GetStoresIfPresent(uint32_t tokenId, const std::string &storeName = ""); API_EXPORT void CloseStore(uint32_t tokenId, const std::string &storeId = ""); diff --git a/datamgr_service/services/distributeddataservice/framework/include/store/general_store.h b/datamgr_service/services/distributeddataservice/framework/include/store/general_store.h index 80d9569b5a0a8d8aa43886770255c13aca5b7a86..ee5e8504127933160874edf86de09c34987bc4d3 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/store/general_store.h +++ b/datamgr_service/services/distributeddataservice/framework/include/store/general_store.h @@ -54,6 +54,7 @@ public: enum HighMode : uint32_t { MANUAL_SYNC_MODE = 0x00000, AUTO_SYNC_MODE = 0x10000, + ASSETS_SYNC_MODE = 0x20000, }; enum CleanMode { NEARBY_DATA = 0, @@ -87,6 +88,12 @@ public: return mixMode & ~0xFFFF; } + static inline uint32_t GetPriorityLevel(uint32_t highMode) + { + // shift right 16 bits + return highMode >> 16; + } + struct BindInfo { BindInfo(std::shared_ptr db = nullptr, std::shared_ptr loader = nullptr) : db_(std::move(db)), loader_(std::move(loader)) @@ -123,7 +130,7 @@ public: virtual void SetExecutor(std::shared_ptr executor) = 0; - virtual int32_t Bind(Database &database, const std::map &bindInfos, + virtual int32_t Bind(const Database &database, const std::map &bindInfos, const CloudConfig &config) = 0; virtual bool IsBound(uint32_t user) = 0; @@ -151,7 +158,7 @@ public: virtual std::pair> Query(const std::string &table, GenQuery &query) = 0; virtual std::pair Sync(const Devices &devices, GenQuery &query, - DetailAsync async, const SyncParam &syncParm) = 0; + DetailAsync async, const SyncParam &syncParam) = 0; virtual std::pair> PreSharing(GenQuery &query) = 0; @@ -177,9 +184,7 @@ public: virtual int32_t CleanTrackerData(const std::string &tableName, int64_t cursor) = 0; - virtual std::vector GetWaterVersion(const std::string &deviceId) = 0; - - virtual void SetEqualIdentifier(const std::string &appId, const std::string &storeId, const std::string &account = "") {}; + virtual void SetEqualIdentifier(const std::string &appId, const std::string &storeId, std::string account = "") {}; virtual void SetConfig(const StoreConfig &storeConfig) {}; @@ -188,4 +193,4 @@ public: virtual int32_t UnLockCloudDB() = 0; }; } // namespace OHOS::DistributedData -#endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_GENERAL_STORE_H +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_GENERAL_STORE_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/framework/include/store/general_value.h b/datamgr_service/services/distributeddataservice/framework/include/store/general_value.h index f25f36ab87f9ab7428377270fdfbafd3e7ae23c4..e1f9b3a18a43b90e8756dfb92b7794276d4e437f 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/store/general_value.h +++ b/datamgr_service/services/distributeddataservice/framework/include/store/general_value.h @@ -69,6 +69,7 @@ struct Asset { STATUS_DELETE, STATUS_ABNORMAL, STATUS_DOWNLOADING, + STATUS_SKIP_ASSET, STATUS_BUTT }; @@ -99,6 +100,7 @@ struct SyncParam { int32_t triggerMode = MODE_DEFAULT; std::string prepareTraceId; int32_t user; + bool asyncDownloadAsset = false; }; enum SyncStage : int8_t { @@ -196,4 +198,4 @@ bool Convert(T &&input, std::variant &output) return GetItem(std::move(input), output); } } // namespace OHOS::DistributedData -#endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_GENERAL_VALUE_H +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_GENERAL_VALUE_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/framework/include/thread/thread_manager.h b/datamgr_service/services/distributeddataservice/framework/include/thread/thread_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..c213d6c9891c89ebbe42bda0dc08d0c1b60b0dc1 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/include/thread/thread_manager.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 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 DISTRIBUTEDDATAMGR_THREAD_MANAGER_H +#define DISTRIBUTEDDATAMGR_THREAD_MANAGER_H + +#include "stdint.h" +#include "visibility.h" +namespace OHOS::DistributedData { +class ThreadManager { +public: + API_EXPORT static ThreadManager &GetInstance(); + API_EXPORT void Initialize(uint32_t minThreadNum, uint32_t maxThreadNum, uint32_t ipcThreadNum); + API_EXPORT uint32_t GetMinThreadNum(); + API_EXPORT uint32_t GetMaxThreadNum(); + API_EXPORT uint32_t GetIpcThreadNum(); + +private: + ThreadManager(); + uint32_t minThreadNum_ = 5; // default min executor pool thread num + uint32_t maxThreadNum_ = 12; // default max executor pool thread num + uint32_t ipcThreadNum_ = 16; // normal ipc num +}; +} // namespace OHOS::DistributedData +#endif // DISTRIBUTEDDATAMGR_THREAD_MANAGER_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/framework/include/utils/base64_utils.h b/datamgr_service/services/distributeddataservice/framework/include/utils/base64_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..33687283b367bd0d8b615f47cbcc113d728f871f --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/include/utils/base64_utils.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 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_SERVICES_FRAMEWORK_UTILS_BASE64_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_UTILS_BASE64_H + +#include +#include +#include "visibility.h" +namespace OHOS::DistributedData::Base64 { +API_EXPORT std::string Encode(const std::vector &source); +API_EXPORT std::vector Decode(const std::string &encoded); +} // namespace OHOS::DistributedData::Base64 + +#endif /* OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_UTILS_BASE64_H */ diff --git a/datamgr_service/services/distributeddataservice/framework/include/utils/corrupt_reporter.h b/datamgr_service/services/distributeddataservice/framework/include/utils/corrupt_reporter.h new file mode 100644 index 0000000000000000000000000000000000000000..0a1173ed4c7146882de7390f940b1307da5e1340 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/include/utils/corrupt_reporter.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024 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_SERVICES_FRAMEWORK_UTILS_CORRUPT_REPORTER_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_UTILS_CORRUPT_REPORTER_H + +#include "visibility.h" +#include +namespace OHOS::DistributedData { +class CorruptReporter { +public: + API_EXPORT static bool CreateCorruptedFlag(const std::string &dbPath, const std::string &dbName); + API_EXPORT static bool HasCorruptedFlag(const std::string &dbPath, const std::string &dbName); + API_EXPORT static bool DeleteCorruptedFlag(const std::string &dbPath, const std::string &dbName); +}; +} // namespace OHOS::DistributedData +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_UTILS_CORRUPT_REPORTER_H diff --git a/datamgr_service/services/distributeddataservice/framework/include/utils/time_statistic.h b/datamgr_service/services/distributeddataservice/framework/include/utils/time_statistic.h new file mode 100644 index 0000000000000000000000000000000000000000..1380fcfc488068ce1a2e56d2e07508ae89944238 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/include/utils/time_statistic.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025 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 DISTRIBUTEDDATAMGR_DATAMGR_TIME_STATISTIC_H +#define DISTRIBUTEDDATAMGR_DATAMGR_TIME_STATISTIC_H + +namespace OHOS { +namespace DistributedData { +class TimeStatistic { + +}; + +} // namespace DistributedData +} // namespace OHOS +#endif //DISTRIBUTEDDATAMGR_DATAMGR_TIME_STATISTIC_H diff --git a/datamgr_service/services/distributeddataservice/framework/metadata/meta_data_manager.cpp b/datamgr_service/services/distributeddataservice/framework/metadata/meta_data_manager.cpp index 61ea107677634849e3888e8c08ef33701c695d91..ed12b3635272efb93f68257d180f64ee83dd2df7 100644 --- a/datamgr_service/services/distributeddataservice/framework/metadata/meta_data_manager.cpp +++ b/datamgr_service/services/distributeddataservice/framework/metadata/meta_data_manager.cpp @@ -17,9 +17,11 @@ #include #define LOG_TAG "MetaDataManager" +#include "directory/directory_manager.h" #include "kv_store_nb_delegate.h" #include "log_print.h" #include "utils/anonymous.h" +#include "utils/corrupt_reporter.h" namespace OHOS::DistributedData { class MetaObserver : public DistributedDB::KvStoreObserver { @@ -153,7 +155,7 @@ MetaDataManager::~MetaDataManager() metaObservers_.Clear(); } -void MetaDataManager::Initialize(std::shared_ptr metaStore, const Backup &backup) +void MetaDataManager::Initialize(std::shared_ptr metaStore, const Backup &backup, const std::string storeId) { if (metaStore == nullptr) { return; @@ -165,6 +167,7 @@ void MetaDataManager::Initialize(std::shared_ptr metaStore, const Bac } metaStore_ = std::move(metaStore); backup_ = backup; + storeId_ = std::move(storeId); inited_ = true; } @@ -196,6 +199,7 @@ bool MetaDataManager::SaveMeta(const std::string &key, const Serializable &value if (status == DistributedDB::DBStatus::INVALID_PASSWD_OR_CORRUPTED_DB) { ZLOGE("db corrupted! status:%{public}d isLocal:%{public}d, key:%{public}s", status, isLocal, Anonymous::Change(key).c_str()); + CorruptReporter::CreateCorruptedFlag(DirectoryManager::GetInstance().GetMetaStorePath(), storeId_); StopSA(); return false; } @@ -224,6 +228,7 @@ bool MetaDataManager::LoadMeta(const std::string &key, Serializable &value, bool if (status == DistributedDB::DBStatus::INVALID_PASSWD_OR_CORRUPTED_DB) { ZLOGE("db corrupted! status:%{public}d isLocal:%{public}d, key:%{public}s", status, isLocal, Anonymous::Change(key).c_str()); + CorruptReporter::CreateCorruptedFlag(DirectoryManager::GetInstance().GetMetaStorePath(), storeId_); StopSA(); return false; } @@ -244,6 +249,7 @@ bool MetaDataManager::GetEntries(const std::string &prefix, std::vector & : metaStore_->GetEntries({ prefix.begin(), prefix.end() }, dbEntries); if (status == DistributedDB::DBStatus::INVALID_PASSWD_OR_CORRUPTED_DB) { ZLOGE("db corrupted! status:%{public}d isLocal:%{public}d", status, isLocal); + CorruptReporter::CreateCorruptedFlag(DirectoryManager::GetInstance().GetMetaStorePath(), storeId_); StopSA(); return false; } @@ -271,6 +277,7 @@ bool MetaDataManager::DelMeta(const std::string &key, bool isLocal) if (status == DistributedDB::DBStatus::INVALID_PASSWD_OR_CORRUPTED_DB) { ZLOGE("db corrupted! status:%{public}d isLocal:%{public}d, key:%{public}s", status, isLocal, Anonymous::Change(key).c_str()); + CorruptReporter::CreateCorruptedFlag(DirectoryManager::GetInstance().GetMetaStorePath(), storeId_); StopSA(); return false; } @@ -297,6 +304,7 @@ bool MetaDataManager::Sync(const std::vector &devices, OnComplete c }); if (status == DistributedDB::DBStatus::INVALID_PASSWD_OR_CORRUPTED_DB) { ZLOGE("db corrupted! status:%{public}d", status); + CorruptReporter::CreateCorruptedFlag(DirectoryManager::GetInstance().GetMetaStorePath(), storeId_); StopSA(); return false; } diff --git a/datamgr_service/services/distributeddataservice/framework/metadata/secret_key_meta_data.cpp b/datamgr_service/services/distributeddataservice/framework/metadata/secret_key_meta_data.cpp index 4467d5c48e532fc3eddaca228faf37c750f8bd49..a28bec14697f4c342549b825a0a7aff339c0bc91 100644 --- a/datamgr_service/services/distributeddataservice/framework/metadata/secret_key_meta_data.cpp +++ b/datamgr_service/services/distributeddataservice/framework/metadata/secret_key_meta_data.cpp @@ -74,5 +74,12 @@ std::string SecretKeyMetaData::GetBackupPrefix(const std::initializer_list &fields) +{ + std::string prefix = CLONE_KEY_PREFIX; + prefix.append(Constant::KEY_SEPARATOR).append(GetKey(fields)); + return prefix; +} } // namespace DistributedData } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/framework/metadata/store_meta_data.cpp b/datamgr_service/services/distributeddataservice/framework/metadata/store_meta_data.cpp index dea972be3a1cd91ac2369cba9746e1f2134e7e87..8a950a14e13799eba6e337c98af61d14fa2428a4 100644 --- a/datamgr_service/services/distributeddataservice/framework/metadata/store_meta_data.cpp +++ b/datamgr_service/services/distributeddataservice/framework/metadata/store_meta_data.cpp @@ -56,6 +56,7 @@ bool StoreMetaData::Marshal(json &node) const SetValue(node[GET_NAME(dataType)], dataType); SetValue(node[GET_NAME(enableCloud)], enableCloud); SetValue(node[GET_NAME(cloudAutoSync)], cloudAutoSync); + SetValue(node[GET_NAME(asyncDownloadAsset)], asyncDownloadAsset); // compatible with the versions which lower than VERSION_TAG_0000 SetValue(node[GET_NAME(kvStoreType)], storeType); SetValue(node[GET_NAME(deviceAccountID)], user); @@ -96,6 +97,7 @@ bool StoreMetaData::Unmarshal(const json &node) GetValue(node, GET_NAME(dataType), dataType); GetValue(node, GET_NAME(enableCloud), enableCloud); GetValue(node, GET_NAME(cloudAutoSync), cloudAutoSync); + GetValue(node, GET_NAME(asyncDownloadAsset), asyncDownloadAsset); // compatible with the older versions if (version < FIELD_CHANGED_TAG) { GetValue(node, GET_NAME(kvStoreType), storeType); @@ -230,5 +232,10 @@ StoreInfo StoreMetaData::GetStoreInfo() const info.user = atoi(user.c_str()); return info; } + +std::string StoreMetaData::GetCloneSecretKey() const +{ + return SecretKeyMetaData::GetCloneKey({ user, "default", bundleName, storeId, std::to_string(instanceId) }); +} } // namespace DistributedData } // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/framework/screen/screen_manager.cpp b/datamgr_service/services/distributeddataservice/framework/screen/screen_manager.cpp index 9f7698f5bb28cfd602cd7a453a58d1c907fc2c19..6b939376e54a8a5acb6047c262967a3908412025 100644 --- a/datamgr_service/services/distributeddataservice/framework/screen/screen_manager.cpp +++ b/datamgr_service/services/distributeddataservice/framework/screen/screen_manager.cpp @@ -15,6 +15,7 @@ #define LOG_TAG "ScreenManager" #include "screen/screen_manager.h" + #include "log_print.h" namespace OHOS::DistributedData { @@ -38,9 +39,33 @@ bool ScreenManager::RegisterInstance(std::shared_ptr instance) return true; } +void ScreenManager::Subscribe(std::shared_ptr observer) +{ + return; +} + +void ScreenManager::Unsubscribe(std::shared_ptr observer) +{ + return; +} + +void ScreenManager::BindExecutor(std::shared_ptr executors) +{ + return; +} + +void ScreenManager::SubscribeScreenEvent() +{ + return; +} + +void ScreenManager::UnsubscribeScreenEvent() +{ + return; +} + bool ScreenManager::IsLocked() { return false; } - } // namespace OHOS::DistributedData \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/framework/store/auto_cache.cpp b/datamgr_service/services/distributeddataservice/framework/store/auto_cache.cpp index 0ea9bc7f2e7ce15ecbb618a4dcb7f98bc4bfb72c..ad799d6ecc15fb747dbafd898be69ccfa18f3ad8 100644 --- a/datamgr_service/services/distributeddataservice/framework/store/auto_cache.cpp +++ b/datamgr_service/services/distributeddataservice/framework/store/auto_cache.cpp @@ -17,12 +17,14 @@ #include +#include "account_delegate.h" #include "changeevent/remote_change_event.h" #include "eventcenter/event_center.h" #include "log_print.h" #include "screenlock/screen_lock.h" #include "utils/anonymous.h" namespace OHOS::DistributedData { +using Account = AccountDelegate; AutoCache &AutoCache::GetInstance() { static AutoCache cache; @@ -58,22 +60,32 @@ AutoCache::~AutoCache() } } -AutoCache::Store AutoCache::GetStore(const StoreMetaData &meta, const Watchers &watchers) +std::pair AutoCache::GetDBStore(const StoreMetaData &meta, const Watchers &watchers) { Store store; - if ((meta.area >= GeneralStore::EL4 && ScreenManager::GetInstance()->IsLocked()) || - meta.storeType >= MAX_CREATOR_NUM || meta.storeType < 0 || !creators_[meta.storeType] || - disables_.ContainIf(meta.tokenId, [&meta](const std::set &stores) -> bool { - return stores.count(meta.storeId) != 0; - })) { - return store; + if (meta.storeType >= MAX_CREATOR_NUM || meta.storeType < 0 || !creators_[meta.storeType] || + disables_.ContainIf(meta.tokenId, + [&meta](const std::set &stores) -> bool { return stores.count(meta.storeId) != 0; })) { + ZLOGW("storeType is invalid or store is disabled, user:%{public}s, bundleName:%{public}s, " + "storeName:%{public}s", + meta.user.c_str(), meta.bundleName.c_str(), meta.GetStoreAlias().c_str()); + return { E_ERROR, store }; } - - stores_.Compute( - meta.tokenId, [this, &meta, &watchers, &store](auto &, std::map &stores) -> bool { + if (meta.area == GeneralStore::EL4 && ScreenManager::GetInstance()->IsLocked()) { + ZLOGW("screen is locked, user:%{public}s, bundleName:%{public}s, storeName:%{public}s", meta.user.c_str(), + meta.bundleName.c_str(), meta.GetStoreAlias().c_str()); + return { E_SCREEN_LOCKED, store }; + } + if (Account::GetInstance()->IsDeactivating(atoi(meta.user.c_str()))) { + ZLOGW("user %{public}s is deactivating, bundleName:%{public}s, storeName: %{public}s", meta.user.c_str(), + meta.bundleName.c_str(), meta.GetStoreAlias().c_str()); + return { E_USER_DEACTIVATING, store }; + } + stores_.Compute(meta.tokenId, + [this, &meta, &watchers, &store](auto &, std::map &stores) -> bool { if (disableStores_.count(meta.dataDir) != 0) { ZLOGW("store is closing, tokenId:0x%{public}x user:%{public}s" - "bundleName:%{public}s storeName:%{public}s", + "bundleName:%{public}s storeName:%{public}s", meta.tokenId, meta.user.c_str(), meta.bundleName.c_str(), meta.GetStoreAlias().c_str()); return !stores.empty(); } @@ -97,7 +109,12 @@ AutoCache::Store AutoCache::GetStore(const StoreMetaData &meta, const Watchers & StartTimer(); return !stores.empty(); }); - return store; + return { E_OK, store }; +} + +AutoCache::Store AutoCache::GetStore(const StoreMetaData &meta, const Watchers &watchers) +{ + return GetDBStore(meta, watchers).second; } AutoCache::Stores AutoCache::GetStoresIfPresent(uint32_t tokenId, const std::string &storeName) @@ -153,7 +170,7 @@ void AutoCache::CloseStore(uint32_t tokenId, const std::string &storeId) auto it = delegates.begin(); while (it != delegates.end()) { if ((storeId == it->first || storeId.empty()) && - (!isScreenLocked || it->second.GetArea() < GeneralStore::EL4) && + (!isScreenLocked || it->second.GetArea() != GeneralStore::EL4) && disableStores_.count(it->second.GetDataDir()) == 0) { disableStores_.insert(it->second.GetDataDir()); storeIds.insert(it->first); @@ -232,7 +249,7 @@ void AutoCache::GarbageCollect(bool isForce) stores_.EraseIf([¤t, isForce, isScreenLocked](auto &key, std::map &delegates) { for (auto it = delegates.begin(); it != delegates.end();) { // if the store is BUSY we wait more INTERVAL minutes again - if ((!isScreenLocked || it->second.GetArea() < GeneralStore::EL4) && (isForce || it->second < current) && + if ((!isScreenLocked || it->second.GetArea() != GeneralStore::EL4) && (isForce || it->second < current) && it->second.Close()) { it = delegates.erase(it); } else { diff --git a/datamgr_service/services/distributeddataservice/framework/test/BUILD.gn b/datamgr_service/services/distributeddataservice/framework/test/BUILD.gn index a1351798e30900898839e2df0f2f0fe38fa56cb1..4d644b362658d7662d633e196a3e1e492d9eb654 100644 --- a/datamgr_service/services/distributeddataservice/framework/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/framework/test/BUILD.gn @@ -44,7 +44,6 @@ config("module_private_config") { "${data_service_path}/app/src/security", "${data_service_path}/service/crypto/include", "${data_service_path}/service/matrix/include", - "${data_service_path}/service/waterversion", "//third_party/json/single_include", ] cflags = [ "-Werror" ] @@ -67,8 +66,7 @@ ohos_unittest("CheckerManagerTest") { ] deps = [ - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter:distributeddata_adapter", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/app/src/checker:distributeddata_checker_static", + "${data_service_path}/app/src/checker:distributeddata_checker", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/framework:distributeddatasvcfwk", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/service:distributeddatasvc", "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddata:distributeddata_inner", @@ -90,7 +88,6 @@ ohos_unittest("EventCenterTest") { ] deps = [ - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter:distributeddata_adapter", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/framework:distributeddatasvcfwk", "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddata:distributeddata_inner", "//third_party/googletest:gtest_main", @@ -113,7 +110,6 @@ ohos_unittest("SerializableTest") { ] deps = [ - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter:distributeddata_adapter", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/framework:distributeddatasvcfwk", "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddata:distributeddata_inner", "//third_party/googletest:gtest_main", @@ -171,6 +167,7 @@ ohos_unittest("StoreTest") { "access_token:libaccesstoken_sdk", "access_token:libnativetoken", "c_utils:utils", + "common_event_service:cesfwk_innerkits", "hilog:libhilog", "ipc:ipc_core", "kv_store:distributeddata_inner", @@ -181,6 +178,7 @@ ohos_unittest("StoreTest") { deps = [ "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", + "${data_service_path}/service/common:distributeddata_common", "//third_party/googletest:gtest_main", ] } @@ -325,9 +323,10 @@ ohos_unittest("ServiceMetaDataTest") { "${data_service_path}/app/src/security", "${data_service_path}/service/crypto/include", "${data_service_path}/service/matrix/include", - "${data_service_path}/service/waterversion", "${data_service_path}/service/kvdb", "//third_party/json/single_include", + "${data_service_path}/adapter/include/communicator", + "${data_service_path}/adapter/include/dfx", ] external_deps = [ @@ -347,12 +346,13 @@ ohos_unittest("ServiceMetaDataTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", - "${data_service_path}/adapter/broadcaster:distributeddata_broadcaster_static", - "${data_service_path}/adapter/utils:distributeddata_utils_static", - "${data_service_path}/app/src/checker:distributeddata_checker_static", + "${data_service_path}/adapter/account:distributeddata_account", + "${data_service_path}/adapter/broadcaster:distributeddata_broadcaster", + "${data_service_path}/adapter/communicator:distributeddata_communicator", + "${data_service_path}/adapter/utils:distributeddata_utils", + "${data_service_path}/app/src/checker:distributeddata_checker", "${data_service_path}/framework:distributeddatasvcfwk", - "${data_service_path}/service:distributeddatasvc", + "${data_service_path}/service/kvdb:distributeddata_kvdb", "${kv_store_distributeddb_path}:distributeddb", "${kv_store_path}/interfaces/innerkits/distributeddata:distributeddata_inner", "${kv_store_path}/interfaces/innerkits/distributeddatamgr:distributeddata_mgr", diff --git a/datamgr_service/services/distributeddataservice/framework/test/asset_loader_test.cpp b/datamgr_service/services/distributeddataservice/framework/test/asset_loader_test.cpp index 7f2f0da6a795b89d54cb1d494c305ea2708c0b35..311d87e81237ccd54a69308cc991f340bb26aeb6 100644 --- a/datamgr_service/services/distributeddataservice/framework/test/asset_loader_test.cpp +++ b/datamgr_service/services/distributeddataservice/framework/test/asset_loader_test.cpp @@ -55,13 +55,13 @@ HWTEST_F(AssetLoaderTest, RemoveLocalAssets, TestSize.Level1) } /** -* @tc.name: Cancel -* @tc.desc: cancel. +* @tc.name: CancelDownload +* @tc.desc: cancel download asset. * @tc.type: FUNC */ -HWTEST_F(AssetLoaderTest, Cancel, TestSize.Level1) +HWTEST_F(AssetLoaderTest, CancelDownload, TestSize.Level1) { AssetLoader loader; - auto ret = loader.Cancel(); + auto ret = loader.CancelDownload(); ASSERT_EQ(ret, E_NOT_SUPPORT); } diff --git a/datamgr_service/services/distributeddataservice/framework/test/utils_test.cpp b/datamgr_service/services/distributeddataservice/framework/test/utils_test.cpp index 7f5da600c25cbc89b3ea3b8fe54dd45b94acc4ed..31e8ecf17f0b8aee3c2f705933c39294ce1f2001 100644 --- a/datamgr_service/services/distributeddataservice/framework/test/utils_test.cpp +++ b/datamgr_service/services/distributeddataservice/framework/test/utils_test.cpp @@ -23,11 +23,14 @@ #include "utils/block_integer.h" #include "utils/constant.h" #include "utils/converter.h" +#include "utils/corrupt_reporter.h" #include "utils/ref_count.h" #include "utils/endian_converter.h" using namespace testing::ext; using namespace OHOS::DistributedData; namespace OHOS::Test { +static constexpr const char *TEST_CORRUPT_PATH = "/data/service/el1/public/database/utils_test/"; +static constexpr const char *TEST_CORRUPT_STOREID = "utils_test_store"; class ServiceUtilsTest : public testing::Test { public: static constexpr uint16_t HOST_VALUE16 = 0x1234; @@ -226,4 +229,40 @@ HWTEST_F(ServiceUtilsTest, DCopy, TestSize.Level1) EXPECT_FALSE(constant.DCopy(tags, tagLen, srcs, srcLen)); EXPECT_TRUE(constant.DCopy(tags, tagsLen, srcs, srcsLen)); } -} // namespace OHOS::Test \ No newline at end of file + +/** +* @tc.name: CorruptTest001 +* @tc.desc: test CorruptReporter function with invalid parameter. +* @tc.type: FUNC +* @tc.require: +* @tc.author: yanhui +*/ +HWTEST_F(ServiceUtilsTest, CorruptTest001, TestSize.Level1) +{ + ASSERT_EQ(false, CorruptReporter::CreateCorruptedFlag(TEST_CORRUPT_PATH, "")); + ASSERT_EQ(false, CorruptReporter::CreateCorruptedFlag("", TEST_CORRUPT_STOREID)); + ASSERT_EQ(false, CorruptReporter::CreateCorruptedFlag(TEST_CORRUPT_PATH, TEST_CORRUPT_STOREID)); + ASSERT_EQ(false, CorruptReporter::HasCorruptedFlag(TEST_CORRUPT_PATH, "")); + ASSERT_EQ(false, CorruptReporter::HasCorruptedFlag("", TEST_CORRUPT_STOREID)); + ASSERT_EQ(false, CorruptReporter::DeleteCorruptedFlag(TEST_CORRUPT_PATH, "")); + ASSERT_EQ(false, CorruptReporter::DeleteCorruptedFlag("", TEST_CORRUPT_STOREID)); + ASSERT_EQ(false, CorruptReporter::DeleteCorruptedFlag(TEST_CORRUPT_PATH, TEST_CORRUPT_STOREID)); +} + +/** +* @tc.name: CorruptTest002 +* @tc.desc: test CorruptReporter function with normal parameter. +* @tc.type: FUNC +* @tc.require: +* @tc.author: yanhui +*/ +HWTEST_F(ServiceUtilsTest, CorruptTest002, TestSize.Level1) +{ + mode_t mode = S_IRWXU | S_IRWXG | S_IXOTH; // 0771 + mkdir(TEST_CORRUPT_PATH, mode); + ASSERT_EQ(true, CorruptReporter::CreateCorruptedFlag(TEST_CORRUPT_PATH, TEST_CORRUPT_STOREID)); + ASSERT_EQ(true, CorruptReporter::HasCorruptedFlag(TEST_CORRUPT_PATH, TEST_CORRUPT_STOREID)); + ASSERT_EQ(true, CorruptReporter::DeleteCorruptedFlag(TEST_CORRUPT_PATH, TEST_CORRUPT_STOREID)); + rmdir(TEST_CORRUPT_PATH); +} +} // namespace OHOS::Test diff --git a/datamgr_service/services/distributeddataservice/framework/thread/thread_manager.cpp b/datamgr_service/services/distributeddataservice/framework/thread/thread_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ea66a2e604071639c1937b743f2a77f6453c6fc9 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/thread/thread_manager.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025 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 "ThreadManager" +#include "thread/thread_manager.h" + +#include "log_print.h" +#include "types.h" +#include "unistd.h" +namespace OHOS::DistributedData { +ThreadManager::ThreadManager() +{ +} + +ThreadManager &ThreadManager::GetInstance() +{ + static ThreadManager instance; + return instance; +} + +void ThreadManager::Initialize(uint32_t minThreadNum, uint32_t maxThreadNum, uint32_t ipcThreadNum) +{ + minThreadNum_ = minThreadNum; + maxThreadNum_ = maxThreadNum; + ipcThreadNum_ = ipcThreadNum; +} + +uint32_t ThreadManager::GetMinThreadNum() +{ + return minThreadNum_; +} + +uint32_t ThreadManager::GetMaxThreadNum() +{ + return maxThreadNum_; +} + +uint32_t ThreadManager::GetIpcThreadNum() +{ + return ipcThreadNum_; +} +} // namespace OHOS::DistributedData \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/data_share/common/base64_utils.cpp b/datamgr_service/services/distributeddataservice/framework/utils/base64_utils.cpp similarity index 97% rename from datamgr_service/services/distributeddataservice/service/data_share/common/base64_utils.cpp rename to datamgr_service/services/distributeddataservice/framework/utils/base64_utils.cpp index f51f92682ed0ba00d17e1444887ddcc8a6e7a127..1a52447f42f6c6380daab257d5eb2b71c7f824cf 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/common/base64_utils.cpp +++ b/datamgr_service/services/distributeddataservice/framework/utils/base64_utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -13,12 +13,12 @@ * limitations under the License. */ -#include "base64_utils.h" +#include "utils/base64_utils.h" #include #include -namespace OHOS::DataShare::Base64 { +namespace OHOS::DistributedData::Base64 { static constexpr const std::string_view BASE64_CHARS = /* NOLINT */ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" @@ -178,4 +178,4 @@ std::vector Decode(const std::string &encoded) } return ret; } -} // namespace OHOS::DataShare::Base64 +} // namespace OHOS::DistributedData::Base64 diff --git a/datamgr_service/services/distributeddataservice/framework/utils/corrupt_reporter.cpp b/datamgr_service/services/distributeddataservice/framework/utils/corrupt_reporter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..90c25a3b9b4b8c81d6648c11eb9c04b18af295af --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/utils/corrupt_reporter.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2024 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 "CorruptReporter" +#include "utils/corrupt_reporter.h" + +#include "log_print.h" +#include "utils/anonymous.h" +#include +#include +#include + +namespace OHOS::DistributedData { +constexpr const char *DB_CORRUPTED_POSTFIX = ".corruptedflg"; + +bool CorruptReporter::CreateCorruptedFlag(const std::string &path, const std::string &dbName) +{ + if (path.empty() || dbName.empty()) { + ZLOGW("The path or dbName is empty, path:%{public}s, dbName:%{public}s", path.c_str(), + Anonymous::Change(dbName).c_str()); + return false; + } + std::string flagFileName = path + "/" + dbName + DB_CORRUPTED_POSTFIX; + int fd = creat(flagFileName.c_str(), S_IRWXU | S_IRWXG); + if (fd == -1) { + ZLOGW("Create corrupted flag fail, flagFileName:%{public}s, errno:%{public}d", + Anonymous::Change(flagFileName).c_str(), errno); + return false; + } + close(fd); + return true; +} + +bool CorruptReporter::HasCorruptedFlag(const std::string &path, const std::string &dbName) +{ + if (path.empty() || dbName.empty()) { + ZLOGW("The path or dbName is empty, path:%{public}s, dbName:%{public}s", path.c_str(), + Anonymous::Change(dbName).c_str()); + return false; + } + std::string flagFileName = path + "/" + dbName + DB_CORRUPTED_POSTFIX; + return access(flagFileName.c_str(), F_OK) == 0; +} + +bool CorruptReporter::DeleteCorruptedFlag(const std::string &path, const std::string &dbName) +{ + if (path.empty() || dbName.empty()) { + ZLOGW("The path or dbName is empty, path:%{public}s, dbName:%{public}s", path.c_str(), + Anonymous::Change(dbName).c_str()); + return false; + } + std::string flagFileName = path + "/" + dbName + DB_CORRUPTED_POSTFIX; + int result = remove(flagFileName.c_str()); + if (result != 0) { + ZLOGW("Remove corrupted flag fail, flagFileName:%{public}s, errno:%{public}d", + Anonymous::Change(flagFileName).c_str(), errno); + return false; + } + return true; +} +} // namespace OHOS::DistributedData diff --git a/datamgr_service/services/distributeddataservice/framework/utils/time_statistic.cpp b/datamgr_service/services/distributeddataservice/framework/utils/time_statistic.cpp new file mode 100644 index 0000000000000000000000000000000000000000..971b4c07fe04071a4c2d0405fb4233d703a55daf --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/utils/time_statistic.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 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 "TimeStatistic" +//#include "time_statistic.h" + +namespace OHOS::DistributedData { + +} // namespace OHOS::DistributedData \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/rust/extension/BUILD.gn b/datamgr_service/services/distributeddataservice/rust/extension/BUILD.gn index ab8f148b9a2eb5c39fecc47a9005d1a6126d102c..d1c0fdc1d9dcba25c6c8102985f7961a48a950df 100644 --- a/datamgr_service/services/distributeddataservice/rust/extension/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/rust/extension/BUILD.gn @@ -15,7 +15,9 @@ import("//build/ohos_var.gni") import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") group("build_module") { - deps = [ ":opencloudextension" ] + if (datamgr_service_cloud) { + deps = [ ":opencloudextension" ] + } } config("module_public_config") { visibility = [ ":*" ] @@ -60,7 +62,7 @@ ohos_shared_library("opencloudextension") { "access_token:libaccesstoken_sdk", "hilog:libhilog", "json:nlohmann_json_static", - "kv_store:distributeddata_inner", + "kv_store:datamgr_common", ] subsystem_name = "distributeddatamgr" part_name = "datamgr_service" diff --git a/datamgr_service/services/distributeddataservice/rust/extension/cloud_server_impl.cpp b/datamgr_service/services/distributeddataservice/rust/extension/cloud_server_impl.cpp index 41a5f486feb9fddf99eddd8839dc58a27c3d267f..f47a26209787b06c9b2dcd049f4cd8fee9cd9e11 100644 --- a/datamgr_service/services/distributeddataservice/rust/extension/cloud_server_impl.cpp +++ b/datamgr_service/services/distributeddataservice/rust/extension/cloud_server_impl.cpp @@ -33,12 +33,12 @@ __attribute__((used)) static bool g_isInit = using namespace Security::AccessToken; using DBMetaMgr = DistributedData::MetaDataManager; using Anonymous = DistributedData::Anonymous; -DBCloudInfo CloudServerImpl::GetServerInfo(int32_t userId, bool needSpaceInfo) +std::pair CloudServerImpl::GetServerInfo(int32_t userId, bool needSpaceInfo) { DBCloudInfo result; OhCloudExtCloudSync *server = OhCloudExtCloudSyncNew(userId); if (server == nullptr) { - return result; + return { DBErr::E_ERROR, result }; } auto pServer = std::shared_ptr(server, [](auto *server) { OhCloudExtCloudSyncFree(server); @@ -46,19 +46,19 @@ DBCloudInfo CloudServerImpl::GetServerInfo(int32_t userId, bool needSpaceInfo) OhCloudExtCloudInfo *info = nullptr; auto status = OhCloudExtCloudSyncGetServiceInfo(pServer.get(), &info); if (status != ERRNO_SUCCESS || info == nullptr) { - return result; + return { DBErr::E_ERROR, result }; } auto pInfo = std::shared_ptr(info, [](auto *info) { OhCloudExtCloudInfoFree(info); }); status = OhCloudExtCloudInfoGetUser(pInfo.get(), &result.user); if (status != ERRNO_SUCCESS || result.user != userId) { ZLOGE("[IN]user: %{public}d, [OUT]user: %{public}d", userId, result.user); - return result; + return { DBErr::E_ERROR, result }; } unsigned char *id = nullptr; size_t idLen = 0; status = OhCloudExtCloudInfoGetId(pInfo.get(), &id, reinterpret_cast(&idLen)); if (status != ERRNO_SUCCESS || id == nullptr) { - return result; + return { DBErr::E_ERROR, result }; } result.id = std::string(reinterpret_cast(id), idLen); if (needSpaceInfo) { @@ -73,13 +73,13 @@ DBCloudInfo CloudServerImpl::GetServerInfo(int32_t userId, bool needSpaceInfo) OhCloudExtHashMap *briefInfo = nullptr; status = OhCloudExtCloudInfoGetAppInfo(pInfo.get(), &briefInfo); if (status != ERRNO_SUCCESS || briefInfo == nullptr) { - return result; + return { DBErr::E_ERROR, result }; } auto pBriefInfo = std::shared_ptr(briefInfo, [](auto *briefInfo) { OhCloudExtHashMapFree(briefInfo); }); GetAppInfo(pBriefInfo, result); - return result; + return { DBErr::E_ERROR, result }; } void CloudServerImpl::GetAppInfo(std::shared_ptr briefInfo, DBCloudInfo &cloudInfo) @@ -376,7 +376,7 @@ int32_t CloudServerImpl::DoSubscribe(int32_t userId, std::shared_ptr(value); if (err != ERRNO_SUCCESS) { - ZLOGE("sub fail, err:%{oublic}d", err); + ZLOGE("sub fail, user:%{public}d, err:%{public}d", userId, err); return DBErr::E_ERROR; } } diff --git a/datamgr_service/services/distributeddataservice/rust/extension/cloud_server_impl.h b/datamgr_service/services/distributeddataservice/rust/extension/cloud_server_impl.h index c5e072707e6219d074212533316228990e5aa150..bd7c185e7818e31a7879fd31f1a5fedc4a39aba1 100644 --- a/datamgr_service/services/distributeddataservice/rust/extension/cloud_server_impl.h +++ b/datamgr_service/services/distributeddataservice/rust/extension/cloud_server_impl.h @@ -36,7 +36,7 @@ using DBRelation = DBSub::Relation; using DBErr = DistributedData::GeneralError; class CloudServerImpl : public DistributedData::CloudServer { public: - DBCloudInfo GetServerInfo(int32_t userId, bool needSpaceInfo) override; + std::pair GetServerInfo(int32_t userId, bool needSpaceInfo) override; std::pair GetAppSchema(int32_t userId, const std::string &bundleName) override; int32_t Subscribe(int32_t userId, const std::map> &dbs) override; int32_t Unsubscribe(int32_t userId, const std::map> &dbs) override; diff --git a/datamgr_service/services/distributeddataservice/sa_profile/1301.json b/datamgr_service/services/distributeddataservice/sa_profile/1301.json index a625ee9fc05a4cb7ff9154c1bedadc2c7533adf4..8628a02d17d6dd2a7055e81d3a2fd9ad553ccab8 100644 --- a/datamgr_service/services/distributeddataservice/sa_profile/1301.json +++ b/datamgr_service/services/distributeddataservice/sa_profile/1301.json @@ -6,7 +6,8 @@ "libpath": "libdistributeddataservice.z.so", "run-on-create": true, "distributed": false, - "dump_level": 1 + "dump_level": 1, + "extension": ["backup", "restore"] } ] } \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/BUILD.gn b/datamgr_service/services/distributeddataservice/service/BUILD.gn index 6f64cdeb3b9a2cbd9efb65f7c1a41f93da789997..4f264fdecdc166d3403b84e14f332cfa54afa203 100644 --- a/datamgr_service/services/distributeddataservice/service/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/BUILD.gn @@ -16,10 +16,6 @@ import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") group("build_module") { deps = [ ":distributeddatasvc" ] - - if (datamgr_service_udmf) { - deps += [ "${data_service_path}/service/udmf:udmf_server" ] - } } config("module_public_config") { visibility = [ ":*" ] @@ -36,7 +32,6 @@ config("module_public_config") { "object", "permission/include", "rdb", - "waterversion", "${data_service_path}/adapter/include", "${data_service_path}/app/src", "${data_service_path}/framework/include", @@ -58,115 +53,69 @@ ohos_shared_library("distributeddatasvc") { cfi_cross_dso = true debug = false } - include_dirs = [ - "${dataobject_path}/frameworks/innerkitsimpl/include", - "${dataobject_path}/frameworks/innerkitsimpl/include/common", - "${dataobject_path}/interfaces/innerkits", - "../../../../relational_store/interfaces/inner_api/cloud_data/include", - "../../../../relational_store/interfaces/inner_api/common_type/include", - "../../../../relational_store/interfaces/inner_api/rdb/include", - "${kv_store_distributeddb_path}", - ] - sources = [ - "${dataobject_path}/frameworks/innerkitsimpl/src/object_radar_reporter.cpp", - "backup/src/backup_manager.cpp", - "bootstrap/src/bootstrap.cpp", - "cloud/cloud_service_impl.cpp", - "cloud/cloud_service_stub.cpp", - "cloud/cloud_types_util.cpp", - "cloud/cloud_value_util.cpp", - "cloud/sync_manager.cpp", - "cloud/sync_strategies/network_sync_strategy.cpp", - "common/common_types_utils.cpp", - "common/value_proxy.cpp", - "common/xcollie.cpp", - "config/src/config_factory.cpp", - "config/src/model/app_id_mapping_config.cpp", - "config/src/model/backup_config.cpp", - "config/src/model/checker_config.cpp", - "config/src/model/cloud_config.cpp", - "config/src/model/component_config.cpp", - "config/src/model/directory_config.cpp", - "config/src/model/global_config.cpp", - "config/src/model/network_config.cpp", - "config/src/model/protocol_config.cpp", - "crypto/src/crypto_manager.cpp", - "dumper/src/dump_helper.cpp", - "kvdb/auth_delegate.cpp", - "kvdb/kvdb_exporter.cpp", - "kvdb/kvdb_general_store.cpp", - "kvdb/kvdb_notifier_proxy.cpp", - "kvdb/kvdb_service_impl.cpp", - "kvdb/kvdb_service_stub.cpp", - "kvdb/kvdb_watcher.cpp", - "kvdb/kvstore_sync_manager.cpp", - "kvdb/query_helper.cpp", - "kvdb/upgrade.cpp", - "kvdb/user_delegate.cpp", - "matrix/src/device_matrix.cpp", - "matrix/src/matrix_event.cpp", - "object/object_asset_loader.cpp", - "object/object_asset_machine.cpp", - "object/object_callback_proxy.cpp", - "object/object_data_listener.cpp", - "object/object_dms_handler.cpp", - "object/object_manager.cpp", - "object/object_service_impl.cpp", - "object/object_service_stub.cpp", - "object/object_snapshot.cpp", - "object/object_types_utils.cpp", - "permission/src/permit_delegate.cpp", - "rdb/cache_cursor.cpp", - "rdb/rdb_asset_loader.cpp", - "rdb/rdb_cloud.cpp", - "rdb/rdb_cloud_data_translate.cpp", - "rdb/rdb_cursor.cpp", - "rdb/rdb_general_store.cpp", - "rdb/rdb_notifier_proxy.cpp", - "rdb/rdb_query.cpp", - "rdb/rdb_result_set_impl.cpp", - "rdb/rdb_result_set_stub.cpp", - "rdb/rdb_service_impl.cpp", - "rdb/rdb_service_stub.cpp", - "rdb/rdb_watcher.cpp", - "waterversion/water_version_manager.cpp", - ] + cflags = [ "-Werror", "-Wno-multichar", "-Wno-c99-designator", "-D_LIBCPP_HAS_COND_CLOCKWAIT", + "-Oz", ] - cflags_cc = [ "-fvisibility=hidden" ] + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] configs = [ ":module_public_config" ] + public_configs = [ ":module_public_config" ] deps = [ - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter:distributeddata_adapter", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/utils:distributeddata_utils_static", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/framework:distributeddatasvcfwk", + "${data_service_path}/adapter/account:distributeddata_account", + "${data_service_path}/adapter/communicator:distributeddata_communicator", + "${data_service_path}/adapter/utils:distributeddata_utils", + "${data_service_path}/framework:distributeddatasvcfwk", + "${data_service_path}/service/backup:distributeddata_backup", + "${data_service_path}/service/bootstrap:distributeddata_bootstrap", + "${data_service_path}/service/common:distributeddata_common", + "${data_service_path}/service/config:distributeddata_config", + "${data_service_path}/service/crypto:distributeddata_crypto", + "${data_service_path}/service/dumper:distributeddata_dumper", + "${data_service_path}/service/matrix:distributeddata_matrix", + "${data_service_path}/service/permission:distributeddata_permit", ] - external_deps = [ - "access_token:libaccesstoken_sdk", - "access_token:libtokenid_sdk", - "c_utils:utils", - "device_auth:deviceauth_sdk", - "device_manager:devicemanagersdk", - "dfs_service:cloudsync_asset_kit_inner", - "dfs_service:distributed_file_daemon_kit_inner", - "dmsfwk:distributed_sdk", - "hicollie:libhicollie", - "hilog:libhilog", - "hisysevent:libhisysevent", - "huks:libhukssdk", - "ipc:ipc_core", - "json:nlohmann_json_static", - "kv_store:distributeddata_inner", - "kv_store:distributeddb", - "relational_store:native_rdb", - ] + if (defined(global_parts_info) && + defined(global_parts_info.theme_screenlock_mgr)) { + deps += + [ "${data_service_path}/adapter/screenlock:distributeddata_screenlock" ] + } + + if (datamgr_service_cloud) { + deps += [ "${data_service_path}/service/cloud:distributeddata_cloud" ] + } + + if (datamgr_service_kvdb) { + deps += [ "${data_service_path}/service/kvdb:distributeddata_kvdb" ] + } + + if (datamgr_service_udmf) { + deps += [ "${data_service_path}/service/udmf:udmf_server" ] + } + + if (datamgr_service_rdb) { + deps += [ "${data_service_path}/service/rdb:distributeddata_rdb" ] + } + + if (datamgr_service_data_share) { + deps += [ "${data_service_path}/service/data_share:data_share_service" ] + } + + if (datamgr_service_object) { + deps += [ "${data_service_path}/service/object:distributeddata_object" ] + } + + external_deps = [ "hilog:libhilog" ] subsystem_name = "distributeddatamgr" part_name = "datamgr_service" diff --git a/datamgr_service/services/distributeddataservice/service/CMakeLists.txt b/datamgr_service/services/distributeddataservice/service/CMakeLists.txt index 31fe3b6a040a28a2aa8098f36ebe4be95dcb2f18..e3334218c1f39d738a5e1fc4193b12280ac3d30b 100644 --- a/datamgr_service/services/distributeddataservice/service/CMakeLists.txt +++ b/datamgr_service/services/distributeddataservice/service/CMakeLists.txt @@ -23,9 +23,10 @@ aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/crypto/src serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/rdb serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/kvdb serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/matrix/src serviceSrc) -aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/object serviceSrc) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/object/src serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/data_share/common serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/data_share/data serviceSrc) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/data_share/dfx serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/data_share/strategies/data_proxy serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/data_share/strategies/data_share serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/data_share/strategies/general serviceSrc) @@ -33,13 +34,14 @@ aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/data_share/strategies serviceSr aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/data_share/subscriber_managers serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/data_share serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/dumper/src serviceSrc) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/network serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/udmf/lifecycle serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/udmf/permission serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/udmf/preprocess serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/udmf/store serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/udmf/utd serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/udmf serviceSrc) -aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/waterversion serviceSrc) +#aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/waterversion serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/permission/src serviceSrc) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/backup/include) @@ -52,17 +54,19 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/matrix/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/cloud/sync_strategies) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/data_share/common) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/data_share/data) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/data_share/dfx) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/data_share/strategies/data_proxy) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/data_share/strategies/data_share) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/data_share/strategies/general) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/data_share/strategies) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/data_share/subscriber_managers) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/dumper/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/network) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/udmf/lifecycle) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/udmf/permission) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/udmf/preprocess) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/udmf/store) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/waterversion) +#include_directories(${CMAKE_CURRENT_SOURCE_DIR}/waterversion) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../framework/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../app/src) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../../kv_store/frameworks/common) @@ -85,5 +89,8 @@ target_include_directories(service PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/kvdb) target_include_directories(service PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/rdb) target_include_directories(service PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/udmf) target_include_directories(service PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/data_share) +target_include_directories(service PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(service PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/dumper/include) -target_include_directories(service PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/waterversion) +target_include_directories(service PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/network) +target_include_directories(service PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/object/include) +#target_include_directories(service PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/waterversion) diff --git a/datamgr_service/services/distributeddataservice/service/backup/BUILD.gn b/datamgr_service/services/distributeddataservice/service/backup/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..6baaacf3a171523f8adb95fcf28be3f7c69e317b --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/backup/BUILD.gn @@ -0,0 +1,63 @@ +# Copyright (c) 2024 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. +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +config("backup_public_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +ohos_source_set("distributeddata_backup") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + boundary_sanitize = true + ubsan = true + } + sources = [ "src/backup_manager.cpp" ] + + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] + + include_dirs = [ + "${data_service_path}/service/crypto/include", + "${data_service_path}/adapter/include/communicator", + ] + configs = [ ":backup_public_config" ] + public_configs = [ ":backup_public_config" ] + cflags = [ + "-Werror", + "-Wno-multichar", + "-Wno-c99-designator", + "-D_LIBCPP_HAS_COND_CLOCKWAIT", + "-Oz", + ] + + deps = [ + "${data_service_path}/framework:distributeddatasvcfwk", + "${data_service_path}/service/crypto:distributeddata_crypto", + ] + + external_deps = [ + "device_manager:devicemanagersdk", + "hilog:libhilog", + "kv_store:datamgr_common", + ] + subsystem_name = "distributeddatamgr" + part_name = "datamgr_service" +} diff --git a/datamgr_service/services/distributeddataservice/service/backup/include/backup_manager.h b/datamgr_service/services/distributeddataservice/service/backup/include/backup_manager.h index 1d4c38e5d13079cc1c7002320b1fd0837a11ec91..7600155987f4f6f0a45ed17739220d187c5a77d9 100644 --- a/datamgr_service/services/distributeddataservice/service/backup/include/backup_manager.h +++ b/datamgr_service/services/distributeddataservice/service/backup/include/backup_manager.h @@ -16,10 +16,13 @@ #ifndef OHOS_DISTRIBUTED_DATA_SERVICES_BACKUP_BACKUP_MANAGER_H #define OHOS_DISTRIBUTED_DATA_SERVICES_BACKUP_BACKUP_MANAGER_H -#include "executor_pool.h" +#include + #include "metadata/secret_key_meta_data.h" #include "metadata/store_meta_data.h" -#include "types.h" +namespace OHOS { +class ExecutorPool; +} namespace OHOS::DistributedData { class BackupManager { public: diff --git a/datamgr_service/services/distributeddataservice/service/backup/src/backup_manager.cpp b/datamgr_service/services/distributeddataservice/service/backup/src/backup_manager.cpp index be05b0be00f1340427ff2c7ff2f2ad4343641dd9..204ac5b9cf814abc5d0695a2ac4ea84bc0bdb5d0 100644 --- a/datamgr_service/services/distributeddataservice/service/backup/src/backup_manager.cpp +++ b/datamgr_service/services/distributeddataservice/service/backup/src/backup_manager.cpp @@ -26,7 +26,6 @@ #include "directory/directory_manager.h" #include "log_print.h" #include "metadata/meta_data_manager.h" -#include "types.h" namespace OHOS::DistributedData { namespace { constexpr const int COPY_SIZE = 1024; diff --git a/datamgr_service/services/distributeddataservice/service/bootstrap/BUILD.gn b/datamgr_service/services/distributeddataservice/service/bootstrap/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..ff48eaecef9718f2b318e3a2ba349707e54b67a8 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/bootstrap/BUILD.gn @@ -0,0 +1,62 @@ +# Copyright (c) 2024 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. +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +config("bootstrap_public_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +ohos_source_set("distributeddata_bootstrap") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + boundary_sanitize = true + ubsan = true + } + sources = [ "src/bootstrap.cpp" ] + + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] + + include_dirs = [ "${data_service_path}/service/config/include" ] + configs = [ ":bootstrap_public_config" ] + public_configs = [ ":bootstrap_public_config" ] + cflags = [ + "-Werror", + "-Wno-multichar", + "-Wno-c99-designator", + "-D_LIBCPP_HAS_COND_CLOCKWAIT", + "-Oz", + ] + + deps = [ + "${data_service_path}/framework:distributeddatasvcfwk", + "${data_service_path}/service/backup:distributeddata_backup", + "${data_service_path}/service/config:distributeddata_config", + "${data_service_path}/service/crypto:distributeddata_crypto", + ] + + external_deps = [ + "hilog:libhilog", + "json:nlohmann_json_static", + "kv_store:datamgr_common", + ] + subsystem_name = "distributeddatamgr" + part_name = "datamgr_service" +} diff --git a/datamgr_service/services/distributeddataservice/service/bootstrap/include/bootstrap.h b/datamgr_service/services/distributeddataservice/service/bootstrap/include/bootstrap.h index 50b86fd88dfa0ae9221c5c6fbf0c0f56b9e25c22..852d3af312c6970ab2e716b45753566c515728d9 100644 --- a/datamgr_service/services/distributeddataservice/service/bootstrap/include/bootstrap.h +++ b/datamgr_service/services/distributeddataservice/service/bootstrap/include/bootstrap.h @@ -32,6 +32,7 @@ public: API_EXPORT void LoadCloud(); API_EXPORT void LoadBackup(std::shared_ptr executors); API_EXPORT void LoadAppIdMappings(); + API_EXPORT void LoadThread(); private: static constexpr const char *DEFAULT_LABEL = "distributeddata"; static constexpr const char *DEFAULT_META = "service_meta"; diff --git a/datamgr_service/services/distributeddataservice/service/bootstrap/src/bootstrap.cpp b/datamgr_service/services/distributeddataservice/service/bootstrap/src/bootstrap.cpp index 3dda8f457ec897ed05ae5b399b181cd8c1f3542a..1752431c82e88abffce834fb70174663ad173d4d 100644 --- a/datamgr_service/services/distributeddataservice/service/bootstrap/src/bootstrap.cpp +++ b/datamgr_service/services/distributeddataservice/service/bootstrap/src/bootstrap.cpp @@ -17,6 +17,7 @@ #include +#include "app_id_mapping/app_id_mapping_config_manager.h" #include "backup_manager.h" #include "backuprule/backup_rule_manager.h" #include "checker/checker_manager.h" @@ -24,7 +25,7 @@ #include "config_factory.h" #include "directory/directory_manager.h" #include "log_print.h" -#include "app_id_mapping/app_id_mapping_config_manager.h" +#include "thread/thread_manager.h" namespace OHOS { namespace DistributedData { Bootstrap &Bootstrap::GetInstance() @@ -181,5 +182,14 @@ void Bootstrap::LoadAppIdMappings() } AppIdMappingConfigManager::GetInstance().Initialize(infos); } + +void Bootstrap::LoadThread() +{ + auto *config = ConfigFactory::GetInstance().GetThreadConfig(); + if (config == nullptr) { + return; + } + ThreadManager::GetInstance().Initialize(config->minThreadNum, config->maxThreadNum, config->ipcThreadNum); +} } // namespace DistributedData } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/service/cloud/BUILD.gn b/datamgr_service/services/distributeddataservice/service/cloud/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..d2f8c227ecff818f8ceef785cf8fba9a71be30e5 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/cloud/BUILD.gn @@ -0,0 +1,78 @@ +# Copyright (c) 2024 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. +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +config("cloud_public_config") { + visibility = [ ":*" ] +} + +ohos_source_set("distributeddata_cloud") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + boundary_sanitize = true + ubsan = true + } + sources = [ + "cloud_data_translate.cpp", + "cloud_service_impl.cpp", + "cloud_service_stub.cpp", + "cloud_types_util.cpp", + "cloud_value_util.cpp", + "sync_manager.cpp", + "sync_strategies/network_sync_strategy.cpp", + ] + + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] + + include_dirs = [ + "${data_service_path}/service/common", + "${data_service_path}/service/bootstrap/include", + "${data_service_path}/service/kvdb", + "${data_service_path}/service/matrix/include", + "${data_service_path}/service/network", + "${data_service_path}/service/permission/include", + "${data_service_path}/framework/include", + "${data_service_path}/adapter/include/communicator", + "sync_strategies", + "${data_service_path}/adapter/include/dfx", + ] + configs = [ ":cloud_public_config" ] + cflags = [ + "-Werror", + "-Wno-multichar", + "-Wno-c99-designator", + "-D_LIBCPP_HAS_COND_CLOCKWAIT", + "-Oz", + ] + + deps = [ "${data_service_path}/service/network:distributeddata_network" ] + + external_deps = [ + "access_token:libtokenid_sdk", + "device_manager:devicemanagersdk", + "hicollie:libhicollie", + "kv_store:datamgr_common", + "kv_store:distributeddb", + "relational_store:cloud_data_inner", + ] + + subsystem_name = "distributeddatamgr" + part_name = "datamgr_service" +} diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud_data_translate.cpp b/datamgr_service/services/distributeddataservice/service/cloud/cloud_data_translate.cpp similarity index 98% rename from datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud_data_translate.cpp rename to datamgr_service/services/distributeddataservice/service/cloud/cloud_data_translate.cpp index 6f4723c4f3325fd6961f811f3ad38d2b200c074c..80762e38753201781258eb3e455a9b9b3f4f2c19 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud_data_translate.cpp +++ b/datamgr_service/services/distributeddataservice/service/cloud/cloud_data_translate.cpp @@ -13,12 +13,12 @@ * limitations under the License. */ -#include "rdb_cloud_data_translate.h" +#include "cloud_data_translate.h" #include "utils/endian_converter.h" #include "value_proxy.h" -namespace OHOS::DistributedRdb { +namespace OHOS::CloudData { using Asset = DistributedDB::Asset; using Assets = DistributedDB::Assets; using DataAsset = NativeRdb::ValueObject::Asset; diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud_data_translate.h b/datamgr_service/services/distributeddataservice/service/cloud/cloud_data_translate.h similarity index 98% rename from datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud_data_translate.h rename to datamgr_service/services/distributeddataservice/service/cloud/cloud_data_translate.h index dd8129e5d22444d006255f8418e498150cfa48b4..feb988f81defdc3b7753785ae6932a601e48a874 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud_data_translate.h +++ b/datamgr_service/services/distributeddataservice/service/cloud/cloud_data_translate.h @@ -18,7 +18,7 @@ #include "cloud/icloud_data_translate.h" #include "serializable/serializable.h" #include "value_object.h" -namespace OHOS::DistributedRdb { +namespace OHOS::CloudData { class RdbCloudDataTranslate : public DistributedDB::ICloudDataTranslate { public: using Asset = DistributedDB::Asset; diff --git a/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.cpp b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.cpp index badff50f50d1f946dafe7b927476938e206a20c4..a2d43de0fec38801d265f29aa0520f87ec0bd40a 100644 --- a/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.cpp +++ b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.cpp @@ -27,21 +27,21 @@ #include "cloud/cloud_share_event.h" #include "cloud/make_query_event.h" #include "cloud/sharing_center.h" +#include "cloud_data_translate.h" #include "cloud_value_util.h" -#include "communicator/device_manager_adapter.h" -#include "device_matrix.h" -#include "dfx/radar_reporter.h" +#include "device_manager_adapter.h" +#include "radar_reporter.h" #include "eventcenter/event_center.h" #include "hap_token_info.h" #include "ipc_skeleton.h" #include "log_print.h" #include "metadata/meta_data_manager.h" -#include "rdb_cloud_data_translate.h" +#include "network_adapter.h" #include "rdb_types.h" +#include "reporter.h" #include "relational_store_manager.h" #include "runtime_config.h" #include "store/auto_cache.h" -#include "store/general_store.h" #include "sync_manager.h" #include "sync_strategies/network_sync_strategy.h" #include "utils/anonymous.h" @@ -50,14 +50,24 @@ namespace OHOS::CloudData { using namespace DistributedData; -using namespace DistributedKv; using namespace std::chrono; using namespace SharingUtil; using namespace Security::AccessToken; using namespace DistributedDataDfx; using DmAdapter = OHOS::DistributedData::DeviceManagerAdapter; -using Account = OHOS::DistributedKv::AccountDelegate; +using Account = AccountDelegate; using AccessTokenKit = Security::AccessToken::AccessTokenKit; +static constexpr uint32_t RESTART_SERVICE_TIME_THRESHOLD = 60; +static constexpr const char *FT_ENABLE_CLOUD = "ENABLE_CLOUD"; +static constexpr const char *FT_DISABLE_CLOUD = "DISABLE_CLOUD"; +static constexpr const char *FT_SWITCH_ON = "SWITCH_ON"; +static constexpr const char *FT_SWITCH_OFF = "SWITCH_OFF"; +static constexpr const char *FT_QUERY_INFO = "QUERY_SYNC_INFO"; +static constexpr const char *FT_USER_CHANGE = "USER_CHANGE"; +static constexpr const char *FT_USER_UNLOCK = "USER_UNLOCK"; +static constexpr const char *FT_NETWORK_RECOVERY = "NETWORK_RECOVERY"; +static constexpr const char *FT_SERVICE_INIT = "SERVICE_INIT"; +static constexpr const char *FT_SYNC_TASK = "SYNC_TASK"; __attribute__((used)) CloudServiceImpl::Factory CloudServiceImpl::factory_; const CloudServiceImpl::SaveStrategy CloudServiceImpl::STRATEGY_SAVERS[Strategy::STRATEGY_BUTT] = { &CloudServiceImpl::SaveNetworkStrategy @@ -103,11 +113,13 @@ CloudServiceImpl::CloudServiceImpl() int32_t CloudServiceImpl::EnableCloud(const std::string &id, const std::map &switches) { - XCollie xcollie(__FUNCTION__, HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_RECOVERY); + XCollie xcollie( + __FUNCTION__, HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_RECOVERY, RESTART_SERVICE_TIME_THRESHOLD); auto tokenId = IPCSkeleton::GetCallingTokenID(); auto user = Account::GetInstance()->GetUserByToken(tokenId); auto [status, cloudInfo] = GetCloudInfo(user); if (status != SUCCESS) { + Report(FT_ENABLE_CLOUD, Fault::CSF_CLOUD_INFO, "", "EnableCloud ret=" + std::to_string(status)); return status; } cloudInfo.enableCloud = true; @@ -121,19 +133,33 @@ int32_t CloudServiceImpl::EnableCloud(const std::string &id, const std::map(errCode) + SyncManager::GenStore::CLOUD_ERR_OFFSET, + .appendixMsg = appendix }; + Reporter::GetInstance()->CloudSyncFault()->Report(msg); +} + int32_t CloudServiceImpl::DisableCloud(const std::string &id) { XCollie xcollie(__FUNCTION__, HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_RECOVERY); auto tokenId = IPCSkeleton::GetCallingTokenID(); auto user = Account::GetInstance()->GetUserByToken(tokenId); + ReleaseUserInfo(user, CloudSyncScene::DISABLE_CLOUD); std::lock_guard lock(rwMetaMutex_); auto [status, cloudInfo] = GetCloudInfo(user); if (status != SUCCESS) { + Report(FT_DISABLE_CLOUD, Fault::CSF_CLOUD_INFO, "", "DisableCloud ret=" + std::to_string(status)); return status; } if (cloudInfo.id != id) { @@ -145,7 +171,7 @@ int32_t CloudServiceImpl::DisableCloud(const std::string &id) if (!MetaDataManager::GetInstance().SaveMeta(cloudInfo.GetKey(), cloudInfo, true)) { return ERROR; } - Execute(GenTask(0, cloudInfo.user, { WORK_STOP_CLOUD_SYNC, WORK_RELEASE, WORK_SUB })); + Execute(GenTask(0, cloudInfo.user, CloudSyncScene::DISABLE_CLOUD, { WORK_STOP_CLOUD_SYNC, WORK_SUB })); ZLOGI("DisableCloud success, id:%{public}s", Anonymous::Change(id).c_str()); return SUCCESS; } @@ -155,15 +181,23 @@ int32_t CloudServiceImpl::ChangeAppSwitch(const std::string &id, const std::stri XCollie xcollie(__FUNCTION__, HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_RECOVERY); auto tokenId = IPCSkeleton::GetCallingTokenID(); auto user = Account::GetInstance()->GetUserByToken(tokenId); + CloudSyncScene scene; + if (appSwitch == SWITCH_ON) { + scene = CloudSyncScene::SWITCH_ON; + } else { + scene = CloudSyncScene::SWITCH_OFF; + } std::lock_guard lock(rwMetaMutex_); auto [status, cloudInfo] = GetCloudInfo(user); if (status != SUCCESS || !cloudInfo.enableCloud) { + Report(appSwitch == SWITCH_ON ? FT_SWITCH_ON : FT_SWITCH_OFF, Fault::CSF_CLOUD_INFO, bundleName, + "ChangeAppSwitch ret = " + std::to_string(status)); return status; } if (cloudInfo.id != id) { ZLOGW("invalid args, [input] id:%{public}s, [exist] id:%{public}s, bundleName:%{public}s", Anonymous::Change(id).c_str(), Anonymous::Change(cloudInfo.id).c_str(), bundleName.c_str()); - Execute(GenTask(0, cloudInfo.user, { WORK_CLOUD_INFO_UPDATE, WORK_SCHEMA_UPDATE, WORK_SUB, + Execute(GenTask(0, cloudInfo.user, scene, { WORK_CLOUD_INFO_UPDATE, WORK_SCHEMA_UPDATE, WORK_SUB, WORK_DO_CLOUD_SYNC })); return INVALID_ARGUMENT; } @@ -173,6 +207,8 @@ int32_t CloudServiceImpl::ChangeAppSwitch(const std::string &id, const std::stri ZLOGE("invalid args, status:%{public}d, enableCloud:%{public}d, [input] id:%{public}s," "[exist] id:%{public}s, bundleName:%{public}s", status, cloudInfo.enableCloud, Anonymous::Change(id).c_str(), Anonymous::Change(cloudInfo.id).c_str(), bundleName.c_str()); + Report(appSwitch == SWITCH_ON ? FT_SWITCH_ON : FT_SWITCH_OFF, Fault::CSF_CLOUD_INFO, bundleName, + "ChangeAppSwitch ret=" + std::to_string(status)); return INVALID_ARGUMENT; } ZLOGI("add app switch, bundleName:%{public}s", bundleName.c_str()); @@ -181,7 +217,7 @@ int32_t CloudServiceImpl::ChangeAppSwitch(const std::string &id, const std::stri if (!MetaDataManager::GetInstance().SaveMeta(cloudInfo.GetKey(), cloudInfo, true)) { return ERROR; } - Execute(GenTask(0, cloudInfo.user, { WORK_CLOUD_INFO_UPDATE, WORK_SCHEMA_UPDATE, WORK_SUB })); + Execute(GenTask(0, cloudInfo.user, scene, { WORK_CLOUD_INFO_UPDATE, WORK_SCHEMA_UPDATE, WORK_SUB })); if (cloudInfo.enableCloud && appSwitch == SWITCH_ON) { SyncManager::SyncInfo info(cloudInfo.user, bundleName); syncManager_.DoCloudSync(info); @@ -579,6 +615,8 @@ std::pair CloudServiceImpl::QueryLastSyncInfo(const s auto user = Account::GetInstance()->GetUserByToken(IPCSkeleton::GetCallingTokenID()); auto [status, cloudInfo] = GetCloudInfo(user); if (status != SUCCESS) { + Report(FT_QUERY_INFO, Fault::CSF_CLOUD_INFO, bundleName, + "QueryLastSyncInfo ret=" + std::to_string(status) + ",storeId=" + storeId); return { ERROR, results }; } if (cloudInfo.apps.find(bundleName) == cloudInfo.apps.end()) { @@ -628,8 +666,10 @@ std::pair CloudServiceImpl::QueryLastSyncInfo(const s int32_t CloudServiceImpl::OnInitialize() { XCollie xcollie(__FUNCTION__, HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_RECOVERY); - DistributedDB::RuntimeConfig::SetCloudTranslate(std::make_shared()); - Execute(GenTask(0, 0, { WORK_CLOUD_INFO_UPDATE, WORK_SCHEMA_UPDATE, WORK_DO_CLOUD_SYNC, WORK_SUB })); + NetworkAdapter::GetInstance().RegOnNetworkChange(); + DistributedDB::RuntimeConfig::SetCloudTranslate(std::make_shared()); + Execute(GenTask(0, 0, CloudSyncScene::SERVICE_INIT, + { WORK_CLOUD_INFO_UPDATE, WORK_SCHEMA_UPDATE, WORK_DO_CLOUD_SYNC, WORK_SUB })); std::vector users; Account::GetInstance()->QueryUsers(users); for (auto user : users) { @@ -666,18 +706,20 @@ int32_t CloudServiceImpl::OnUserChange(uint32_t code, const std::string &user, c XCollie xcollie(__FUNCTION__, HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_RECOVERY); int32_t userId = atoi(user.c_str()); ZLOGI("code:%{public}d, user:%{public}s, account:%{public}s", code, user.c_str(), - Anonymous::Change(account).c_str()); + Anonymous::Change(account).c_str()); switch (code) { case static_cast(AccountStatus::DEVICE_ACCOUNT_SWITCHED): - Execute(GenTask(0, userId, { WORK_CLOUD_INFO_UPDATE, WORK_SCHEMA_UPDATE, WORK_DO_CLOUD_SYNC, WORK_SUB })); + Execute(GenTask(0, userId, CloudSyncScene::USER_CHANGE, + { WORK_CLOUD_INFO_UPDATE, WORK_SCHEMA_UPDATE, WORK_DO_CLOUD_SYNC, WORK_SUB })); break; case static_cast(AccountStatus::DEVICE_ACCOUNT_DELETE): case static_cast(AccountStatus::DEVICE_ACCOUNT_STOPPING): case static_cast(AccountStatus::DEVICE_ACCOUNT_STOPPED): - Execute(GenTask(0, userId, { WORK_STOP_CLOUD_SYNC, WORK_RELEASE })); + Execute(GenTask(0, userId, CloudSyncScene::ACCOUNT_STOP, { WORK_STOP_CLOUD_SYNC, WORK_RELEASE })); break; case static_cast(AccountStatus::DEVICE_ACCOUNT_UNLOCKED): - Execute(GenTask(0, userId, { WORK_CLOUD_INFO_UPDATE, WORK_SCHEMA_UPDATE, WORK_DO_CLOUD_SYNC, WORK_SUB })); + Execute(GenTask(0, userId, CloudSyncScene::USER_UNLOCK, + { WORK_CLOUD_INFO_UPDATE, WORK_SCHEMA_UPDATE, WORK_DO_CLOUD_SYNC, WORK_SUB })); break; default: break; @@ -696,9 +738,13 @@ int32_t CloudServiceImpl::OnReady(const std::string &device) if (users.empty()) { return SUCCESS; } + if (!NetworkAdapter::GetInstance().IsNetworkAvailable()) { + return NETWORK_ERROR; + } for (auto user : users) { DoKvCloudSync(user, "", MODE_ONLINE); - Execute(GenTask(0, user, { WORK_CLOUD_INFO_UPDATE, WORK_SCHEMA_UPDATE, WORK_DO_CLOUD_SYNC, WORK_SUB })); + Execute(GenTask(0, user, CloudSyncScene::NETWORK_RECOVERY, + { WORK_CLOUD_INFO_UPDATE, WORK_SCHEMA_UPDATE, WORK_DO_CLOUD_SYNC, WORK_SUB })); } return SUCCESS; } @@ -735,7 +781,7 @@ std::pair CloudServiceImpl::GetCloudInfoFromServer(int32_t u { CloudInfo cloudInfo; cloudInfo.user = userId; - if (!DmAdapter::GetInstance().IsNetworkAvailable()) { + if (!NetworkAdapter::GetInstance().IsNetworkAvailable()) { ZLOGD("network is not available"); return { NETWORK_ERROR, cloudInfo }; } @@ -744,12 +790,7 @@ std::pair CloudServiceImpl::GetCloudInfoFromServer(int32_t u ZLOGD("cloud server is nullptr, user:%{public}d", userId); return { SERVER_UNAVAILABLE, cloudInfo }; } - cloudInfo = instance->GetServerInfo(cloudInfo.user); - if (!cloudInfo.IsValid()) { - ZLOGE("cloud is empty, user:%{public}d", cloudInfo.user); - return { CLOUD_INFO_INVALID, cloudInfo }; - } - return { SUCCESS, cloudInfo }; + return instance->GetServerInfo(cloudInfo.user, false); } int32_t CloudServiceImpl::UpdateCloudInfoFromServer(int32_t user) @@ -762,11 +803,12 @@ int32_t CloudServiceImpl::UpdateCloudInfoFromServer(int32_t user) return MetaDataManager::GetInstance().SaveMeta(cloudInfo.GetKey(), cloudInfo, true) ? E_OK : E_ERROR; } -bool CloudServiceImpl::UpdateCloudInfo(int32_t user) +bool CloudServiceImpl::UpdateCloudInfo(int32_t user, CloudSyncScene scene) { auto [status, cloudInfo] = GetCloudInfoFromServer(user); if (status != SUCCESS) { ZLOGE("user:%{public}d, status:%{public}d", user, status); + Report(GetDfxFaultType(scene), Fault::CSF_CLOUD_INFO, "", "UpdateCloudInfo ret=" + std::to_string(status)); return false; } ZLOGI("[server] id:%{public}s, enableCloud:%{public}d, user:%{public}d, app size:%{public}zu", @@ -778,7 +820,7 @@ bool CloudServiceImpl::UpdateCloudInfo(int32_t user) } MetaDataManager::GetInstance().SaveMeta(cloudInfo.GetKey(), cloudInfo, true); if (oldInfo.id != cloudInfo.id) { - ReleaseUserInfo(user); + ReleaseUserInfo(user, scene); ZLOGE("different id, [server] id:%{public}s, [meta] id:%{public}s", Anonymous::Change(cloudInfo.id).c_str(), Anonymous::Change(oldInfo.id).c_str()); MetaDataManager::GetInstance().DelMeta(Subscription::GetKey(user), true); @@ -792,10 +834,11 @@ bool CloudServiceImpl::UpdateCloudInfo(int32_t user) return true; } -bool CloudServiceImpl::UpdateSchema(int32_t user) +bool CloudServiceImpl::UpdateSchema(int32_t user, CloudSyncScene scene) { auto [status, cloudInfo] = GetCloudInfo(user); if (status != SUCCESS) { + Report(GetDfxFaultType(scene), Fault::CSF_APP_SCHEMA, "", "UpdateSchema ret=" + std::to_string(status)); return false; } auto keys = cloudInfo.GetSchemaKey(); @@ -822,7 +865,7 @@ bool CloudServiceImpl::UpdateSchema(int32_t user) std::pair CloudServiceImpl::GetAppSchemaFromServer(int32_t user, const std::string &bundleName) { SchemaMeta schemaMeta; - if (!DmAdapter::GetInstance().IsNetworkAvailable()) { + if (!NetworkAdapter::GetInstance().IsNetworkAvailable()) { ZLOGD("network is not available"); return { NETWORK_ERROR, schemaMeta }; } @@ -853,14 +896,14 @@ void CloudServiceImpl::UpgradeSchemaMeta(int32_t user, const SchemaMeta &schemaM } } -ExecutorPool::Task CloudServiceImpl::GenTask(int32_t retry, int32_t user, Handles handles) +ExecutorPool::Task CloudServiceImpl::GenTask(int32_t retry, int32_t user, CloudSyncScene scene, Handles handles) { - return [this, retry, user, works = std::move(handles)]() mutable { + return [this, retry, user, scene, works = std::move(handles)]() mutable { auto executor = executor_; if (retry >= RETRY_TIMES || executor == nullptr || works.empty()) { return; } - if (!DmAdapter::GetInstance().IsNetworkAvailable()) { + if (!NetworkAdapter::GetInstance().IsNetworkAvailable()) { ZLOGD("network is not available"); return; } @@ -878,15 +921,15 @@ ExecutorPool::Task CloudServiceImpl::GenTask(int32_t retry, int32_t user, Handle if (user == 0 || !Account::GetInstance()->IsVerified(user)) { continue; } - finished = (this->*handle)(user) && finished; + finished = (this->*handle)(user, scene) && finished; } if (!finished || users.empty()) { - executor->Schedule(std::chrono::seconds(RETRY_INTERVAL), GenTask(retry + 1, user, std::move(works))); + executor->Schedule(std::chrono::seconds(RETRY_INTERVAL), GenTask(retry + 1, user, scene, std::move(works))); return; } works.pop_front(); if (!works.empty()) { - executor->Execute(GenTask(retry, user, std::move(works))); + executor->Execute(GenTask(retry, user, scene, std::move(works))); } }; } @@ -916,6 +959,11 @@ std::pair CloudServiceImpl::GetSchemaMeta(int32_t userId, c return { ERROR, schemaMeta }; } std::tie(status, schemaMeta) = GetAppSchemaFromServer(userId, bundleName); + if (status == NOT_SUPPORT) { + ZLOGW("app not support, del cloudInfo! userId:%{public}d, bundleName:%{public}s", userId, bundleName.c_str()); + MetaDataManager::GetInstance().DelMeta(cloudInfo.GetKey(), true); + return { status, schemaMeta }; + } if (status != SUCCESS) { return { status, schemaMeta }; } @@ -1016,7 +1064,7 @@ std::pair> CloudServiceImpl::P meta.GetStoreAlias().c_str()); return { GeneralError::E_ERROR, nullptr }; } - AutoCache::Store store = SyncManager::GetStore(meta, storeInfo.user, true); + auto [status, store] = SyncManager::GetStore(meta, storeInfo.user, true); if (store == nullptr) { ZLOGE("store null, storeId:%{public}s", meta.GetStoreAlias().c_str()); return { GeneralError::E_ERROR, nullptr }; @@ -1024,30 +1072,39 @@ std::pair> CloudServiceImpl::P return store->PreSharing(query); } -bool CloudServiceImpl::ReleaseUserInfo(int32_t user) +bool CloudServiceImpl::ReleaseUserInfo(int32_t user, CloudSyncScene scene) { auto instance = CloudServer::GetInstance(); if (instance == nullptr) { return true; } instance->ReleaseUserInfo(user); + ZLOGI("notify release user info, user:%{public}d", user); return true; } -bool CloudServiceImpl::DoCloudSync(int32_t user) +bool CloudServiceImpl::DoCloudSync(int32_t user, CloudSyncScene scene) { - SyncManager::SyncInfo info(user); - syncManager_.DoCloudSync(info); + auto [status, cloudInfo] = GetCloudInfo(user); + if (status != SUCCESS) { + Report(GetDfxFaultType(scene), Fault::CSF_CLOUD_INFO, "", "DoCloudSync ret=" + std::to_string(status)); + return false; + } + for (const auto &appInfo : cloudInfo.apps) { + SyncManager::SyncInfo info(user, appInfo.first); + syncManager_.DoCloudSync(info); + } return true; } -bool CloudServiceImpl::StopCloudSync(int32_t user) +bool CloudServiceImpl::StopCloudSync(int32_t user, CloudSyncScene scene) { syncManager_.StopCloudSync(user); + syncManager_.CleanCompensateSync(user); return true; } -bool CloudServiceImpl::DoSubscribe(int32_t user) +bool CloudServiceImpl::DoSubscribe(int32_t user, CloudSyncScene scene) { Subscription sub; sub.userId = user; @@ -1056,7 +1113,6 @@ bool CloudServiceImpl::DoSubscribe(int32_t user) ZLOGE("not support cloud server"); return true; } - CloudInfo cloudInfo; cloudInfo.user = sub.userId; if (!MetaDataManager::GetInstance().LoadMeta(cloudInfo.GetKey(), cloudInfo, true)) { @@ -1065,12 +1121,7 @@ bool CloudServiceImpl::DoSubscribe(int32_t user) } if (!sub.id.empty() && sub.id != cloudInfo.id) { CleanSubscription(sub); - sub.id.clear(); - sub.expiresTime.clear(); } - - ZLOGD("begin cloud:%{public}d user:%{public}d apps:%{public}zu", cloudInfo.enableCloud, sub.userId, - cloudInfo.apps.size()); auto onThreshold = duration_cast((system_clock::now() + hours(EXPIRE_INTERVAL)).time_since_epoch()); auto offThreshold = duration_cast(system_clock::now().time_since_epoch()); std::map> subDbs; @@ -1087,19 +1138,21 @@ bool CloudServiceImpl::DoSubscribe(int32_t user) if (!enabled && (it == sub.expiresTime.end() || it->second <= static_cast(offThreshold.count()))) { continue; } - SchemaMeta schemaMeta; if (MetaDataManager::GetInstance().LoadMeta(cloudInfo.GetSchemaKey(bundle), schemaMeta, true)) { dbs.insert_or_assign(bundle, std::move(schemaMeta.databases)); } } - ZLOGI("cloud switch:%{public}d user%{public}d, sub:%{public}zu, unsub:%{public}zu", cloudInfo.enableCloud, sub.userId, subDbs.size(), unsubDbs.size()); - ZLOGD("Subscribe user%{public}d details:%{public}s", sub.userId, Serializable::Marshall(subDbs).c_str()); - ZLOGD("Unsubscribe user%{public}d details:%{public}s", sub.userId, Serializable::Marshall(unsubDbs).c_str()); - CloudServer::GetInstance()->Subscribe(sub.userId, subDbs); - CloudServer::GetInstance()->Unsubscribe(sub.userId, unsubDbs); + auto status = CloudServer::GetInstance()->Subscribe(sub.userId, subDbs); + if (status != SUCCESS) { + Report(GetDfxFaultType(scene), Fault::CSF_SUBSCRIBE, "", "Subscribe ret=" + std::to_string(status)); + } + status = CloudServer::GetInstance()->Unsubscribe(sub.userId, unsubDbs); + if (status != SUCCESS && scene != CloudSyncScene::DISABLE_CLOUD) { + Report(GetDfxFaultType(scene), Fault::CSF_UNSUBSCRIBE, "", "Unsubscribe, ret=" + std::to_string(status)); + } return subDbs.empty() && unsubDbs.empty(); } @@ -1110,6 +1163,8 @@ void CloudServiceImpl::CleanSubscription(Subscription &sub) for (const auto &[bundle, expireTime] : sub.expiresTime) { MetaDataManager::GetInstance().DelMeta(sub.GetRelationKey(bundle), true); } + sub.id.clear(); + sub.expiresTime.clear(); } void CloudServiceImpl::Execute(Task task) @@ -1229,6 +1284,32 @@ CloudServiceImpl::HapInfo CloudServiceImpl::GetHapInfo(uint32_t tokenId) return { tokenInfo.userID, tokenInfo.instIndex, tokenInfo.bundleName }; } +std::string CloudServiceImpl::GetDfxFaultType(CloudSyncScene scene) +{ + switch (scene) { + case CloudSyncScene::ENABLE_CLOUD: + return FT_ENABLE_CLOUD; + case CloudSyncScene::DISABLE_CLOUD: + return FT_DISABLE_CLOUD; + case CloudSyncScene::SWITCH_ON: + return FT_SWITCH_ON; + case CloudSyncScene::SWITCH_OFF: + return FT_SWITCH_OFF; + case CloudSyncScene::QUERY_SYNC_INFO: + return FT_QUERY_INFO; + case CloudSyncScene::USER_CHANGE: + return FT_USER_CHANGE; + case CloudSyncScene::USER_UNLOCK: + return FT_USER_UNLOCK; + case CloudSyncScene::NETWORK_RECOVERY: + return FT_NETWORK_RECOVERY; + case CloudSyncScene::SERVICE_INIT: + return FT_SERVICE_INIT; + default: + return FT_SYNC_TASK; + } +} + int32_t CloudServiceImpl::Share(const std::string &sharingRes, const Participants &participants, Results &results) { XCollie xcollie(__FUNCTION__, HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_RECOVERY); @@ -1450,7 +1531,7 @@ void CloudServiceImpl::InitSubTask(const Subscription &sub, uint64_t minInterval } return; } - subTask_ = executor->Schedule(delay, GenSubTask(GenTask(0, sub.userId), sub.userId)); + subTask_ = executor->Schedule(delay, GenSubTask(GenTask(0, sub.userId, CloudSyncScene::SERVICE_INIT), sub.userId)); expireTime_ = expire > now ? expire : now; } @@ -1491,4 +1572,10 @@ int32_t CloudServiceImpl::SaveNetworkStrategy(const std::vector staticActs_; }; static Factory factory_; + enum class CloudSyncScene { + ENABLE_CLOUD = 0, + DISABLE_CLOUD = 1, + SWITCH_ON = 2, + SWITCH_OFF = 3, + QUERY_SYNC_INFO = 4, + USER_CHANGE = 5, + USER_UNLOCK = 6, + NETWORK_RECOVERY = 7, + SERVICE_INIT = 8, + ACCOUNT_STOP = 9, + }; using CloudInfo = DistributedData::CloudInfo; using SchemaMeta = DistributedData::SchemaMeta; using Event = DistributedData::Event; using CloudEvent = DistributedData::CloudEvent; using Subscription = DistributedData::Subscription; - using Handle = bool (CloudServiceImpl::*)(int32_t); + using Handle = bool (CloudServiceImpl::*)(int32_t, CloudSyncScene); using Handles = std::deque; using Task = ExecutorPool::Task; using TaskId = ExecutorPool::TaskId; @@ -109,6 +125,7 @@ private: static std::map ConvertAction(const std::map &actions); static HapInfo GetHapInfo(uint32_t tokenId); + static std::string GetDfxFaultType(CloudSyncScene scene); static constexpr uint64_t INVALID_SUB_TIME = 0; static constexpr int32_t RETRY_TIMES = 3; @@ -119,12 +136,12 @@ private: static constexpr int32_t TIME_BEFORE_SUB = 12 * 60 * 60 * 1000; // 12hours, ms static constexpr int32_t SUBSCRIPTION_INTERVAL = 60 * 60 * 1000; // 1hours - bool UpdateCloudInfo(int32_t user); - bool UpdateSchema(int32_t user); - bool DoSubscribe(int32_t user); - bool ReleaseUserInfo(int32_t user); - bool DoCloudSync(int32_t user); - bool StopCloudSync(int32_t user); + bool UpdateCloudInfo(int32_t user, CloudSyncScene scene); + bool UpdateSchema(int32_t user, CloudSyncScene scene); + bool DoSubscribe(int32_t user, CloudSyncScene scene); + bool ReleaseUserInfo(int32_t user, CloudSyncScene scene); + bool DoCloudSync(int32_t user, CloudSyncScene scene); + bool StopCloudSync(int32_t user, CloudSyncScene scene); static std::pair GetCloudInfo(int32_t userId); static std::pair GetCloudInfoFromMeta(int32_t userId); @@ -143,7 +160,7 @@ private: void GetSchema(const Event &event); void CloudShare(const Event &event); - Task GenTask(int32_t retry, int32_t user, Handles handles = { WORK_SUB }); + Task GenTask(int32_t retry, int32_t user, CloudSyncScene scene, Handles handles = { WORK_SUB }); Task GenSubTask(Task task, int32_t user); void InitSubTask(const Subscription &sub, uint64_t minInterval = 0); void Execute(Task task); @@ -163,6 +180,8 @@ private: using SaveStrategy = int32_t (*)(const std::vector &values, const HapInfo &hapInfo); static const SaveStrategy STRATEGY_SAVERS[Strategy::STRATEGY_BUTT]; static int32_t SaveNetworkStrategy(const std::vector &values, const HapInfo &hapInfo); + void Report(const std::string &faultType, DistributedDataDfx::Fault errCode, const std::string &bundleName, + const std::string &appendix); std::shared_ptr executor_; SyncManager syncManager_; 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 ef5c357e711f63778537a15a1744aacf50294072..ace668b55e88bc646a91010ff1327d23a697f28a 100644 --- a/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_stub.cpp +++ b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_stub.cpp @@ -19,7 +19,7 @@ #include "cloud_types_util.h" #include "ipc_skeleton.h" #include "log_print.h" -#include "permission/permission_validator.h" +#include "permission_validator.h" #include "rdb_types.h" #include "tokenid_kit.h" #include "utils/anonymous.h" diff --git a/datamgr_service/services/distributeddataservice/service/cloud/sync_manager.cpp b/datamgr_service/services/distributeddataservice/service/cloud/sync_manager.cpp index b666a88fc1ee472eed4d2f291df5922aa6c16d75..e914ce6afbfc85590b4cb262820adafe929708ee 100644 --- a/datamgr_service/services/distributeddataservice/service/cloud/sync_manager.cpp +++ b/datamgr_service/services/distributeddataservice/service/cloud/sync_manager.cpp @@ -27,10 +27,14 @@ #include "cloud/sync_event.h" #include "cloud_value_util.h" #include "device_manager_adapter.h" -#include "dfx/radar_reporter.h" +#include "dfx_types.h" +#include "radar_reporter.h" #include "eventcenter/event_center.h" #include "log_print.h" #include "metadata/meta_data_manager.h" +#include "network_adapter.h" +#include "reporter.h" +#include "screen/screen_manager.h" #include "sync_strategies/network_sync_strategy.h" #include "user_delegate.h" #include "utils/anonymous.h" @@ -40,11 +44,13 @@ using namespace DistributedDataDfx; using namespace DistributedKv; using namespace SharingUtil; using namespace std::chrono; -using Account = OHOS::DistributedKv::AccountDelegate; +using Account = OHOS::DistributedData::AccountDelegate; using DmAdapter = OHOS::DistributedData::DeviceManagerAdapter; using Defer = EventCenter::Defer; std::atomic SyncManager::genId_ = 0; constexpr int32_t SYSTEM_USER_ID = 0; +static constexpr const char *FT_GET_STORE = "GET_STORE"; +static constexpr const char *FT_CALLBACK = "CALLBACK"; SyncManager::SyncInfo::SyncInfo( int32_t user, const std::string &bundleName, const Store &store, const Tables &tables, int32_t triggerMode) : user_(user), bundleName_(bundleName), triggerMode_(triggerMode) @@ -179,7 +185,7 @@ std::function SyncManager::GetLockChangeHandler() storeInfo.bundleName.c_str(), Anonymous::Change(storeInfo.storeName).c_str(), storeInfo.user); return; } - auto store = GetStore(meta, storeInfo.user); + auto [status, store] = GetStore(meta, storeInfo.user); if (store == nullptr) { ZLOGE("failed to get store. bundleName: %{public}s, storeName: %{public}s, user: %{public}d.", storeInfo.bundleName.c_str(), Anonymous::Change(storeInfo.storeName).c_str(), storeInfo.user); @@ -272,7 +278,7 @@ GeneralError SyncManager::IsValid(SyncInfo &info, CloudInfo &cloud) ZLOGD("enable:%{public}d, bundleName:%{public}s", cloud.enableCloud, info.bundleName_.c_str()); return E_CLOUD_DISABLED; } - if (!DmAdapter::GetInstance().IsNetworkAvailable()) { + if (!NetworkAdapter::GetInstance().IsNetworkAvailable()) { info.SetError(E_NETWORK_ERROR); ZLOGD("network unavailable"); return E_NETWORK_ERROR; @@ -392,40 +398,42 @@ std::function SyncManager::GetSyncHandler(Retryer retryer) GenDetails details; auto &detail = details[SyncInfo::DEFAULT_ID]; detail.progress = GenProgress::SYNC_FINISH; - auto [result, meta] = GetMetaData(storeInfo); - if (!result) { + auto [hasMeta, meta] = GetMetaData(storeInfo); + if (!hasMeta) { return DoExceptionalCallback(async, details, storeInfo, prepareTraceId); } - auto store = GetStore(meta, storeInfo.user); + auto [code, store] = GetStore(meta, storeInfo.user); + if (code == E_SCREEN_LOCKED) { + AddCompensateSync(meta); + } if (store == nullptr) { ZLOGE("store null, storeId:%{public}s, prepareTraceId:%{public}s", meta.GetStoreAlias().c_str(), prepareTraceId.c_str()); return DoExceptionalCallback(async, details, storeInfo, prepareTraceId); } - ZLOGI("database:<%{public}d:%{public}s:%{public}s:%{public}s> sync start", storeInfo.user, - storeInfo.bundleName.c_str(), meta.GetStoreAlias().c_str(), prepareTraceId.c_str()); - RadarReporter::Report( - { storeInfo.bundleName.c_str(), CLOUD_SYNC, TRIGGER_SYNC, storeInfo.syncId, evt.GetTriggerMode() }, - "GetSyncHandler", BizState::BEGIN); + ZLOGI("database:<%{public}d:%{public}s:%{public}s:%{public}s> sync start, asyncDownloadAsset?[%{public}d]", + storeInfo.user, storeInfo.bundleName.c_str(), meta.GetStoreAlias().c_str(), prepareTraceId.c_str(), + meta.asyncDownloadAsset); + RadarReporter::Report({ storeInfo.bundleName.c_str(), CLOUD_SYNC, TRIGGER_SYNC, storeInfo.syncId, + evt.GetTriggerMode() }, "GetSyncHandler", BizState::BEGIN); Report({ user, storeInfo.bundleName, prepareTraceId, SyncStage::START, E_OK }); SyncParam syncParam = { evt.GetMode(), evt.GetWait(), evt.IsCompensation(), MODE_DEFAULT, prepareTraceId }; + syncParam.asyncDownloadAsset = meta.asyncDownloadAsset; auto [status, dbCode] = store->Sync({ SyncInfo::DEFAULT_ID }, *(evt.GetQuery()), evt.AutoRetry() ? RetryCallback(storeInfo, retryer, evt.GetTriggerMode(), prepareTraceId, user) - : GetCallback(evt.GetAsyncDetail(), storeInfo, evt.GetTriggerMode(), prepareTraceId, user), - syncParam); + : GetCallback(async, storeInfo, evt.GetTriggerMode(), prepareTraceId, user), syncParam); if (status != E_OK) { if (async) { detail.code = status; async(std::move(details)); } UpdateFinishSyncInfo({ GetAccountId(storeInfo.user), storeInfo.bundleName, "" }, storeInfo.syncId, E_ERROR); - if (status == GeneralError::E_NOT_SUPPORT) { - return; + if (status != GeneralError::E_NOT_SUPPORT) { + auto code = dbCode == 0 ? GenStore::CLOUD_ERR_OFFSET + status : dbCode; + RadarReporter::Report({ storeInfo.bundleName.c_str(), CLOUD_SYNC, FINISH_SYNC, storeInfo.syncId, + evt.GetTriggerMode(), code }, "GetSyncHandler", BizState::END); + Report({ user, storeInfo.bundleName, prepareTraceId, SyncStage::END, code }); } - auto code = dbCode == 0 ? GenStore::CLOUD_ERR_OFFSET + status : dbCode; - RadarReporter::Report({ storeInfo.bundleName.c_str(), CLOUD_SYNC, FINISH_SYNC, storeInfo.syncId, - evt.GetTriggerMode(), false, code }, "GetSyncHandler", BizState::END); - Report({ user, storeInfo.bundleName, prepareTraceId, SyncStage::END, code }); } }; } @@ -447,6 +455,17 @@ std::function SyncManager::GetClientChangeHandler() }; } +void SyncManager::Report( + const std::string &faultType, const std::string &bundleName, int32_t errCode, const std::string &appendix) +{ + ArkDataFaultMsg msg = { .faultType = faultType, + .bundleName = bundleName, + .moduleName = ModuleName::CLOUD_SERVER, + .errorType = errCode + GenStore::CLOUD_ERR_OFFSET, + .appendixMsg = appendix }; + Reporter::GetInstance()->CloudSyncFault()->Report(msg); +} + SyncManager::Retryer SyncManager::GetRetryer(int32_t times, const SyncInfo &syncInfo, int32_t user) { if (times >= RETRY_TIMES) { @@ -457,10 +476,12 @@ SyncManager::Retryer SyncManager::GetRetryer(int32_t times, const SyncInfo &sync } info.SetError(code); RadarReporter::Report({ info.bundleName_.c_str(), CLOUD_SYNC, FINISH_SYNC, info.syncId_, info.triggerMode_, - false, dbCode }, + dbCode }, "GetRetryer", BizState::END); Report({ user, info.bundleName_, prepareTraceId, SyncStage::END, dbCode == GenStore::DB_ERR_OFFSET ? 0 : dbCode }); + Report(FT_CALLBACK, info.bundleName_, static_cast(Fault::CSF_GS_CLOUD_SYNC), + "code=" + std::to_string(code) + ",dbCode=" + std::to_string(static_cast(dbCode))); return true; }; } @@ -472,10 +493,12 @@ SyncManager::Retryer SyncManager::GetRetryer(int32_t times, const SyncInfo &sync if (code == E_NO_SPACE_FOR_ASSET || code == E_RECODE_LIMIT_EXCEEDED) { info.SetError(code); RadarReporter::Report({ info.bundleName_.c_str(), CLOUD_SYNC, FINISH_SYNC, info.syncId_, info.triggerMode_, - false, dbCode }, + dbCode }, "GetRetryer", BizState::END); Report({ user, info.bundleName_, prepareTraceId, SyncStage::END, dbCode == GenStore::DB_ERR_OFFSET ? 0 : dbCode }); + Report(FT_CALLBACK, info.bundleName_, static_cast(Fault::CSF_GS_CLOUD_SYNC), + "code=" + std::to_string(code) + ",dbCode=" + std::to_string(static_cast(dbCode))); return true; } @@ -536,6 +559,8 @@ std::map SyncManager::GetBindInfos(const Store if (cloudDB == nullptr) { ZLOGE("failed, no cloud DB <%{public}d:0x%{public}x %{public}s<->%{public}s>", meta.tokenId, activeUser, Anonymous::Change(schemaDatabase.name).c_str(), Anonymous::Change(schemaDatabase.alias).c_str()); + Report(FT_GET_STORE, meta.bundleName, static_cast(Fault::CSF_CONNECT_CLOUD_DB), + "ConnectCloudDB failed, database=" + schemaDatabase.name); return {}; } if (meta.storeType >= StoreMetaData::StoreType::STORE_KV_BEGIN && @@ -547,6 +572,8 @@ std::map SyncManager::GetBindInfos(const Store if (assetLoader == nullptr) { ZLOGE("failed, no cloud DB <%{public}d:0x%{public}x %{public}s<->%{public}s>", meta.tokenId, activeUser, Anonymous::Change(schemaDatabase.name).c_str(), Anonymous::Change(schemaDatabase.alias).c_str()); + Report(FT_GET_STORE, meta.bundleName, static_cast(Fault::CSF_CONNECT_CLOUD_ASSET_LOADER), + "ConnectAssetLoader failed, database=" + schemaDatabase.name); return {}; } bindInfos.insert_or_assign(activeUser, GeneralStore::BindInfo{ std::move(cloudDB), std::move(assetLoader) }); @@ -554,21 +581,21 @@ std::map SyncManager::GetBindInfos(const Store return bindInfos; } -AutoCache::Store SyncManager::GetStore(const StoreMetaData &meta, int32_t user, bool mustBind) +std::pair SyncManager::GetStore(const StoreMetaData &meta, int32_t user, bool mustBind) { if (user != 0 && !Account::GetInstance()->IsVerified(user)) { ZLOGW("user:%{public}d is locked!", user); - return nullptr; + return { E_USER_UNLOCK, nullptr }; } - auto instance = CloudServer::GetInstance(); - if (instance == nullptr) { + if (CloudServer::GetInstance() == nullptr) { ZLOGD("not support cloud sync"); - return nullptr; + return { E_NOT_SUPPORT, nullptr }; } - auto store = AutoCache::GetInstance().GetStore(meta, {}); - if (store == nullptr) { - ZLOGE("store null, storeId:%{public}s", meta.GetStoreAlias().c_str()); - return nullptr; + auto [status, store] = AutoCache::GetInstance().GetDBStore(meta, {}); + if (status == E_SCREEN_LOCKED) { + return { E_SCREEN_LOCKED, nullptr }; + } else if (store == nullptr) { + return { E_ERROR, nullptr }; } CloudInfo info; info.user = user; @@ -581,7 +608,7 @@ AutoCache::Store SyncManager::GetStore(const StoreMetaData &meta, int32_t user, } if (info.user == SYSTEM_USER_ID) { ZLOGE("invalid cloud users, bundleName:%{public}s", meta.bundleName.c_str()); - return nullptr; + return { E_ERROR, nullptr }; } if (!store->IsBound(info.user)) { SchemaMeta schemaMeta; @@ -589,12 +616,12 @@ AutoCache::Store SyncManager::GetStore(const StoreMetaData &meta, int32_t user, if (!MetaDataManager::GetInstance().LoadMeta(schemaKey, schemaMeta, true)) { ZLOGE("failed, no schema bundleName:%{public}s, storeId:%{public}s", meta.bundleName.c_str(), meta.GetStoreAlias().c_str()); - return nullptr; + return { E_ERROR, nullptr }; } auto dbMeta = schemaMeta.GetDataBase(meta.storeId); std::map bindInfos = GetBindInfos(meta, users, dbMeta); if (mustBind && bindInfos.size() != users.size()) { - return nullptr; + return { E_ERROR, nullptr }; } GeneralStore::CloudConfig config; if (MetaDataManager::GetInstance().LoadMeta(info.GetKey(), info, true)) { @@ -603,7 +630,7 @@ AutoCache::Store SyncManager::GetStore(const StoreMetaData &meta, int32_t user, } store->Bind(dbMeta, bindInfos, config); } - return store; + return { E_OK, store }; } void SyncManager::Report(const ReportParam &reportParam) @@ -639,7 +666,7 @@ SyncManager::TraceIds SyncManager::GetPrepareTraceId(const SyncInfo &info, const bool SyncManager::NeedGetCloudInfo(CloudInfo &cloud) { return (!MetaDataManager::GetInstance().LoadMeta(cloud.GetKey(), cloud, true) || !cloud.enableCloud) && - DmAdapter::GetInstance().IsNetworkAvailable() && Account::GetInstance()->IsLoginAccount(); + NetworkAdapter::GetInstance().IsNetworkAvailable() && Account::GetInstance()->IsLoginAccount(); } std::vector> SyncManager::GetCloudSyncInfo(const SyncInfo &info, CloudInfo &cloud) @@ -651,7 +678,8 @@ std::vector> SyncManager::GetCloudSyncInfo(const if (instance == nullptr) { return cloudSyncInfos; } - cloud = instance->GetServerInfo(cloud.user, false); + int32_t errCode = SUCCESS; + std::tie(errCode, cloud) = instance->GetServerInfo(cloud.user, false); if (!cloud.IsValid()) { ZLOGE("cloud is empty, user: %{public}d", cloud.user); return cloudSyncInfos; @@ -763,10 +791,13 @@ std::function SyncManager::GetCallback(const Gen int32_t dbCode = (result.begin()->second.dbCode == GenStore::DB_ERR_OFFSET) ? 0 : result.begin()->second.dbCode; RadarReporter::Report({ storeInfo.bundleName.c_str(), CLOUD_SYNC, FINISH_SYNC, storeInfo.syncId, triggerMode, - result.begin()->second.changeCount, dbCode }, + dbCode, result.begin()->second.changeCount }, "GetCallback", BizState::END); Report({ user, storeInfo.bundleName, prepareTraceId, SyncStage::END, dbCode }); - + if (dbCode != 0) { + Report(FT_CALLBACK, storeInfo.bundleName, static_cast(Fault::CSF_GS_CLOUD_SYNC), + "callback failed, dbCode=" + std::to_string(dbCode)); + } auto id = GetAccountId(storeInfo.user); if (id.empty()) { ZLOGD("account id is empty"); @@ -854,7 +885,7 @@ std::function SyncManager::Retr UpdateFinishSyncInfo(queryKey, storeInfo.syncId, code); if (code == E_OK) { RadarReporter::Report({ storeInfo.bundleName.c_str(), CLOUD_SYNC, FINISH_SYNC, storeInfo.syncId, - triggerMode, details.begin()->second.changeCount }, + triggerMode, code, details.begin()->second.changeCount }, "RetryCallback", BizState::END); Report({ user, storeInfo.bundleName, prepareTraceId, SyncStage::END, dbCode == GenStore::DB_ERR_OFFSET ? 0 : dbCode }); @@ -895,4 +926,43 @@ std::pair SyncManager::GetMetaData(const StoreInfo &storeIn } return { true, meta }; } + +void SyncManager::OnScreenUnlocked(int32_t user) +{ + std::vector infos; + compensateSyncInfos_.ComputeIfPresent(user, + [&infos](auto &userId, const std::map> &apps) { + for (const auto &[bundle, storeIds] : apps) { + std::vector stores(storeIds.begin(), storeIds.end()); + infos.push_back(SyncInfo(userId, bundle, stores)); + } + return false; + }); + compensateSyncInfos_.ComputeIfPresent(SYSTEM_USER_ID, + [&infos](auto &userId, const std::map> &apps) { + for (const auto &[bundle, storeIds] : apps) { + std::vector stores(storeIds.begin(), storeIds.end()); + infos.push_back(SyncInfo(userId, bundle, stores)); + } + return false; + }); + for (auto &info : infos) { + info.SetTriggerMode(MODE_UNLOCK); + DoCloudSync(info); + } +} + +void SyncManager::CleanCompensateSync(int32_t userId) +{ + compensateSyncInfos_.Erase(userId); +} + +void SyncManager::AddCompensateSync(const StoreMetaData &meta) +{ + compensateSyncInfos_.Compute(std::stoi(meta.user), + [&meta](auto &, std::map> &apps) { + apps[meta.bundleName].insert(meta.storeId); + return true; + }); +} } // namespace OHOS::CloudData \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/cloud/sync_manager.h b/datamgr_service/services/distributeddataservice/service/cloud/sync_manager.h index 1c7eb993fc08df138e6ff46ae62305454429978a..e250bd6ccca1f1fee698907aabd445c6ff7f7cdb 100644 --- a/datamgr_service/services/distributeddataservice/service/cloud/sync_manager.h +++ b/datamgr_service/services/distributeddataservice/service/cloud/sync_manager.h @@ -42,7 +42,7 @@ public: using TraceIds = std::map; using SyncStage = DistributedData::SyncStage; using ReportParam = DistributedData::ReportParam; - static AutoCache::Store GetStore(const StoreMetaData &meta, int32_t user, bool mustBind = true); + static std::pair GetStore(const StoreMetaData &meta, int32_t user, bool mustBind = true); class SyncInfo final { public: using Store = std::string; @@ -96,6 +96,8 @@ public: int32_t StopCloudSync(int32_t user = 0); int32_t QueryLastSyncInfo(const std::vector &queryKeys, QueryLastResults &results); void Report(const ReportParam &reportParam); + void OnScreenUnlocked(int32_t user); + void CleanCompensateSync(int32_t userId); private: using Event = DistributedData::Event; @@ -156,6 +158,9 @@ private: void BatchReport(int32_t userId, const TraceIds &traceIds, SyncStage syncStage, int32_t errCode); TraceIds GetPrepareTraceId(const SyncInfo &info, const CloudInfo &cloud); std::pair GetMetaData(const StoreInfo &storeInfo); + void AddCompensateSync(const StoreMetaData &meta); + static void Report( + const std::string &faultType, const std::string &bundleName, int32_t errCode, const std::string &appendix); static std::atomic genId_; std::shared_ptr executor_; @@ -164,6 +169,7 @@ private: std::shared_ptr syncStrategy_; ConcurrentMap> lastSyncInfos_; std::set kvApps_; + ConcurrentMap>> compensateSyncInfos_; }; } // namespace OHOS::CloudData #endif // OHOS_DISTRIBUTED_DATA_SERVICES_CLOUD_SYNC_MANAGER_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/cloud/sync_strategies/network_sync_strategy.cpp b/datamgr_service/services/distributeddataservice/service/cloud/sync_strategies/network_sync_strategy.cpp index cb8a86f17b992066742701d62e38b31124578bf8..9af8d76959f693a48fad41cb9741ea5ed81d1966 100644 --- a/datamgr_service/services/distributeddataservice/service/cloud/sync_strategies/network_sync_strategy.cpp +++ b/datamgr_service/services/distributeddataservice/service/cloud/sync_strategies/network_sync_strategy.cpp @@ -18,6 +18,7 @@ #include "network_sync_strategy.h" #include "device_manager_adapter.h" +#include "network_adapter.h" #include "error/general_error.h" #include "log_print.h" #include "metadata/meta_data_manager.h" @@ -52,10 +53,7 @@ NetworkSyncStrategy::~NetworkSyncStrategy() int32_t NetworkSyncStrategy::CheckSyncAction(const StoreInfo &storeInfo) { - if (storeInfo.user == StrategyInfo::ROOT_USER) { - return next_ ? next_->CheckSyncAction(storeInfo) : E_OK; - } - if (!DeviceManagerAdapter::GetInstance().IsNetworkAvailable()) { + if (!NetworkAdapter::GetInstance().IsNetworkAvailable()) { return E_NETWORK_ERROR; } if (storeInfo.user != user_) { @@ -105,15 +103,15 @@ std::string NetworkSyncStrategy::GetKey(int32_t user, const std::string &bundleN bool NetworkSyncStrategy::Check(uint32_t strategy) { - auto networkType = DeviceManagerAdapter::GetInstance().GetNetworkType(); - if (networkType == DeviceManagerAdapter::NONE) { - networkType = DeviceManagerAdapter::GetInstance().GetNetworkType(true); + auto networkType = NetworkAdapter::GetInstance().GetNetworkType(); + if (networkType == NetworkAdapter::NONE) { + networkType = NetworkAdapter::GetInstance().GetNetworkType(true); } switch (networkType) { - case DeviceManagerAdapter::WIFI: - case DeviceManagerAdapter::ETHERNET: + case NetworkAdapter::WIFI: + case NetworkAdapter::ETHERNET: return (strategy & WIFI) == WIFI; - case DeviceManagerAdapter::CELLULAR: + case NetworkAdapter::CELLULAR: return (strategy & CELLULAR) == CELLULAR; default: ZLOGD("verification failed! strategy:%{public}d, networkType:%{public}d", strategy, networkType); @@ -131,4 +129,4 @@ NetworkSyncStrategy::StrategyInfo NetworkSyncStrategy::GetStrategy(int32_t user, strategies_.Insert(info.bundleName, info); return info; } -} // namespace OHOS::CloudData \ No newline at end of file +} \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/cloud/sync_strategies/network_sync_strategy.h b/datamgr_service/services/distributeddataservice/service/cloud/sync_strategies/network_sync_strategy.h index af2680a194b31cb6d184cb36bd8e9d5a66d258d1..2c32abc0b3feb22722d7f0fe2011c35e6aa75de6 100644 --- a/datamgr_service/services/distributeddataservice/service/cloud/sync_strategies/network_sync_strategy.h +++ b/datamgr_service/services/distributeddataservice/service/cloud/sync_strategies/network_sync_strategy.h @@ -36,7 +36,6 @@ public: bool Unmarshal(const json &node) override; std::string GetKey(); static constexpr int32_t INVALID_USER = -1; - static constexpr int32_t ROOT_USER = 0; static constexpr const char *PREFIX = "NETWORK_SYNC_STRATEGY"; }; NetworkSyncStrategy(); diff --git a/datamgr_service/services/distributeddataservice/service/common/BUILD.gn b/datamgr_service/services/distributeddataservice/service/common/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..3a8e1990d8c5f57740832f1fafd0079c03aff348 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/common/BUILD.gn @@ -0,0 +1,54 @@ +# Copyright (c) 2024 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. +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +ohos_source_set("distributeddata_common") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + boundary_sanitize = true + ubsan = true + } + sources = [ + "common_types_utils.cpp", + "value_proxy.cpp", + "xcollie.cpp", + ] + + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] + + include_dirs = [ "include" ] + cflags = [ + "-Werror", + "-Wno-multichar", + "-Wno-c99-designator", + "-D_LIBCPP_HAS_COND_CLOCKWAIT", + "-Oz", + ] + + deps = [ "${data_service_path}/framework:distributeddatasvcfwk" ] + external_deps = [ + "hicollie:libhicollie", + "hilog:libhilog", + "kv_store:distributeddb", + "relational_store:native_rdb", + ] + subsystem_name = "distributeddatamgr" + part_name = "datamgr_service" +} diff --git a/datamgr_service/services/distributeddataservice/service/common/value_proxy.cpp b/datamgr_service/services/distributeddataservice/service/common/value_proxy.cpp index a650c66f416d4935b08ac05fa0600900a142399b..9809185d6226f70e63edd68bb9efd14faa1f8078 100644 --- a/datamgr_service/services/distributeddataservice/service/common/value_proxy.cpp +++ b/datamgr_service/services/distributeddataservice/service/common/value_proxy.cpp @@ -332,6 +332,7 @@ uint32_t ValueProxy::Asset::ConvertToDBStatus(const uint32_t &status) lowStatus = static_cast(DistributedDB::AssetStatus::NORMAL); break; case DistributedData::Asset::STATUS_ABNORMAL: + case DistributedData::Asset::STATUS_SKIP_ASSET : lowStatus = static_cast(DistributedDB::AssetStatus::ABNORMAL); break; case DistributedData::Asset::STATUS_INSERT: diff --git a/datamgr_service/services/distributeddataservice/service/common/xcollie.cpp b/datamgr_service/services/distributeddataservice/service/common/xcollie.cpp index 2bf5bec702e76e8f31d92f59d33f2ef19e8bc5b3..60715885c91d59b7542fdcc93f0cbba6194ae19d 100644 --- a/datamgr_service/services/distributeddataservice/service/common/xcollie.cpp +++ b/datamgr_service/services/distributeddataservice/service/common/xcollie.cpp @@ -15,10 +15,17 @@ #include "xcollie.h" namespace OHOS::DistributedData { -XCollie::XCollie(const std::string &tag, uint32_t flag, uint32_t timeoutSeconds, - std::function func, void *arg) +XCollie::XCollie(const std::string &tag, uint32_t flag, uint32_t timeoutSeconds, std::function func, + void *arg) { - id_ = HiviewDFX::XCollie::GetInstance().SetTimer(tag, timeoutSeconds, func, arg, flag); + uint32_t xCollieFlag = 0; + if ((flag & XCOLLIE_LOG) == XCOLLIE_LOG) { + xCollieFlag |= HiviewDFX::XCOLLIE_FLAG_LOG; + } + if ((flag & XCOLLIE_RECOVERY) == XCOLLIE_RECOVERY) { + xCollieFlag |= HiviewDFX::XCOLLIE_FLAG_RECOVERY; + } + id_ = HiviewDFX::XCollie::GetInstance().SetTimer(tag, timeoutSeconds, func, arg, xCollieFlag); } XCollie::~XCollie() { diff --git a/datamgr_service/services/distributeddataservice/service/common/xcollie.h b/datamgr_service/services/distributeddataservice/service/common/xcollie.h index aa7732679a3990e1e5bd7b2e3ae3c5402c16ede1..68f8436cef7a57a3fa2074e4472d65c75fe1b4b2 100644 --- a/datamgr_service/services/distributeddataservice/service/common/xcollie.h +++ b/datamgr_service/services/distributeddataservice/service/common/xcollie.h @@ -22,6 +22,10 @@ namespace OHOS::DistributedData { class XCollie { public: + enum FLAG { + XCOLLIE_LOG = 0x1, + XCOLLIE_RECOVERY = 0x2 + }; XCollie(const std::string &tag, uint32_t flag, uint32_t timeoutSeconds = RESTART_TIME_THRESHOLD, std::function func = nullptr, void *arg = nullptr); ~XCollie(); diff --git a/datamgr_service/services/distributeddataservice/service/config/BUILD.gn b/datamgr_service/services/distributeddataservice/service/config/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..a2ea71cf44720ce97423cf1140f3de53a08ea313 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/config/BUILD.gn @@ -0,0 +1,64 @@ +# Copyright (c) 2024 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. +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +ohos_source_set("distributeddata_config") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + boundary_sanitize = true + ubsan = true + } + sources = [ + "src/config_factory.cpp", + "src/model/app_id_mapping_config.cpp", + "src/model/backup_config.cpp", + "src/model/checker_config.cpp", + "src/model/cloud_config.cpp", + "src/model/component_config.cpp", + "src/model/directory_config.cpp", + "src/model/global_config.cpp", + "src/model/network_config.cpp", + "src/model/protocol_config.cpp", + "src/model/thread_config.cpp", + ] + + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] + + include_dirs = [ + "include", + "include/model", + ] + + cflags = [ + "-Werror", + "-Wno-multichar", + "-Wno-c99-designator", + "-D_LIBCPP_HAS_COND_CLOCKWAIT", + "-Oz", + ] + + deps = [ "${data_service_path}/framework:distributeddatasvcfwk" ] + external_deps = [ + "hilog:libhilog", + "json:nlohmann_json_static", + ] + subsystem_name = "distributeddatamgr" + part_name = "datamgr_service" +} diff --git a/datamgr_service/services/distributeddataservice/service/config/include/config_factory.h b/datamgr_service/services/distributeddataservice/service/config/include/config_factory.h index 6ebb1e0db025495eb261667e8bbb23d845dc8466..727dcec2137e684d4b972d1c141580e2bc10eefc 100644 --- a/datamgr_service/services/distributeddataservice/service/config/include/config_factory.h +++ b/datamgr_service/services/distributeddataservice/service/config/include/config_factory.h @@ -32,6 +32,7 @@ public: API_EXPORT BackupConfig *GetBackupConfig(); API_EXPORT CloudConfig *GetCloudConfig(); API_EXPORT std::vector *GetAppIdMappingConfig(); + API_EXPORT ThreadConfig *GetThreadConfig(); private: static constexpr const char *CONF_PATH = "/system/etc/distributeddata/conf"; ConfigFactory(); diff --git a/datamgr_service/services/distributeddataservice/service/config/include/model/global_config.h b/datamgr_service/services/distributeddataservice/service/config/include/model/global_config.h index 0d974d5bec9b6930904aaa3bbd1a2f962593fa5c..8bb7b9c66187a6529fcf851e6f71f90f32c0dc97 100644 --- a/datamgr_service/services/distributeddataservice/service/config/include/model/global_config.h +++ b/datamgr_service/services/distributeddataservice/service/config/include/model/global_config.h @@ -15,14 +15,15 @@ #ifndef OHOS_DISTRIBUTED_DATA_SERVICES_CONFIG_MODEL_GLOBAL_CONFIG_H #define OHOS_DISTRIBUTED_DATA_SERVICES_CONFIG_MODEL_GLOBAL_CONFIG_H -#include "serializable/serializable.h" +#include "model/app_id_mapping_config.h" +#include "model/backup_config.h" #include "model/checker_config.h" #include "model/cloud_config.h" #include "model/component_config.h" -#include "model/network_config.h" #include "model/directory_config.h" -#include "model/backup_config.h" -#include "model/app_id_mapping_config.h" +#include "model/network_config.h" +#include "model/thread_config.h" +#include "serializable/serializable.h" namespace OHOS { namespace DistributedData { class GlobalConfig final : public Serializable { @@ -38,6 +39,7 @@ public: BackupConfig *backup = nullptr; CloudConfig *cloud = nullptr; std::vector *appIdMapping = nullptr; + ThreadConfig *thread = nullptr; ~GlobalConfig(); bool Marshal(json &node) const override; bool Unmarshal(const json &node) override; diff --git a/datamgr_service/services/distributeddataservice/service/config/include/model/thread_config.h b/datamgr_service/services/distributeddataservice/service/config/include/model/thread_config.h new file mode 100644 index 0000000000000000000000000000000000000000..741f7e96f64726a656ac83e4b3b2fd9cef1dff1b --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/config/include/model/thread_config.h @@ -0,0 +1,31 @@ +/* +* Copyright (c) 2025 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_SERVICES_CONFIG_MODEL_THREAD_CONFIG_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_CONFIG_MODEL_THREAD_CONFIG_H + +#include "serializable/serializable.h" +namespace OHOS { +namespace DistributedData { +class ThreadConfig final : public Serializable { +public: + bool Marshal(json &node) const override; + bool Unmarshal(const json &node) override; + uint32_t minThreadNum; + uint32_t maxThreadNum; + uint32_t ipcThreadNum; +}; +} // namespace DistributedData +} // namespace OHOS +#endif //OHOS_DISTRIBUTED_DATA_SERVICES_CONFIG_MODEL_THREAD_CONFIG_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/config/src/config_factory.cpp b/datamgr_service/services/distributeddataservice/service/config/src/config_factory.cpp index 996f6e585bde9141a1a0e956860a1cb16ad0d99a..3b05fce80631bf9ee5ea0b5bad1b6a56172cf3c8 100644 --- a/datamgr_service/services/distributeddataservice/service/config/src/config_factory.cpp +++ b/datamgr_service/services/distributeddataservice/service/config/src/config_factory.cpp @@ -16,8 +16,7 @@ #include namespace OHOS { namespace DistributedData { -ConfigFactory::ConfigFactory() - : file_(std::string(CONF_PATH) + "/config.json") +ConfigFactory::ConfigFactory() : file_(std::string(CONF_PATH) + "/config.json") { } @@ -87,5 +86,10 @@ std::vector *ConfigFactory::GetAppIdMappingConfig() { return config_.appIdMapping; } + +ThreadConfig *ConfigFactory::GetThreadConfig() +{ + return config_.thread; +} } // namespace DistributedData -} // namespace OHOS +} // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/config/src/model/global_config.cpp b/datamgr_service/services/distributeddataservice/service/config/src/model/global_config.cpp index d4ee79710b9cedcc9f8581b168b2d3301693c135..e64b012260e566a811e6883f32ab5f12e90bce1b 100644 --- a/datamgr_service/services/distributeddataservice/service/config/src/model/global_config.cpp +++ b/datamgr_service/services/distributeddataservice/service/config/src/model/global_config.cpp @@ -29,6 +29,7 @@ bool GlobalConfig::Marshal(json &node) const SetValue(node[GET_NAME(backup)], backup); SetValue(node[GET_NAME(cloud)], cloud); SetValue(node[GET_NAME(appIdMapping)], appIdMapping); + SetValue(node[GET_NAME(thread)], thread); return true; } @@ -45,6 +46,7 @@ bool GlobalConfig::Unmarshal(const json &node) GetValue(node, GET_NAME(backup), backup); GetValue(node, GET_NAME(cloud), cloud); GetValue(node, GET_NAME(appIdMapping), appIdMapping); + GetValue(node, GET_NAME(thread), thread); return true; } @@ -57,6 +59,7 @@ GlobalConfig::~GlobalConfig() delete backup; delete cloud; delete appIdMapping; + delete thread; } } // namespace DistributedData -} // namespace OHOS +} // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/config/src/model/thread_config.cpp b/datamgr_service/services/distributeddataservice/service/config/src/model/thread_config.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f3146ab49c0f4f7c339a42e6687368824ea4a209 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/config/src/model/thread_config.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 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 "model/thread_config.h" +namespace OHOS { +namespace DistributedData { +bool ThreadConfig::Marshal(json &node) const +{ + SetValue(node[GET_NAME(minThreadNum)], minThreadNum); + SetValue(node[GET_NAME(maxThreadNum)], maxThreadNum); + SetValue(node[GET_NAME(ipcThreadNum)], ipcThreadNum); + return true; +} + +bool ThreadConfig::Unmarshal(const json &node) +{ + GetValue(node, GET_NAME(minThreadNum), minThreadNum); + GetValue(node, GET_NAME(maxThreadNum), maxThreadNum); + GetValue(node, GET_NAME(ipcThreadNum), ipcThreadNum); + return true; +} +} // namespace DistributedData +} // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/crypto/BUILD.gn b/datamgr_service/services/distributeddataservice/service/crypto/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..2b8003be8137c4bd19b0cd10f74b2c36137b1033 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/crypto/BUILD.gn @@ -0,0 +1,56 @@ +# Copyright (c) 2024 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. +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +config("crypto_public_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +ohos_source_set("distributeddata_crypto") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + boundary_sanitize = true + ubsan = true + } + sources = [ "src/crypto_manager.cpp" ] + + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] + + include_dirs = [ "include" ] + + cflags = [ + "-Werror", + "-Wno-multichar", + "-Wno-c99-designator", + "-D_LIBCPP_HAS_COND_CLOCKWAIT", + "-Oz", + ] + configs = [ ":crypto_public_config" ] + public_configs = [ ":crypto_public_config" ] + deps = [ "${data_service_path}/framework:distributeddatasvcfwk" ] + external_deps = [ + "dmsfwk:distributed_sdk", + "hilog:libhilog", + "huks:libhukssdk", + ] + subsystem_name = "distributeddatamgr" + part_name = "datamgr_service" +} diff --git a/datamgr_service/services/distributeddataservice/service/crypto/include/crypto_manager.h b/datamgr_service/services/distributeddataservice/service/crypto/include/crypto_manager.h index 0f8504763667ba0110def7bb37c94b82cef63245..36c4df71c9c4367d8754c2588f3239d393fe8553 100644 --- a/datamgr_service/services/distributeddataservice/service/crypto/include/crypto_manager.h +++ b/datamgr_service/services/distributeddataservice/service/crypto/include/crypto_manager.h @@ -14,18 +14,27 @@ */ #ifndef OHOS_DISTRIBUTED_DATA_SERVICES_SERVICE_CRYPTO_CRYPTO_MANAGER_H #define OHOS_DISTRIBUTED_DATA_SERVICES_SERVICE_CRYPTO_CRYPTO_MANAGER_H + +#include #include #include #include "visibility.h" namespace OHOS::DistributedData { +enum RootKeys { + ROOT_KEY, + CLONE_KEY, +}; class API_EXPORT CryptoManager { public: static CryptoManager &GetInstance(); int32_t GenerateRootKey(); int32_t CheckRootKey(); std::vector Encrypt(const std::vector &key); + std::vector EncryptCloneKey(const std::vector &key); bool Decrypt(std::vector &source, std::vector &key); + bool DecryptCloneKey(std::vector &source, std::vector &key); + bool ImportCloneKey(std::vector &key, std::vector &iv); enum ErrCode : int32_t { SUCCESS, @@ -34,15 +43,18 @@ public: }; private: static constexpr const char *ROOT_KEY_ALIAS = "distributed_db_root_key"; + static constexpr const char *BACKUP_KEY_ALIAS = "distributed_db_backup_key"; static constexpr const char *HKS_BLOB_TYPE_NONCE = "Z5s0Bo571KoqwIi6"; static constexpr const char *HKS_BLOB_TYPE_AAD = "distributeddata"; static constexpr int KEY_SIZE = 32; + static constexpr int AES_256_NONCE_SIZE = 32; static constexpr int HOURS_PER_YEAR = (24 * 365); + + std::vector EncryptInner(const std::vector &key, const RootKeys type); + bool DecryptInner(std::vector &source, std::vector &key, const RootKeys type); CryptoManager(); ~CryptoManager(); - std::vector vecRootKeyAlias_{}; - std::vector vecNonce_{}; - std::vector vecAad_{}; + std::mutex mutex_; }; } // namespace OHOS::DistributedData #endif // OHOS_DISTRIBUTED_DATA_SERVICES_SERVICE_CRYPTO_CRYPTO_MANAGER_H diff --git a/datamgr_service/services/distributeddataservice/service/crypto/src/crypto_manager.cpp b/datamgr_service/services/distributeddataservice/service/crypto/src/crypto_manager.cpp index 5cbaef47f4fbf2c0b8440f21c1dbb23047af8c3a..0f1369b73da446b5cbeee1bf970f1fcf7dcf5e44 100644 --- a/datamgr_service/services/distributeddataservice/service/crypto/src/crypto_manager.cpp +++ b/datamgr_service/services/distributeddataservice/service/crypto/src/crypto_manager.cpp @@ -22,9 +22,16 @@ #include "log_print.h" #include "securec.h" namespace OHOS::DistributedData { +std::vector backupNonce_{}; +std::vector vecAad_{}; +std::vector vecCloneKeyAlias_{}; +std::vector vecNonce_{}; +std::vector vecRootKeyAlias_{}; + CryptoManager::CryptoManager() { vecRootKeyAlias_ = std::vector(ROOT_KEY_ALIAS, ROOT_KEY_ALIAS + strlen(ROOT_KEY_ALIAS)); + vecCloneKeyAlias_ = std::vector(BACKUP_KEY_ALIAS, BACKUP_KEY_ALIAS + strlen(BACKUP_KEY_ALIAS)); vecNonce_ = std::vector(HKS_BLOB_TYPE_NONCE, HKS_BLOB_TYPE_NONCE + strlen(HKS_BLOB_TYPE_NONCE)); vecAad_ = std::vector(HKS_BLOB_TYPE_AAD, HKS_BLOB_TYPE_AAD + strlen(HKS_BLOB_TYPE_AAD)); } @@ -39,6 +46,50 @@ CryptoManager &CryptoManager::GetInstance() return instance; } +struct HksParam aes256Param[] = { + { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, + { .tag = HKS_TAG_KEY_SIZE, .uint32Param = HKS_AES_KEY_SIZE_256 }, + { .tag = HKS_TAG_DIGEST, .uint32Param = HKS_DIGEST_NONE }, + { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, + { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, + { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE }, +}; + +bool AddParams(struct HksParamSet *params, RootKeys type, HksKeyPurpose purpose) +{ + struct HksBlob blobNonce; + struct HksBlob keyName; + if (type == RootKeys::ROOT_KEY) { + blobNonce = { uint32_t(vecNonce_.size()), vecNonce_.data() }; + keyName = { uint32_t(vecRootKeyAlias_.size()), vecRootKeyAlias_.data() }; + } else if (type == RootKeys::CLONE_KEY) { + blobNonce = { uint32_t(backupNonce_.size()), backupNonce_.data() }; + keyName = { uint32_t(vecCloneKeyAlias_.size()), vecCloneKeyAlias_.data() }; + } else { + return false; + } + struct HksBlob blobAad = { uint32_t(vecAad_.size()), vecAad_.data() }; + struct HksParam hksParam[] = { + { .tag = HKS_TAG_PURPOSE, .uint32Param = purpose }, + { .tag = HKS_TAG_NONCE, .blob = blobNonce }, + { .tag = HKS_TAG_ASSOCIATED_DATA, .blob = blobAad }, + }; + + auto ret = HksAddParams(params, aes256Param, sizeof(aes256Param) / sizeof(aes256Param[0])); + if (ret != HKS_SUCCESS) { + ZLOGE("HksAddParams failed with error %{public}d", ret); + HksFreeParamSet(¶ms); + return false; + } + ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); + if (ret != HKS_SUCCESS) { + ZLOGE("HksAddParams failed with error %{public}d", ret); + HksFreeParamSet(¶ms); + return false; + } + return true; +} + int32_t GetRootKeyParams(HksParamSet *¶ms) { ZLOGI("GetRootKeyParams."); @@ -119,33 +170,25 @@ int32_t CryptoManager::CheckRootKey() std::vector CryptoManager::Encrypt(const std::vector &key) { - struct HksBlob blobAad = { uint32_t(vecAad_.size()), vecAad_.data() }; - struct HksBlob blobNonce = { uint32_t(vecNonce_.size()), vecNonce_.data() }; - struct HksBlob rootKeyName = { uint32_t(vecRootKeyAlias_.size()), vecRootKeyAlias_.data() }; - struct HksBlob plainKey = { uint32_t(key.size()), const_cast(key.data()) }; + return EncryptInner(key, RootKeys::ROOT_KEY); +} + +std::vector CryptoManager::EncryptCloneKey(const std::vector &key) +{ + return EncryptInner(key, RootKeys::CLONE_KEY); +} + +std::vector CryptoManager::EncryptInner(const std::vector &key, const RootKeys type) +{ struct HksParamSet *params = nullptr; int32_t ret = HksInitParamSet(¶ms); if (ret != HKS_SUCCESS) { ZLOGE("HksInitParamSet() failed with error %{public}d", ret); return {}; } - struct HksParam hksParam[] = { - { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, - { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_ENCRYPT }, - { .tag = HKS_TAG_DIGEST, .uint32Param = 0 }, - { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, - { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, - { .tag = HKS_TAG_NONCE, .blob = blobNonce }, - { .tag = HKS_TAG_ASSOCIATED_DATA, .blob = blobAad }, - { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE }, - }; - ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); - if (ret != HKS_SUCCESS) { - ZLOGE("HksAddParams failed with error %{public}d", ret); - HksFreeParamSet(¶ms); + if (!AddParams(params, type, HKS_KEY_PURPOSE_ENCRYPT)) { return {}; } - ret = HksBuildParamSet(¶ms); if (ret != HKS_SUCCESS) { ZLOGE("HksBuildParamSet failed with error %{public}d", ret); @@ -155,7 +198,14 @@ std::vector CryptoManager::Encrypt(const std::vector &key) uint8_t cipherBuf[256] = { 0 }; struct HksBlob cipherText = { sizeof(cipherBuf), cipherBuf }; - ret = HksEncrypt(&rootKeyName, params, &plainKey, &cipherText); + struct HksBlob keyName; + if (type == RootKeys::ROOT_KEY) { + keyName = { uint32_t(vecRootKeyAlias_.size()), vecRootKeyAlias_.data() }; + } else if (type == RootKeys::CLONE_KEY) { + keyName = { uint32_t(vecCloneKeyAlias_.size()), vecCloneKeyAlias_.data() }; + } + struct HksBlob plainKey = { uint32_t(key.size()), const_cast(key.data()) }; + ret = HksEncrypt(&keyName, params, &plainKey, &cipherText); (void)HksFreeParamSet(¶ms); if (ret != HKS_SUCCESS) { ZLOGE("HksEncrypt failed with error %{public}d", ret); @@ -169,32 +219,25 @@ std::vector CryptoManager::Encrypt(const std::vector &key) bool CryptoManager::Decrypt(std::vector &source, std::vector &key) { - struct HksBlob blobAad = { uint32_t(vecAad_.size()), &(vecAad_[0]) }; - struct HksBlob blobNonce = { uint32_t(vecNonce_.size()), &(vecNonce_[0]) }; - struct HksBlob rootKeyName = { uint32_t(vecRootKeyAlias_.size()), &(vecRootKeyAlias_[0]) }; - struct HksBlob encryptedKeyBlob = { uint32_t(source.size()), source.data() }; + return DecryptInner(source, key, RootKeys::ROOT_KEY); +} +bool CryptoManager::DecryptCloneKey(std::vector &source, std::vector &key) +{ + return DecryptInner(source, key, RootKeys::CLONE_KEY); +} + +bool CryptoManager::DecryptInner(std::vector &source, std::vector &key, RootKeys type) +{ struct HksParamSet *params = nullptr; int32_t ret = HksInitParamSet(¶ms); if (ret != HKS_SUCCESS) { ZLOGE("HksInitParamSet() failed with error %{public}d", ret); return false; } - struct HksParam hksParam[] = { - { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, - { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_DECRYPT }, - { .tag = HKS_TAG_DIGEST, .uint32Param = 0 }, - { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, - { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, - { .tag = HKS_TAG_NONCE, .blob = blobNonce }, - { .tag = HKS_TAG_ASSOCIATED_DATA, .blob = blobAad }, - { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE }, - }; - ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); - if (ret != HKS_SUCCESS) { - ZLOGE("HksAddParams failed with error %{public}d", ret); - HksFreeParamSet(¶ms); - return false; + + if (!AddParams(params, type, HKS_KEY_PURPOSE_DECRYPT)) { + return {}; } ret = HksBuildParamSet(¶ms); @@ -206,7 +249,14 @@ bool CryptoManager::Decrypt(std::vector &source, std::vector & uint8_t plainBuf[256] = { 0 }; struct HksBlob plainKeyBlob = { sizeof(plainBuf), plainBuf }; - ret = HksDecrypt(&rootKeyName, params, &encryptedKeyBlob, &plainKeyBlob); + struct HksBlob keyName; + if (type == RootKeys::ROOT_KEY) { + keyName = { uint32_t(vecRootKeyAlias_.size()), vecRootKeyAlias_.data() }; + } else if (type == RootKeys::CLONE_KEY) { + keyName = { uint32_t(vecCloneKeyAlias_.size()), vecCloneKeyAlias_.data() }; + } + struct HksBlob encryptedKeyBlob = { uint32_t(source.size()), source.data() }; + ret = HksDecrypt(&keyName, params, &encryptedKeyBlob, &plainKeyBlob); (void)HksFreeParamSet(¶ms); if (ret != HKS_SUCCESS) { ZLOGE("HksDecrypt failed with error %{public}d", ret); @@ -217,4 +267,60 @@ bool CryptoManager::Decrypt(std::vector &source, std::vector & (void)memset_s(plainBuf, sizeof(plainBuf), 0, sizeof(plainBuf)); return true; } + +bool BuildImportKeyParams(struct HksParamSet *¶ms) +{ + int32_t ret = HksInitParamSet(¶ms); + if (ret != HKS_SUCCESS) { + ZLOGE("HksInitParamSet failed with error %{public}d", ret); + return false; + } + struct HksParam purposeParam[] = { + {.tag = HKS_TAG_IS_KEY_ALIAS, .boolParam = true}, + {.tag = HKS_TAG_KEY_GENERATE_TYPE, .uint32Param = HKS_KEY_GENERATE_TYPE_DEFAULT}, + {.tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_ENCRYPT | HKS_KEY_PURPOSE_DECRYPT}, + }; + ret = HksAddParams(params, aes256Param, sizeof(aes256Param) / sizeof(aes256Param[0])); + if (ret != HKS_SUCCESS) { + ZLOGE("HksAddParams failed with error %{public}d", ret); + HksFreeParamSet(¶ms); + return false; + } + ret = HksAddParams(params, purposeParam, sizeof(purposeParam) / sizeof(purposeParam[0])); + if (ret != HKS_SUCCESS) { + ZLOGE("HksAddParams failed with error %{public}d", ret); + HksFreeParamSet(¶ms); + return false; + } + ret = HksBuildParamSet(¶ms); + if (ret != HKS_SUCCESS) { + ZLOGE("HksBuildParamSet failed with error %{public}d", ret); + HksFreeParamSet(¶ms); + return false; + } + return true; +} + +bool CryptoManager::ImportCloneKey(std::vector &key, std::vector &iv) +{ + std::lock_guard lock(mutex_); + ZLOGI("ImportCloneKey enter."); + backupNonce_ = std::vector(iv.begin(), iv.end()); + struct HksBlob hksKey = { static_cast(key.size()), key.data()}; + struct HksParamSet *params = nullptr; + if (!BuildImportKeyParams(params)) { + ZLOGE("Build import key params failed."); + return false; + } + + struct HksBlob backupKeyName = { uint32_t(vecCloneKeyAlias_.size()), vecCloneKeyAlias_.data() }; + int32_t ret = HksImportKey(&backupKeyName, params, &hksKey); + if (ret != HKS_SUCCESS) { + ZLOGE("Import key failed: %{public}d.", ret); + HksFreeParamSet(¶ms); + return false; + } + HksFreeParamSet(¶ms); + return true; +} } // namespace OHOS::DistributedData \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/data_share/BUILD.gn b/datamgr_service/services/distributeddataservice/service/data_share/BUILD.gn index e2e7181642aaca7fd90025750b9b42d5cda59296..5e0d4c7dde81a2685cb17d7f4a86470017ac076e 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/data_share/BUILD.gn @@ -20,12 +20,14 @@ config("module_public_config") { "strategies", "common", "data", + "dfx", "../../adapter/include", "../../app/src", "../../framework/include", "${datashare_path}/frameworks/native/common/include", "${datashare_path}/interfaces/inner_api/common/include", "${datashare_path}/interfaces/inner_api/consumer/include", + "${data_service_path}/adapter/include/communicator", "../common", "../crypto/include", "../permission/include", @@ -34,7 +36,7 @@ config("module_public_config") { group("build_module") { deps = [ ":data_share_service" ] } -ohos_shared_library("data_share_service") { +ohos_source_set("data_share_service") { branch_protector_ret = "pac_ret" sanitize = { ubsan = true @@ -44,9 +46,7 @@ ohos_shared_library("data_share_service") { debug = false } sources = [ - "${data_service_path}/service/common/xcollie.cpp", "common/app_connect_manager.cpp", - "common/base64_utils.cpp", "common/bundle_mgr_proxy.cpp", "common/db_delegate.cpp", "common/div_strategy.cpp", @@ -69,6 +69,8 @@ ohos_shared_library("data_share_service") { "data_share_service_stub.cpp", "data_share_silent_config.cpp", "data_share_types_util.cpp", + "dfx/hiview_adapter.cpp", + "dfx/hiview_fault_adapter.cpp", "strategies/data_proxy/load_config_from_data_proxy_node_strategy.cpp", "strategies/data_share/load_config_from_data_share_bundle_info_strategy.cpp", "strategies/general/check_is_data_proxy_strategy.cpp", @@ -91,22 +93,24 @@ ohos_shared_library("data_share_service") { "-Werror", "-Wno-multichar", "-D_LIBCPP_HAS_COND_CLOCKWAIT", + "-Oz", ] - cflags_cc = [ "-fvisibility=hidden" ] + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] configs = [ ":module_public_config" ] deps = [ - "../../adapter:distributeddata_adapter", - "../../adapter/utils:distributeddata_utils_static", + "${data_service_path}/adapter/utils:distributeddata_utils", + "${data_service_path}/service/common:distributeddata_common", "../../framework:distributeddatasvcfwk", - "../../service:distributeddatasvc", ] external_deps = [ "ability_base:want", - "ability_base:zuri", "ability_runtime:ability_connect_callback_stub", "ability_runtime:dataobs_manager", "ability_runtime:extension_manager", @@ -116,7 +120,6 @@ ohos_shared_library("data_share_service") { "bundle_framework:appexecfwk_base", "bundle_framework:appexecfwk_core", "c_utils:utils", - "common_event_service:cesfwk_innerkits", "data_share:datashare_common", "device_manager:devicemanagersdk", "hicollie:libhicollie", @@ -124,10 +127,10 @@ ohos_shared_library("data_share_service") { "hisysevent:libhisysevent", "ipc:ipc_core", "json:nlohmann_json_static", + "kv_store:datamgr_common", "kv_store:distributeddb", "relational_store:native_rdb", "relational_store:rdb_data_share_adapter", - "resource_management:global_resmgr", "samgr:samgr_proxy", "time_service:time_client", ] diff --git a/datamgr_service/services/distributeddataservice/service/data_share/common/bundle_mgr_proxy.cpp b/datamgr_service/services/distributeddataservice/service/data_share/common/bundle_mgr_proxy.cpp index 03e91f19bacd6af3b5bd88a9c06b37fcb9f743c0..8aeeb00327f007766dc5a6b1e1feb2b79fb9c70a 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/common/bundle_mgr_proxy.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/common/bundle_mgr_proxy.cpp @@ -98,7 +98,7 @@ int BundleMgrProxy::GetBundleInfoFromBMS( } } } - + if (!ret) { RADAR_REPORT(__FUNCTION__, RadarReporter::SILENT_ACCESS, RadarReporter::GET_BMS, RadarReporter::FAILED, RadarReporter::ERROR_CODE, RadarReporter::GET_BUNDLE_INFP_FAILED); @@ -115,6 +115,39 @@ int BundleMgrProxy::GetBundleInfoFromBMS( return E_OK; } +std::pair BundleMgrProxy::GetCallerAppIdentifier( + const std::string &bundleName, int32_t userId) +{ + std::string callerAppIdentifier; + std::string callerKey = bundleName + std::to_string(userId); + auto it = callerInfoCache_.Find(callerKey); + if (it.first) { + callerAppIdentifier = it.second; + return std::make_pair(E_OK, callerAppIdentifier); + } + AppExecFwk::BundleInfo bundleInfo; + auto bmsClient = GetBundleMgrProxy(); + if (bmsClient == nullptr) { + RADAR_REPORT(__FUNCTION__, RadarReporter::SILENT_ACCESS, RadarReporter::GET_BMS, + RadarReporter::FAILED, RadarReporter::ERROR_CODE, RadarReporter::GET_BMS_FAILED); + ZLOGE("GetBundleMgrProxy is nullptr!"); + return std::make_pair(E_BMS_NOT_READY, bundleInfo.signatureInfo.appIdentifier); + } + + int ret = bmsClient->GetBundleInfoV9(bundleName, + static_cast(AppExecFwk::GetBundleInfoFlag::GET_BUNDLE_INFO_WITH_SIGNATURE_INFO), bundleInfo, userId); + if (ret != 0) { + RADAR_REPORT(__FUNCTION__, RadarReporter::SILENT_ACCESS, RadarReporter::GET_BMS, + RadarReporter::FAILED, RadarReporter::ERROR_CODE, RadarReporter::GET_BUNDLE_INFP_FAILED); + ZLOGE("GetBundleInfo failed!bundleName is %{public}s, userId is %{public}d, errcode is %{public}d", + bundleName.c_str(), userId, ret); + return std::make_pair(E_BUNDLE_NAME_NOT_EXIST, bundleInfo.signatureInfo.appIdentifier); + } + + callerInfoCache_.Insert(callerKey, bundleInfo.signatureInfo.appIdentifier); + return std::make_pair(ret, bundleInfo.signatureInfo.appIdentifier); +} + void BundleMgrProxy::OnProxyDied() { std::lock_guard lock(mutex_); @@ -141,6 +174,7 @@ void BundleMgrProxy::Delete(const std::string &bundleName, int32_t userId, int32 } else { bundleCache_.Erase(bundleName + std::to_string(userId)); } + callerInfoCache_.Erase(bundleName + std::to_string(userId)); return; } diff --git a/datamgr_service/services/distributeddataservice/service/data_share/common/bundle_mgr_proxy.h b/datamgr_service/services/distributeddataservice/service/data_share/common/bundle_mgr_proxy.h index 75edf5bbfd6ca0d05563f6104a56dc6d7a829162..71bcc496eb74f059dc2830fcd47a6aaa767bb735 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/common/bundle_mgr_proxy.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/common/bundle_mgr_proxy.h @@ -69,7 +69,7 @@ public: BundleConfig &bundleConfig, int32_t appIndex = 0); void Delete(const std::string &bundleName, int32_t userId, int32_t appIndex); sptr CheckBMS(); - + std::pair GetCallerAppIdentifier(const std::string &bundleName, int32_t userId); private: BundleMgrProxy() = default; class ServiceDeathRecipient : public IRemoteObject::DeathRecipient { @@ -95,6 +95,7 @@ private: sptr proxy_; sptr deathRecipient_; ConcurrentMap bundleCache_; + ConcurrentMap callerInfoCache_; static constexpr const char *DATA_SHARE_EXTENSION_META = "ohos.extension.dataShare"; static constexpr const char *DATA_SHARE_PROPERTIES_META = "dataProperties"; }; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/common/context.h b/datamgr_service/services/distributeddataservice/service/data_share/common/context.h index 71988eb20eedd5323afde3da7a7307b7a15a3d1f..62da611a254d8d44c04454d0a122c9623d542028 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/common/context.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/common/context.h @@ -38,8 +38,10 @@ public: std::string uri; int32_t currentUserId = -1; int32_t appIndex = 0; + int32_t haMode = 0; std::string permission; uint32_t callerTokenId = 0; + uint32_t calledTokenId = 0; std::string callerBundleName; std::string calledBundleName; std::string calledModuleName; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/common/db_delegate.cpp b/datamgr_service/services/distributeddataservice/service/data_share/common/db_delegate.cpp index abc2c1925ea6f766d6044a10c4c9995c92c166fa..50196297bc07fdfe60a94bcbc58ff6d62a6fbc46 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/common/db_delegate.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/common/db_delegate.cpp @@ -16,39 +16,52 @@ #define LOG_TAG "DBAdaptor" #include "db_delegate.h" +#include "account_delegate.h" #include "kv_delegate.h" #include "log_print.h" #include "rdb_delegate.h" +#include "log_debug.h" + namespace OHOS::DataShare { +using Account = DistributedData::AccountDelegate; ExecutorPool::TaskId DBDelegate::taskId_ = ExecutorPool::INVALID_TASK_ID; +ExecutorPool::TaskId DBDelegate::taskIdEncrypt_ = ExecutorPool::INVALID_TASK_ID; ConcurrentMap>> DBDelegate::stores_ = {}; +ConcurrentMap>> DBDelegate::storesEncrypt_ = {}; std::shared_ptr DBDelegate::executor_ = nullptr; std::shared_ptr DBDelegate::Create(DistributedData::StoreMetaData &metaData, const std::string &extUri, const std::string &backup) { - if (metaData.tokenId == 0) { - return std::make_shared(metaData, NO_CHANGE_VERSION, true, extUri, backup); + if (Account::GetInstance()->IsDeactivating(atoi(metaData.user.c_str()))) { + ZLOGW("user %{public}s is deactivating, storeName: %{public}s", metaData.user.c_str(), + metaData.GetStoreAlias().c_str()); + return nullptr; } std::shared_ptr store; - stores_.Compute(metaData.tokenId, - [&metaData, &store, extUri, &backup](auto &, std::map> &stores) -> bool { - auto it = stores.find(metaData.storeId); - if (it != stores.end()) { - store = it->second->store_; - it->second->time_ = std::chrono::steady_clock::now() + std::chrono::seconds(INTERVAL); - return !stores.empty(); - } - store = std::make_shared(metaData, NO_CHANGE_VERSION, true, extUri, backup); - if (store->IsInvalid()) { - store = nullptr; - ZLOGE("creator failed, storeName: %{public}s", metaData.GetStoreAlias().c_str()); - return false; - } - auto entity = std::make_shared(store, metaData); - stores.emplace(metaData.storeId, entity); - StartTimer(); + auto storeFunc = [&metaData, &store, extUri, &backup] + (auto &, std::map> &stores) -> bool { + auto it = stores.find(metaData.storeId); + if (it != stores.end()) { + store = it->second->store_; + it->second->time_ = std::chrono::steady_clock::now() + std::chrono::seconds(INTERVAL); return !stores.empty(); - }); + } + store = std::make_shared(metaData, NO_CHANGE_VERSION, true, extUri, backup); + if (store->IsInvalid()) { + store = nullptr; + ZLOGE("creator failed, storeName: %{public}s", metaData.GetStoreAlias().c_str()); + return false; + } + auto entity = std::make_shared(store, metaData); + stores.emplace(metaData.storeId, entity); + StartTimer(metaData.isEncrypt); + return !stores.empty(); + }; + if (metaData.isEncrypt) { + storesEncrypt_.Compute(metaData.tokenId, storeFunc); + } else { + stores_.Compute(metaData.tokenId, storeFunc); + } return store; } @@ -63,7 +76,7 @@ void DBDelegate::Close(const DBDelegate::Filter &filter) return; } std::list> closeStores; - stores_.EraseIf([&closeStores, &filter](auto &, std::map> &stores) { + auto eraseFunc = [&closeStores, &filter](auto &, std::map> &stores) { for (auto it = stores.begin(); it != stores.end();) { if (it->second == nullptr || filter(it->second->user)) { closeStores.push_back(it->second); @@ -73,13 +86,15 @@ void DBDelegate::Close(const DBDelegate::Filter &filter) } } return stores.empty(); - }); + }; + stores_.EraseIf(eraseFunc); + storesEncrypt_.EraseIf(eraseFunc); } -void DBDelegate::GarbageCollect() +void DBDelegate::GarbageCollect(bool encrypt) { std::list> closeStores; - stores_.EraseIf([&closeStores](auto &, std::map> &stores) { + auto eraseFunc = [&closeStores](auto &, std::map> &stores) { auto current = std::chrono::steady_clock::now(); for (auto it = stores.begin(); it != stores.end();) { if (it->second->time_ < current) { @@ -90,28 +105,41 @@ void DBDelegate::GarbageCollect() } } return stores.empty(); - }); + }; + if (encrypt) { + storesEncrypt_.EraseIf(eraseFunc); + } else { + stores_.EraseIf(eraseFunc); + } } -void DBDelegate::StartTimer() +void DBDelegate::StartTimer(bool encrypt) { - if (executor_ == nullptr || taskId_ != Executor::INVALID_TASK_ID) { + ExecutorPool::TaskId& dstTaskId = encrypt ? taskIdEncrypt_ : taskId_; + + if (executor_ == nullptr || dstTaskId != Executor::INVALID_TASK_ID) { return; } - taskId_ = executor_->Schedule( - []() { - GarbageCollect(); - stores_.DoActionIfEmpty([]() { - if (executor_ == nullptr || taskId_ == Executor::INVALID_TASK_ID) { + dstTaskId = executor_->Schedule( + [encrypt]() { + GarbageCollect(encrypt); + auto task = [encrypt]() { + ExecutorPool::TaskId& dstTaskIdTemp = encrypt ? taskIdEncrypt_ : taskId_; + if (executor_ == nullptr || dstTaskIdTemp == Executor::INVALID_TASK_ID) { return; } - executor_->Remove(taskId_); - ZLOGD("remove timer, taskId: %{public}" PRIu64, taskId_); - taskId_ = Executor::INVALID_TASK_ID; - }); + executor_->Remove(dstTaskIdTemp); + ZLOGD_MACRO("remove timer, taskId: %{public}" PRIu64, dstTaskIdTemp); + dstTaskIdTemp = Executor::INVALID_TASK_ID; + }; + if (encrypt) { + stores_.DoActionIfEmpty(task); + } else { + storesEncrypt_.DoActionIfEmpty(task); + } }, std::chrono::seconds(INTERVAL), std::chrono::seconds(INTERVAL)); - ZLOGD("start timer, taskId: %{public}" PRIu64, taskId_); + ZLOGD_MACRO("start timer, taskId: %{public}" PRIu64, dstTaskId); } DBDelegate::Entity::Entity(std::shared_ptr store, const DistributedData::StoreMetaData &meta) @@ -124,6 +152,7 @@ DBDelegate::Entity::Entity(std::shared_ptr store, const DistributedD void DBDelegate::EraseStoreCache(const int32_t tokenId) { stores_.Erase(tokenId); + storesEncrypt_.Erase(tokenId); } std::shared_ptr KvDBDelegate::GetInstance( diff --git a/datamgr_service/services/distributeddataservice/service/data_share/common/db_delegate.h b/datamgr_service/services/distributeddataservice/service/data_share/common/db_delegate.h index 06da8d8d1239b2b9b4e4e38418fd9f843b7a831d..54056e0f4a66e6eeae920244643f54027efc17d8 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/common/db_delegate.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/common/db_delegate.h @@ -39,7 +39,7 @@ public: static void Close(const Filter &filter); virtual std::pair> Query(const std::string &tableName, const DataSharePredicates &predicates, const std::vector &columns, - const int32_t callingPid) = 0; + int32_t callingPid, uint32_t callingTokenId) = 0; virtual std::string Query( const std::string &sql, const std::vector &selectionArgs = std::vector()) = 0; virtual std::shared_ptr QuerySql(const std::string &sql) = 0; @@ -54,8 +54,8 @@ public: virtual std::pair DeleteEx(const std::string &tableName, const DataSharePredicates &predicate) = 0; private: - static void GarbageCollect(); - static void StartTimer(); + static void GarbageCollect(bool encrypt); + static void StartTimer(bool encrypt); struct Entity { explicit Entity(std::shared_ptr store, const DistributedData::StoreMetaData &meta); std::shared_ptr store_; @@ -64,9 +64,13 @@ private: }; static constexpr int NO_CHANGE_VERSION = -1; static constexpr int64_t INTERVAL = 20; //seconds + // Encrypt store of RDB depends on other components, and other components will use datashare, + // causing circular dependencies and deadlocks, the encrypt store is separated from the non-encryption store here. static ConcurrentMap>> stores_; + static ConcurrentMap>> storesEncrypt_; static std::shared_ptr executor_; static ExecutorPool::TaskId taskId_; + static ExecutorPool::TaskId taskIdEncrypt_; }; class Id : public DistributedData::Serializable { diff --git a/datamgr_service/services/distributeddataservice/service/data_share/common/extension_mgr_proxy.cpp b/datamgr_service/services/distributeddataservice/service/data_share/common/extension_mgr_proxy.cpp index 1d7f44d10edfe8e256e7b60eab7e9d995254ea43..dacd6ce8826dc757ba5b0839b4d41bc2d3ecd8c0 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/common/extension_mgr_proxy.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/common/extension_mgr_proxy.cpp @@ -23,6 +23,9 @@ #include "log_print.h" #include "system_ability_definition.h" #include "want.h" +#include "uri_utils.h" +#include "datashare_errno.h" + namespace OHOS::DataShare { void ExtensionMgrProxy::OnProxyDied() { @@ -53,11 +56,16 @@ int ExtensionMgrProxy::Connect( AAFwk::WantParams &wantParams) { AAFwk::Want want; - want.SetUri(uri); + auto [success, userId] = URIUtils::GetUserFromProxyURI(uri); + if (!success) { + return E_INVALID_USER_ID; + } + want.SetUri(URIUtils::FormatConstUri(uri)); want.SetParams(wantParams); std::lock_guard lock(mutex_); if (ConnectSA()) { - int ret = proxy_->ConnectAbilityCommon(want, connect, callerToken, AppExecFwk::ExtensionAbilityType::DATASHARE); + int ret = proxy_->ConnectAbilityCommon(want, connect, callerToken, AppExecFwk::ExtensionAbilityType::DATASHARE, + userId); if (ret != ERR_OK) { ZLOGE("ConnectAbilityCommon failed, %{public}d", ret); } diff --git a/datamgr_service/services/distributeddataservice/service/data_share/common/kv_delegate.cpp b/datamgr_service/services/distributeddataservice/service/data_share/common/kv_delegate.cpp index e9c66e2c296f77fcbff5dd818d70fe4fba0d06a1..06f8cc6a2f803af9f0b12b1318ff9445ddc3e7ed 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/common/kv_delegate.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/common/kv_delegate.cpp @@ -27,6 +27,7 @@ #include "grd_document/grd_document_api.h" #include "ipc_skeleton.h" #include "log_print.h" +#include "log_debug.h" namespace OHOS::DataShare { constexpr int WAIT_TIME = 30; @@ -87,7 +88,7 @@ void KvDelegate::Restore() { // No need to lock because this inner method will only be called when upper methods lock up CopyFile(false); - ZLOGD("finish restoring kv"); + ZLOGD_MACRO("finish restoring kv"); } // Backup database data by copying its key files. This mechanism might be costly, but acceptable when updating @@ -95,12 +96,12 @@ void KvDelegate::Restore() void KvDelegate::Backup() { // No need to lock because this inner method will only be called when upper methods lock up - ZLOGD("backup kv"); + ZLOGD_MACRO("backup kv"); if (hasChange_) { CopyFile(true); hasChange_ = false; } - ZLOGD("finish backing up kv"); + ZLOGD_MACRO("finish backing up kv"); } // Set hasChange_ to true. Caller can use this to control when to back up db. diff --git a/datamgr_service/services/distributeddataservice/service/data_share/common/log_debug.h b/datamgr_service/services/distributeddataservice/service/data_share/common/log_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..514eb7786f8ca086182352dc3761f1b8a0db6034 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/data_share/common/log_debug.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 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 LOG_DEBUG_H +#define LOG_DEBUG_H + +#ifdef _DEBUG_LOG_FLAG +#define ZLOGD_MACRO(fmt, ...) ZLOGD(fmt, ##__VA_ARGS__) +#else +#define ZLOGD_MACRO(fmt, ...) +#endif + +#endif // LOG_DEBUG_H diff --git a/datamgr_service/services/distributeddataservice/service/data_share/common/rdb_delegate.cpp b/datamgr_service/services/distributeddataservice/service/data_share/common/rdb_delegate.cpp index 3b8203b4e60e4b51daa08c4f573ef9b38f411a4f..94cd9c2c1e5372e52d919c89fea0ef9d541104b9 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/common/rdb_delegate.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/common/rdb_delegate.cpp @@ -20,6 +20,7 @@ #include "datashare_radar_reporter.h" #include "device_manager_adapter.h" #include "extension_connect_adaptor.h" +#include "hiview_fault_adapter.h" #include "int_wrapper.h" #include "metadata/meta_data_manager.h" #include "metadata/store_meta_data.h" @@ -32,6 +33,8 @@ #include "string_wrapper.h" #include "utils/anonymous.h" #include "want_params.h" +#include "db_delegate.h" +#include "log_debug.h" namespace OHOS::DataShare { constexpr static int32_t MAX_RESULTSET_COUNT = 32; @@ -40,11 +43,13 @@ std::atomic RdbDelegate::resultSetCount = 0; ConcurrentMap RdbDelegate::resultSetCallingPids; enum REMIND_TIMER_ARGS : int32_t { ARG_DB_PATH = 0, - ARG_VERSION, + ARG_TOKEN_ID, ARG_URI, ARG_SUBSCRIBER_ID, ARG_BUNDLE_NAME, ARG_USER_ID, + ARG_STORE_ID, + ARG_HA_MODE, ARG_TIME, ARGS_SIZE }; @@ -55,12 +60,15 @@ std::string RemindTimerFunc(const std::vector &args) ZLOGE("RemindTimerFunc args size error, %{public}zu", size); return ""; } - std::string dbPath = args[ARG_DB_PATH]; - int version = std::strtol(args[ARG_VERSION].c_str(), nullptr, 0); - Key key(args[ARG_URI], std::strtoll(args[ARG_SUBSCRIBER_ID].c_str(), nullptr, 0), args[ARG_BUNDLE_NAME]); - int64_t reminderTime = std::strtoll(args[ARG_TIME].c_str(), nullptr, 0); - int32_t userId = std::strtol(args[ARG_USER_ID].c_str(), nullptr, 0); - SchedulerManager::GetInstance().SetTimer(dbPath, userId, version, key, reminderTime); + DistributedData::StoreMetaData metaData; + metaData.tokenId = static_cast(std::atol(args[ARG_TOKEN_ID].c_str())); + metaData.storeId = args[ARG_STORE_ID]; + metaData.dataDir = args[ARG_DB_PATH]; + metaData.haMode = std::atol(args[ARG_HA_MODE].c_str()); + Key key(args[ARG_URI], std::atoll(args[ARG_SUBSCRIBER_ID].c_str()), args[ARG_BUNDLE_NAME]); + int64_t reminderTime = std::atoll(args[ARG_TIME].c_str()); + int32_t userId = std::atol(args[ARG_USER_ID].c_str()); + SchedulerManager::GetInstance().SetTimer(userId, metaData, key, reminderTime); return args[ARG_TIME]; } @@ -92,7 +100,7 @@ std::pair RdbDelegate::GetConfig(const DistributedData::Sto RdbDelegate::RdbDelegate(const DistributedData::StoreMetaData &meta, int version, bool registerFunction, const std::string &extUri, const std::string &backup) : tokenId_(meta.tokenId), bundleName_(meta.bundleName), storeName_(meta.storeId), - haMode_(meta.haMode), extUri_(extUri), backup_(backup) + haMode_(meta.haMode), extUri_(extUri), backup_(backup), user_(meta.user) { auto [err, config] = GetConfig(meta, registerFunction); if (err != E_OK) { @@ -108,7 +116,11 @@ RdbDelegate::RdbDelegate(const DistributedData::StoreMetaData &meta, int version RdbDelegate::TryAndSend(errCode_); } } - +RdbDelegate::~RdbDelegate() +{ + ZLOGI("Destruct. BundleName: %{public}s. StoreName: %{public}s. user: %{public}s", bundleName_.c_str(), + DistributedData::Anonymous::Change(storeName_).c_str(), user_.c_str()); +} void RdbDelegate::TryAndSend(int errCode) { if (errCode != E_SQLITE_CORRUPT || (haMode_ == HAMode::SINGLE && (backup_ != DUAL_WRITE && backup_ != PERIODIC))) { @@ -194,15 +206,15 @@ std::pair RdbDelegate::DeleteEx(const std::string &tableName, std::pair> RdbDelegate::Query(const std::string &tableName, const DataSharePredicates &predicates, const std::vector &columns, - const int32_t callingPid) + int32_t callingPid, uint32_t callingTokenId) { if (store_ == nullptr) { ZLOGE("store is null"); return std::make_pair(errCode_, nullptr); } int count = resultSetCount.fetch_add(1); - ZLOGD("start query %{public}d", count); - if (count > MAX_RESULTSET_COUNT && IsLimit(count, callingPid)) { + ZLOGD_MACRO("start query %{public}d", count); + if (count > MAX_RESULTSET_COUNT && IsLimit(count, callingPid, callingTokenId)) { resultSetCount--; return std::make_pair(E_RESULTSET_BUSY, nullptr); } @@ -229,7 +241,7 @@ std::pair> RdbDelegate::Query(const std std::chrono::system_clock::now().time_since_epoch()).count(); auto bridge = RdbDataShareAdapter::RdbUtils::ToResultSetBridge(resultSet); std::shared_ptr result = { new DataShareResultSet(bridge), [callingPid, beginTime](auto p) { - ZLOGD("release resultset"); + ZLOGD_MACRO("release resultset"); resultSetCount--; int64_t endTime = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()).count(); @@ -306,7 +318,7 @@ bool RdbDelegate::IsInvalid() return store_ == nullptr; } -bool RdbDelegate::IsLimit(int count, const int32_t callingPid) +bool RdbDelegate::IsLimit(int count, int32_t callingPid, uint32_t callingTokenId) { bool isFull = true; for (int32_t retryCount = 0; retryCount < RETRY; retryCount++) { @@ -325,6 +337,10 @@ bool RdbDelegate::IsLimit(int count, const int32_t callingPid) return false; }); ZLOGE("resultSetCount is full, pid: %{public}d, owner is %{public}s", callingPid, logStr.c_str()); + std::string appendix = "callingName:" + HiViewFaultAdapter::GetCallingName(callingTokenId).first; + DataShareFaultInfo faultInfo{RESULTSET_FULL, "callingTokenId:" + std::to_string(callingTokenId), + "Pid:" + std::to_string(callingPid), "owner:" + logStr, __FUNCTION__, E_RESULTSET_BUSY, appendix}; + HiViewFaultAdapter::ReportDataFault(faultInfo); return true; } } // namespace OHOS::DataShare \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/data_share/common/rdb_delegate.h b/datamgr_service/services/distributeddataservice/service/data_share/common/rdb_delegate.h index b65e6f9a4f3ae3fd161cb5e26a1be3b8a3b47824..d7c3eedaf8d018549a28a9d2bd6097f29318fc1f 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/common/rdb_delegate.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/common/rdb_delegate.h @@ -33,9 +33,10 @@ class RdbDelegate final : public DBDelegate { public: explicit RdbDelegate(const DistributedData::StoreMetaData &meta, int version, bool registerFunction, const std::string &extUri, const std::string &backup); + ~RdbDelegate(); std::pair> Query(const std::string &tableName, const DataSharePredicates &predicates, const std::vector &columns, - const int32_t callingPid) override; + int32_t callingPid, uint32_t callingTokenId) override; std::string Query(const std::string &sql, const std::vector &selectionArgs) override; std::shared_ptr QuerySql(const std::string &sql) override; std::pair UpdateSql(const std::string &sql) override; @@ -49,7 +50,7 @@ public: private: void TryAndSend(int errCode); std::pair GetConfig(const DistributedData::StoreMetaData &meta, bool registerFunction); - bool IsLimit(int count, const int32_t callingPid); + bool IsLimit(int count, int32_t callingPid, uint32_t callingTokenId); static std::atomic resultSetCount; static ConcurrentMap resultSetCallingPids; static constexpr std::chrono::milliseconds WAIT_TIME = std::chrono::milliseconds(50); @@ -64,6 +65,7 @@ private: int32_t haMode_; std::string extUri_; std::string backup_; + std::string user_; }; class DefaultOpenCallback : public RdbOpenCallback { public: diff --git a/datamgr_service/services/distributeddataservice/service/data_share/common/scheduler_manager.cpp b/datamgr_service/services/distributeddataservice/service/data_share/common/scheduler_manager.cpp index 8ed1869761a28d98d49f19dfe26fee597ff35ce6..79ca80155a6e32bfd36ac2af3417040ab57d13b1 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/common/scheduler_manager.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/common/scheduler_manager.cpp @@ -22,6 +22,7 @@ #include "timer_info.h" #include "uri_utils.h" #include "utils/anonymous.h" +#include "log_debug.h" namespace OHOS::DataShare { static constexpr int64_t MAX_MILLISECONDS = 31536000000; // 365 days @@ -32,37 +33,85 @@ SchedulerManager &SchedulerManager::GetInstance() return instance; } -void SchedulerManager::Execute(const std::string &uri, const int32_t userId, const std::string &rdbDir, int version, - const std::string &bundleName) +void SchedulerManager::Execute(const std::string &uri, const int32_t userId, DistributedData::StoreMetaData &metaData) { if (!URIUtils::IsDataProxyURI(uri)) { return; } - DistributedData::StoreMetaData meta; - meta.dataDir = rdbDir; - meta.bundleName = bundleName; - auto delegate = DBDelegate::Create(meta); + metaData.user = std::to_string(userId); + auto delegate = DBDelegate::Create(metaData); if (delegate == nullptr) { ZLOGE("malloc fail %{public}s", DistributedData::Anonymous::Change(uri).c_str()); return; } std::vector keys = RdbSubscriberManager::GetInstance().GetKeysByUri(uri); for (auto const &key : keys) { - ExecuteSchedulerSQL(rdbDir, userId, version, key, delegate); + ExecuteSchedulerSQL(userId, metaData, key, delegate); } } -void SchedulerManager::Execute(const Key &key, const int32_t userId, const std::string &rdbDir, int version) +void SchedulerManager::Execute(const Key &key, const int32_t userId, const DistributedData::StoreMetaData &metaData) { - DistributedData::StoreMetaData meta; - meta.dataDir = rdbDir; + DistributedData::StoreMetaData meta = metaData; meta.bundleName = key.bundleName; + meta.user = std::to_string(userId); auto delegate = DBDelegate::Create(meta); if (delegate == nullptr) { ZLOGE("malloc fail %{public}s", DistributedData::Anonymous::Change(key.uri).c_str()); return; } - ExecuteSchedulerSQL(rdbDir, userId, version, key, delegate); + ExecuteSchedulerSQL(userId, meta, key, delegate); +} + +void SchedulerManager::Start(const Key &key, int32_t userId, const DistributedData::StoreMetaData &metaData) +{ + { + std::lock_guard lock(mutex_); + auto it = schedulerStatusCache_.find(key); + if (it == schedulerStatusCache_.end()) { + schedulerStatusCache_.emplace(key, true); + } + } + Execute(key, userId, metaData); +} + +void SchedulerManager::Stop(const Key &key) +{ + std::lock_guard lock(mutex_); + RemoveTimer(key); + auto it = schedulerStatusCache_.find(key); + if (it != schedulerStatusCache_.end()) { + schedulerStatusCache_.erase(it); + } +} + +void SchedulerManager::Enable(const Key &key, int32_t userId, const DistributedData::StoreMetaData &metaData) +{ + bool isTimerStopped = false; + { + std::lock_guard lock(mutex_); + auto it = schedulerStatusCache_.find(key); + if (it != schedulerStatusCache_.end()) { + it->second = true; + } + auto timer = timerCache_.find(key); + if (timer == timerCache_.end()) { + isTimerStopped = true; + } + } + if (isTimerStopped) { + Execute(key, userId, metaData); + RdbSubscriberManager::GetInstance().EmitByKey(key, userId, metaData); + } +} + +void SchedulerManager::Disable(const Key &key) +{ + std::lock_guard lock(mutex_); + auto it = schedulerStatusCache_.find(key); + if (it != schedulerStatusCache_.end()) { + it->second = false; + } } bool SchedulerManager::SetTimerTask(uint64_t &timerId, const std::function &callback, @@ -95,8 +144,31 @@ void SchedulerManager::ResetTimerTask(int64_t timerId, int64_t reminderTime) TimeServiceClient::GetInstance()->StartTimer(timerId, static_cast(reminderTime)); } +int64_t SchedulerManager::EraseTimerTaskId(const Key &key) +{ + int64_t timerId = -1; + std::lock_guard lock(mutex_); + auto it = timerCache_.find(key); + if (it != timerCache_.end()) { + timerId = it->second; + timerCache_.erase(key); + } + return timerId; +} + +bool SchedulerManager::GetSchedulerStatus(const Key &key) +{ + bool enabled = false; + std::lock_guard lock(mutex_); + auto it = schedulerStatusCache_.find(key); + if (it != schedulerStatusCache_.end()) { + enabled = it->second; + } + return enabled; +} + void SchedulerManager::SetTimer( - const std::string &dbPath, const int32_t userId, int version, const Key &key, int64_t reminderTime) + const int32_t userId, DistributedData::StoreMetaData &metaData, const Key &key, int64_t reminderTime) { std::lock_guard lock(mutex_); if (executor_ == nullptr) { @@ -115,28 +187,22 @@ void SchedulerManager::SetTimer( duration, key.subscriberId, key.bundleName.c_str()); auto it = timerCache_.find(key); if (it != timerCache_.end()) { - ZLOGD("has current taskId, uri is %{private}s, subscriberId is %{public}" PRId64 ", bundleName is %{public}s", + ZLOGD_MACRO("has current taskId: %{private}s, subscriberId is %{public}" PRId64 ", bundleName is %{public}s", DistributedData::Anonymous::Change(key.uri).c_str(), key.subscriberId, key.bundleName.c_str()); auto timerId = it->second; ResetTimerTask(timerId, reminderTime); return; } - auto callback = [key, dbPath, version, userId, this]() { + auto callback = [key, metaData, userId, this]() { ZLOGI("schedule notify start, uri is %{private}s, subscriberId is %{public}" PRId64 ", bundleName is " "%{public}s", DistributedData::Anonymous::Change(key.uri).c_str(), key.subscriberId, key.bundleName.c_str()); - int64_t timerId = -1; - { - std::lock_guard lock(mutex_); - auto it = timerCache_.find(key); - if (it != timerCache_.end()) { - timerId = it->second; - timerCache_.erase(key); - } - } + int64_t timerId = EraseTimerTaskId(key); DestoryTimerTask(timerId); - Execute(key, userId, dbPath, version); - RdbSubscriberManager::GetInstance().EmitByKey(key, userId, dbPath, version); + if (GetSchedulerStatus(key)) { + Execute(key, userId, metaData); + RdbSubscriberManager::GetInstance().EmitByKey(key, userId, metaData); + } }; uint64_t timerId = 0; if (!SetTimerTask(timerId, callback, reminderTime)) { @@ -148,8 +214,8 @@ void SchedulerManager::SetTimer( timerCache_.emplace(key, timerId); } -void SchedulerManager::ExecuteSchedulerSQL(const std::string &rdbDir, const int32_t userId, int version, const Key &key, - std::shared_ptr delegate) +void SchedulerManager::ExecuteSchedulerSQL(const int32_t userId, DistributedData::StoreMetaData &metaData, + const Key &key, std::shared_ptr delegate) { Template tpl; if (!TemplateManager::GetInstance().Get(key, userId, tpl)) { @@ -162,7 +228,7 @@ void SchedulerManager::ExecuteSchedulerSQL(const std::string &rdbDir, const int3 DistributedData::Anonymous::Change(key.uri).c_str(), key.subscriberId, key.bundleName.c_str()); return; } - GenRemindTimerFuncParams(rdbDir, userId, version, key, tpl.scheduler_); + GenRemindTimerFuncParams(userId, metaData, key, tpl.scheduler_); auto resultSet = delegate->QuerySql(tpl.scheduler_); if (resultSet == nullptr) { ZLOGE("resultSet is nullptr, %{public}s, %{public}" PRId64 ", %{public}s", @@ -181,7 +247,7 @@ void SchedulerManager::ExecuteSchedulerSQL(const std::string &rdbDir, const int3 } void SchedulerManager::GenRemindTimerFuncParams( - const std::string &rdbDir, const int32_t userId, int version, const Key &key, std::string &schedulerSQL) + const int32_t userId, DistributedData::StoreMetaData &metaData, const Key &key, std::string &schedulerSQL) { auto index = schedulerSQL.find(REMIND_TIMER_FUNC); if (index == std::string::npos) { @@ -189,16 +255,15 @@ void SchedulerManager::GenRemindTimerFuncParams( return; } index += REMIND_TIMER_FUNC_LEN; - std::string keyStr = "'" + rdbDir + "', " + std::to_string(version) + ", '" + key.uri + "', " + + std::string keyStr = "'" + metaData.dataDir + "', " + std::to_string(metaData.tokenId) + ", '" + key.uri + "', " + std::to_string(key.subscriberId) + ", '" + key.bundleName + "', " + std::to_string(userId) + - ", "; + ", '" + metaData.storeId + "', " + std::to_string(metaData.haMode) + ", "; schedulerSQL.insert(index, keyStr); return; } void SchedulerManager::RemoveTimer(const Key &key) { - std::lock_guard lock(mutex_); if (executor_ == nullptr) { ZLOGE("executor_ is nullptr"); return; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/common/scheduler_manager.h b/datamgr_service/services/distributeddataservice/service/data_share/common/scheduler_manager.h index c112dcb58bb6eac00ceb948727c76e226c59eed0..934f39757585d73ddb1c9c6b8af4a1ddfed6fde5 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/common/scheduler_manager.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/common/scheduler_manager.h @@ -26,30 +26,36 @@ namespace OHOS::DataShare { class SchedulerManager { public: static SchedulerManager &GetInstance(); - void Execute(const std::string &uri, const int32_t userId, const std::string &rdbDir, int version, - const std::string &bundleName); - void Execute(const Key &key, const int32_t userId, const std::string &rdbDir, int version); + void Execute(const std::string &uri, const int32_t userId, DistributedData::StoreMetaData &metaData); + void Execute(const Key &key, const int32_t userId, const DistributedData::StoreMetaData &metaData); void ReExecuteAll(); - void SetTimer(const std::string &dbPath, const int32_t userId, int version, const Key &key, int64_t reminderTime); + void SetTimer(const int32_t userId, DistributedData::StoreMetaData &metaData, const Key &key, int64_t reminderTime); void RemoveTimer(const Key &key); void ClearTimer(); void SetExecutorPool(std::shared_ptr executor); + void Start(const Key &key, int32_t userId, const DistributedData::StoreMetaData &metaData); + void Stop(const Key &key); + void Enable(const Key &key, int32_t userId, const DistributedData::StoreMetaData &metaData); + void Disable(const Key &key); private: static constexpr const char *REMIND_TIMER_FUNC = "remindTimer("; static constexpr int REMIND_TIMER_FUNC_LEN = 12; SchedulerManager() = default; ~SchedulerManager() = default; - static void GenRemindTimerFuncParams(const std::string &rdbDir, const int32_t userId, int version, const Key &key, + static void GenRemindTimerFuncParams(const int32_t userId, DistributedData::StoreMetaData &metaData, const Key &key, std::string &schedulerSQL); - void ExecuteSchedulerSQL(const std::string &rdbDir, const int32_t userId, int version, const Key &key, + void ExecuteSchedulerSQL(const int32_t userId, DistributedData::StoreMetaData &metaData, const Key &key, std::shared_ptr delegate); bool SetTimerTask(uint64_t &timerId, const std::function &callback, int64_t reminderTime); void DestoryTimerTask(int64_t timerId); void ResetTimerTask(int64_t timerId, int64_t reminderTime); + int64_t EraseTimerTaskId(const Key &key); + bool GetSchedulerStatus(const Key &key); std::mutex mutex_; std::map timerCache_; + std::map schedulerStatusCache_; std::shared_ptr executor_ = nullptr; }; } // namespace OHOS::DataShare diff --git a/datamgr_service/services/distributeddataservice/service/data_share/common/uri_utils.cpp b/datamgr_service/services/distributeddataservice/service/data_share/common/uri_utils.cpp index fef9de081466554b192a71c783f7bd6693c47480..48d4dfce0b37a17109a989bf4a5a475138296b02 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/common/uri_utils.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/common/uri_utils.cpp @@ -77,6 +77,23 @@ bool URIUtils::GetAppIndexFromProxyURI(const std::string &uri, int32_t &appIndex return true; } +std::pair URIUtils::GetUserFromProxyURI(const std::string &uri) +{ + auto queryParams = URIUtils::GetQueryParams(uri); + if (queryParams[USER_PARAM].empty()) { + // -1 is placeholder for visit provider's user + return std::make_pair(true, -1); + } + auto [success, data] = URIUtils::Strtoul(queryParams[USER_PARAM]); + if (!success) { + return std::make_pair(false, -1); + } + if (data < 0 || data > INT32_MAX) { + return std::make_pair(false, -1); + } + return std::make_pair(true, data); +} + void URIUtils::FormatUri(std::string &uri) { auto pos = uri.find_last_of('?'); @@ -87,6 +104,16 @@ void URIUtils::FormatUri(std::string &uri) uri.resize(pos); } +std::string URIUtils::FormatConstUri(const std::string &uri) +{ + auto pos = uri.find_last_of('?'); + if (pos == std::string::npos) { + return uri; + } + + return uri.substr(0, pos); +} + __attribute__((no_sanitize("cfi"))) UriConfig URIUtils::GetUriConfig(const std::string &uri) { UriConfig uriConfig; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/common/uri_utils.h b/datamgr_service/services/distributeddataservice/service/data_share/common/uri_utils.h index 77ebfdc9e0d7f73329c99da65a719c2b415db119..8f2298506f8c454cfad95dd44f162a7aa23c181c 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/common/uri_utils.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/common/uri_utils.h @@ -40,8 +40,10 @@ public: static bool GetInfoFromURI(const std::string &uri, UriInfo &uriInfo); static bool GetBundleNameFromProxyURI(const std::string &uri, std::string &bundleName); static bool GetAppIndexFromProxyURI(const std::string &uri, int32_t &appIndex); + static std::pair GetUserFromProxyURI(const std::string &uri); static bool IsDataProxyURI(const std::string &uri); static void FormatUri(std::string &uri); + static std::string FormatConstUri(const std::string &uri); static UriConfig GetUriConfig(const std::string &uri); static std::string Anonymous(const std::string &uri); static std::map GetQueryParams(const std::string& uri); @@ -52,6 +54,7 @@ public: static constexpr const char *SCHEME_SEPARATOR = "://"; static constexpr const char *URI_SEPARATOR = "/"; static constexpr const char *APP_INDEX = "appIndex"; // for Application Clone + static constexpr const char USER_PARAM[] = "user"; static constexpr int DATA_PROXY_SCHEMA_LEN = sizeof(DATA_PROXY_SCHEMA) - 1; static constexpr uint32_t PARAM_URI_SEPARATOR_LEN = 4; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data/published_data.cpp b/datamgr_service/services/distributeddataservice/service/data_share/data/published_data.cpp index 2ae1231d82f25744b45b79eca5edeffa9612e631..894a8e58346f1623103f86b440c0b39e123a9596 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data/published_data.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/data/published_data.cpp @@ -17,7 +17,7 @@ #include "log_print.h" #include "subscriber_managers/published_data_subscriber_manager.h" -#include "base64_utils.h" +#include "utils/base64_utils.h" namespace OHOS::DataShare { bool PublishedData::HasVersion() const @@ -115,7 +115,7 @@ std::variant, std::string> PublishedDataNode::MoveTo(const } auto *valueBytes = std::get_if(&data); if (valueBytes != nullptr) { - return Base64::Decode(valueBytes->data); + return DistributedData::Base64::Decode(valueBytes->data); } ZLOGE("error"); return ""; @@ -129,7 +129,7 @@ PublishedDataNode::Data PublishedDataNode::MoveTo(std::variant>(&data); if (valueBytes != nullptr) { - std::string valueEncode = Base64::Encode(*valueBytes); + std::string valueEncode = DistributedData::Base64::Encode(*valueBytes); return BytesData(std::move(valueEncode)); } ZLOGE("error"); diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_provider_config.cpp b/datamgr_service/services/distributeddataservice/service/data_share/data_provider_config.cpp index 3689b802ff8aa4ad783c3b26695d4ac0f5560a4b..a45379fd6f4722c4e441c13d9c0ef63ef05e8a98 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_provider_config.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_provider_config.cpp @@ -32,12 +32,21 @@ using namespace OHOS::DistributedData; DataProviderConfig::DataProviderConfig(const std::string &uri, uint32_t callerTokenId) { providerInfo_.uri = uri; - providerInfo_.currentUserId = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(callerTokenId); + providerInfo_.currentUserId = AccountDelegate::GetInstance()->GetUserByToken(callerTokenId); + providerInfo_.visitedUserId = providerInfo_.currentUserId; URIUtils::GetAppIndexFromProxyURI(providerInfo_.uri, providerInfo_.appIndex); if (providerInfo_.currentUserId == 0) { - LoadConfigCommonStrategy::GetInfoFromProxyURI(providerInfo_.uri, providerInfo_.currentUserId, + LoadConfigCommonStrategy::GetInfoFromProxyURI(providerInfo_.uri, providerInfo_.visitedUserId, callerTokenId, providerInfo_.bundleName); URIUtils::FormatUri(providerInfo_.uri); + } else { + auto [success, data] = URIUtils::GetUserFromProxyURI(providerInfo_.uri); + if (success) { + // if data is -1, it means visiting provider's user + providerInfo_.visitedUserId = (data == -1 ? providerInfo_.currentUserId : data); + } else { + providerInfo_.visitedUserId = -1; + } } uriConfig_ = URIUtils::GetUriConfig(providerInfo_.uri); } @@ -53,7 +62,7 @@ std::pair DataProviderConfig::GetBundleInfo() providerInfo_.bundleName = uriConfig_.pathSegments[0]; } auto ret = BundleMgrProxy::GetInstance()->GetBundleInfoFromBMS( - providerInfo_.bundleName, providerInfo_.currentUserId, bundleInfo, providerInfo_.appIndex); + providerInfo_.bundleName, providerInfo_.visitedUserId, bundleInfo, providerInfo_.appIndex); return std::make_pair(ret, bundleInfo); } @@ -61,8 +70,8 @@ int DataProviderConfig::GetFromProxyData() { auto [errCode, bundleInfo] = GetBundleInfo(); if (errCode != E_OK) { - ZLOGE("Get bundleInfo failed! bundleName:%{public}s, userId:%{public}d, uri:%{public}s", - providerInfo_.bundleName.c_str(), providerInfo_.currentUserId, + ZLOGE("Get bundleInfo failed! bundleName:%{public}s, userId:%{public}d, visitedId:%{public}d, uri:%{public}s", + providerInfo_.bundleName.c_str(), providerInfo_.currentUserId, providerInfo_.visitedUserId, URIUtils::Anonymous(providerInfo_.uri).c_str()); return errCode; } @@ -87,6 +96,7 @@ int DataProviderConfig::GetFromProxyData() } providerInfo_.readPermission = std::move(data.requiredReadPermission); providerInfo_.writePermission = std::move(data.requiredWritePermission); + providerInfo_.allowLists = std::move(data.profileInfo.profile.allowLists); auto profileInfo = data.profileInfo; if (profileInfo.resultCode == NOT_FOUND) { return E_OK; @@ -132,7 +142,7 @@ int DataProviderConfig::GetFromExtensionProperties(const ProfileInfo &profileInf return E_ERROR; } if (providerInfo_.singleton && providerInfo_.accessCrossMode == AccessCrossMode::USER_SINGLE) { - providerInfo_.tableName.append("_").append(std::to_string(providerInfo_.currentUserId)); + providerInfo_.tableName.append("_").append(std::to_string(providerInfo_.visitedUserId)); } return E_OK; } @@ -145,7 +155,7 @@ int DataProviderConfig::GetFromExtension() } BundleConfig bundleInfo; auto ret = BundleMgrProxy::GetInstance()->GetBundleInfoFromBMS( - providerInfo_.bundleName, providerInfo_.currentUserId, bundleInfo, providerInfo_.appIndex); + providerInfo_.bundleName, providerInfo_.visitedUserId, bundleInfo, providerInfo_.appIndex); if (ret != E_OK) { ZLOGE("BundleInfo failed! bundleName: %{public}s", providerInfo_.bundleName.c_str()); return ret; @@ -206,6 +216,9 @@ std::pair DataProviderConfig::GetProvider if (providerInfo_.appIndex == -1) { return std::make_pair(E_APPINDEX_INVALID, providerInfo_); } + if (providerInfo_.visitedUserId == -1) { + return std::make_pair(E_INVALID_USER_ID, providerInfo_); + } auto ret = GetFromProxyData(); if (ret == E_OK) { GetMetaDataFromUri(); diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_provider_config.h b/datamgr_service/services/distributeddataservice/service/data_share/data_provider_config.h index a58a78f3a9535c886284a417a02ba94e69823ffb..13c2b88c0a181c1445aa6691574103811a1ac400 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_provider_config.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_provider_config.h @@ -34,6 +34,7 @@ public: struct ProviderInfo { std::string uri; int32_t currentUserId = -1; + int32_t visitedUserId = -1; int32_t appIndex = 0; // appIndex is in [1, 1000], and original app's index is 0 std::string bundleName; std::string moduleName; @@ -41,6 +42,7 @@ public: std::string tableName; std::string readPermission; std::string writePermission; + std::string acrossAccountsPermission = "ohos.permission.INTERACT_ACROSS_LOCAL_ACCOUNTS"; std::string type = "rdb"; std::string backup; std::string extensionUri; @@ -49,6 +51,7 @@ public: bool allowEmptyPermission = false; bool storeMetaDataFromUri = false; AccessCrossMode accessCrossMode = AccessCrossMode::USER_UNDEFINED; + std::vector allowLists; }; std::pair GetProviderInfo(); diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_share_obs_proxy.cpp b/datamgr_service/services/distributeddataservice/service/data_share/data_share_obs_proxy.cpp index 769ea0b3e10b9d24ca35c0208f7c5c534ea34fb7..f63090f1f94462a8bb1f70c023fcd79901139dc1 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_share_obs_proxy.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_share_obs_proxy.cpp @@ -20,10 +20,17 @@ #include "itypes_util.h" #include "datashare_itypes_utils.h" #include "log_print.h" +#include "log_debug.h" namespace OHOS { namespace DataShare { static constexpr int REQUEST_CODE = 0; +// length of int32 bytes +static constexpr int32_t INT32_BYTE_LEN = static_cast(sizeof(int32_t)); +// using DATA_SIZEASHMEM_TRANSFER_LIMIT as the maximum length of changeNode.data_[i] +static constexpr size_t MAX_STR_LEN = static_cast(DATA_SIZE_ASHMEM_TRANSFER_LIMIT); +// maximum size of changeNode.data_(all 0-length strings) +static constexpr size_t MAX_DATA_SIZE = MAX_STR_LEN >> 2; int RdbObserverProxy::CreateAshmem(RdbChangeNode &changeNode) { OHOS::sptr memory = Ashmem::CreateAshmem(ASHMEM_NAME, DATA_SIZE_ASHMEM_TRANSFER_LIMIT); @@ -48,7 +55,7 @@ int RdbObserverProxy::CreateAshmem(RdbChangeNode &changeNode) return E_OK; } -int RdbObserverProxy::WriteAshmem(RdbChangeNode &changeNode, void *data, int len, int &offset) +int RdbObserverProxy::WriteAshmem(RdbChangeNode &changeNode, void *data, int32_t len, int32_t &offset) { if (changeNode.memory_ == nullptr) { ZLOGE("changeNode memory is nullptr."); @@ -75,25 +82,36 @@ int RdbObserverProxy::SerializeDataIntoAshmem(RdbChangeNode &changeNode) // move data // simple serialization: [vec_size(int32); str1_len(int32), str1; str2_len(int32), str2; ...], // total byte size is recorded in changeNode.size - int offset = 0; - // 4 byte for length int - int intLen = 4; - int dataSize = changeNode.data_.size(); - if (WriteAshmem(changeNode, (void *)&dataSize, intLen, offset) != E_OK) { - ZLOGE("failed to write data with len %{public}d, offset %{public}d.", intLen, offset); + int32_t offset = 0; + size_t dataSize = changeNode.data_.size(); + // maximum dataSize + if (dataSize > MAX_DATA_SIZE) { + ZLOGE("changeNode size:%{public}zu, exceeds the maximum limit.", dataSize); return E_ERROR; } - for (int i = 0; i < dataSize; i++) { + if (WriteAshmem(changeNode, (void *)&dataSize, INT32_BYTE_LEN, offset) != E_OK) { + ZLOGE("failed to write data with len %{public}d, offset %{public}d.", INT32_BYTE_LEN, offset); + return E_ERROR; + } + for (size_t i = 0; i < dataSize; i++) { const char *str = changeNode.data_[i].c_str(); - int strLen = changeNode.data_[i].length(); + size_t uStrLen = changeNode.data_[i].length(); + // maximum strLen + if (uStrLen > MAX_STR_LEN) { + ZLOGE("string length:%{public}zu, exceeds the maximum limit.", uStrLen); + return E_ERROR; + } + int32_t strLen = static_cast(uStrLen); // write length int - if (WriteAshmem(changeNode, (void *)&strLen, intLen, offset) != E_OK) { - ZLOGE("failed to write data with index %{public}d, len %{public}d, offset %{public}d.", i, intLen, offset); + if (WriteAshmem(changeNode, (void *)&strLen, INT32_BYTE_LEN, offset) != E_OK) { + ZLOGE("failed to write data with index %{public}zu, len %{public}d, offset %{public}d.", + i, INT32_BYTE_LEN, offset); return E_ERROR; } // write str if (WriteAshmem(changeNode, (void *)str, strLen, offset) != E_OK) { - ZLOGE("failed to write data with index %{public}d, len %{public}d, offset %{public}d.", i, strLen, offset); + ZLOGE("failed to write data with index %{public}zu, len %{public}d, offset %{public}d.", + i, strLen, offset); return E_ERROR; } } @@ -104,19 +122,30 @@ int RdbObserverProxy::SerializeDataIntoAshmem(RdbChangeNode &changeNode) int RdbObserverProxy::PrepareRdbChangeNodeData(RdbChangeNode &changeNode) { // If data size is bigger than the limit, move it to the shared memory - // 4 byte for length int - int intByteLen = 4; - int size = intByteLen; - for (int i = 0; i < changeNode.data_.size(); i++) { - size += intByteLen; - size += changeNode.data_[i].length(); + int32_t size = INT32_BYTE_LEN; + size_t dataSize = changeNode.data_.size(); + // maximum dataSize + if (dataSize > MAX_DATA_SIZE) { + ZLOGE("changeNode size:%{public}zu, exceeds the maximum limit.", dataSize); + return E_ERROR; + } + for (size_t i = 0; i < dataSize; i++) { + size += INT32_BYTE_LEN; + size_t uStrLen = changeNode.data_[i].length(); + // maximum strLen + if (uStrLen > DATA_SIZE_ASHMEM_TRANSFER_LIMIT) { + ZLOGE("string length:%{public}zu, exceeds the maximum limit.", uStrLen); + return E_ERROR; + } + int32_t strLen = static_cast(uStrLen); + size += strLen; } if (size > DATA_SIZE_ASHMEM_TRANSFER_LIMIT) { ZLOGE("Data to write into ashmem is %{public}d bytes, over 10M.", size); return E_ERROR; } if (size > DATA_SIZE_IPC_TRANSFER_LIMIT) { - ZLOGD("Data size is over 200k, transfer it by the shared memory"); + ZLOGD_MACRO("Data size is over 200k, transfer it by the shared memory"); if (RdbObserverProxy::CreateAshmem(changeNode) != E_OK) { ZLOGE("failed to create ashmem."); return E_ERROR; @@ -128,7 +157,7 @@ int RdbObserverProxy::PrepareRdbChangeNodeData(RdbChangeNode &changeNode) // clear original data spot changeNode.data_.clear(); changeNode.isSharedMemory_ = true; - ZLOGD("Preparation done. Data size: %{public}d", changeNode.size_); + ZLOGD_MACRO("Preparation done. Data size: %{public}d", changeNode.size_); } return E_OK; } diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_share_obs_proxy.h b/datamgr_service/services/distributeddataservice/service/data_share/data_share_obs_proxy.h index 42a3f1065730051c965b9239ce0d66c1074cb5df..c6726d591ea9f2488c2c820995ea5dc0542c68b8 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_share_obs_proxy.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_share_obs_proxy.h @@ -30,7 +30,7 @@ public: private: int PrepareRdbChangeNodeData(RdbChangeNode &changeNode); int CreateAshmem(RdbChangeNode &changeNode); - int WriteAshmem(RdbChangeNode &changeNode, void *data, int len, int &offset); + int WriteAshmem(RdbChangeNode &changeNode, void *data, int32_t len, int32_t &offset); int SerializeDataIntoAshmem(RdbChangeNode &changeNode); static inline BrokerDelegator delegator_; }; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_share_profile_config.cpp b/datamgr_service/services/distributeddataservice/service/data_share/data_share_profile_config.cpp index 302fbebd35d85fd3138c2ce92f6327f1b1581935..ffff28420437b16215f25145e9ad89a5e9915fdd 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_share_profile_config.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_share_profile_config.cpp @@ -28,6 +28,7 @@ #include "log_print.h" #include "uri_utils.h" #include "utils/anonymous.h" +#include "log_debug.h" namespace OHOS { namespace DataShare { @@ -67,6 +68,22 @@ bool LaunchInfo::Unmarshal(const json &node) return true; } +bool AllowList::Marshal(json &node) const +{ + SetValue(node[GET_NAME(appIdentifier)], appIdentifier); + SetValue(node[GET_NAME(onlyMain)], onlyMain); + return true; +} + +bool AllowList::Unmarshal(const json &node) +{ + // when onlyMain is invalid, do not get appIdentifier, or if appIdentifier matched, onlyMain may not be expected + if (GetValue(node, GET_NAME(onlyMain), onlyMain)) { + GetValue(node, GET_NAME(appIdentifier), appIdentifier); + } + return true; +} + bool ProfileInfo::Marshal(json &node) const { SetValue(node[GET_NAME(tableConfig)], tableConfig); @@ -75,6 +92,7 @@ bool ProfileInfo::Marshal(json &node) const SetValue(node[GET_NAME(scope)], scope); SetValue(node[GET_NAME(type)], type); SetValue(node[GET_NAME(launchInfos)], launchInfos); + SetValue(node[GET_NAME(allowLists)], allowLists); SetValue(node[GET_NAME(storeMetaDataFromUri)], storeMetaDataFromUri); SetValue(node[GET_NAME(launchForCleanData)], launchForCleanData); SetValue(node[GET_NAME(backup)], backup); @@ -89,6 +107,7 @@ bool ProfileInfo::Unmarshal(const json &node) GetValue(node, GET_NAME(scope), scope); GetValue(node, GET_NAME(type), type); GetValue(node, GET_NAME(launchInfos), launchInfos); + GetValue(node, GET_NAME(allowLists), allowLists); GetValue(node, GET_NAME(storeMetaDataFromUri), storeMetaDataFromUri); GetValue(node, GET_NAME(launchForCleanData), launchForCleanData); GetValue(node, GET_NAME(backup), backup); @@ -180,7 +199,7 @@ std::string DataShareProfileConfig::GetResFromResMgr( std::string profileName = resName.substr(pos + PROFILE_PREFIX_LEN); // hap is compressed status, get file content. if (!hapPath.empty()) { - ZLOGD("compressed status."); + ZLOGD_MACRO("compressed status."); std::unique_ptr fileContent = nullptr; size_t len = 0; RState ret = resMgr.GetProfileDataByName(profileName.c_str(), len, fileContent); diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_share_profile_config.h b/datamgr_service/services/distributeddataservice/service/data_share/data_share_profile_config.h index 9fc6df898af97bb4db84fbae61b63d2e535fb641..781cd5f348dbf2c3a5216d1aed336b841e947265 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_share_profile_config.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_share_profile_config.h @@ -43,6 +43,14 @@ struct LaunchInfo final : public DistributedData::Serializable { bool Unmarshal(const json &node) override; }; +// List of applications that can access shared data +struct AllowList final : public DistributedData::Serializable { + std::string appIdentifier; + bool onlyMain = false; + bool Marshal(json &node) const override; + bool Unmarshal(const json &node) override; +}; + struct ProfileInfo : public DistributedData::Serializable { std::vector tableConfig; bool isSilentProxyEnable = true; @@ -53,6 +61,7 @@ struct ProfileInfo : public DistributedData::Serializable { std::string backup; std::string extUri; std::vector launchInfos; + std::vector allowLists; bool storeMetaDataFromUri = false; bool launchForCleanData = false; bool Marshal(json &node) const override; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.cpp b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.cpp index 3c0d6854bf0b80f5f02f26635ab38edb09e61a90..f6b886f721400b14ec2765ba0aed0a8d66715ff2 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.cpp @@ -20,7 +20,6 @@ #include #include -#include "accesstoken_kit.h" #include "account/account_delegate.h" #include "app_connect_manager.h" #include "common_event_manager.h" @@ -38,6 +37,8 @@ #include "dump/dump_manager.h" #include "extension_ability_manager.h" #include "hap_token_info.h" +#include "hiview_adapter.h" +#include "hiview_fault_adapter.h" #include "if_system_ability_manager.h" #include "ipc_skeleton.h" #include "iservice_registry.h" @@ -56,6 +57,7 @@ #include "template_data.h" #include "utils/anonymous.h" #include "xcollie.h" +#include "log_debug.h" namespace OHOS::DataShare { using FeatureSystem = DistributedData::FeatureSystem; @@ -100,17 +102,24 @@ DataShareServiceImpl::Factory::~Factory() {} std::pair DataShareServiceImpl::InsertEx(const std::string &uri, const std::string &extUri, const DataShareValuesBucket &valuesBucket) { - XCollie xcollie(__FUNCTION__, HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_RECOVERY); + std::string func = __FUNCTION__; + XCollie xcollie(func, HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_RECOVERY); if (GetSilentProxyStatus(uri, false) != E_OK) { ZLOGW("silent proxy disable, %{public}s", URIUtils::Anonymous(uri).c_str()); return std::make_pair(ERROR, 0); } - auto callBack = [&uri, &valuesBucket, this](ProviderInfo &providerInfo, DistributedData::StoreMetaData &metaData, + auto callingTokenId = IPCSkeleton::GetCallingTokenID(); + auto callBack = [&uri, &valuesBucket, this, &callingTokenId, &func](ProviderInfo &providerInfo, + DistributedData::StoreMetaData &metaData, std::shared_ptr dbDelegate) -> std::pair { + RdbTimeCostInfo rdbTimeCostInfo(providerInfo.bundleName, providerInfo.moduleName, providerInfo.storeName, + func, callingTokenId); auto [errCode, ret] = dbDelegate->InsertEx(providerInfo.tableName, valuesBucket); if (errCode == E_OK && ret > 0) { NotifyChange(uri); - RdbSubscriberManager::GetInstance().Emit(uri, providerInfo.currentUserId, metaData); + RdbSubscriberManager::GetInstance().Emit(uri, providerInfo.visitedUserId, metaData); + } else { + ReportExcuteFault(callingTokenId, providerInfo, errCode, func); } return std::make_pair(errCode, ret); }; @@ -140,48 +149,62 @@ bool DataShareServiceImpl::NotifyChange(const std::string &uri) std::pair DataShareServiceImpl::UpdateEx(const std::string &uri, const std::string &extUri, const DataSharePredicates &predicate, const DataShareValuesBucket &valuesBucket) { - XCollie xcollie(__FUNCTION__, HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_RECOVERY); + std::string func = __FUNCTION__; + XCollie xcollie(func, HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_RECOVERY); if (GetSilentProxyStatus(uri, false) != E_OK) { ZLOGW("silent proxy disable, %{public}s", URIUtils::Anonymous(uri).c_str()); return std::make_pair(ERROR, 0); } - auto callBack = [&uri, &predicate, &valuesBucket, this](ProviderInfo &providerInfo, + auto callingTokenId = IPCSkeleton::GetCallingTokenID(); + auto callBack = [&uri, &predicate, &valuesBucket, this, &callingTokenId, &func](ProviderInfo &providerInfo, DistributedData::StoreMetaData &metaData, std::shared_ptr dbDelegate) -> std::pair { + RdbTimeCostInfo rdbTimeCostInfo(providerInfo.bundleName, providerInfo.moduleName, providerInfo.storeName, + func, callingTokenId); auto [errCode, ret] = dbDelegate->UpdateEx(providerInfo.tableName, predicate, valuesBucket); if (errCode == E_OK && ret > 0) { NotifyChange(uri); - RdbSubscriberManager::GetInstance().Emit(uri, providerInfo.currentUserId, metaData); + RdbSubscriberManager::GetInstance().Emit(uri, providerInfo.visitedUserId, metaData); + } else { + ReportExcuteFault(callingTokenId, providerInfo, errCode, func); } return std::make_pair(errCode, ret); }; - return ExecuteEx(uri, extUri, IPCSkeleton::GetCallingTokenID(), false, callBack); + return ExecuteEx(uri, extUri, callingTokenId, false, callBack); } std::pair DataShareServiceImpl::DeleteEx(const std::string &uri, const std::string &extUri, const DataSharePredicates &predicate) { - XCollie xcollie(__FUNCTION__, HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_RECOVERY); + std::string func = __FUNCTION__; + XCollie xcollie(func, HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_RECOVERY); if (GetSilentProxyStatus(uri, false) != E_OK) { ZLOGW("silent proxy disable, %{public}s", URIUtils::Anonymous(uri).c_str()); return std::make_pair(ERROR, 0); } - auto callBack = [&uri, &predicate, this](ProviderInfo &providerInfo, DistributedData::StoreMetaData &metaData, + auto callingTokenId = IPCSkeleton::GetCallingTokenID(); + auto callBack = [&uri, &predicate, this, &callingTokenId, &func](ProviderInfo &providerInfo, + DistributedData::StoreMetaData &metaData, std::shared_ptr dbDelegate) -> std::pair { + RdbTimeCostInfo rdbTimeCostInfo(providerInfo.bundleName, providerInfo.moduleName, providerInfo.storeName, + func, callingTokenId); auto [errCode, ret] = dbDelegate->DeleteEx(providerInfo.tableName, predicate); if (errCode == E_OK && ret > 0) { NotifyChange(uri); - RdbSubscriberManager::GetInstance().Emit(uri, providerInfo.currentUserId, metaData); + RdbSubscriberManager::GetInstance().Emit(uri, providerInfo.visitedUserId, metaData); + } else { + ReportExcuteFault(callingTokenId, providerInfo, errCode, func); } return std::make_pair(errCode, ret); }; - return ExecuteEx(uri, extUri, IPCSkeleton::GetCallingTokenID(), false, callBack); + return ExecuteEx(uri, extUri, callingTokenId, false, callBack); } std::shared_ptr DataShareServiceImpl::Query(const std::string &uri, const std::string &extUri, const DataSharePredicates &predicates, const std::vector &columns, int &errCode) { - XCollie xcollie(std::string(LOG_TAG) + "::" + std::string(__FUNCTION__), + std::string func = __FUNCTION__; + XCollie xcollie(std::string(LOG_TAG) + "::" + func, HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_RECOVERY); if (GetSilentProxyStatus(uri, false) != E_OK) { ZLOGW("silent proxy disable, %{public}s", URIUtils::Anonymous(uri).c_str()); @@ -189,14 +212,21 @@ std::shared_ptr DataShareServiceImpl::Query(const std::strin } std::shared_ptr resultSet; auto callingPid = IPCSkeleton::GetCallingPid(); - auto callBack = [&uri, &predicates, &columns, &resultSet, &callingPid](ProviderInfo &providerInfo, - DistributedData::StoreMetaData &, std::shared_ptr dbDelegate) -> std::pair { + auto callingTokenId = IPCSkeleton::GetCallingTokenID(); + auto callBack = [&uri, &predicates, &columns, &resultSet, &callingPid, &callingTokenId, &func, this] + (ProviderInfo &providerInfo, DistributedData::StoreMetaData &, + std::shared_ptr dbDelegate) -> std::pair { + RdbTimeCostInfo rdbTimeCostInfo(providerInfo.bundleName, providerInfo.moduleName, providerInfo.storeName, + func, callingTokenId); auto [err, result] = dbDelegate->Query(providerInfo.tableName, - predicates, columns, callingPid); + predicates, columns, callingPid, callingTokenId); + if (err != E_OK) { + ReportExcuteFault(callingTokenId, providerInfo, err, func); + } resultSet = std::move(result); return std::make_pair(err, E_OK); }; - auto [errVal, status] = ExecuteEx(uri, extUri, IPCSkeleton::GetCallingTokenID(), true, callBack); + auto [errVal, status] = ExecuteEx(uri, extUri, callingTokenId, true, callBack); errCode = errVal; return resultSet; } @@ -258,6 +288,28 @@ bool DataShareServiceImpl::GetCallerBundleName(std::string &bundleName) return true; } +std::pair DataShareServiceImpl::GetCallerInfo( + std::string &bundleName, int32_t &appIndex) +{ + auto tokenId = IPCSkeleton::GetCallingTokenID(); + auto type = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId); + if (type == Security::AccessToken::TOKEN_NATIVE) { + return std::make_pair(true, type); + } + if (type != Security::AccessToken::TOKEN_HAP) { + return std::make_pair(false, type); + } + Security::AccessToken::HapTokenInfo tokenInfo; + auto result = Security::AccessToken::AccessTokenKit::GetHapTokenInfo(tokenId, tokenInfo); + if (result != Security::AccessToken::RET_SUCCESS) { + ZLOGE("token:0x%{public}x, result:%{public}d", tokenId, result); + return std::make_pair(false, type); + } + bundleName = tokenInfo.bundleName; + appIndex = tokenInfo.instIndex; + return std::make_pair(true, type); +} + std::vector DataShareServiceImpl::Publish(const Data &data, const std::string &bundleNameOfProvider) { std::vector results; @@ -507,8 +559,8 @@ enum DataShareKvStoreType : int32_t { int32_t DataShareServiceImpl::OnBind(const BindInfo &binderInfo) { binderInfo_ = binderInfo; - const std::string accountId = DistributedKv::AccountDelegate::GetInstance()->GetCurrentAccountId(); - const auto userId = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(binderInfo.selfTokenId); + const std::string accountId = AccountDelegate::GetInstance()->GetCurrentAccountId(); + const auto userId = AccountDelegate::GetInstance()->GetUserByToken(binderInfo.selfTokenId); DistributedData::StoreMetaData saveMeta; saveMeta.appType = "default"; saveMeta.storeId = "data_share_data_"; @@ -529,6 +581,7 @@ int32_t DataShareServiceImpl::OnBind(const BindInfo &binderInfo) SchedulerManager::GetInstance().SetExecutorPool(binderInfo.executors); ExtensionAbilityManager::GetInstance().SetExecutorPool(binderInfo.executors); DBDelegate::SetExecutorPool(binderInfo.executors); + HiViewAdapter::GetInstance().SetThreadPool(binderInfo.executors); SubscribeCommonEvent(); SubscribeTimeChanged(); SubscribeChange(); @@ -570,7 +623,6 @@ void DataShareServiceImpl::SaveLaunchInfo(const std::string &bundleName, const s if (profileInfos.empty()) { return; } - std::map maps; for (auto &[uri, value] : profileInfos) { if (uri.find(EXT_URI_SCHEMA) == std::string::npos) { continue; @@ -682,8 +734,8 @@ int32_t DataShareServiceImpl::OnAppExit(pid_t uid, pid_t pid, uint32_t tokenId, { ZLOGI("AppExit uid=%{public}d, pid=%{public}d, tokenId=0x%{public}x, bundleName=%{public}s", uid, pid, tokenId, bundleName.c_str()); - RdbSubscriberManager::GetInstance().Delete(tokenId); - PublishedDataSubscriberManager::GetInstance().Delete(tokenId); + RdbSubscriberManager::GetInstance().Delete(tokenId, pid); + PublishedDataSubscriberManager::GetInstance().Delete(tokenId, pid); return E_OK; } @@ -730,7 +782,7 @@ int32_t DataShareServiceImpl::OnAppUpdate(const std::string &bundleName, int32_t void DataShareServiceImpl::NotifyObserver(const std::string &uri) { - ZLOGD("%{private}s try notified", uri.c_str()); + ZLOGD_MACRO("%{private}s try notified", uri.c_str()); auto context = std::make_shared(uri); if (!GetCallerBundleName(context->callerBundleName)) { ZLOGE("get bundleName error, %{private}s", uri.c_str()); @@ -745,7 +797,7 @@ void DataShareServiceImpl::NotifyObserver(const std::string &uri) bool DataShareServiceImpl::SubscribeTimeChanged() { - ZLOGD("start"); + ZLOGD_MACRO("start"); EventFwk::MatchingSkills matchingSkills; matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_TIME_CHANGED); matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_TIMEZONE_CHANGED); @@ -838,7 +890,7 @@ int32_t DataShareServiceImpl::GetSilentProxyStatus(const std::string &uri, bool return errCode; } } - int32_t currentUserId = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(callerTokenId); + int32_t currentUserId = AccountDelegate::GetInstance()->GetUserByToken(callerTokenId); UriInfo uriInfo; if (!URIUtils::GetInfoFromURI(uri, uriInfo)) { return E_OK; @@ -873,6 +925,11 @@ int32_t DataShareServiceImpl::RegisterObserver(const std::string &uri, ZLOGE("ProviderInfo failed! token:0x%{public}x,ret:%{public}d,uri:%{public}s", callerTokenId, errCode, URIUtils::Anonymous(providerInfo.uri).c_str()); } + if (!CheckAllowList(providerInfo.currentUserId, callerTokenId, providerInfo.allowLists)) { + ZLOGE("CheckAllowList failed, permission denied! token:0x%{public}x, uri:%{public}s", + callerTokenId, URIUtils::Anonymous(providerInfo.uri).c_str()); + return ERROR; + } if (!providerInfo.allowEmptyPermission && providerInfo.readPermission.empty()) { ZLOGE("reject permission, tokenId:0x%{public}x, uri:%{public}s", callerTokenId, URIUtils::Anonymous(uri).c_str()); @@ -907,6 +964,11 @@ int32_t DataShareServiceImpl::UnregisterObserver(const std::string &uri, ZLOGE("ProviderInfo failed! token:0x%{public}x,ret:%{public}d,uri:%{public}s", callerTokenId, errCode, URIUtils::Anonymous(providerInfo.uri).c_str()); } + if (!CheckAllowList(providerInfo.currentUserId, callerTokenId, providerInfo.allowLists)) { + ZLOGE("CheckAllowList failed, permission denied! token:0x%{public}x, uri:%{public}s", + callerTokenId, URIUtils::Anonymous(providerInfo.uri).c_str()); + return ERROR; + } if (!providerInfo.allowEmptyPermission && providerInfo.readPermission.empty()) { ZLOGE("reject permission, tokenId:0x%{public}x, uri:%{public}s", callerTokenId, URIUtils::Anonymous(uri).c_str()); @@ -929,18 +991,43 @@ int32_t DataShareServiceImpl::UnregisterObserver(const std::string &uri, return obsMgrClient->UnregisterObserver(Uri(uri), obServer); } +bool DataShareServiceImpl::VerifyAcrossAccountsPermission(int32_t currentUserId, int32_t visitedUserId, + const std::string &acrossAccountsPermission, uint32_t callerTokenId) +{ + // if it's SA, or visit itself, no need to verify permission + if (currentUserId == 0 || currentUserId == visitedUserId) { + return true; + } + return PermitDelegate::VerifyPermission(acrossAccountsPermission, callerTokenId); +} + std::pair DataShareServiceImpl::ExecuteEx(const std::string &uri, const std::string &extUri, const int32_t tokenId, bool isRead, ExecuteCallbackEx callback) { DataProviderConfig providerConfig(uri, tokenId); auto [errCode, providerInfo] = providerConfig.GetProviderInfo(); if (errCode != E_OK) { - ZLOGE("Provider failed! token:0x%{public}x,ret:%{public}d,uri:%{public}s", tokenId, - errCode, URIUtils::Anonymous(providerInfo.uri).c_str()); + ZLOGE("Provider failed! token:0x%{public}x,ret:%{public}d,uri:%{public}s,visitedUserId:%{public}d", tokenId, + errCode, URIUtils::Anonymous(providerInfo.uri).c_str(), providerInfo.visitedUserId); RADAR_REPORT(__FUNCTION__, RadarReporter::SILENT_ACCESS, RadarReporter::PROXY_GET_SUPPLIER, RadarReporter::FAILED, RadarReporter::ERROR_CODE, RadarReporter::SUPPLIER_ERROR); return std::make_pair(errCode, 0); } + // when HAP interacts across users, it needs to check across users permission + if (!VerifyAcrossAccountsPermission(providerInfo.currentUserId, providerInfo.visitedUserId, + providerInfo.acrossAccountsPermission, tokenId)) { + ZLOGE("Across accounts permission denied! token:0x%{public}x, uri:%{public}s, current user:%{public}d," + "visited user:%{public}d", tokenId, URIUtils::Anonymous(providerInfo.uri).c_str(), + providerInfo.currentUserId, providerInfo.visitedUserId); + RADAR_REPORT(__FUNCTION__, RadarReporter::SILENT_ACCESS, RadarReporter::PROXY_PERMISSION, + RadarReporter::FAILED, RadarReporter::ERROR_CODE, RadarReporter::PERMISSION_DENIED_ERROR); + return std::make_pair(ERROR_PERMISSION_DENIED, 0); + } + if (!CheckAllowList(providerInfo.currentUserId, tokenId, providerInfo.allowLists)) { + ZLOGE("CheckAllowList failed, permission denied! token:0x%{public}x, uri:%{public}s", + tokenId, URIUtils::Anonymous(providerInfo.uri).c_str()); + return std::make_pair(ERROR_PERMISSION_DENIED, 0); + } std::string permission = isRead ? providerInfo.readPermission : providerInfo.writePermission; if (!permission.empty() && !PermitDelegate::VerifyPermission(permission, tokenId)) { ZLOGE("Permission denied! token:0x%{public}x, permission:%{public}s, uri:%{public}s", @@ -955,8 +1042,8 @@ std::pair DataShareServiceImpl::ExecuteEx(const std::string &u extensionUri = providerInfo.extensionUri; } DataShareDbConfig::DbConfig config {providerInfo.uri, extensionUri, providerInfo.bundleName, - providerInfo.storeName, providerInfo.backup, - providerInfo.singleton ? 0 : providerInfo.currentUserId, providerInfo.appIndex, providerInfo.hasExtension}; + providerInfo.storeName, providerInfo.backup, providerInfo.singleton ? 0 : providerInfo.visitedUserId, + providerInfo.appIndex, providerInfo.hasExtension}; auto [code, metaData, dbDelegate] = dbConfig.GetDbConfig(config); if (code != E_OK) { ZLOGE("Get dbConfig fail,bundleName:%{public}s,tableName:%{public}s,tokenId:0x%{public}x, uri:%{public}s", @@ -967,6 +1054,43 @@ std::pair DataShareServiceImpl::ExecuteEx(const std::string &u return callback(providerInfo, metaData, dbDelegate); } +bool DataShareServiceImpl::CheckAllowList(const uint32_t ¤tUserId, const uint32_t &callerTokenId, + const std::vector &allowLists) +{ + if (allowLists.empty()) { + return true; + } + std::string callerBundleName; + int32_t callerAppIndex; + auto [success, type] = GetCallerInfo(callerBundleName, callerAppIndex); + if (!success) { + ZLOGE("Get caller info failed, token:0x%{public}x", callerTokenId); + return false; + } + // SA calling + if (type == Security::AccessToken::TOKEN_NATIVE) { + return true; + } + + auto [ret, callerAppIdentifier] = BundleMgrProxy::GetInstance()->GetCallerAppIdentifier( + callerBundleName, currentUserId); + if (ret != 0) { + ZLOGE("Get caller appIdentifier failed, callerBundleName is %{public}s", callerBundleName.c_str()); + return false; + } + + for (auto const& allowList : allowLists) { + if (callerAppIdentifier == allowList.appIdentifier) { + if (callerAppIndex != 0 && allowList.onlyMain) { + ZLOGE("Provider only allow main application!"); + return false; + } + return true; + } + } + return false; +} + int32_t DataShareServiceImpl::GetBMSAndMetaDataStatus(const std::string &uri, const int32_t tokenId) { DataProviderConfig calledConfig(uri, tokenId); @@ -986,7 +1110,7 @@ int32_t DataShareServiceImpl::GetBMSAndMetaDataStatus(const std::string &uri, co dbArg.uri = calledInfo.uri; dbArg.bundleName = calledInfo.bundleName; dbArg.storeName = calledInfo.storeName; - dbArg.userId = calledInfo.singleton ? 0 : calledInfo.currentUserId; + dbArg.userId = calledInfo.singleton ? 0 : calledInfo.visitedUserId; dbArg.hasExtension = calledInfo.hasExtension; dbArg.appIndex = calledInfo.appIndex; auto [code, metaData] = dbConfig.GetMetaData(dbArg); @@ -1001,6 +1125,11 @@ int32_t DataShareServiceImpl::GetBMSAndMetaDataStatus(const std::string &uri, co void DataShareServiceImpl::InitSubEvent() { + static std::atomic alreadySubscribe = false; + bool except = false; + if (!alreadySubscribe.compare_exchange_strong(except, true)) { + return; + } EventFwk::MatchingSkills matchingSkills; matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_BUNDLE_SCAN_FINISHED); EventFwk::CommonEventSubscribeInfo subscribeInfo(matchingSkills); @@ -1008,6 +1137,7 @@ void DataShareServiceImpl::InitSubEvent() auto sysEventSubscriber = std::make_shared(subscribeInfo); if (!EventFwk::CommonEventManager::SubscribeCommonEvent(sysEventSubscriber)) { ZLOGE("Subscribe sys event failed."); + alreadySubscribe = false; } if (BundleMgrProxy::GetInstance()->CheckBMS() != nullptr) { sysEventSubscriber->OnBMSReady(); @@ -1019,17 +1149,22 @@ int32_t DataShareServiceImpl::OnUserChange(uint32_t code, const std::string &use ZLOGI("code:%{public}d, user:%{public}s, account:%{public}s", code, user.c_str(), Anonymous::Change(account).c_str()); switch (code) { - case static_cast(DistributedKv::AccountStatus::DEVICE_ACCOUNT_DELETE): - case static_cast(DistributedKv::AccountStatus::DEVICE_ACCOUNT_STOPPED): { + case static_cast(AccountStatus::DEVICE_ACCOUNT_DELETE): + case static_cast(AccountStatus::DEVICE_ACCOUNT_STOPPED): { std::vector users; - DistributedKv::AccountDelegate::GetInstance()->QueryUsers(users); + AccountDelegate::GetInstance()->QueryUsers(users); std::set userIds(users.begin(), users.end()); + userIds.insert(0); DBDelegate::Close([&userIds](const std::string &userId) { - return userIds.count(atoi(userId.c_str())) == 0; + if (userIds.count(atoi(userId.c_str())) == 0) { + ZLOGW("Illegal use of database by user %{public}s", userId.c_str()); + return true; + } + return false; }); break; } - case static_cast(DistributedKv::AccountStatus::DEVICE_ACCOUNT_STOPPING): + case static_cast(AccountStatus::DEVICE_ACCOUNT_STOPPING): DBDelegate::Close([&user](const std::string &userId) { return user == userId; }); @@ -1039,4 +1174,13 @@ int32_t DataShareServiceImpl::OnUserChange(uint32_t code, const std::string &use } return E_OK; } + +void DataShareServiceImpl::ReportExcuteFault(uint32_t callingTokenId, DataProviderConfig::ProviderInfo &providerInfo, + int32_t errCode, std::string &func) +{ + std::string appendix = "callingName:" + HiViewFaultAdapter::GetCallingName(callingTokenId).first; + DataShareFaultInfo faultInfo = {CURD_FAILED, providerInfo.bundleName, providerInfo.moduleName, + providerInfo.storeName, func, errCode, appendix}; + HiViewFaultAdapter::ReportDataFault(faultInfo); +} } // namespace OHOS::DataShare diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.h b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.h index 2fcc6420133f2740eaa0292310fddd2be391ae90..b2d99087c5fe1ca0be94536638358a47e07af873 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.h @@ -20,6 +20,7 @@ #include #include +#include "accesstoken_kit.h" #include "bundle_mgr_proxy.h" #include "common_event_subscribe_info.h" #include "common_event_subscriber.h" @@ -121,6 +122,7 @@ private: bool GetCallerBundleName(std::string &bundleName); std::pair ExecuteEx(const std::string &uri, const std::string &extUri, const int32_t tokenId, bool isRead, ExecuteCallbackEx callback); + std::pair GetCallerInfo(std::string &bundleName, int32_t &appIndex); int32_t GetBMSAndMetaDataStatus(const std::string &uri, const int32_t tokenId); void SubscribeCommonEvent(); static void InitSubEvent(); @@ -131,6 +133,12 @@ private: const std::string &deviceId); static DistributedData::StoreMetaData MakeMetaData(const std::string &bundleName, const std::string &userId, const std::string &deviceId, const std::string storeId = ""); + bool VerifyAcrossAccountsPermission(int32_t currentUserId, int32_t visitedUserId, + const std::string &acrossAccountsPermission, uint32_t callerTokenId); + void ReportExcuteFault(uint32_t callingTokenId, DataProviderConfig::ProviderInfo &providerInfo, + int32_t errCode, std::string &func); + bool CheckAllowList(const uint32_t ¤tUserId, const uint32_t &callerTokenId, + const std::vector &allowLists); static Factory factory_; static constexpr int32_t ERROR = -1; static constexpr int32_t ERROR_PERMISSION_DENIED = -2; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_stub.cpp b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_stub.cpp index fca1209d0bfce9bfe782c2a2d5be0029765dbbf4..bb44ff6c85873247998fad33f7937a9ab5ba0b9f 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_stub.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_stub.cpp @@ -19,6 +19,8 @@ #include #include "data_share_obs_proxy.h" +#include "hiview_adapter.h" +#include "hiview_fault_adapter.h" #include "ipc_skeleton.h" #include "ishared_result_set.h" #include "itypes_util.h" @@ -339,15 +341,19 @@ int DataShareServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, Me } int res = -1; if (code < DATA_SHARE_SERVICE_CMD_MAX) { + auto callingTokenid = IPCSkeleton::GetCallingTokenID(); auto start = std::chrono::steady_clock::now(); res = (this->*HANDLERS[code])(data, reply); auto finish = std::chrono::steady_clock::now(); auto duration = std::chrono::duration_cast(finish - start); + CallerInfo callerInfo(callingTokenid, IPCSkeleton::GetCallingUid(), callingPid, duration.count(), code); if (duration >= TIME_THRESHOLD) { int64_t milliseconds = duration.count(); ZLOGW("over time, code:%{public}u callingPid:%{public}d, cost:%{public}" PRIi64 "ms", code, callingPid, milliseconds); + callerInfo.isSlowRequest = true; } + HiViewAdapter::GetInstance().ReportDataStatistic(callerInfo); } return res; } diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_share_silent_config.cpp b/datamgr_service/services/distributeddataservice/service/data_share/data_share_silent_config.cpp index dba45026414108fa1139fcd5d8dda3b885ae8a0c..18b221acb602f048b5c97bae1838ac09acdce8f1 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_share_silent_config.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_share_silent_config.cpp @@ -27,7 +27,7 @@ #include "utils/anonymous.h" namespace OHOS::DataShare { -const std::string ALL_URI = "*"; +const char *ALL_URI = "*"; bool DataShareSilentConfig::IsSilentProxyEnable(uint32_t callerTokenId, int32_t currentUserId, const std::string &calledBundleName, const std::string &originUriStr) { @@ -56,7 +56,7 @@ bool DataShareSilentConfig::EnableSilentProxy(uint32_t callerTokenId, const std: URIUtils::FormatUri(uri); if (uri.empty()) { enableSilentUris_.Erase(callerTokenId); - uri = ALL_URI; + uri = std::string(ALL_URI); } ZLOGI("Enable silent proxy, callerTokenId:%{public}u, enable:%{public}d, uri:%{public}s", callerTokenId, enable, DistributedData::Anonymous::Change(uri).c_str()); @@ -80,7 +80,7 @@ int DataShareSilentConfig::CheckExistEnableSilentUris(uint32_t callerTokenId, status = E_OK; return true; } - iter = uris.find(ALL_URI); + iter = uris.find(std::string(ALL_URI)); if (iter != uris.end()) { isEnable = iter->second; status = E_OK; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_share_types_util.cpp b/datamgr_service/services/distributeddataservice/service/data_share/data_share_types_util.cpp index 32f850f1d0164e6559bb49eea6504edb2ca3ea1c..78fd79b633e7f22a4dfc57bec36261ed6e1a86b6 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_share_types_util.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_share_types_util.cpp @@ -14,6 +14,7 @@ */ #define LOG_TAG "DataShareTypesUtil" #include "data_share_types_util.h" +#include "log_debug.h" #include "log_print.h" namespace OHOS::ITypesUtil { @@ -21,7 +22,7 @@ using namespace OHOS::DataShare; template<> bool Unmarshalling(Predicates &predicates, MessageParcel &parcel) { - ZLOGD("Unmarshalling DataSharePredicates Start"); + ZLOGD_MACRO("Unmarshalling DataSharePredicates Start"); std::vector operations {}; std::string whereClause = ""; std::vector whereArgs; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/dfx/hiview_adapter.cpp b/datamgr_service/services/distributeddataservice/service/data_share/dfx/hiview_adapter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6b1216b3619eb9b94fdfd76cd12be1088fc4d40d --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/data_share/dfx/hiview_adapter.cpp @@ -0,0 +1,131 @@ +/* +* Copyright (c) 2025 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 "HiViewAdapter" + +#include "hiview_adapter.h" + +#include +#include "hiview_fault_adapter.h" +#include "log_print.h" + +namespace OHOS { +namespace DataShare { +namespace { +constexpr char DOMAIN[] = "DISTDATAMGR"; +constexpr const char *EVENT_NAME = "DATA_SHARE_STATISTIC"; +constexpr const uint32_t MAX_COLLECT_COUNT = 20; +constexpr const uint32_t MIN_CALL_COUNT = 1000; +constexpr const size_t PARAMS_SIZE = 7; +} + +using namespace std::chrono; + +HiViewAdapter& HiViewAdapter::GetInstance() +{ + static HiViewAdapter instance; + return instance; +} + +void HiViewAdapter::ReportDataStatistic(const CallerInfo &callerInfo) +{ + if (executors_ == nullptr) { + ZLOGE("executors is nullptr, collect failed"); + return; + } + + callers_.Compute(callerInfo.callerTokenId, [&callerInfo, this](const uint64_t &key, CallerTotalInfo &value) { + if (value.totalCount == 0) { + value.callerUid = callerInfo.callerUid; + std::string callingName = HiViewFaultAdapter::GetCallingName(key).first; + value.callerName = callingName.empty() ? std::to_string(callerInfo.callerPid) : callingName; + } + value.totalCount += 1; + value.maxCostTime = std::max(callerInfo.costTime, value.maxCostTime); + value.totalCostTime += callerInfo.costTime; + value.slowRequestCount = value.slowRequestCount + (callerInfo.isSlowRequest ? 1 : 0); + auto it = funcIdMap_.find(callerInfo.funcId); + if (it != funcIdMap_.end()) { + auto funcName = it->second; + value.funcCounts[funcName] = value.funcCounts[funcName] + 1; + } + return true; + }); +} + +void HiViewAdapter::InvokeData() +{ + uint32_t mapSize = callers_.Size(); + if (mapSize == 0) { return; } + std::vector callerTotalInfos; + GetCallerTotalInfoVec(callerTotalInfos); + uint32_t count = std::min(static_cast(callerTotalInfos.size()), MAX_COLLECT_COUNT); + if (count == 0) { return; } + int64_t callerUids[count]; + char* callerNames[count]; + int64_t totalCounts[count]; + int64_t slowRequestCounts[count]; + int64_t maxCostTimes[count]; + int64_t totalCostTimes[count]; + char* funcCounts[count]; + for (uint32_t i = 0; i < count; i++) { + CallerTotalInfo &callerTotalInfo = callerTotalInfos[i]; + callerUids[i] = callerTotalInfo.callerUid; + callerNames[i] = const_cast(callerTotalInfo.callerName.c_str()); + totalCounts[i] = callerTotalInfo.totalCount; + slowRequestCounts[i] = callerTotalInfo.slowRequestCount; + maxCostTimes[i] = callerTotalInfo.maxCostTime; + totalCostTimes[i] = callerTotalInfo.totalCostTime; + std::string funcCount = "{"; + for (const auto &it : callerTotalInfo.funcCounts) { + funcCount += it.first + ":" + std::to_string(it.second) + ","; + } + funcCount = funcCount.substr(0, funcCount.size() - 1) + "}"; + funcCounts[i] = const_cast(funcCount.c_str()); + } + + HiSysEventParam callerUid = { .name = "COLLIE_UID", .t = HISYSEVENT_INT64_ARRAY, + .v = { .array = callerUids }, .arraySize = count }; + HiSysEventParam callerName = { .name = "CALLER_NAME", .t = HISYSEVENT_STRING_ARRAY, + .v = { .array = callerNames }, .arraySize = count }; + HiSysEventParam totalCount = { .name = "TOTAL_COUNT", .t = HISYSEVENT_INT64_ARRAY, + .v = { .array = totalCounts }, .arraySize = count }; + HiSysEventParam slowRequestCount = { .name = "SLOW_RQUEST_COUNT", .t = HISYSEVENT_INT64_ARRAY, + .v = { .array = slowRequestCounts }, .arraySize = count }; + HiSysEventParam maxCostTime = { .name = "MAX_COST_TIME", .t = HISYSEVENT_INT64_ARRAY, + .v = { .array = maxCostTimes }, .arraySize = count }; + HiSysEventParam totalCostTime = { .name = "TOTAL_COST_TIME", .t = HISYSEVENT_INT64_ARRAY, + .v = { .array = totalCostTimes }, .arraySize = count }; + HiSysEventParam funcCount = { .name = "FUNC_COUNTS", .t = HISYSEVENT_STRING_ARRAY, + .v = { .array = funcCounts }, .arraySize = count }; + HiSysEventParam params[] = {callerUid, callerName, totalCount, slowRequestCount, + maxCostTime, totalCostTime, funcCount}; + int res = OH_HiSysEvent_Write(DOMAIN, EVENT_NAME, HISYSEVENT_STATISTIC, params, PARAMS_SIZE); + ZLOGI("OH_HiSysEvent_Write, res = %{public}d", res); +} + +void HiViewAdapter::GetCallerTotalInfoVec(std::vector &callerTotalInfos) +{ + callers_.EraseIf([&callerTotalInfos](const uint64_t key, CallerTotalInfo &callerTotalInfo) { + if (callerTotalInfo.totalCount >= MIN_CALL_COUNT) + callerTotalInfos.push_back(callerTotalInfo); + return true; + }); + std::sort(callerTotalInfos.begin(), callerTotalInfos.end(), + [](const CallerTotalInfo &first, const CallerTotalInfo &second) { + return first.totalCount > second.totalCount; + }); +} +} // namespace DataShare +} // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/data_share/dfx/hiview_adapter.h b/datamgr_service/services/distributeddataservice/service/data_share/dfx/hiview_adapter.h new file mode 100644 index 0000000000000000000000000000000000000000..0b13a3bb017df3a761d049ee88c75c49d0c45ef3 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/data_share/dfx/hiview_adapter.h @@ -0,0 +1,69 @@ +/* +* Copyright (c) 2025 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 DATASHARESERVICE_HIVIEW_ADAPTER_H +#define DATASHARESERVICE_HIVIEW_ADAPTER_H + + +#include "hiview_base_adapter.h" +#include "concurrent_map.h" +#include "data_share_service_stub.h" +namespace OHOS { +namespace DataShare { +struct CallerInfo { + uint64_t callerTokenId = 0; + uint64_t callerUid = 0; + uint64_t callerPid = 0; + uint64_t costTime = 0; + bool isSlowRequest = false; + uint32_t funcId = 0; + + CallerInfo(uint64_t tokenId, uint64_t uid, uint64_t pid, uint64_t time, uint32_t id) + : callerTokenId(tokenId), callerUid(uid), callerPid(pid), costTime(time), funcId(id) + {} +}; + +struct CallerTotalInfo { + uint64_t callerUid = 0; + uint64_t totalCount = 0; + uint64_t slowRequestCount = 0; + uint64_t maxCostTime = 0; + uint64_t totalCostTime = 0; + std::string callerName; + std::map funcCounts; +}; + +class HiViewAdapter : public HiViewBaseAdapter { +public: + static HiViewAdapter &GetInstance(); + void InvokeData() override; + void ReportDataStatistic(const CallerInfo &callerInfo); + +private: + ConcurrentMap callers_; + std::map funcIdMap_ = { + {static_cast(IDataShareService::DATA_SHARE_SERVICE_CMD_QUERY), "OnQuery"}, + {static_cast(IDataShareService::DATA_SHARE_SERVICE_CMD_INSERTEX), "OnInsertEx"}, + {static_cast(IDataShareService::DATA_SHARE_SERVICE_CMD_DELETEEX), "OnDeleteEx"}, + {static_cast(IDataShareService::DATA_SHARE_SERVICE_CMD_UPDATEEX), "OnUpdateEx"}, + {static_cast(IDataShareService::DATA_SHARE_SERVICE_CMD_NOTIFY_OBSERVERS), "OnNotifyObserver"}, + {static_cast(IDataShareService::DATA_SHARE_SERVICE_CMD_GET_SILENT_PROXY_STATUS), + "OnGetSilentProxyStatus"} + }; + void GetCallerTotalInfoVec(std::vector &callerTotalInfos); +}; +} // namespace DataShare +} // namespace OHOS +#endif // DATASHARESERVICE_HIVIEW_ADAPTER_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/data_share/dfx/hiview_base_adapter.h b/datamgr_service/services/distributeddataservice/service/data_share/dfx/hiview_base_adapter.h new file mode 100644 index 0000000000000000000000000000000000000000..50a6eaa7b4996562b14d9714db1b701c723f51f6 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/data_share/dfx/hiview_base_adapter.h @@ -0,0 +1,56 @@ +/* +* Copyright (c) 2025 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 DATASHARESERVICE_HIVIEW_BASE_ADAPTER_H +#define DATASHARESERVICE_HIVIEW_BASE_ADAPTER_H + +#include + +#include "executor_pool.h" +#include "hisysevent_c.h" + +namespace OHOS { +namespace DataShare { + +class HiViewBaseAdapter { +public: + const int waitTime = 180 * 60; + std::shared_ptr executors_ = nullptr; + std::atomic running_ = false; + + void SetThreadPool(std::shared_ptr executors) + { + executors_ = executors; + StartTimerThread(); + } + + void StartTimerThread() + { + if (executors_ == nullptr) { + return; + } + if (running_.exchange(true)) { + return; + } + auto interval = std::chrono::seconds(waitTime); + auto fun = [this]() { InvokeData(); }; + executors_->Schedule(fun, interval); + } + + virtual void InvokeData() = 0; +}; +} +} +#endif // DATASHARESERVICE_HIVIEW_ADAPTER_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/data_share/dfx/hiview_fault_adapter.cpp b/datamgr_service/services/distributeddataservice/service/data_share/dfx/hiview_fault_adapter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..db04c7eb5ecad5012dce54aabe833ccfe50cf484 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/data_share/dfx/hiview_fault_adapter.cpp @@ -0,0 +1,102 @@ +/* +* Copyright (c) 2025 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 "HiViewFaultAdapter" + +#include "hiview_fault_adapter.h" + +#include +#include +#include "log_print.h" + +namespace OHOS { +namespace DataShare { +namespace { + constexpr char DOMAIN[] = "DISTDATAMGR"; + constexpr const char *EVENT_NAME = "DISTRIBUTED_DATA_SHARE_FAULT"; + constexpr const size_t PARAMS_SIZE = 8; + // digits for milliseconds + constexpr uint8_t MILLSECOND_DIGIT = 3; +} + +void HiViewFaultAdapter::ReportDataFault(const DataShareFaultInfo &faultInfo) +{ + auto now = std::chrono::system_clock::now(); + auto t = std::chrono::system_clock::to_time_t(now); + std::stringstream ss; + ss << std::put_time(std::localtime(&t), "%F %T"); + // get milliseconds + auto ms = std::chrono::duration_cast(now.time_since_epoch()) % 1000; + ss << '.' << std::setfill('0') << std::setw(MILLSECOND_DIGIT) << ms.count(); + auto time = ss.str(); + HiSysEventParam faultTime = { .name = "FAULT_TIME", .t = HISYSEVENT_STRING, + .v = { .s = const_cast(time.c_str()) }, .arraySize = 0 }; + HiSysEventParam faultType = { .name = "FAULT_TYPE", .t = HISYSEVENT_STRING, + .v = { .s = const_cast(faultInfo.faultType.c_str()) }, .arraySize = 0 }; + HiSysEventParam bundleName = { .name = "BUNDLE_NAME", .t = HISYSEVENT_STRING, + .v = { .s = const_cast(faultInfo.bundleName.c_str()) }, .arraySize = 0 }; + HiSysEventParam moduleName = { .name = "MODULE_NAME", .t = HISYSEVENT_STRING, + .v = { .s = const_cast(faultInfo.moduleName.c_str()) }, .arraySize = 0 }; + HiSysEventParam storeName = { .name = "STORE_NAME", .t = HISYSEVENT_STRING, + .v = { .s = const_cast(faultInfo.storeName.c_str()) }, .arraySize = 0 }; + HiSysEventParam businessType = { .name = "BUSINESS_TYPE", .t = HISYSEVENT_STRING, + .v = { .s = const_cast(faultInfo.businessType.c_str()) }, .arraySize = 0 }; + HiSysEventParam errorCode = { .name = "ERROR_CODE", .t = HISYSEVENT_INT32, + .v = { .i32 = faultInfo.errorCode }, .arraySize = 0 }; + HiSysEventParam appendix = { .name = "APPENDIX", .t = HISYSEVENT_STRING, + .v = { .s = const_cast(faultInfo.appendix.c_str()) }, .arraySize = 0 }; + HiSysEventParam params[] = { faultTime, faultType, bundleName, moduleName, + storeName, businessType, errorCode, appendix }; + int res = OH_HiSysEvent_Write(DOMAIN, EVENT_NAME, HISYSEVENT_FAULT, params, PARAMS_SIZE); + ZLOGI("OH_HiSysEvent_Write, res = %{public}d", res); +} + +std::pair HiViewFaultAdapter::GetCallingName(uint32_t callingTokenid) +{ + std::string callingName; + auto tokenType = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(callingTokenid); + int result = -1; + if (tokenType == Security::AccessToken::TOKEN_HAP) { + Security::AccessToken::HapTokenInfo tokenInfo; + result = Security::AccessToken::AccessTokenKit::GetHapTokenInfo(callingTokenid, tokenInfo); + if (result == Security::AccessToken::RET_SUCCESS) { + callingName = tokenInfo.bundleName; + } + } else if (tokenType == Security::AccessToken::TOKEN_NATIVE || tokenType == Security::AccessToken::TOKEN_SHELL) { + Security::AccessToken::NativeTokenInfo tokenInfo; + result = Security::AccessToken::AccessTokenKit::GetNativeTokenInfo(callingTokenid, tokenInfo); + if (result == Security::AccessToken::RET_SUCCESS) { + callingName = tokenInfo.processName; + } + } else { + ZLOGE("tokenType is invalid, tokenType:%{public}d, Tokenid:%{public}x", tokenType, callingTokenid); + } + return std::make_pair(callingName, result); +} + +RdbTimeCostInfo::~RdbTimeCostInfo() +{ + auto end = std::chrono::steady_clock::now(); + auto duration = std::chrono::duration_cast(end - start); + if (duration > TIME_OUT_MS) { + int64_t milliseconds = duration.count(); + std::string appendix = "callingName:" + HiViewFaultAdapter::GetCallingName(callingTokenId).first; + appendix += ",cost:" + std::to_string(milliseconds) + "ms"; + DataShareFaultInfo faultInfo{TIME_OUT, bundleName, moduleName, storeName, businessType, errorCode, appendix}; + HiViewFaultAdapter::ReportDataFault(faultInfo); + } +} +} +} \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/data_share/dfx/hiview_fault_adapter.h b/datamgr_service/services/distributeddataservice/service/data_share/dfx/hiview_fault_adapter.h new file mode 100644 index 0000000000000000000000000000000000000000..e7a33b273b3a4702cfef0c7f54ce66ef0ffc03e8 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/data_share/dfx/hiview_fault_adapter.h @@ -0,0 +1,66 @@ +/* +* Copyright (c) 2025 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 DATASHARESERVICE_HIVIEW_FAULT_ADAPTER_H +#define DATASHARESERVICE_HIVIEW_FAULT_ADAPTER_H + +#include +#include +#include +#include "accesstoken_kit.h" +#include "hisysevent_c.h" +namespace OHOS { +namespace DataShare { +struct DataShareFaultInfo { + std::string faultType; + std::string bundleName; + std::string moduleName; + std::string storeName; + std::string businessType; + int32_t errorCode; + std::string appendix; +}; + +struct RdbTimeCostInfo { + std::chrono::time_point start = std::chrono::steady_clock::now(); + std::string bundleName; + std::string moduleName; + std::string storeName; + std::string businessType; + int32_t errorCode = 0; + uint64_t callingTokenId; + + explicit RdbTimeCostInfo(const std::string &bundleName, const std::string &moduleName, + const std::string &storeName, const std::string &businessType, + uint64_t tokenId) : bundleName(bundleName), moduleName(moduleName), + storeName(storeName), businessType(businessType), callingTokenId(tokenId) + {} + ~RdbTimeCostInfo(); +}; + + +class HiViewFaultAdapter { +public: + static void ReportDataFault(const DataShareFaultInfo &faultInfo); + static std::pair GetCallingName(uint32_t callingTokenid); +}; + +inline const char* TIME_OUT = "TIME_OUT"; +inline const char* RESULTSET_FULL = "RESULTSET_FULL"; +inline const char* CURD_FAILED = "CURD_FAILED"; +inline const std::chrono::milliseconds TIME_OUT_MS = std::chrono::milliseconds(300); +} +} +#endif \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/data_share/strategies/general/load_config_common_strategy.cpp b/datamgr_service/services/distributeddataservice/service/data_share/strategies/general/load_config_common_strategy.cpp index f0ce98ceca2dc383076b6726044bb0e0c8aa7e5c..b8dece0fd2173572ea22fdba2f9e0bd8c833205f 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/strategies/general/load_config_common_strategy.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/strategies/general/load_config_common_strategy.cpp @@ -23,6 +23,7 @@ #include "uri_utils.h" namespace OHOS::DataShare { +using namespace OHOS::DistributedData; constexpr const char USER_PARAM[] = "user"; constexpr const char TOKEN_ID_PARAM[] = "srcToken"; constexpr const char DST_BUNDLE_NAME_PARAM[] = "dstBundleName"; @@ -31,7 +32,7 @@ bool LoadConfigCommonStrategy::operator()(std::shared_ptr context) if (context->callerTokenId == 0) { context->callerTokenId = IPCSkeleton::GetCallingTokenID(); } - context->currentUserId = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(context->callerTokenId); + context->currentUserId = AccountDelegate::GetInstance()->GetUserByToken(context->callerTokenId); if (!URIUtils::GetAppIndexFromProxyURI(context->uri, context->appIndex)) { return false; } diff --git a/datamgr_service/services/distributeddataservice/service/data_share/strategies/general/load_config_data_info_strategy.cpp b/datamgr_service/services/distributeddataservice/service/data_share/strategies/general/load_config_data_info_strategy.cpp index ee18ab8a769cf2faa5ac38cb1d4a1be58e7c336a..d5283e4d3a82bffd0cea72b2d3e3d5ab236f2e03 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/strategies/general/load_config_data_info_strategy.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/strategies/general/load_config_data_info_strategy.cpp @@ -66,6 +66,9 @@ bool LoadConfigNormalDataInfoStrategy::operator()(std::shared_ptr conte } context->calledSourceDir = metaData.dataDir; context->isEncryptDb = metaData.isEncrypt; + context->calledTokenId = metaData.tokenId; + context->calledStoreName = metaData.storeId; + context->haMode = metaData.haMode; if (context->isEncryptDb) { context->secretMetaKey = metaData.GetSecretKey(); } @@ -86,6 +89,9 @@ bool LoadConfigSingleDataInfoStrategy::operator()(std::shared_ptr conte } } context->calledSourceDir = metaData.dataDir; + context->calledTokenId = metaData.tokenId; + context->calledStoreName = metaData.storeId; + context->haMode = metaData.haMode; return true; } } // namespace OHOS::DataShare \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/data_share/strategies/rdb_notify_strategy.cpp b/datamgr_service/services/distributeddataservice/service/data_share/strategies/rdb_notify_strategy.cpp index 4502f6701b157541604d4d9a82ad85f355127110..95ca0ceba28026a55ec1659ca1849518053e6f24 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/strategies/rdb_notify_strategy.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/strategies/rdb_notify_strategy.cpp @@ -21,6 +21,7 @@ #include "general/load_config_from_bundle_info_strategy.h" #include "log_print.h" #include "utils/anonymous.h" +#include "log_debug.h" namespace OHOS::DataShare { bool RdbNotifyStrategy::Execute(std::shared_ptr context) @@ -35,7 +36,7 @@ bool RdbNotifyStrategy::Execute(std::shared_ptr context) return false; } if (context->callerBundleName != context->calledBundleName) { - ZLOGD("not your data, cannot notify, callerBundleName: %{public}s, calledBundleName: %{public}s", + ZLOGD_MACRO("not your data, cannot notify, callerBundleName: %{public}s, calledBundleName: %{public}s", context->callerBundleName.c_str(), context->calledBundleName.c_str()); return false; } diff --git a/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/published_data_subscriber_manager.cpp b/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/published_data_subscriber_manager.cpp index 4b4f62e6b58fc0d81dbda50da0683da7a9608480..3df3c0164fb2c95a87478b0ee6d52dc87aa4e710 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/published_data_subscriber_manager.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/published_data_subscriber_manager.cpp @@ -39,7 +39,8 @@ int PublishedDataSubscriberManager::Add( key, [&observer, &firstCallerTokenId, this](const PublishedDataKey &key, std::vector &value) { ZLOGI("add publish subscriber, uri %{public}s tokenId 0x%{public}x", DistributedData::Anonymous::Change(key.key).c_str(), firstCallerTokenId); - value.emplace_back(observer, firstCallerTokenId, IPCSkeleton::GetCallingTokenID()); + value.emplace_back(observer, firstCallerTokenId, IPCSkeleton::GetCallingTokenID(), + IPCSkeleton::GetCallingPid()); return true; }); return E_OK; @@ -64,13 +65,13 @@ int PublishedDataSubscriberManager::Delete(const PublishedDataKey &key, uint32_t return result ? E_OK : E_SUBSCRIBER_NOT_EXIST; } -void PublishedDataSubscriberManager::Delete(uint32_t callerTokenId) +void PublishedDataSubscriberManager::Delete(uint32_t callerTokenId, uint32_t callerPid) { - publishedDataCache_.EraseIf([&callerTokenId](const auto &key, std::vector &value) { + publishedDataCache_.EraseIf([&callerTokenId, &callerPid](const auto &key, std::vector &value) { for (auto it = value.begin(); it != value.end();) { - if (it->callerTokenId == callerTokenId) { - ZLOGI("erase start, uri is %{public}s, tokenId is 0x%{public}x", - DistributedData::Anonymous::Change(key.key).c_str(), callerTokenId); + if (it->callerTokenId == callerTokenId && it->callerPid == callerPid) { + ZLOGI("erase start, uri is %{public}s, tokenId is 0x%{public}x, pid is %{public}d", + DistributedData::Anonymous::Change(key.key).c_str(), callerTokenId, callerPid); it = value.erase(it); } else { it++; @@ -266,8 +267,8 @@ bool PublishedDataKey::operator!=(const PublishedDataKey &rhs) const } PublishedDataSubscriberManager::ObserverNode::ObserverNode(const sptr &observer, - uint32_t firstCallerTokenId, uint32_t callerTokenId) - : observer(observer), firstCallerTokenId(firstCallerTokenId), callerTokenId(callerTokenId) + uint32_t firstCallerTokenId, uint32_t callerTokenId, uint32_t callerPid) + : observer(observer), firstCallerTokenId(firstCallerTokenId), callerTokenId(callerTokenId), callerPid(callerPid) { } } // namespace OHOS::DataShare diff --git a/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/published_data_subscriber_manager.h b/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/published_data_subscriber_manager.h index 4f934b100a2af6867e741cc7f5f6d7e6b8cf6e22..81024cac574368b3b3c0f7dfee18bd669f3cea65 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/published_data_subscriber_manager.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/published_data_subscriber_manager.h @@ -44,7 +44,7 @@ public: int Add(const PublishedDataKey &key, const sptr observer, uint32_t firstCallerTokenId); int Delete(const PublishedDataKey &key, uint32_t firstCallerTokenId); - void Delete(uint32_t callerTokenId); + void Delete(uint32_t callerTokenId, uint32_t callerPid); int Disable(const PublishedDataKey &key, uint32_t firstCallerTokenId); int Enable(const PublishedDataKey &key, uint32_t firstCallerTokenId); void Emit(const std::vector &keys, int32_t userId, const std::string &ownerBundleName, @@ -58,10 +58,11 @@ public: private: struct ObserverNode { ObserverNode(const sptr &observer, uint32_t firstCallerTokenId, - uint32_t callerTokenId = 0); + uint32_t callerTokenId = 0, uint32_t callerPid = 0); sptr observer; uint32_t firstCallerTokenId; uint32_t callerTokenId; + uint32_t callerPid; bool enabled = true; bool isNotifyOnEnabled = false; }; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/rdb_subscriber_manager.cpp b/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/rdb_subscriber_manager.cpp index 9608475a332b66e5d93f01185b87bf6e6aa88b5b..de0d94af7385e335bd120951cbb94fde6bb8089d 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/rdb_subscriber_manager.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/rdb_subscriber_manager.cpp @@ -50,7 +50,7 @@ int32_t TemplateManager::Delete(const Key &key, int32_t userId) ZLOGE("Delete failed, %{public}d", status); return E_ERROR; } - SchedulerManager::GetInstance().RemoveTimer(key); + SchedulerManager::GetInstance().Stop(key); return E_OK; } @@ -118,9 +118,10 @@ int RdbSubscriberManager::Add(const Key &key, const sptr rdbCache_.Compute(key, [&observer, &context, executorPool, this](const auto &key, auto &value) { ZLOGI("add subscriber, uri %{private}s tokenId 0x%{public}x", key.uri.c_str(), context->callerTokenId); auto callerTokenId = IPCSkeleton::GetCallingTokenID(); - value.emplace_back(observer, context->callerTokenId, callerTokenId); + auto callerPid = IPCSkeleton::GetCallingPid(); + value.emplace_back(observer, context->callerTokenId, callerTokenId, callerPid); std::vector node; - node.emplace_back(observer, context->callerTokenId, callerTokenId); + node.emplace_back(observer, context->callerTokenId, callerTokenId, callerPid); ExecutorPool::Task task = [key, node, context, this]() { LoadConfigDataInfoStrategy loadDataInfo; if (!loadDataInfo(context)) { @@ -128,10 +129,10 @@ int RdbSubscriberManager::Add(const Key &key, const sptr DistributedData::Anonymous::Change(key.uri).c_str(), context->callerTokenId); return; } - Notify(key, context->currentUserId, node, context->calledSourceDir, context->version); + DistributedData::StoreMetaData metaData = RdbSubscriberManager::GenMetaDataFromContext(context); + Notify(key, context->currentUserId, node, metaData); if (GetEnableObserverCount(key) == 1) { - SchedulerManager::GetInstance().Execute( - key, context->currentUserId, context->calledSourceDir, context->version); + SchedulerManager::GetInstance().Start(key, context->currentUserId, metaData); } }; executorPool->Execute(task); @@ -156,18 +157,18 @@ int RdbSubscriberManager::Delete(const Key &key, uint32_t firstCallerTokenId) } } if (value.empty()) { - SchedulerManager::GetInstance().RemoveTimer(key); + SchedulerManager::GetInstance().Stop(key); } return !value.empty(); }); return result ? E_OK : E_SUBSCRIBER_NOT_EXIST; } -void RdbSubscriberManager::Delete(uint32_t callerTokenId) +void RdbSubscriberManager::Delete(uint32_t callerTokenId, uint32_t callerPid) { - rdbCache_.EraseIf([&callerTokenId, this](const auto &key, std::vector &value) { + rdbCache_.EraseIf([&callerTokenId, &callerPid, this](const auto &key, std::vector &value) { for (auto it = value.begin(); it != value.end();) { - if (it->callerTokenId == callerTokenId) { + if (it->callerTokenId == callerTokenId && it->callerPid == callerPid) { it = value.erase(it); } else { it++; @@ -177,7 +178,7 @@ void RdbSubscriberManager::Delete(uint32_t callerTokenId) ZLOGI("delete timer, subId %{public}" PRId64 ", bundleName %{public}s, tokenId %{public}x, uri %{public}s.", key.subscriberId, key.bundleName.c_str(), callerTokenId, DistributedData::Anonymous::Change(key.uri).c_str()); - SchedulerManager::GetInstance().RemoveTimer(key); + SchedulerManager::GetInstance().Stop(key); } return value.empty(); }); @@ -185,39 +186,55 @@ void RdbSubscriberManager::Delete(uint32_t callerTokenId) int RdbSubscriberManager::Disable(const Key &key, uint32_t firstCallerTokenId) { + bool isAllDisabled = true; auto result = - rdbCache_.ComputeIfPresent(key, [&firstCallerTokenId, this](const auto &key, + rdbCache_.ComputeIfPresent(key, [&firstCallerTokenId, &isAllDisabled, this](const auto &key, std::vector &value) { for (auto it = value.begin(); it != value.end(); it++) { if (it->firstCallerTokenId == firstCallerTokenId) { it->enabled = false; it->isNotifyOnEnabled = false; } + if (it->enabled) { + isAllDisabled = false; + } } return true; }); + if (isAllDisabled) { + SchedulerManager::GetInstance().Disable(key); + } return result ? E_OK : E_SUBSCRIBER_NOT_EXIST; } int RdbSubscriberManager::Enable(const Key &key, std::shared_ptr context) { - auto result = rdbCache_.ComputeIfPresent(key, [&context, this](const auto &key, std::vector &value) { + bool isChanged = false; + DistributedData::StoreMetaData metaData; + auto result = rdbCache_.ComputeIfPresent(key, [&context, &metaData, &isChanged, this](const auto &key, + std::vector &value) { for (auto it = value.begin(); it != value.end(); it++) { if (it->firstCallerTokenId != context->callerTokenId) { continue; } it->enabled = true; + LoadConfigDataInfoStrategy loadDataInfo; + if (!loadDataInfo(context)) { + return true; + } + isChanged = true; + metaData = RdbSubscriberManager::GenMetaDataFromContext(context); if (it->isNotifyOnEnabled) { std::vector node; node.emplace_back(it->observer, context->callerTokenId); - LoadConfigDataInfoStrategy loadDataInfo; - if (loadDataInfo(context)) { - Notify(key, context->currentUserId, node, context->calledSourceDir, context->version); - } + Notify(key, context->currentUserId, node, metaData); } } return true; }); + if (isChanged) { + SchedulerManager::GetInstance().Enable(key, context->currentUserId, metaData); + } return result ? E_OK : E_SUBSCRIBER_NOT_EXIST; } @@ -230,16 +247,17 @@ void RdbSubscriberManager::Emit(const std::string &uri, std::shared_ptr LoadConfigDataInfoStrategy loadDataInfo; loadDataInfo(context); } - rdbCache_.ForEach([&uri, &context, this](const Key &key, std::vector &val) { + DistributedData::StoreMetaData metaData = RdbSubscriberManager::GenMetaDataFromContext(context); + rdbCache_.ForEach([&uri, &context, &metaData, this](const Key &key, std::vector &val) { if (key.uri != uri) { return false; } - Notify(key, context->currentUserId, val, context->calledSourceDir, context->version); + Notify(key, context->currentUserId, val, metaData); SetObserverNotifyOnEnabled(val); return false; }); SchedulerManager::GetInstance().Execute( - uri, context->currentUserId, context->calledSourceDir, context->version, context->calledBundleName); + uri, context->currentUserId, metaData); } void RdbSubscriberManager::Emit(const std::string &uri, int32_t userId, @@ -254,7 +272,7 @@ void RdbSubscriberManager::Emit(const std::string &uri, int32_t userId, return false; } hasObserver = true; - Notify(key, userId, val, metaData.dataDir, metaData.version); + Notify(key, userId, val, metaData); SetObserverNotifyOnEnabled(val); return false; }); @@ -262,7 +280,7 @@ void RdbSubscriberManager::Emit(const std::string &uri, int32_t userId, return; } SchedulerManager::GetInstance().Execute( - uri, userId, metaData.dataDir, metaData.version, metaData.bundleName); + uri, userId, metaData); } void RdbSubscriberManager::SetObserverNotifyOnEnabled(std::vector &nodes) @@ -287,13 +305,13 @@ std::vector RdbSubscriberManager::GetKeysByUri(const std::string &uri) return results; } -void RdbSubscriberManager::EmitByKey(const Key &key, int32_t userId, const std::string &rdbPath, int version) +void RdbSubscriberManager::EmitByKey(const Key &key, int32_t userId, const DistributedData::StoreMetaData &metaData) { if (!URIUtils::IsDataProxyURI(key.uri)) { return; } - rdbCache_.ComputeIfPresent(key, [&rdbPath, &version, &userId, this](const Key &key, auto &val) { - Notify(key, userId, val, rdbPath, version); + rdbCache_.ComputeIfPresent(key, [&userId, &metaData, this](const Key &key, auto &val) { + Notify(key, userId, val, metaData); SetObserverNotifyOnEnabled(val); return true; }); @@ -315,7 +333,7 @@ int RdbSubscriberManager::GetEnableObserverCount(const Key &key) } int RdbSubscriberManager::Notify(const Key &key, int32_t userId, const std::vector &val, - const std::string &rdbDir, int rdbVersion) + const DistributedData::StoreMetaData &metaData) { Template tpl; if (!TemplateManager::GetInstance().Get(key, userId, tpl)) { @@ -323,9 +341,9 @@ int RdbSubscriberManager::Notify(const Key &key, int32_t userId, const std::vect DistributedData::Anonymous::Change(key.uri).c_str(), key.subscriberId, key.bundleName.c_str()); return E_TEMPLATE_NOT_EXIST; } - DistributedData::StoreMetaData meta; - meta.dataDir = rdbDir; + DistributedData::StoreMetaData meta = metaData; meta.bundleName = key.bundleName; + meta.user = std::to_string(userId); auto delegate = DBDelegate::Create(meta, key.uri); if (delegate == nullptr) { ZLOGE("Create fail %{public}s %{public}s", DistributedData::Anonymous::Change(key.uri).c_str(), @@ -376,21 +394,32 @@ void RdbSubscriberManager::Emit(const std::string &uri, int64_t subscriberId, LoadConfigDataInfoStrategy loadDataInfo; loadDataInfo(context); } - rdbCache_.ForEach([&uri, &context, &subscriberId, this](const Key &key, std::vector &val) { + DistributedData::StoreMetaData metaData = RdbSubscriberManager::GenMetaDataFromContext(context); + rdbCache_.ForEach([&uri, &context, &subscriberId, &metaData, this](const Key &key, std::vector &val) { if (key.uri != uri || key.subscriberId != subscriberId) { return false; } - Notify(key, context->currentUserId, val, context->calledSourceDir, context->version); + Notify(key, context->currentUserId, val, metaData); SetObserverNotifyOnEnabled(val); return false; }); Key executeKey(uri, subscriberId, bundleName); - SchedulerManager::GetInstance().Execute(executeKey, context->currentUserId, - context->calledSourceDir, context->version); + SchedulerManager::GetInstance().Start(executeKey, context->currentUserId, metaData); +} + +DistributedData::StoreMetaData RdbSubscriberManager::GenMetaDataFromContext(const std::shared_ptr context) +{ + DistributedData::StoreMetaData metaData; + metaData.tokenId = context->calledTokenId; + metaData.dataDir = context->calledSourceDir; + metaData.storeId = context->calledStoreName; + metaData.haMode = context->haMode; + return metaData; } + RdbSubscriberManager::ObserverNode::ObserverNode(const sptr &observer, - uint32_t firstCallerTokenId, uint32_t callerTokenId) - : observer(observer), firstCallerTokenId(firstCallerTokenId), callerTokenId(callerTokenId) + uint32_t firstCallerTokenId, uint32_t callerTokenId, uint32_t callerPid) + : observer(observer), firstCallerTokenId(firstCallerTokenId), callerTokenId(callerTokenId), callerPid(callerPid) { } } // namespace OHOS::DataShare \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/rdb_subscriber_manager.h b/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/rdb_subscriber_manager.h index 108c01d6c773e018339d72dafe2b1e2f61af0625..9379ed1aeee6c68d8c47a0fa57b43586b442b3dc 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/rdb_subscriber_manager.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers/rdb_subscriber_manager.h @@ -58,32 +58,34 @@ public: int Add(const Key &key, const sptr observer, std::shared_ptr context, std::shared_ptr executorPool); int Delete(const Key &key, uint32_t firstCallerTokenId); - void Delete(uint32_t callerTokenId); + void Delete(uint32_t callerTokenId, uint32_t callerPid); int Disable(const Key &key, uint32_t firstCallerTokenId); int Enable(const Key &key, std::shared_ptr context); void Emit(const std::string &uri, int64_t subscriberId, const std::string &bundleName, std::shared_ptr context); void Emit(const std::string &uri, std::shared_ptr context); void Emit(const std::string &uri, int32_t userId, DistributedData::StoreMetaData &metaData); - void EmitByKey(const Key &key, int32_t userId, const std::string &rdbPath, int version); + void EmitByKey(const Key &key, int32_t userId, const DistributedData::StoreMetaData &metaData); + DistributedData::StoreMetaData GenMetaDataFromContext(const std::shared_ptr context); std::vector GetKeysByUri(const std::string &uri); void Clear(); private: struct ObserverNode { ObserverNode(const sptr &observer, uint32_t firstCallerTokenId, - uint32_t callerTokenId = 0); + uint32_t callerTokenId = 0, uint32_t callerPid = 0); sptr observer; uint32_t firstCallerTokenId; uint32_t callerTokenId; + uint32_t callerPid; bool enabled = true; bool isNotifyOnEnabled = false; }; RdbSubscriberManager() = default; ConcurrentMap> rdbCache_; - int Notify(const Key &key, int32_t userId, const std::vector &val, const std::string &rdbDir, - int rdbVersion); + int Notify(const Key &key, int32_t userId, + const std::vector &val, const DistributedData::StoreMetaData &metaData); int GetEnableObserverCount(const Key &key); void SetObserverNotifyOnEnabled(std::vector &nodes); }; diff --git a/datamgr_service/services/distributeddataservice/service/dumper/BUILD.gn b/datamgr_service/services/distributeddataservice/service/dumper/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..72b194d7931caefdcea75bf011235bf903cb219b --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/dumper/BUILD.gn @@ -0,0 +1,51 @@ +# Copyright (c) 2024 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. +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +ohos_source_set("distributeddata_dumper") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + boundary_sanitize = true + ubsan = true + } + sources = [ "src/dump_helper.cpp" ] + + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] + + include_dirs = [ "include" ] + + cflags = [ + "-Werror", + "-Wno-multichar", + "-Wno-c99-designator", + "-D_LIBCPP_HAS_COND_CLOCKWAIT", + "-Oz", + ] + + deps = [ "${data_service_path}/framework:distributeddatasvcfwk" ] + external_deps = [ + "hilog:libhilog", + "json:nlohmann_json_static", + "kv_store:datamgr_common", + "kv_store:distributeddb", + ] + subsystem_name = "distributeddatamgr" + part_name = "datamgr_service" +} diff --git a/datamgr_service/services/distributeddataservice/service/dumper/src/dump_helper.cpp b/datamgr_service/services/distributeddataservice/service/dumper/src/dump_helper.cpp index 477a06d324ed2558370f1549bc9407cf67d31eda..04c125b06b043335b06342a2fa3fabec516990e0 100644 --- a/datamgr_service/services/distributeddataservice/service/dumper/src/dump_helper.cpp +++ b/datamgr_service/services/distributeddataservice/service/dumper/src/dump_helper.cpp @@ -18,7 +18,6 @@ #include #include "log_print.h" -#include "rdb_types.h" #include "runtime_config.h" #include "string_ex.h" diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/BUILD.gn b/datamgr_service/services/distributeddataservice/service/kvdb/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..bb3d45257bff761c5986aed51b97f18cc3653610 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/kvdb/BUILD.gn @@ -0,0 +1,89 @@ +# Copyright (c) 2024 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. +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +ohos_source_set("distributeddata_kvdb") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + boundary_sanitize = true + ubsan = true + } + + include_dirs = [ + "${data_service_path}/service/matrix/include", + "${data_service_path}/adapter/include", + "${data_service_path}/adapter/include/communicator", + "${data_service_path}/adapter/include/dfx", + "${data_service_path}/adapter/include/utils", + "${data_service_path}/framework/include", + "${data_service_path}/service/bootstrap/include", + "${data_service_path}/service/crypto/include", + "${data_service_path}/service/kvdb", + "${data_service_path}/service/permission/include", + "${data_service_path}/service/common", + "${data_service_path}/service/rdb", + ] + + sources = [ + "auth_delegate.cpp", + "kvdb_exporter.cpp", + "kvdb_general_store.cpp", + "kvdb_notifier_proxy.cpp", + "kvdb_observer_proxy.cpp", + "kvdb_service_impl.cpp", + "kvdb_service_stub.cpp", + "kvdb_watcher.cpp", + "kvstore_sync_manager.cpp", + "query_helper.cpp", + "upgrade.cpp", + ] + + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] + + cflags = [ + "-Werror", + "-Wno-multichar", + "-Wno-c99-designator", + "-D_LIBCPP_HAS_COND_CLOCKWAIT", + "-Oz", + ] + + deps = [ + "${data_service_path}/service/backup:distributeddata_backup", + "${data_service_path}/service/rdb:distributeddata_rdb", + ] + + external_deps = [ + "access_token:libaccesstoken_sdk", + "access_token:libtokenid_sdk", + "c_utils:utils", + "device_manager:devicemanagersdk", + "hilog:libhilog", + "hisysevent:libhisysevent", + "ipc:ipc_core", + "json:nlohmann_json_static", + "kv_store:datamgr_common", + "kv_store:distributeddb", + "kv_store:kvdb_inner_lite", + ] + + subsystem_name = "distributeddatamgr" + part_name = "datamgr_service" +} diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/auth_delegate.cpp b/datamgr_service/services/distributeddataservice/service/kvdb/auth_delegate.cpp index 234a1698c6933c52fd8be026350a34adc1703adf..320db40c8e4213538be38e0985695fdbdfbcfc64 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/auth_delegate.cpp +++ b/datamgr_service/services/distributeddataservice/service/kvdb/auth_delegate.cpp @@ -17,8 +17,6 @@ #include "auth_delegate.h" #include "checker/checker_manager.h" -#include "device_auth.h" -#include "device_auth_defines.h" #include "device_manager_adapter.h" #include "log_print.h" #include "user_delegate.h" diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_general_store.cpp b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_general_store.cpp index 1066024e7738cefc9e354ee3ed449d3a6600f10b..0a5daafc1eb7c3a6592c614b6c3613def5bd9803 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_general_store.cpp +++ b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_general_store.cpp @@ -25,6 +25,7 @@ #include "crypto_manager.h" #include "device_manager_adapter.h" #include "device_matrix.h" +#include "dfx_types.h" #include "directory/directory_manager.h" #include "eventcenter/event_center.h" #include "kvdb_query.h" @@ -34,21 +35,23 @@ #include "metadata/store_meta_data_local.h" #include "query_helper.h" #include "rdb_cloud.h" +#include "reporter.h" #include "snapshot/bind_event.h" #include "types.h" #include "user_delegate.h" #include "utils/anonymous.h" -#include "water_version_manager.h" namespace OHOS::DistributedKv { using namespace DistributedData; using namespace DistributedDB; +using namespace DistributedDataDfx; using DBField = DistributedDB::Field; using DBTable = DistributedDB::TableSchema; using DBSchema = DistributedDB::DataBaseSchema; using ClearMode = DistributedDB::ClearMode; using DMAdapter = DistributedData::DeviceManagerAdapter; using DBInterceptedData = DistributedDB::InterceptedData; +static constexpr const char *FT_CLOUD_SYNC = "CLOUD_SYNC"; constexpr int UUID_WIDTH = 4; const std::map KVDBGeneralStore::dbStatusMap_ = { { DBStatus::OK, GenErr::E_OK }, @@ -210,13 +213,15 @@ KVDBGeneralStore::~KVDBGeneralStore() manager_.CloseKvStore(delegate_); delegate_ = nullptr; } - for (auto &bindInfo : bindInfos_) { - if (bindInfo.db_ != nullptr) { - bindInfo.db_->Close(); + { + std::unique_lock lock(bindMutex_); + for (auto &[userId, bindInfo] : bindInfos_) { + if (bindInfo.db_ != nullptr) { + bindInfo.db_->Close(); + } } + bindInfos_.clear(); } - bindInfos_.clear(); - dbClouds_.clear(); } int32_t KVDBGeneralStore::BindSnapshots(std::shared_ptr>> bindAssets) @@ -225,30 +230,26 @@ int32_t KVDBGeneralStore::BindSnapshots(std::shared_ptr &bindInfos, const CloudConfig &config) + const Database &database, const std::map &bindInfos, const CloudConfig &config) { if (bindInfos.empty()) { ZLOGW("No cloudDB!"); return GeneralError::E_OK; } std::map schemas; + std::map> dbClouds{}; auto dbSchema = GetDBSchema(database); - std::set users; - for (auto &[userId, bindInfo] : bindInfos) { - if (bindInfo.db_ == nullptr) { - return GeneralError::E_INVALID_ARGS; - } - users.insert(userId); - dbClouds_.insert({ std::to_string(userId), std::make_shared(bindInfo.db_, nullptr) }); - bindInfos_.insert(std::move(bindInfo)); - schemas.insert({ std::to_string(userId), dbSchema }); - } { - std::unique_lock lock(bindMutex_); - if (users_ == users) { - return GeneralError::E_OK; + std::unique_lock lock(bindMutex_); + for (auto &[userId, bindInfo] : bindInfos) { + if (bindInfo.db_ == nullptr) { + return GeneralError::E_INVALID_ARGS; + } + dbClouds.insert({ std::to_string(userId), + std::make_shared(bindInfo.db_, nullptr) }); + bindInfos_.insert(std::make_pair(userId, std::move(bindInfo))); + schemas.insert({ std::to_string(userId), dbSchema }); } - users_ = users; } DistributedDB::CloudSyncConfig dbConfig; dbConfig.maxUploadCount = config.maxNumber; @@ -258,7 +259,7 @@ int32_t KVDBGeneralStore::Bind( if (delegate_ == nullptr) { return GeneralError::E_ALREADY_CLOSED; } - delegate_->SetCloudDB(dbClouds_); + delegate_->SetCloudDB(std::move(dbClouds)); delegate_->SetCloudDbSchema(std::move(schemas)); delegate_->SetCloudSyncConfig(dbConfig); return GeneralError::E_OK; @@ -267,7 +268,7 @@ int32_t KVDBGeneralStore::Bind( bool KVDBGeneralStore::IsBound(uint32_t user) { std::shared_lock lock(bindMutex_); - return users_.find(user) != users_.end(); + return bindInfos_.find(user) != bindInfos_.end(); } int32_t KVDBGeneralStore::Close(bool isForce) @@ -379,6 +380,17 @@ DBStatus KVDBGeneralStore::CloudSync(const Devices &devices, DistributedDB::Sync return delegate_->Sync(syncOption, GetDBProcessCB(async)); } +void KVDBGeneralStore::Report(const std::string &faultType, int32_t errCode, const std::string &appendix) +{ + ArkDataFaultMsg msg = { .faultType = faultType, + .bundleName = storeInfo_.bundleName, + .moduleName = ModuleName::KV_STORE, + .storeName = storeInfo_.storeName, + .errorType = errCode + GeneralStore::CLOUD_ERR_OFFSET, + .appendixMsg = appendix }; + Reporter::GetInstance()->CloudSyncFault()->Report(msg); +} + std::pair KVDBGeneralStore::Sync(const Devices &devices, GenQuery &query, DetailAsync async, const SyncParam &syncParam) { @@ -396,6 +408,10 @@ std::pair KVDBGeneralStore::Sync(const Devices &devices, GenQu return { GeneralError::E_NOT_SUPPORT, DBStatus::OK }; } dbStatus = CloudSync(devices, dbMode, async, syncParam.wait, syncParam.prepareTraceId); + if (dbStatus != DBStatus::OK) { + Report(FT_CLOUD_SYNC, static_cast(Fault::CSF_GS_CLOUD_SYNC), + "Cloud sync ret=" + std::to_string(static_cast(dbStatus))); + } } else { if (devices.empty()) { ZLOGE("Devices is empty! mode:%{public}d", syncParam.mode); @@ -428,7 +444,7 @@ std::pair KVDBGeneralStore::Sync(const Devices &devices, GenQu return { ConvertStatus(dbStatus), dbStatus }; } -void KVDBGeneralStore::SetEqualIdentifier(const std::string &appId, const std::string &storeId, const std::string &account) +void KVDBGeneralStore::SetEqualIdentifier(const std::string &appId, const std::string &storeId, std::string account) { std::shared_lock lock(rwMutex_); if (delegate_ == nullptr) { @@ -602,24 +618,6 @@ int32_t KVDBGeneralStore::UnregisterDetailProgressObserver() return GenErr::E_OK; } -std::vector KVDBGeneralStore::GetWaterVersion(const std::string &deviceId) -{ - std::shared_lock lock(rwMutex_); - if (delegate_ == nullptr) { - ZLOGE("store already closed! deviceId:%{public}s", Anonymous::Change(deviceId).c_str()); - return {}; - } - auto [status, versions] = delegate_->GetCloudVersion(deviceId); - if (status != DBStatus::OK || versions.empty()) { - return {}; - } - std::vector res; - for (auto &[_, version] : versions) { - res.push_back(std::move(version)); - } - return res; -} - void KVDBGeneralStore::ObserverProxy::OnChange(DBOrigin origin, const std::string &originalId, DBChangeData &&data) { if (!HasWatcher()) { @@ -679,7 +677,7 @@ KVDBGeneralStore::DBProcessCB KVDBGeneralStore::GetDBProcessCB(DetailAsync async auto &detail = details[id]; detail.progress = process.process; detail.code = ConvertStatus(process.errCode); - detail.dbCode = DB_ERR_OFFSET + process.errCode; + detail.dbCode = process.errCode; for (auto [key, value] : process.tableProcess) { auto &table = detail.details[key]; table.upload.total = value.upLoadInfo.total; diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_general_store.h b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_general_store.h index fe37ac820d70ea22bb0ac2b12c78a9ae12baae18..80e030f05502be847d9d51d4c89f70fc2ca9d1f3 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_general_store.h +++ b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_general_store.h @@ -43,7 +43,8 @@ public: explicit KVDBGeneralStore(const StoreMetaData &meta); ~KVDBGeneralStore(); - int32_t Bind(Database &database, const std::map &bindInfos, const CloudConfig &config) override; + int32_t Bind(const Database &database, + const std::map &bindInfos, const CloudConfig &config) override; bool IsBound(uint32_t user) override; bool IsValid(); int32_t Execute(const std::string &table, const std::string &sql) override; @@ -60,7 +61,7 @@ public: const std::string &table, const std::string &sql, Values &&args) override; std::pair> Query(const std::string &table, GenQuery &query) override; std::pair Sync(const Devices &devices, GenQuery &query, DetailAsync async, - const SyncParam &syncParm) override; + const SyncParam &syncParam) override; std::pair> PreSharing(GenQuery &query) override; int32_t Clean(const std::vector &devices, int32_t mode, const std::string &tableName) override; int32_t Watch(int32_t origin, Watcher &watcher) override; @@ -73,15 +74,14 @@ public: int32_t BindSnapshots(std::shared_ptr>> bindAssets) override; int32_t MergeMigratedData(const std::string &tableName, VBuckets &&values) override; int32_t CleanTrackerData(const std::string &tableName, int64_t cursor) override; - std::vector GetWaterVersion(const std::string &deviceId) override; - void SetEqualIdentifier(const std::string &appId, const std::string &storeId, const std::string &account = "") override; + void SetEqualIdentifier(const std::string &appId, const std::string &storeId, std::string account = "") override; void SetConfig(const StoreConfig &storeConfig) override; void SetExecutor(std::shared_ptr executor) override; static DBPassword GetDBPassword(const StoreMetaData &data); static DBOption GetDBOption(const StoreMetaData &data, const DBPassword &password); static DBSecurity GetDBSecurity(int32_t secLevel); - virtual std::pair LockCloudDB() override; - virtual int32_t UnLockCloudDB() override; + std::pair LockCloudDB() override; + int32_t UnLockCloudDB() override; private: using KvDelegate = DistributedDB::KvStoreNbDelegate; @@ -99,6 +99,7 @@ private: const std::string &prepareTraceId); void GetIdentifierParams( std::vector &devices, const std::vector &uuids, int32_t authType); + void Report(const std::string &faultType, int32_t errCode, const std::string &appendix); class ObserverProxy : public DistributedDB::KvStoreObserver { public: using DBOrigin = DistributedDB::Origin; @@ -124,10 +125,8 @@ private: ObserverProxy observer_; KvManager manager_; KvDelegate *delegate_ = nullptr; - std::map> dbClouds_{}; - std::set bindInfos_; std::shared_mutex bindMutex_; - std::set users_{}; + std::map bindInfos_{}; std::mutex mutex_; int32_t ref_ = 1; mutable std::shared_timed_mutex rwMutex_; diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_observer_proxy.cpp b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_observer_proxy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3eb5413ef7a34faf0fed0d8d53f6ca6723bd4b87 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_observer_proxy.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025 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 "KVDBObserverProxy" + +#include "kvdb_observer_proxy.h" + +#include +#include +#include "kv_types_util.h" +#include "itypes_util.h" +#include "log_print.h" +#include "message_parcel.h" +namespace OHOS { +namespace DistributedKv { +using namespace std::chrono; + +enum { + CLOUD_ONCHANGE, + ONCHANGE, +}; + +KVDBObserverProxy::KVDBObserverProxy(const sptr &impl) : IRemoteProxy(impl) +{ +} + +void KVDBObserverProxy::OnChange(const ChangeNotification &changeNotification) +{ + MessageParcel data; + MessageParcel reply; + if (!data.WriteInterfaceToken(KVDBObserverProxy::GetDescriptor())) { + ZLOGE("Write descriptor failed"); + return; + } + int64_t insertSize = ITypesUtil::GetTotalSize(changeNotification.GetInsertEntries()); + int64_t updateSize = ITypesUtil::GetTotalSize(changeNotification.GetUpdateEntries()); + int64_t deleteSize = ITypesUtil::GetTotalSize(changeNotification.GetDeleteEntries()); + int64_t totalSize = insertSize + updateSize + deleteSize + sizeof(uint32_t); + if (insertSize < 0 || updateSize < 0 || deleteSize < 0 || !data.WriteInt32(totalSize)) { + ZLOGE("Write ChangeNotification buffer size to parcel failed."); + return; + } + ZLOGD("I(%" PRId64 ") U(%" PRId64 ") D(%" PRId64 ") T(%" PRId64 ")", insertSize, updateSize, deleteSize, totalSize); + if (totalSize < SWITCH_RAW_DATA_SIZE) { + if (!ITypesUtil::Marshal(data, changeNotification)) { + ZLOGW("Write ChangeNotification to parcel failed."); + return; + } + } else { + if (!ITypesUtil::Marshal(data, changeNotification.GetDeviceId(), uint32_t(changeNotification.IsClear())) || + !ITypesUtil::MarshalToBuffer(changeNotification.GetInsertEntries(), insertSize, data) || + !ITypesUtil::MarshalToBuffer(changeNotification.GetUpdateEntries(), updateSize, data) || + !ITypesUtil::MarshalToBuffer(changeNotification.GetDeleteEntries(), deleteSize, data)) { + ZLOGE("WriteChangeList to Parcel by buffer failed"); + return; + } + } + + MessageOption mo{ MessageOption::TF_WAIT_TIME }; + int error = Remote()->SendRequest(ONCHANGE, data, reply, mo); + if (error != 0) { + ZLOGE("SendRequest failed, error %d", error); + } +} + +void KVDBObserverProxy::OnChange(const DataOrigin &origin, Keys &&keys) +{ + MessageParcel data; + MessageParcel reply; + if (!data.WriteInterfaceToken(KVDBObserverProxy::GetDescriptor())) { + ZLOGE("Write descriptor failed"); + return; + } + if (!ITypesUtil::Marshal(data, origin.store, keys[OP_INSERT], keys[OP_UPDATE], keys[OP_DELETE])) { + ZLOGE("WriteChangeInfo to Parcel failed."); + return; + } + + MessageOption mo{ MessageOption::TF_WAIT_TIME }; + int error = Remote()->SendRequest(CLOUD_ONCHANGE, data, reply, mo); + if (error != 0) { + ZLOGE("SendRequest failed, error %d", error); + } +} +} // namespace DistributedKv +} // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_observer_proxy.h b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_observer_proxy.h new file mode 100644 index 0000000000000000000000000000000000000000..9a706fd260c99091ef1d8e401517c00b4f68e1cf --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_observer_proxy.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 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 KVDB_OBSERVER_PROXY_H +#define KVDB_OBSERVER_PROXY_H + +#include "change_notification.h" +#include "iremote_broker.h" +#include "ikvstore_observer.h" +#include "iremote_proxy.h" +#include "types.h" + +namespace OHOS { +namespace DistributedKv { +class API_EXPORT KVDBObserverProxy : public IRemoteProxy { +public: + explicit KVDBObserverProxy(const sptr &impl); + ~KVDBObserverProxy() = default; + void OnChange(const ChangeNotification &changeNotification) override; + void OnChange(const DataOrigin &origin, Keys &&keys) override; +private: + static inline BrokerDelegator delegator_; +}; +} // namespace DistributedKv +} // namespace OHOS + +#endif // KVDB_OBSERVER_PROXY_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_query.h b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_query.h index 0640867dc16b4510cc0894445e45fd333ee30bc6..3eec4f49661b50aec0d8e6af5c1bcdfcadea488d 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_query.h +++ b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_query.h @@ -61,4 +61,4 @@ public: }; } // namespace OHOS::DistributedKv -#endif //OHOS_DISTRIBUTED_DATA_DATAMGR_SERVICE_KVDB_QUERY_H +#endif //OHOS_DISTRIBUTED_DATA_DATAMGR_SERVICE_KVDB_QUERY_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_impl.cpp b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_impl.cpp index 5593bc0b4d0c144a89c23810c53fda89f018e8ee..6e4c75843433dda32309fb6936b5dc54e2447274 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_impl.cpp +++ b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_impl.cpp @@ -48,7 +48,6 @@ #include "utils/anonymous.h" #include "utils/constant.h" #include "utils/converter.h" -#include "water_version_manager.h" #include "app_id_mapping/app_id_mapping_config_manager.h" namespace OHOS::DistributedKv { @@ -61,6 +60,9 @@ using DumpManager = OHOS::DistributedData::DumpManager; using CommContext = OHOS::DistributedData::CommunicatorContext; using SecretKeyMeta = DistributedData::SecretKeyMetaData; static constexpr const char *DEFAULT_USER_ID = "0"; +static constexpr const char *PASTEBOARD_SERVICE = "pasteboard_service"; +static constexpr const char *PASTEBOARD_USER_ID = "100"; +static const size_t SECRET_KEY_COUNT = 2; __attribute__((used)) KVDBServiceImpl::Factory KVDBServiceImpl::factory_; KVDBServiceImpl::Factory::Factory() { @@ -199,6 +201,7 @@ Status KVDBServiceImpl::Delete(const AppId &appId, const StoreId &storeId) MetaDataManager::GetInstance().DelMeta(metaData.GetBackupSecretKey(), true); MetaDataManager::GetInstance().DelMeta(metaData.GetAutoLaunchKey(), true); MetaDataManager::GetInstance().DelMeta(metaData.GetDebugInfoKey(), true); + MetaDataManager::GetInstance().DelMeta(metaData.GetCloneSecretKey(), true); PermitDelegate::GetInstance().DelCache(metaData.GetKey()); AutoCache::GetInstance().CloseStore(tokenId, storeId); ZLOGD("appId:%{public}s storeId:%{public}s instanceId:%{public}d", appId.appId.c_str(), @@ -274,7 +277,6 @@ Status KVDBServiceImpl::NotifyDataChange(const AppId &appId, const StoreId &stor } if (DeviceMatrix::GetInstance().IsSupportMatrix() && (DeviceMatrix::GetInstance().IsStatics(meta) || DeviceMatrix::GetInstance().IsDynamic(meta))) { - WaterVersionManager::GetInstance().GenerateWaterVersion(meta.bundleName, meta.storeId); DeviceMatrix::GetInstance().OnChanged(meta); } @@ -322,7 +324,7 @@ Status KVDBServiceImpl::PutSwitch(const AppId &appId, const SwitchData &data) Status KVDBServiceImpl::GetSwitch(const AppId &appId, const std::string &networkId, SwitchData &data) { - auto uuid = DMAdapter::GetInstance().ToUUID(networkId); + auto uuid = DMAdapter::GetInstance().GetUuidByNetworkId(networkId); if (uuid.empty()) { return Status::INVALID_ARGUMENT; } @@ -593,17 +595,36 @@ Status KVDBServiceImpl::Unsubscribe(const AppId &appId, const StoreId &storeId, return SUCCESS; } -Status KVDBServiceImpl::GetBackupPassword(const AppId &appId, const StoreId &storeId, std::vector &password, - int32_t passwordType) +Status KVDBServiceImpl::GetBackupPassword(const AppId &appId, const StoreId &storeId, + std::vector> &passwords, int32_t passwordType) { StoreMetaData metaData = GetStoreMetaData(appId, storeId); if (passwordType == KVDBService::PasswordType::BACKUP_SECRET_KEY) { - return BackupManager::GetInstance().GetPassWord(metaData, password) ? SUCCESS : ERROR; + std::vector backupPwd; + bool res = BackupManager::GetInstance().GetPassWord(metaData, backupPwd); + if (res) { + passwords.emplace_back(backupPwd); + } + backupPwd.assign(backupPwd.size(), 0); + return res ? SUCCESS : ERROR; } if (passwordType == KVDBService::PasswordType::SECRET_KEY) { + passwords.reserve(SECRET_KEY_COUNT); SecretKeyMetaData secretKey; - MetaDataManager::GetInstance().LoadMeta(metaData.GetSecretKey(), secretKey, true); - return CryptoManager::GetInstance().Decrypt(secretKey.sKey, password) ? SUCCESS : ERROR; + std::vector password; + if (MetaDataManager::GetInstance().LoadMeta(metaData.GetSecretKey(), secretKey, true) && + CryptoManager::GetInstance().Decrypt(secretKey.sKey, password)) { + passwords.emplace_back(password); + password.assign(password.size(), 0); + } + + std::vector clonePwd; + if (MetaDataManager::GetInstance().LoadMeta(metaData.GetCloneSecretKey(), secretKey, true) && + CryptoManager::GetInstance().Decrypt(secretKey.sKey, clonePwd)) { + passwords.emplace_back(clonePwd); + clonePwd.assign(clonePwd.size(), 0); + } + return passwords.size() > 0 ? SUCCESS : ERROR; } ZLOGE("passwordType is invalid, appId:%{public}s, storeId:%{public}s, passwordType:%{public}d", appId.appId.c_str(), Anonymous::Change(storeId.storeId).c_str(), passwordType); @@ -790,7 +811,8 @@ int32_t KVDBServiceImpl::ResolveAutoLaunch(const std::string &identifier, DBLaun for (const auto &storeMeta : metaData) { if (storeMeta.storeType < StoreMetaData::StoreType::STORE_KV_BEGIN || storeMeta.storeType > StoreMetaData::StoreType::STORE_KV_END || - (!param.userId.empty() && (param.userId != storeMeta.user))) { + (!param.userId.empty() && (param.userId != storeMeta.user)) || + storeMeta.appId == DistributedData::Bootstrap::GetInstance().GetProcessLabel()) { continue; } auto identifierTag = DBManager::GetKvStoreIdentifier("", storeMeta.appId, storeMeta.storeId, true); @@ -804,7 +826,7 @@ int32_t KVDBServiceImpl::ResolveAutoLaunch(const std::string &identifier, DBLaun store->SetEqualIdentifier(storeMeta.appId, storeMeta.storeId, accountId); } ZLOGI("isTriple:%{public}d,storeId:%{public}s,appId:%{public}s,size:%{public}zu,user:%{public}s", - isTripleIdentifierEqual, Anonymous::Change(storeMeta.storeId).c_str(), storeMeta.storeId.c_str(), + isTripleIdentifierEqual, Anonymous::Change(storeMeta.storeId).c_str(), storeMeta.appId.c_str(), watchers.size(), storeMeta.user.c_str()); } return SUCCESS; @@ -844,7 +866,14 @@ void KVDBServiceImpl::AddOptions(const Options &options, StoreMetaData &metaData metaData.appId = CheckerManager::GetInstance().GetAppId(Converter::ConvertToStoreInfo(metaData)); metaData.appType = "harmony"; metaData.hapName = options.hapName; - metaData.dataDir = DirectoryManager::GetInstance().GetStorePath(metaData); + if (metaData.appId == PASTEBOARD_SERVICE) { + auto userId = metaData.user; + metaData.user = PASTEBOARD_USER_ID; + metaData.dataDir = DirectoryManager::GetInstance().GetStorePath(metaData); + metaData.user = userId; + } else { + metaData.dataDir = DirectoryManager::GetInstance().GetStorePath(metaData); + } metaData.schema = options.schema; metaData.account = AccountDelegate::GetInstance()->GetCurrentAccountId(); metaData.isNeedCompress = options.isNeedCompress; @@ -936,9 +965,6 @@ Status KVDBServiceImpl::DoCloudSync(const StoreMetaData &meta, const SyncInfo &s if (instance == nullptr) { return Status::CLOUD_DISABLED; } - if (!DMAdapter::GetInstance().IsNetworkAvailable()) { - return Status::NETWORK_ERROR; - } std::vector users; if (meta.user != StoreMetaData::ROOT_USER) { users.push_back(std::atoi(meta.user.c_str())); @@ -1138,9 +1164,6 @@ Status KVDBServiceImpl::DoComplete(const StoreMetaData &meta, const SyncInfo &in { ZLOGD("seqId:0x%{public}" PRIx64 " tokenId:0x%{public}x remote:%{public}zu", info.seqId, meta.tokenId, dbResult.size()); - RADAR_REPORT(STANDARD_DEVICE_SYNC, FINISH_SYNC, RADAR_SUCCESS, BIZ_STATE, END, - SYNC_STORE_ID, Anonymous::Change(meta.storeId), SYNC_APP_ID, meta.bundleName, CONCURRENT_ID, - std::to_string(info.syncId), DATA_TYPE, meta.dataType); std::map result; if (AccessTokenKit::GetTokenTypeFlag(meta.tokenId) != TOKEN_HAP) { for (auto &[key, status] : dbResult) { @@ -1151,6 +1174,21 @@ Status KVDBServiceImpl::DoComplete(const StoreMetaData &meta, const SyncInfo &in result[key] = ConvertDbStatus(status); } } + bool success = true; + for (auto &[key, status] : result) { + if (status != SUCCESS) { + success = false; + RADAR_REPORT(STANDARD_DEVICE_SYNC, FINISH_SYNC, RADAR_FAILED, ERROR_CODE, status, BIZ_STATE, END, + SYNC_STORE_ID, Anonymous::Change(meta.storeId), SYNC_APP_ID, meta.bundleName, CONCURRENT_ID, + std::to_string(info.syncId), DATA_TYPE, meta.dataType); + break; + } + } + if (success) { + RADAR_REPORT(STANDARD_DEVICE_SYNC, FINISH_SYNC, RADAR_SUCCESS, BIZ_STATE, END, + SYNC_STORE_ID, Anonymous::Change(meta.storeId), SYNC_APP_ID, meta.bundleName, CONCURRENT_ID, + std::to_string(info.syncId), DATA_TYPE, meta.dataType); + } for (const auto &device : info.devices) { auto it = result.find(device); if (it != result.end() && it->second == SUCCESS) { diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_impl.h b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_impl.h index dba6babebabc681459955ba4b80dc3758558be74..ce87b551191bae1b4e56cffa197e4ddb2670ce30 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_impl.h +++ b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_impl.h @@ -34,13 +34,13 @@ #include "store/general_value.h" #include "utils/ref_count.h" namespace OHOS::DistributedKv { -class API_EXPORT KVDBServiceImpl final : public KVDBServiceStub { +class KVDBServiceImpl final : public KVDBServiceStub { public: using DBLaunchParam = DistributedDB::AutoLaunchParam; using Handler = std::function> &)>; using RefCount = DistributedData::RefCount; using StoreMetaData = OHOS::DistributedData::StoreMetaData; - API_EXPORT KVDBServiceImpl(); + KVDBServiceImpl(); virtual ~KVDBServiceImpl(); Status GetStoreIds(const AppId &appId, std::vector &storeIds) override; Status BeforeCreate(const AppId &appId, const StoreId &storeId, const Options &options) override; @@ -62,7 +62,7 @@ public: Status RmvSubscribeInfo(const AppId &appId, const StoreId &storeId, const SyncInfo &syncInfo) override; Status Subscribe(const AppId &appId, const StoreId &storeId, sptr observer) override; Status Unsubscribe(const AppId &appId, const StoreId &storeId, sptr observer) override; - Status GetBackupPassword(const AppId &appId, const StoreId &storeId, std::vector &password, + Status GetBackupPassword(const AppId &appId, const StoreId &storeId, std::vector> &passwords, int32_t passwordType) override; Status NotifyDataChange(const AppId &appId, const StoreId &storeId, uint64_t delay) override; Status PutSwitch(const AppId &appId, const SwitchData &data) override; diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.cpp b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.cpp index 5921553c4cc754a26a285cdbd21dd51b8d064db2..78e1e966f3600c5cbcb5632c4bf0355701781bd8 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.cpp +++ b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.cpp @@ -427,15 +427,19 @@ int32_t KVDBServiceStub::OnGetBackupPassword( Anonymous::Change(storeId.storeId).c_str()); return IPC_STUB_INVALID_DATA_ERR; } - std::vector password; - int32_t status = GetBackupPassword(appId, storeId, password, passwordType); - if (!ITypesUtil::Marshal(reply, status, password)) { + std::vector> passwords; + int32_t status = GetBackupPassword(appId, storeId, passwords, passwordType); + if (!ITypesUtil::Marshal(reply, status, passwords)) { ZLOGE("Marshal status:0x%{public}x appId:%{public}s storeId:%{public}s", status, appId.appId.c_str(), Anonymous::Change(storeId.storeId).c_str()); - password.assign(password.size(), 0); + for (auto &password : passwords) { + password.assign(password.size(), 0); + } return IPC_STUB_WRITE_PARCEL_ERR; } - password.assign(password.size(), 0); + for (auto &password : passwords) { + password.assign(password.size(), 0); + } return ERR_NONE; } diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_watcher.cpp b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_watcher.cpp index f98da5f563029e5dfe50a3d8782f8713654a2e67..f04180ab5a65d17d1dfefdda2e5f6376e0033198 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_watcher.cpp +++ b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_watcher.cpp @@ -18,7 +18,7 @@ #include "kvdb_watcher.h" #include "error/general_error.h" -#include "ikvstore_observer.h" +#include "kvdb_observer_proxy.h" #include "log_print.h" #include "types.h" #include "utils/anonymous.h" diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_watcher.h b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_watcher.h index 932ab2621735143b4392ab059ffb9d67fded9f45..301bcc6b4d1734d8ed036c269e07c4752dda2835 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_watcher.h +++ b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_watcher.h @@ -18,7 +18,7 @@ #include #include -#include "ikvstore_observer.h" +#include "kvdb_observer_proxy.h" #include "kv_store_changed_data.h" #include "store/general_value.h" #include "store/general_watcher.h" diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/query_helper.cpp b/datamgr_service/services/distributeddataservice/service/kvdb/query_helper.cpp index e8cd752b8bfe5912e89c3fd5042940647e773d7b..f877df1f2a845ce36cc2878b0c2fbf21560d6ab4 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/query_helper.cpp +++ b/datamgr_service/services/distributeddataservice/service/kvdb/query_helper.cpp @@ -26,8 +26,49 @@ constexpr int QUERY_SKIP_SIZE = 1; constexpr int QUERY_WORD_SIZE = 2; constexpr int MAX_QUERY_LENGTH = 5 * 1024; // Max query string length 5k constexpr int MAX_QUERY_COMPLEXITY = 500; // Max query complexity 500 +constexpr int QUERY_WORD_INDEX = 3; +constexpr int QUERY_WORD_LEN = 4; bool QueryHelper::hasPrefixKey_ = false; std::string QueryHelper::deviceId_; +const char * const EQUAL_TO = "^EQUAL"; +const char * const NOT_EQUAL_TO = "^NOT_EQUAL"; +const char * const GREATER_THAN = "^GREATER"; +const char * const LESS_THAN = "^LESS"; +const char * const GREATER_THAN_OR_EQUAL_TO = "^GREATER_EQUAL"; +const char * const LESS_THAN_OR_EQUAL_TO = "^LESS_EQUAL"; +const char * const IS_NULL = "^IS_NULL"; +const char * const IN = "^IN"; +const char * const NOT_IN = "^NOT_IN"; +const char * const LIKE = "^LIKE"; +const char * const NOT_LIKE = "^NOT_LIKE"; +const char * const AND = "^AND"; +const char * const OR = "^OR"; +const char * const ORDER_BY_ASC = "^ASC"; +const char * const ORDER_BY_DESC = "^DESC"; +const char * const ORDER_BY_WRITE_TIME = "^OrderByWriteTime"; +const char * const IS_ASC = "^IS_ASC"; +const char * const LIMIT = "^LIMIT"; +const char * const SPACE = " "; +const char * const SPECIAL = "^"; +const char * const SPECIAL_ESCAPE = "(^)"; +const char * const SPACE_ESCAPE = "^^"; +const char * const EMPTY_STRING = "^EMPTY_STRING"; +const char * const START_IN = "^START"; +const char * const END_IN = "^END"; +const char * const BEGIN_GROUP = "^BEGIN_GROUP"; +const char * const END_GROUP = "^END_GROUP"; +const char * const KEY_PREFIX = "^KEY_PREFIX"; +const char * const DEVICE_ID = "^DEVICE_ID"; +const char * const IS_NOT_NULL = "^IS_NOT_NULL"; +const char * const TYPE_STRING = "STRING"; +const char * const TYPE_INTEGER = "INTEGER"; +const char * const TYPE_LONG = "LONG"; +const char * const TYPE_DOUBLE = "DOUBLE"; +const char * const TYPE_BOOLEAN = "BOOL"; +const char * const VALUE_TRUE = "true"; +const char * const VALUE_FALSE = "false"; +const char * const SUGGEST_INDEX = "^SUGGEST_INDEX"; +const char * const IN_KEYS = "^IN_KEYS"; DistributedDB::Query QueryHelper::StringToDbQuery(const std::string &query, bool &isSuccess) { @@ -44,8 +85,8 @@ DistributedDB::Query QueryHelper::StringToDbQuery(const std::string &query, bool return dbQuery; } deviceId_.clear(); - hasPrefixKey_ = (query.find(DataQuery::KEY_PREFIX) != std::string::npos); - size_t pos = query.find_first_not_of(DataQuery::SPACE); + hasPrefixKey_ = (query.find(KEY_PREFIX) != std::string::npos); + size_t pos = query.find_first_not_of(SPACE); std::string inputTrim = (pos == std::string::npos) ? "" : query.substr(pos); std::regex regex(" "); // regex split string by space @@ -61,17 +102,17 @@ DistributedDB::Query QueryHelper::StringToDbQuery(const std::string &query, bool // Counts how many keywords has been handled for (int count = 0; pointer <= end && count <= MAX_QUERY_COMPLEXITY; ++count) { std::string keyword = words.at(pointer); - if (keyword == DataQuery::EQUAL_TO) { + if (keyword == EQUAL_TO) { isSuccess = HandleEqualTo(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::NOT_EQUAL_TO) { + } else if (keyword == NOT_EQUAL_TO) { isSuccess = HandleNotEqualTo(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::GREATER_THAN) { + } else if (keyword == GREATER_THAN) { isSuccess = HandleGreaterThan(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::LESS_THAN) { + } else if (keyword == LESS_THAN) { isSuccess = HandleLessThan(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::GREATER_THAN_OR_EQUAL_TO) { + } else if (keyword == GREATER_THAN_OR_EQUAL_TO) { isSuccess = HandleGreaterThanOrEqualTo(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::LESS_THAN_OR_EQUAL_TO) { + } else if (keyword == LESS_THAN_OR_EQUAL_TO) { isSuccess = HandleLessThanOrEqualTo(words, pointer, end, dbQuery); } else { isSuccess = Handle(words, pointer, end, dbQuery); @@ -87,27 +128,27 @@ DistributedDB::Query QueryHelper::StringToDbQuery(const std::string &query, bool bool QueryHelper::Handle(const std::vector &words, int &pointer, int end, DBQuery &dbQuery) { std::string keyword = words.at(pointer); - if (keyword == DataQuery::IS_NULL) { + if (keyword == IS_NULL) { return HandleIsNull(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::IN) { + } else if (keyword == IN) { return HandleIn(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::NOT_IN) { + } else if (keyword == NOT_IN) { return HandleNotIn(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::LIKE) { + } else if (keyword == LIKE) { return HandleLike(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::NOT_LIKE) { + } else if (keyword == NOT_LIKE) { return HandleNotLike(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::AND) { + } else if (keyword == AND) { return HandleAnd(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::OR) { + } else if (keyword == OR) { return HandleOr(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::ORDER_BY_ASC) { + } else if (keyword == ORDER_BY_ASC) { return HandleOrderByAsc(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::ORDER_BY_DESC) { + } else if (keyword == ORDER_BY_DESC) { return HandleOrderByDesc(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::ORDER_BY_WRITE_TIME) { + } else if (keyword == ORDER_BY_WRITE_TIME) { return HandleOrderByWriteTime(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::LIMIT) { + } else if (keyword == LIMIT) { return HandleLimit(words, pointer, end, dbQuery); } else { return HandleExtra(words, pointer, end, dbQuery); @@ -117,19 +158,19 @@ bool QueryHelper::Handle(const std::vector &words, int &pointer, in bool QueryHelper::HandleExtra(const std::vector &words, int &pointer, int end, DBQuery &dbQuery) { std::string keyword = words.at(pointer); - if (keyword == DataQuery::BEGIN_GROUP) { + if (keyword == BEGIN_GROUP) { return HandleBeginGroup(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::END_GROUP) { + } else if (keyword == END_GROUP) { return HandleEndGroup(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::KEY_PREFIX) { + } else if (keyword == KEY_PREFIX) { return HandleKeyPrefix(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::IS_NOT_NULL) { + } else if (keyword == IS_NOT_NULL) { return HandleIsNotNull(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::DEVICE_ID) { + } else if (keyword == DEVICE_ID) { return HandleDeviceId(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::SUGGEST_INDEX) { + } else if (keyword == SUGGEST_INDEX) { return HandleSetSuggestIndex(words, pointer, end, dbQuery); - } else if (keyword == DataQuery::IN_KEYS) { + } else if (keyword == IN_KEYS) { return HandleInKeys(words, pointer, end, dbQuery); } ZLOGE("Invalid keyword."); @@ -145,15 +186,15 @@ bool QueryHelper::HandleEqualTo(const std::vector &words, int &poin const std::string &fieldType = words.at(pointer + 1); // fieldType const std::string &fieldName = words.at(pointer + 2); // fieldName const std::string &fieldValue = words.at(pointer + 3); // fieldValue - if (fieldType == DataQuery::TYPE_INTEGER) { + if (fieldType == TYPE_INTEGER) { dbQuery.EqualTo(StringToString(fieldName), StringToInt(fieldValue)); - } else if (fieldType == DataQuery::TYPE_LONG) { + } else if (fieldType == TYPE_LONG) { dbQuery.EqualTo(StringToString(fieldName), StringToLong(fieldValue)); - } else if (fieldType == DataQuery::TYPE_DOUBLE) { + } else if (fieldType == TYPE_DOUBLE) { dbQuery.EqualTo(StringToString(fieldName), StringToDouble(fieldValue)); - } else if (fieldType == DataQuery::TYPE_BOOLEAN) { + } else if (fieldType == TYPE_BOOLEAN) { dbQuery.EqualTo(StringToString(fieldName), StringToBoolean(fieldValue)); - } else if (fieldType == DataQuery::TYPE_STRING) { + } else if (fieldType == TYPE_STRING) { dbQuery.EqualTo(StringToString(fieldName), StringToString(fieldValue)); } else { ZLOGE("EqualTo wrong type."); @@ -172,15 +213,15 @@ bool QueryHelper::HandleNotEqualTo(const std::vector &words, int &p const std::string &fieldType = words.at(pointer + 1); // fieldType const std::string &fieldName = words.at(pointer + 2); // fieldName const std::string &fieldValue = words.at(pointer + 3); // fieldValue - if (fieldType == DataQuery::TYPE_INTEGER) { + if (fieldType == TYPE_INTEGER) { dbQuery.NotEqualTo(StringToString(fieldName), StringToInt(fieldValue)); - } else if (fieldType == DataQuery::TYPE_LONG) { + } else if (fieldType == TYPE_LONG) { dbQuery.NotEqualTo(StringToString(fieldName), StringToLong(fieldValue)); - } else if (fieldType == DataQuery::TYPE_DOUBLE) { + } else if (fieldType == TYPE_DOUBLE) { dbQuery.NotEqualTo(StringToString(fieldName), StringToDouble(fieldValue)); - } else if (fieldType == DataQuery::TYPE_BOOLEAN) { + } else if (fieldType == TYPE_BOOLEAN) { dbQuery.NotEqualTo(StringToString(fieldName), StringToBoolean(fieldValue)); - } else if (fieldType == DataQuery::TYPE_STRING) { + } else if (fieldType == TYPE_STRING) { dbQuery.NotEqualTo(StringToString(fieldName), StringToString(fieldValue)); } else { ZLOGE("NotEqualTo wrong type."); @@ -199,13 +240,13 @@ bool QueryHelper::HandleGreaterThan(const std::vector &words, int & const std::string &fieldType = words.at(pointer + 1); // fieldType const std::string &fieldName = words.at(pointer + 2); // fieldName const std::string &fieldValue = words.at(pointer + 3); // fieldValue - if (fieldType == DataQuery::TYPE_INTEGER) { + if (fieldType == TYPE_INTEGER) { dbQuery.GreaterThan(StringToString(fieldName), StringToInt(fieldValue)); - } else if (fieldType == DataQuery::TYPE_LONG) { + } else if (fieldType == TYPE_LONG) { dbQuery.GreaterThan(StringToString(fieldName), StringToLong(fieldValue)); - } else if (fieldType == DataQuery::TYPE_DOUBLE) { + } else if (fieldType == TYPE_DOUBLE) { dbQuery.GreaterThan(StringToString(fieldName), StringToDouble(fieldValue)); - } else if (fieldType == DataQuery::TYPE_STRING) { + } else if (fieldType == TYPE_STRING) { dbQuery.GreaterThan(StringToString(fieldName), StringToString(fieldValue)); } else { ZLOGE("GreaterThan wrong type."); @@ -224,13 +265,13 @@ bool QueryHelper::HandleLessThan(const std::vector &words, int &poi const std::string &fieldType = words.at(pointer + 1); // fieldType const std::string &fieldName = words.at(pointer + 2); // fieldName const std::string &fieldValue = words.at(pointer + 3); // fieldValue - if (fieldType == DataQuery::TYPE_INTEGER) { + if (fieldType == TYPE_INTEGER) { dbQuery.LessThan(StringToString(fieldName), StringToInt(fieldValue)); - } else if (fieldType == DataQuery::TYPE_LONG) { + } else if (fieldType == TYPE_LONG) { dbQuery.LessThan(StringToString(fieldName), StringToLong(fieldValue)); - } else if (fieldType == DataQuery::TYPE_DOUBLE) { + } else if (fieldType == TYPE_DOUBLE) { dbQuery.LessThan(StringToString(fieldName), StringToDouble(fieldValue)); - } else if (fieldType == DataQuery::TYPE_STRING) { + } else if (fieldType == TYPE_STRING) { dbQuery.LessThan(StringToString(fieldName), StringToString(fieldValue)); } else { ZLOGE("LessThan wrong type."); @@ -250,13 +291,13 @@ bool QueryHelper::HandleGreaterThanOrEqualTo( const std::string &fieldType = words.at(pointer + 1); // fieldType const std::string &fieldName = words.at(pointer + 2); // fieldName const std::string &fieldValue = words.at(pointer + 3); // fieldValue - if (fieldType == DataQuery::TYPE_INTEGER) { + if (fieldType == TYPE_INTEGER) { dbQuery.GreaterThanOrEqualTo(StringToString(fieldName), StringToInt(fieldValue)); - } else if (fieldType == DataQuery::TYPE_LONG) { + } else if (fieldType == TYPE_LONG) { dbQuery.GreaterThanOrEqualTo(StringToString(fieldName), StringToLong(fieldValue)); - } else if (fieldType == DataQuery::TYPE_DOUBLE) { + } else if (fieldType == TYPE_DOUBLE) { dbQuery.GreaterThanOrEqualTo(StringToString(fieldName), StringToDouble(fieldValue)); - } else if (fieldType == DataQuery::TYPE_STRING) { + } else if (fieldType == TYPE_STRING) { dbQuery.GreaterThanOrEqualTo(StringToString(fieldName), StringToString(fieldValue)); } else { ZLOGE("GreaterThanOrEqualTo wrong type."); @@ -276,13 +317,13 @@ bool QueryHelper::HandleLessThanOrEqualTo( const std::string &fieldType = words.at(pointer + 1); // fieldType const std::string &fieldName = words.at(pointer + 2); // fieldName const std::string &fieldValue = words.at(pointer + 3); // fieldValue - if (fieldType == DataQuery::TYPE_INTEGER) { + if (fieldType == TYPE_INTEGER) { dbQuery.LessThanOrEqualTo(StringToString(fieldName), StringToInt(fieldValue)); - } else if (fieldType == DataQuery::TYPE_LONG) { + } else if (fieldType == TYPE_LONG) { dbQuery.LessThanOrEqualTo(StringToString(fieldName), StringToLong(fieldValue)); - } else if (fieldType == DataQuery::TYPE_DOUBLE) { + } else if (fieldType == TYPE_DOUBLE) { dbQuery.LessThanOrEqualTo(StringToString(fieldName), StringToDouble(fieldValue)); - } else if (fieldType == DataQuery::TYPE_STRING) { + } else if (fieldType == TYPE_STRING) { dbQuery.LessThanOrEqualTo(StringToString(fieldName), StringToString(fieldValue)); } else { ZLOGE("LessThanOrEqualTo wrong type."); @@ -319,29 +360,29 @@ bool QueryHelper::HandleIsNotNull(const std::vector &words, int &po bool QueryHelper::HandleIn(const std::vector &words, int &pointer, int end, DBQuery &dbQuery) { // | <-------------------------4---------------------------->| - // words [ DataQuery::IN, fieldType, fieldName, DataQuery::START_IN, ...valueList, DataQuery::END_IN ] + // words [ IN, fieldType, fieldName, START_IN, ...valueList, END_IN ] // index [ -------0-----, ----1----, ----2----, ---------3---------, ... , ---------n--------] // ^ ^ // | | // pointer end // first fieldValue, or END if list is empty - if (pointer + 4 > end || words.at(pointer + 3) != DataQuery::START_IN) { + if (pointer + QUERY_WORD_LEN > end || words.at(pointer + QUERY_WORD_INDEX) != START_IN) { ZLOGE("In not enough params."); return false; } const std::string &fieldType = words.at(pointer + 1); // fieldType const std::string &fieldName = words.at(pointer + 2); // fieldName int elementPointer = pointer + 4; // first fieldValue, or END if list is empty - if (fieldType == DataQuery::TYPE_INTEGER) { + if (fieldType == TYPE_INTEGER) { const std::vector intValueList = GetIntegerList(words, elementPointer, end); dbQuery.In(StringToString(fieldName), intValueList); - } else if (fieldType == DataQuery::TYPE_LONG) { + } else if (fieldType == TYPE_LONG) { const std::vector longValueList = GetLongList(words, elementPointer, end); dbQuery.In(StringToString(fieldName), longValueList); - } else if (fieldType == DataQuery::TYPE_DOUBLE) { + } else if (fieldType == TYPE_DOUBLE) { const std::vector doubleValueList = GetDoubleList(words, elementPointer, end); dbQuery.In(StringToString(fieldName), doubleValueList); - } else if (fieldType == DataQuery::TYPE_STRING) { + } else if (fieldType == TYPE_STRING) { const std::vector stringValueList = GetStringList(words, elementPointer, end); dbQuery.In(StringToString(fieldName), stringValueList); } else { @@ -355,29 +396,29 @@ bool QueryHelper::HandleIn(const std::vector &words, int &pointer, bool QueryHelper::HandleNotIn(const std::vector &words, int &pointer, int end, DBQuery &dbQuery) { // |<--------------------------4-------------------------------->| - // words [ DataQuery::NOT_IN, fieldType, fieldName, DataQuery::START_IN, ...valueList, DataQuery::END_IN ] + // words [ NOT_IN, fieldType, fieldName, START_IN, ...valueList, END_IN ] // index [ --------0--------, ----1----, ----2----, ---------3---------, ... , ---------n--------] // ^ ^ // | | // pointer end // first fieldValue, or END if list is empty - if (pointer + 4 > end || words.at(pointer + 3) != DataQuery::START_IN) { + if (pointer + QUERY_WORD_LEN > end || words.at(pointer + QUERY_WORD_INDEX) != START_IN) { ZLOGE("NotIn not enough params."); return false; } const std::string &fieldType = words.at(pointer + 1); // fieldType const std::string &fieldName = words.at(pointer + 2); // fieldName int elementPointer = pointer + 4; // first fieldValue, or END if list is empty - if (fieldType == DataQuery::TYPE_INTEGER) { + if (fieldType == TYPE_INTEGER) { const std::vector intValueList = GetIntegerList(words, elementPointer, end); dbQuery.NotIn(StringToString(fieldName), intValueList); - } else if (fieldType == DataQuery::TYPE_LONG) { + } else if (fieldType == TYPE_LONG) { const std::vector longValueList = GetLongList(words, elementPointer, end); dbQuery.NotIn(StringToString(fieldName), longValueList); - } else if (fieldType == DataQuery::TYPE_DOUBLE) { + } else if (fieldType == TYPE_DOUBLE) { const std::vector doubleValueList = GetDoubleList(words, elementPointer, end); dbQuery.NotIn(StringToString(fieldName), doubleValueList); - } else if (fieldType == DataQuery::TYPE_STRING) { + } else if (fieldType == TYPE_STRING) { const std::vector stringValueList = GetStringList(words, elementPointer, end); dbQuery.NotIn(StringToString(fieldName), stringValueList); } else { @@ -460,7 +501,7 @@ bool QueryHelper::HandleOrderByWriteTime(const std::vector &words, } const std::string isAsc = words.at(pointer + 1); // isASC - dbQuery.OrderByWriteTime(isAsc == DataQuery::IS_ASC); + dbQuery.OrderByWriteTime(isAsc == IS_ASC); pointer += 2; // 2 Pointer goes to next keyword return true; } @@ -510,7 +551,7 @@ bool QueryHelper::HandleInKeys(const std::vector &words, int &point // pointer points at keyword "IN_KEYS", (pointer + 1) points at keyword "START_IN" int startInOffSet = pointer + 1; int queryLen = end - pointer; - if (queryLen < 2 || words.at(startInOffSet) != DataQuery::START_IN) { // This keyword has at least 2 params + if (queryLen < 2 || words.at(startInOffSet) != START_IN) { // This keyword has at least 2 params ZLOGE("In not enough params."); return false; } @@ -587,9 +628,9 @@ double QueryHelper::StringToDouble(const std::string &word) bool QueryHelper::StringToBoolean(const std::string &word) { - if (word == DataQuery::VALUE_TRUE) { + if (word == VALUE_TRUE) { return true; - } else if (word == DataQuery::VALUE_FALSE) { + } else if (word == VALUE_FALSE) { return false; } else { ZLOGE("StringToBoolean wrong value."); @@ -600,26 +641,26 @@ bool QueryHelper::StringToBoolean(const std::string &word) std::string QueryHelper::StringToString(const std::string &word) { std::string result = word; - if (result.compare(DataQuery::EMPTY_STRING) == 0) { + if (result.compare(EMPTY_STRING) == 0) { result = ""; return result; } size_t index = 0; // search from the beginning of the string while (true) { - index = result.find(DataQuery::SPACE_ESCAPE, index); + index = result.find(SPACE_ESCAPE, index); if (index == std::string::npos) { break; } - result.replace(index, 2, DataQuery::SPACE); // 2 chars to be replaced + result.replace(index, 2, SPACE); // 2 chars to be replaced index += 1; // replaced with 1 char, keep searching the remaining string } index = 0; // search from the beginning of the string while (true) { - index = result.find(DataQuery::SPECIAL_ESCAPE, index); + index = result.find(SPECIAL_ESCAPE, index); if (index == std::string::npos) { break; } - result.replace(index, 3, DataQuery::SPECIAL); // 3 chars to be replaced + result.replace(index, 3, SPECIAL); // 3 chars to be replaced index += 1; // replaced with 1 char, keep searching the remaining string } return result; @@ -630,7 +671,7 @@ std::vector QueryHelper::GetIntegerList(const std::vector &wor std::vector valueList; bool isEndFound = false; while (elementPointer <= end) { - if (words.at(elementPointer) == DataQuery::END_IN) { + if (words.at(elementPointer) == END_IN) { isEndFound = true; break; } @@ -650,7 +691,7 @@ std::vector QueryHelper::GetLongList(const std::vector &wo std::vector valueList; bool isEndFound = false; while (elementPointer <= end) { - if (words.at(elementPointer) == DataQuery::END_IN) { + if (words.at(elementPointer) == END_IN) { isEndFound = true; break; } @@ -670,7 +711,7 @@ std::vector QueryHelper::GetDoubleList(const std::vector &w std::vector valueList; bool isEndFound = false; while (elementPointer <= end) { - if (words.at(elementPointer) == DataQuery::END_IN) { + if (words.at(elementPointer) == END_IN) { isEndFound = true; break; } @@ -690,7 +731,7 @@ std::vector QueryHelper::GetStringList(const std::vector valueList; bool isEndFound = false; while (elementPointer <= end) { - if (words.at(elementPointer) == DataQuery::END_IN) { + if (words.at(elementPointer) == END_IN) { isEndFound = true; break; } diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/user_delegate.cpp b/datamgr_service/services/distributeddataservice/service/kvdb/user_delegate.cpp index cdb2991afc5955c813dbb7984e8efe55b86b0350..222cfef5baaf3a337edc86d66101f3fec0f2399b 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/user_delegate.cpp +++ b/datamgr_service/services/distributeddataservice/service/kvdb/user_delegate.cpp @@ -20,7 +20,7 @@ #include #include -#include "communicator/device_manager_adapter.h" +#include "device_manager_adapter.h" #include "log_print.h" #include "metadata/meta_data_manager.h" #include "utils/anonymous.h" @@ -200,7 +200,7 @@ bool UserDelegate::NotifyUserEvent(const UserDelegate::UserEvent &userEvent) UserDelegate::LocalUserObserver::LocalUserObserver(UserDelegate &userDelegate) : userDelegate_(userDelegate) {} -void UserDelegate::LocalUserObserver::OnAccountChanged(const DistributedKv::AccountEventInfo &eventInfo) +void UserDelegate::LocalUserObserver::OnAccountChanged(const AccountEventInfo &eventInfo, int32_t timeout) { ZLOGI("event info:%{public}s, %{public}d", eventInfo.userId.c_str(), eventInfo.status); userDelegate_.NotifyUserEvent({}); // just notify diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/user_delegate.h b/datamgr_service/services/distributeddataservice/service/kvdb/user_delegate.h index 3a7a7b319159fb078472678457f900a085338b16..497d16f2908e54d1d6dbb8b3c33aa013618af02e 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/user_delegate.h +++ b/datamgr_service/services/distributeddataservice/service/kvdb/user_delegate.h @@ -26,7 +26,7 @@ #include "visibility.h" namespace OHOS::DistributedData { -using AccountDelegate = DistributedKv::AccountDelegate; +using AccountDelegate = DistributedData::AccountDelegate; using DistributedData::UserStatus; class UserDelegate { public: @@ -48,7 +48,7 @@ private: class LocalUserObserver : public AccountDelegate::Observer { public: explicit LocalUserObserver(UserDelegate &userDelegate); - void OnAccountChanged(const DistributedKv::AccountEventInfo &eventInfo) override; + void OnAccountChanged(const DistributedData::AccountEventInfo &eventInfo, int32_t timeout) override; std::string Name() override; LevelType GetLevel() override { diff --git a/datamgr_service/services/distributeddataservice/service/matrix/BUILD.gn b/datamgr_service/services/distributeddataservice/service/matrix/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..85c4eb2d4b219977701236e0fadec9ea99ddc06d --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/matrix/BUILD.gn @@ -0,0 +1,65 @@ +# Copyright (c) 2024 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. +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +config("matrix_public_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +ohos_source_set("distributeddata_matrix") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + boundary_sanitize = true + ubsan = true + } + sources = [ + "src/device_matrix.cpp", + "src/matrix_event.cpp", + ] + + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] + + include_dirs = [ + "${data_service_path}/service/bootstrap/include", + "${data_service_path}/adapter/include/communicator", + ] + configs = [ ":matrix_public_config" ] + public_configs = [ ":matrix_public_config" ] + cflags = [ + "-Werror", + "-Wno-multichar", + "-Wno-c99-designator", + "-D_LIBCPP_HAS_COND_CLOCKWAIT", + "-Oz", + ] + + deps = [ + "${data_service_path}/framework:distributeddatasvcfwk", + "${data_service_path}/service/bootstrap:distributeddata_bootstrap", + ] + external_deps = [ + "device_manager:devicemanagersdk", + "hilog:libhilog", + "kv_store:datamgr_common", + ] + subsystem_name = "distributeddatamgr" + part_name = "datamgr_service" +} diff --git a/datamgr_service/services/distributeddataservice/service/matrix/src/auto_sync_matrix.cpp b/datamgr_service/services/distributeddataservice/service/matrix/src/auto_sync_matrix.cpp deleted file mode 100644 index 4b6b38b5403c5dc4202b05731e4bd5de8cc9ca7a..0000000000000000000000000000000000000000 --- a/datamgr_service/services/distributeddataservice/service/matrix/src/auto_sync_matrix.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (c) 2024 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 "AutoSyncMatrix" - -#include "auto_sync_matrix.h" - -#include "bootstrap.h" -#include "checker/checker_manager.h" -#include "device_manager_adapter.h" -#include "device_matrix.h" -#include "log_print.h" -#include "metadata/meta_data_manager.h" -#include "utils/anonymous.h" -#include "utils/converter.h" - -namespace OHOS::DistributedData { -using DMAdapter = DeviceManagerAdapter; -AutoSyncMatrix &AutoSyncMatrix::GetInstance() -{ - static AutoSyncMatrix instance; - return instance; -} - -AutoSyncMatrix::AutoSyncMatrix() -{ - auto deviceId = DMAdapter::GetInstance().GetLocalDevice().uuid; - MetaDataManager::GetInstance().Subscribe(StoreMetaData::GetPrefix({ deviceId }), - [this](const std::string &key, const std::string &meta, int32_t action) -> bool { - StoreMetaData metaData; - if (meta.empty()) { - MetaDataManager::GetInstance().LoadMeta(key, metaData); - } else { - StoreMetaData::Unmarshall(meta, metaData); - } - if (!IsAutoSync(metaData)) { - return true; - } - ZLOGI("bundleName:%{public}s storeId:%{public}s action:%{public}d", - metaData.bundleName.c_str(), Anonymous::Change(metaData.storeId).c_str(), action); - auto act = static_cast(action); - switch (act) { - case MetaDataManager::INSERT: - AddStore(metaData); - break; - case MetaDataManager::DELETE: - DelStore(metaData); - break; - case MetaDataManager::UPDATE: - UpdateStore(metaData); - break; - default: - break; - } - return true; - }); -} - -AutoSyncMatrix::~AutoSyncMatrix() -{ -} - -void AutoSyncMatrix::Initialize() -{ - auto deviceId = DMAdapter::GetInstance().GetLocalDevice().uuid; - std::vector metas; - if (!MetaDataManager::GetInstance().LoadMeta(StoreMetaData::GetPrefix({ deviceId }), metas)) { - ZLOGE("load meta failed."); - return; - } - for (const auto &meta : metas) { - if (!IsAutoSync(meta)) { - continue; - } - AddStore(meta); - } -} - -bool AutoSyncMatrix::IsAutoSync(const StoreMetaData &meta) -{ - if (meta.bundleName == Bootstrap::GetInstance().GetProcessLabel()) { - return false; - } - if (meta.dataType != DataType::DYNAMICAL || DeviceMatrix::GetInstance().IsDynamic(meta)) { - return false; - } - return meta.isAutoSync; -} - -void AutoSyncMatrix::AddStore(const StoreMetaData &meta) -{ - std::lock_guard lock(mutex_); - auto it = std::find(metas_.begin(), metas_.end(), meta); - if (it != metas_.end()) { - return; - } - metas_.emplace_back(std::move(meta)); - size_t pos = metas_.size() - 1; - for (auto &[device, mask] : onlines_) { - mask.Set(pos); - } - for (auto &[device, mask] : offlines_) { - mask.Set(pos); - } -} - -void AutoSyncMatrix::DelStore(const StoreMetaData &meta) -{ - std::lock_guard lock(mutex_); - auto it = metas_.begin(); - for (; it < metas_.end(); it++) { - if ((*it) != meta) { - continue; - } - metas_.erase(it); - break; - } - size_t pos = static_cast(it - metas_.begin()); - if (pos == metas_.size()) { - return; - } - for (auto &[device, mask] : onlines_) { - mask.Delete(pos); - } - for (auto &[device, mask] : offlines_) { - mask.Delete(pos); - } -} - -void AutoSyncMatrix::Mask::Delete(size_t pos) -{ - if (pos >= MAX_SIZE) { - ZLOGE("pos:%{public}zu exceeds maximum value:%{public}d", pos, MAX_SIZE); - return; - } - std::bitset tmp; - for (size_t i = 0; i < pos; i++) { - tmp.set(i); - } - tmp = tmp & data; - data >>= pos + 1; - data <<= pos; - data = data | tmp; -} - -void AutoSyncMatrix::Mask::Set(size_t pos) -{ - if (pos >= MAX_SIZE) { - ZLOGE("pos:%{public}zu exceeds maximum value:%{public}d", pos, MAX_SIZE); - return; - } - data.set(pos); -} - -void AutoSyncMatrix::Mask::Init(size_t size) -{ - if (size >= MAX_SIZE) { - ZLOGE("pos:%{public}zu exceeds maximum value:%{public}d", size, MAX_SIZE); - return; - } - for (size_t i = 0; i < size; i++) { - data.set(i); - } -} - -void AutoSyncMatrix::Mask::Reset(size_t pos) -{ - if (pos >= MAX_SIZE) { - ZLOGE("pos:%{public}zu exceeds maximum value:%{public}d", pos, MAX_SIZE); - return; - } - data.reset(pos); -} - -void AutoSyncMatrix::UpdateStore(const StoreMetaData &meta) -{ - std::lock_guard lock(mutex_); - for (auto &store : metas_) { - if (store.GetKey() != meta.GetKey()) { - continue; - } - store = meta; - break; - } -} - -void AutoSyncMatrix::Online(const std::string &device) -{ - if (device.empty()) { - return; - } - std::lock_guard lock(mutex_); - Mask mask; - mask.Init(metas_.size()); - auto it = offlines_.find(device); - if (it != offlines_.end()) { - mask = it->second; - offlines_.erase(it); - } - onlines_.insert_or_assign(device, mask); -} - -void AutoSyncMatrix::Offline(const std::string &device) -{ - if (device.empty()) { - return; - } - std::lock_guard lock(mutex_); - Mask mask; - mask.Init(metas_.size()); - auto it = onlines_.find(device); - if (it != onlines_.end()) { - mask = it->second; - onlines_.erase(it); - } - offlines_.insert_or_assign(device, mask); -} - -void AutoSyncMatrix::OnChanged(const StoreMetaData &metaData) -{ - std::lock_guard lock(mutex_); - auto it = std::find(metas_.begin(), metas_.end(), metaData); - if (it == metas_.end()) { - return; - } - size_t pos = static_cast(it - metas_.begin()); - for (auto &[device, mask] : onlines_) { - mask.Set(pos); - } - for (auto &[device, mask] : offlines_) { - mask.Set(pos); - } -} - -void AutoSyncMatrix::OnExchanged(const std::string &device, const StoreMetaData &metaData) -{ - std::lock_guard lock(mutex_); - auto it = std::find(metas_.begin(), metas_.end(), metaData); - if (it == metas_.end()) { - return; - } - size_t pos = static_cast(it - metas_.begin()); - auto iter = onlines_.find(device); - if (iter != onlines_.end()) { - iter->second.Reset(pos); - } - iter = offlines_.find(device); - if (iter != offlines_.end()) { - iter->second.Reset(pos); - } -} - -std::vector AutoSyncMatrix::GetChangedStore(const std::string &device) -{ - if (device.empty()) { - return {}; - } - std::lock_guard lock(mutex_); - auto it = onlines_.find(device); - if (it == onlines_.end()) { - return {}; - } - auto mask = it->second; - size_t size = metas_.size(); - Mask tmp; - tmp.Set(0); - std::vector result; - for (size_t i = 0; i < size; i++) { - if (tmp.data == (mask.data & tmp.data)) { - result.emplace_back(metas_[i]); - } - mask.data >>= 1; - } - return result; -} -} // namespace OHOS::DistributedData \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/network/BUILD.gn b/datamgr_service/services/distributeddataservice/service/network/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..39bf8025f371936f3f5d4db1950117bfb4ccb5e1 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/network/BUILD.gn @@ -0,0 +1,63 @@ +# Copyright (c) 2024 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. +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +config("network_public_config") { + visibility = [ ":*" ] + include_dirs = [ + "${data_service_path}/service/network", + "${data_service_path}/adapter/include/communicator", + ] +} + +ohos_source_set("distributeddata_network") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + boundary_sanitize = true + ubsan = true + } + sources = [ "network_adapter.cpp" ] + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] + + configs = [ ":network_public_config" ] + cflags = [ + "-fdata-sections", + "-ffunction-sections", + "-Werror", + "-Wno-multichar", + "-Wno-c99-designator", + "-D_LIBCPP_HAS_COND_CLOCKWAIT", + "-Oz", + ] + + deps = [ + "${data_service_path}/adapter/communicator:distributeddata_communicator", + ] + + external_deps = [ + "device_manager:devicemanagersdk", + "hilog:libhilog", + "kv_store:datamgr_common", + "netmanager_base:net_conn_manager_if", + ] + + subsystem_name = "distributeddatamgr" + part_name = "datamgr_service" +} diff --git a/datamgr_service/services/distributeddataservice/service/network/network_adapter.cpp b/datamgr_service/services/distributeddataservice/service/network/network_adapter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7092184a78de1ba84e8b270d9adc2088ba3313a2 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/network/network_adapter.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2025 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 "NetworkAdapter" +#include "network_adapter.h" + +#include "device_manager_adapter.h" +#include "log_print.h" +#include "net_conn_callback_stub.h" +#include "net_conn_client.h" +#include "net_handle.h" +namespace OHOS::DistributedData { +using namespace OHOS::NetManagerStandard; +static NetworkAdapter::NetworkType Convert(NetManagerStandard::NetBearType bearType) +{ + switch (bearType) { + case NetManagerStandard::BEARER_WIFI: + return NetworkAdapter::WIFI; + case NetManagerStandard::BEARER_CELLULAR: + return NetworkAdapter::CELLULAR; + case NetManagerStandard::BEARER_ETHERNET: + return NetworkAdapter::ETHERNET; + default: + return NetworkAdapter::OTHER; + } +} + +class NetConnCallbackObserver : public NetConnCallbackStub { +public: + explicit NetConnCallbackObserver(NetworkAdapter &netAdapter) : netAdapter_(netAdapter) {} + ~NetConnCallbackObserver() override = default; + int32_t NetAvailable(sptr &netHandle) override; + int32_t NetCapabilitiesChange(sptr &netHandle, const sptr &netAllCap) override; + int32_t NetConnectionPropertiesChange(sptr &netHandle, const sptr &info) override; + int32_t NetLost(sptr &netHandle) override; + int32_t NetUnavailable() override; + int32_t NetBlockStatusChange(sptr &netHandle, bool blocked) override; + +private: + NetworkAdapter &netAdapter_; +}; + +int32_t NetConnCallbackObserver::NetAvailable(sptr &netHandle) +{ + ZLOGI("OnNetworkAvailable"); + return 0; +} + +int32_t NetConnCallbackObserver::NetUnavailable() +{ + ZLOGI("OnNetworkUnavailable"); + netAdapter_.SetNet(NetworkAdapter::NONE); + return 0; +} + +int32_t NetConnCallbackObserver::NetCapabilitiesChange(sptr &netHandle, + const sptr &netAllCap) +{ + ZLOGI("OnNetCapabilitiesChange"); + if (netHandle == nullptr || netAllCap == nullptr) { + return 0; + } + if (netAllCap->netCaps_.count(NetManagerStandard::NET_CAPABILITY_VALIDATED) && !netAllCap->bearerTypes_.empty()) { + netAdapter_.SetNet(Convert(*netAllCap->bearerTypes_.begin())); + } else { + netAdapter_.SetNet(NetworkAdapter::NONE); + } + return 0; +} + +int32_t NetConnCallbackObserver::NetConnectionPropertiesChange(sptr &netHandle, + const sptr &info) +{ + ZLOGI("OnNetConnectionPropertiesChange"); + return 0; +} + +int32_t NetConnCallbackObserver::NetLost(sptr &netHandle) +{ + ZLOGI("OnNetLost"); + netAdapter_.SetNet(NetworkAdapter::NONE); + return 0; +} + +int32_t NetConnCallbackObserver::NetBlockStatusChange(sptr &netHandle, bool blocked) +{ + ZLOGI("OnNetBlockStatusChange"); + return 0; +} + +NetworkAdapter::NetworkAdapter() + : cloudDmInfo({ "cloudDeviceId", "cloudDeviceName", 0, "cloudNetworkId", 0 }) +{ +} + +NetworkAdapter::~NetworkAdapter() +{ +} + + NetworkAdapter &NetworkAdapter::GetInstance() +{ + static NetworkAdapter adapter; + return adapter; +} + +void NetworkAdapter::RegOnNetworkChange() +{ + static std::atomic_bool flag = false; + if (flag.exchange(true)) { + ZLOGW("run only one"); + return; + } + sptr observer = new (std::nothrow) NetConnCallbackObserver(*this); + if (observer == nullptr) { + ZLOGE("new operator error.observer is nullptr"); + flag.store(false); + return; + } + auto nRet = NetConnClient::GetInstance().RegisterNetConnCallback(observer); + if (nRet != NETMANAGER_SUCCESS) { + ZLOGE("RegisterNetConnCallback failed, ret = %{public}d", nRet); + flag.store(false); + } +} + +bool NetworkAdapter::IsNetworkAvailable() +{ + if (defaultNetwork_ != NONE || expireTime_ > GetTimeStamp()) { + return defaultNetwork_ != NONE; + } + return RefreshNet() != NONE; +} + +NetworkAdapter::NetworkType NetworkAdapter::SetNet(NetworkType netWorkType) +{ + auto oldNet = defaultNetwork_; + bool ready = oldNet == NONE && netWorkType != NONE && (GetTimeStamp() - netLostTime_) > NET_LOST_DURATION; + bool offline = oldNet != NONE && netWorkType == NONE; + if (offline) { + netLostTime_ = GetTimeStamp(); + } + defaultNetwork_ = netWorkType; + expireTime_ = GetTimeStamp() + EFFECTIVE_DURATION; + if (ready) { + DeviceManagerAdapter::GetInstance().OnReady(cloudDmInfo); + } + if (offline) { + DeviceManagerAdapter::GetInstance().Offline(cloudDmInfo); + } + return netWorkType; +} + +NetworkAdapter::NetworkType NetworkAdapter::GetNetworkType(bool retrieve) +{ + if (!retrieve) { + return defaultNetwork_; + } + return RefreshNet(); +} + +NetworkAdapter::NetworkType NetworkAdapter::RefreshNet() +{ + NetHandle handle; + auto status = NetConnClient::GetInstance().GetDefaultNet(handle); + if (status != 0 || handle.GetNetId() == 0) { + return SetNet(NONE); + } + NetAllCapabilities capabilities; + status = NetConnClient::GetInstance().GetNetCapabilities(handle, capabilities); + if (status != 0 || !capabilities.netCaps_.count(NetManagerStandard::NET_CAPABILITY_VALIDATED) || + capabilities.bearerTypes_.empty()) { + return SetNet(NONE); + } + return SetNet(Convert(*capabilities.bearerTypes_.begin())); +} +} diff --git a/datamgr_service/services/distributeddataservice/service/network/network_adapter.h b/datamgr_service/services/distributeddataservice/service/network/network_adapter.h new file mode 100644 index 0000000000000000000000000000000000000000..63a9da6b2d021697bcbec740fb8b765aeecd7adb --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/network/network_adapter.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025 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_NETWORK_ADAPTER_H +#define OHOS_DISTRIBUTED_DATA_NETWORK_ADAPTER_H + +#include +#include +#include "dm_device_info.h" + +namespace OHOS::DistributedData { +class NetworkAdapter { +public: + enum NetworkType { + NONE, + CELLULAR, + WIFI, + ETHERNET, + OTHER + }; + using DmDeviceInfo = OHOS::DistributedHardware::DmDeviceInfo; + static NetworkAdapter &GetInstance(); + bool IsNetworkAvailable(); + NetworkType GetNetworkType(bool retrieve = false); + void RegOnNetworkChange(); + friend class NetConnCallbackObserver; + static inline uint64_t GetTimeStamp() + { + return std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count(); + } +private: + NetworkAdapter(); + ~NetworkAdapter(); + const DmDeviceInfo cloudDmInfo; + NetworkType SetNet(NetworkType netWorkType); + NetworkType RefreshNet(); + static constexpr int32_t EFFECTIVE_DURATION = 30 * 1000; // ms + static constexpr int32_t NET_LOST_DURATION = 10 * 1000; // ms + NetworkType defaultNetwork_ = NONE; + uint64_t expireTime_ = 0; + uint64_t netLostTime_ = 0; +}; +} +#endif // OHOS_DISTRIBUTED_DATA_NETWORK_ADAPTER_H diff --git a/datamgr_service/services/distributeddataservice/service/object/BUILD.gn b/datamgr_service/services/distributeddataservice/service/object/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..7520d71420e5256abbfbd7f5a2dc643a98219215 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/object/BUILD.gn @@ -0,0 +1,84 @@ +# Copyright (c) 2024 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. +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +config("object_public_config") { + visibility = [ ":*" ] + + include_dirs = [ + "${data_service_path}/service/common", + "${data_service_path}/adapter/include/communicator", + "${data_service_path}/adapter/include/utils", + ] +} + +ohos_source_set("distributeddata_object") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + boundary_sanitize = true + ubsan = true + } + + sources = [ + "src/object_asset_loader.cpp", + "src/object_asset_machine.cpp", + "src/object_callback_proxy.cpp", + "src/object_data_listener.cpp", + "src/object_dms_handler.cpp", + "src/object_manager.cpp", + "src/object_service_impl.cpp", + "src/object_service_stub.cpp", + "src/object_snapshot.cpp", + "src/object_types_utils.cpp", + ] + + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] + + include_dirs = [ "include" ] + + configs = [ ":object_public_config" ] + + cflags = [ + "-Werror", + "-Wno-multichar", + "-Wno-c99-designator", + "-D_LIBCPP_HAS_COND_CLOCKWAIT", + "-Oz", + ] + + deps = [ + "${data_service_path}/framework:distributeddatasvcfwk", + "${data_service_path}/service/bootstrap:distributeddata_bootstrap", + "${data_service_path}/service/common:distributeddata_common", + ] + + external_deps = [ + "access_token:libtokenid_sdk", + "data_object:data_object_inner", + "dfs_service:cloudsync_asset_kit_inner", + "dfs_service:distributed_file_daemon_kit_inner", + "dmsfwk:distributed_sdk", + "kv_store:datamgr_common", + "kv_store:distributeddb", + ] + + subsystem_name = "distributeddatamgr" + part_name = "datamgr_service" +} diff --git a/datamgr_service/services/distributeddataservice/service/object/object_asset_loader.h b/datamgr_service/services/distributeddataservice/service/object/include/object_asset_loader.h similarity index 100% rename from datamgr_service/services/distributeddataservice/service/object/object_asset_loader.h rename to datamgr_service/services/distributeddataservice/service/object/include/object_asset_loader.h diff --git a/datamgr_service/services/distributeddataservice/service/object/object_asset_machine.h b/datamgr_service/services/distributeddataservice/service/object/include/object_asset_machine.h similarity index 100% rename from datamgr_service/services/distributeddataservice/service/object/object_asset_machine.h rename to datamgr_service/services/distributeddataservice/service/object/include/object_asset_machine.h diff --git a/datamgr_service/services/distributeddataservice/service/object/object_callback_proxy.h b/datamgr_service/services/distributeddataservice/service/object/include/object_callback_proxy.h similarity index 100% rename from datamgr_service/services/distributeddataservice/service/object/object_callback_proxy.h rename to datamgr_service/services/distributeddataservice/service/object/include/object_callback_proxy.h diff --git a/datamgr_service/services/distributeddataservice/service/object/object_common.h b/datamgr_service/services/distributeddataservice/service/object/include/object_common.h similarity index 96% rename from datamgr_service/services/distributeddataservice/service/object/object_common.h rename to datamgr_service/services/distributeddataservice/service/object/include/object_common.h index fe252d3cec337919f79306a7fbb3e26f4c580e6f..759a48a5c57ac2bf5b477f9df2ca64948d1c3cfc 100644 --- a/datamgr_service/services/distributeddataservice/service/object/object_common.h +++ b/datamgr_service/services/distributeddataservice/service/object/include/object_common.h @@ -1,39 +1,39 @@ -/* - * Copyright (c) 2022 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 DISTRIBUTEDDATAMGR_OBJECT_COMMON_H -#define DISTRIBUTEDDATAMGR_OBJECT_COMMON_H -namespace OHOS { -namespace DistributedObject { -enum ObjectDistributedType : int32_t { - OBJECT_SINGLE_VERSION = 20, - DISTRIBUTED_TYPE_BUTT -}; - -enum Status : int32_t { - OBJECT_SUCCESS, - OBJECT_DBSTATUS_ERROR, - OBJECT_INNER_ERROR, - OBJECT_PERMISSION_DENIED, - OBJECT_STORE_NOT_FOUND -}; - -class ObjectCommon { -public: - constexpr static const char *OBJECTSTORE_DB_STOREID = "distributedObject_"; -}; -} // namespace DistributedObject -} // namespace OHOS -#endif // DISTRIBUTEDDATAMGR_OBJECT_COMMON_H +/* + * Copyright (c) 2022 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 DISTRIBUTEDDATAMGR_OBJECT_COMMON_H +#define DISTRIBUTEDDATAMGR_OBJECT_COMMON_H +namespace OHOS { +namespace DistributedObject { +enum ObjectDistributedType : int32_t { + OBJECT_SINGLE_VERSION = 20, + DISTRIBUTED_TYPE_BUTT +}; + +enum Status : int32_t { + OBJECT_SUCCESS, + OBJECT_DBSTATUS_ERROR, + OBJECT_INNER_ERROR, + OBJECT_PERMISSION_DENIED, + OBJECT_STORE_NOT_FOUND +}; + +class ObjectCommon { +public: + constexpr static const char *OBJECTSTORE_DB_STOREID = "distributedObject_"; +}; +} // namespace DistributedObject +} // namespace OHOS +#endif // DISTRIBUTEDDATAMGR_OBJECT_COMMON_H diff --git a/datamgr_service/services/distributeddataservice/service/object/object_data_listener.h b/datamgr_service/services/distributeddataservice/service/object/include/object_data_listener.h similarity index 97% rename from datamgr_service/services/distributeddataservice/service/object/object_data_listener.h rename to datamgr_service/services/distributeddataservice/service/object/include/object_data_listener.h index 0ee568c60ba4fb368dc9d1ccf6435eae73f6e3b9..3c1bfdea0dee7cf4dfb4303b42b3b5f2684d64a6 100644 --- a/datamgr_service/services/distributeddataservice/service/object/object_data_listener.h +++ b/datamgr_service/services/distributeddataservice/service/object/include/object_data_listener.h @@ -1,44 +1,44 @@ -/* - * Copyright (c) 2022 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 DISTRIBUTEDDATAMGR_OBJECT_DATA_LISTENER_H -#define DISTRIBUTEDDATAMGR_OBJECT_DATA_LISTENER_H - -#include "kv_store_observer.h" -#include "asset/asset_recv_callback_stub.h" -namespace OHOS { -namespace DistributedObject { -using AssetObj = Storage::DistributedFile::AssetObj; -class ObjectDataListener : public DistributedDB::KvStoreObserver { -public: - ObjectDataListener(); - ~ObjectDataListener(); - // Database change callback - void OnChange(const DistributedDB::KvStoreChangedData &data) override; -}; - -class ObjectAssetsRecvListener : public Storage::DistributedFile::AssetRecvCallbackStub { -public: - ObjectAssetsRecvListener() =default; - ~ObjectAssetsRecvListener() =default; - int32_t OnStart(const std::string &srcNetworkId, - const std::string &dstNetworkId, const std::string &sessionId, - const std::string &dstBundleName) override; - int32_t OnFinished(const std::string &srcNetworkId, - const sptr &assetObj, int32_t result) override; -}; -} // namespace DistributedObject -} // namespace OHOS -#endif // DISTRIBUTEDDATAMGR_OBJECT_DATA_LISTENER_H +/* + * Copyright (c) 2022 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 DISTRIBUTEDDATAMGR_OBJECT_DATA_LISTENER_H +#define DISTRIBUTEDDATAMGR_OBJECT_DATA_LISTENER_H + +#include "kv_store_observer.h" +#include "asset/asset_recv_callback_stub.h" +namespace OHOS { +namespace DistributedObject { +using AssetObj = Storage::DistributedFile::AssetObj; +class ObjectDataListener : public DistributedDB::KvStoreObserver { +public: + ObjectDataListener(); + ~ObjectDataListener(); + // Database change callback + void OnChange(const DistributedDB::KvStoreChangedData &data) override; +}; + +class ObjectAssetsRecvListener : public Storage::DistributedFile::AssetRecvCallbackStub { +public: + ObjectAssetsRecvListener() =default; + ~ObjectAssetsRecvListener() =default; + int32_t OnStart(const std::string &srcNetworkId, + const std::string &dstNetworkId, const std::string &sessionId, + const std::string &dstBundleName) override; + int32_t OnFinished(const std::string &srcNetworkId, + const sptr &assetObj, int32_t result) override; +}; +} // namespace DistributedObject +} // namespace OHOS +#endif // DISTRIBUTEDDATAMGR_OBJECT_DATA_LISTENER_H diff --git a/datamgr_service/services/distributeddataservice/service/object/object_dms_handler.h b/datamgr_service/services/distributeddataservice/service/object/include/object_dms_handler.h similarity index 100% rename from datamgr_service/services/distributeddataservice/service/object/object_dms_handler.h rename to datamgr_service/services/distributeddataservice/service/object/include/object_dms_handler.h diff --git a/datamgr_service/services/distributeddataservice/service/object/object_manager.h b/datamgr_service/services/distributeddataservice/service/object/include/object_manager.h similarity index 97% rename from datamgr_service/services/distributeddataservice/service/object/object_manager.h rename to datamgr_service/services/distributeddataservice/service/object/include/object_manager.h index c750c61345f125e0c4396d03a3a59238cc9ba184..2f4f6302c177cd23197b245ffd2e8a056d3cfdc5 100644 --- a/datamgr_service/services/distributeddataservice/service/object/object_manager.h +++ b/datamgr_service/services/distributeddataservice/service/object/include/object_manager.h @@ -1,225 +1,225 @@ -/* - * Copyright (c) 2022 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 DISTRIBUTEDDATAMGR_OBJECT_MANAGER_H -#define DISTRIBUTEDDATAMGR_OBJECT_MANAGER_H - -#include - -#include "concurrent_map.h" -#include "device_manager_adapter.h" -#include "kv_store_delegate_manager.h" -#include "kvstore_sync_callback.h" -#include "object_asset_loader.h" -#include "object_callback.h" -#include "object_callback_proxy.h" -#include "object_common.h" -#include "object_data_listener.h" -#include "object_snapshot.h" -#include "object_types.h" -#include "serializable/serializable.h" -#include "types.h" -#include "value_proxy.h" -namespace OHOS { -namespace DistributedObject { -using SyncCallBack = std::function &results)>; -using ObjectRecord = std::map>; -class SequenceSyncManager { -public: - enum Result { - SUCCESS_USER_IN_USE, - SUCCESS_USER_HAS_FINISHED, - ERR_SID_NOT_EXIST - }; - static SequenceSyncManager *GetInstance() - { - static SequenceSyncManager sequenceSyncManager; - return &sequenceSyncManager; - } - - uint64_t AddNotifier(const std::string &userId, SyncCallBack &callback); - Result DeleteNotifier(uint64_t sequenceId, std::string &userId); - Result Process( - uint64_t sequenceId, const std::map &results, std::string &userId); - -private: - Result DeleteNotifierNoLock(uint64_t sequenceId, std::string &userId); - std::mutex notifierLock_; - std::map> userIdSeqIdRelations_; - std::map seqIdCallbackRelations_; -}; - -class ObjectStoreManager { -public: - using DmAdaper = OHOS::DistributedData::DeviceManagerAdapter; - using UriToSnapshot = std::shared_ptr>>; - - enum RestoreStatus : int32_t { - NONE = 0, - DATA_READY, - DATA_NOTIFIED, - ASSETS_READY, - ALL_READY, - STATUS_BUTT - }; - - ObjectStoreManager(); - ~ObjectStoreManager(); - static ObjectStoreManager *GetInstance() - { - static ObjectStoreManager *manager = new ObjectStoreManager(); - return manager; - } - int32_t Save(const std::string &appId, const std::string &sessionId, const ObjectRecord &data, - const std::string &deviceId, sptr callback); - int32_t RevokeSave( - const std::string &appId, const std::string &sessionId, sptr callback); - int32_t Retrieve(const std::string &bundleName, const std::string &sessionId, - sptr callback, uint32_t tokenId); - void SetData(const std::string &dataDir, const std::string &userId); - int32_t Clear(); - int32_t DeleteByAppId(const std::string &appId, int32_t user); - void RegisterRemoteCallback(const std::string &bundleName, const std::string &sessionId, - pid_t pid, uint32_t tokenId, - sptr callback); - void UnregisterRemoteCallback(const std::string &bundleName, pid_t pid, uint32_t tokenId, - const std::string &sessionId = ""); - void NotifyChange(ObjectRecord &changedData); - void NotifyAssetsReady(const std::string& objectKey, const std::string& bundleName, - const std::string& srcNetworkId = ""); - void NotifyAssetsStart(const std::string& objectKey, const std::string& srcNetworkId = ""); - void CloseAfterMinute(); - int32_t Open(); - void SetThreadPool(std::shared_ptr executors); - UriToSnapshot GetSnapShots(const std::string &bundleName, const std::string &storeName); - int32_t BindAsset(const uint32_t tokenId, const std::string& appId, const std::string& sessionId, - ObjectStore::Asset& asset, ObjectStore::AssetBindInfo& bindInfo); - int32_t OnAssetChanged(const uint32_t tokenId, const std::string& appId, const std::string& sessionId, - const std::string& deviceId, const ObjectStore::Asset& asset); - void DeleteSnapshot(const std::string &bundleName, const std::string &sessionId); -private: - constexpr static const char *SEPERATOR = "_"; - constexpr static const char *TIME_REGEX = "_\\d{10}_p_"; - constexpr static int BUNDLE_NAME_INDEX = 0; - constexpr static int SESSION_ID_INDEX = 1; - constexpr static int SOURCE_DEVICE_UDID_INDEX = 2; - constexpr static int TIME_INDEX = 4; - constexpr static int PROPERTY_NAME_INDEX = 5; - constexpr static const char *LOCAL_DEVICE = "local"; - constexpr static const char *USERID = "USERID"; - constexpr static int8_t MAX_OBJECT_SIZE_PER_APP = 16; - constexpr static int8_t DECIMAL_BASE = 10; - constexpr static int WAIT_TIME = 60; - static constexpr size_t TIME_TASK_NUM = 1; - static constexpr int64_t INTERVAL = 1; - struct CallbackInfo { - pid_t pid; - std::map> observers_; - bool operator<(const CallbackInfo &it_) const - { - if (pid < it_.pid) { - return true; - } - return false; - } - }; - struct SaveInfo : DistributedData::Serializable { - std::string bundleName; - std::string sessionId; - std::string sourceDeviceId; - std::string targetDeviceId; - std::string timestamp; - SaveInfo() = default; - SaveInfo(const std::string &bundleName, const std::string &sessionId, const std::string &sourceDeviceId, - const std::string &targetDeviceId, const std::string ×tamp); - bool Marshal(json &node) const override; - bool Unmarshal(const json &node) override; - std::string ToPropertyPrefix(); - }; - DistributedDB::KvStoreNbDelegate *OpenObjectKvStore(); - void FlushClosedStore(); - void Close(); - int32_t SetSyncStatus(bool status); - int32_t SaveToStore(const std::string &appId, const std::string &sessionId, const std::string &toDeviceId, - const ObjectRecord &data); - int32_t SyncOnStore(const std::string &prefix, const std::vector &deviceList, SyncCallBack &callback); - int32_t RevokeSaveToStore(const std::string &prefix); - int32_t RetrieveFromStore(const std::string &appId, const std::string &sessionId, ObjectRecord &results); - void SyncCompleted(const std::map &results, uint64_t sequenceId); - std::vector SplitEntryKey(const std::string &key); - void ProcessOldEntry(const std::string &appId); - void ProcessSyncCallback(const std::map &results, const std::string &appId, - const std::string &sessionId, const std::string &deviceId); - void SaveUserToMeta(); - std::string GetCurrentUser(); - void DoNotify(uint32_t tokenId, const CallbackInfo& value, const std::map& data, - bool allReady); - void DoNotifyAssetsReady(uint32_t tokenId, const CallbackInfo& value, const std::string& objectKey, bool allReady); - void DoNotifyWaitAssetTimeout(const std::string &objectKey); - std::map> GetAssetsFromStore(const ObjectRecord& changedData); - static bool IsAssetKey(const std::string& key); - static bool IsAssetComplete(const ObjectRecord& result, const std::string& assetPrefix); - Assets GetAssetsFromDBRecords(const ObjectRecord& result); - bool RegisterAssetsLister(); - void ComputeStatus(const std::string& objectKey, const SaveInfo& saveInfo, - const std::map& data); - void NotifyDataChanged(const std::map& data, const SaveInfo& saveInfo); - int32_t PushAssets(const std::string &srcBundleName, const std::string &dstBundleName, const std::string &sessionId, - const ObjectRecord &data, const std::string &deviceId); - int32_t WaitAssets(const std::string& objectKey, const SaveInfo& saveInfo, - const std::map& data); - void PullAssets(const std::map& data, const SaveInfo& saveInfo); - std::map GetObjectData(const ObjectRecord& changedData, SaveInfo& saveInfo, - bool& hasAsset); - inline std::string GetPropertyPrefix(const std::string &appId, const std::string &sessionId) - { - return appId + SEPERATOR + sessionId + SEPERATOR + DmAdaper::GetInstance().GetLocalDevice().udid + SEPERATOR; - }; - inline std::string GetPropertyPrefix( - const std::string &appId, const std::string &sessionId, const std::string &toDeviceId) - { - return appId + SEPERATOR + sessionId + SEPERATOR + DmAdaper::GetInstance().GetLocalDevice().udid - + SEPERATOR + toDeviceId + SEPERATOR; - }; - inline std::string GetPrefixWithoutDeviceId(const std::string &appId, const std::string &sessionId) - { - return appId + SEPERATOR + sessionId + SEPERATOR; - }; - inline std::string GetMetaUserIdKey(const std::string &userId, const std::string &appId) - { - return std::string(USERID) + SEPERATOR + userId + SEPERATOR + appId + SEPERATOR - + DmAdaper::GetInstance().GetLocalDevice().udid; - }; - std::recursive_mutex kvStoreMutex_; - std::mutex mutex_; - DistributedDB::KvStoreDelegateManager *kvStoreDelegateManager_ = nullptr; - DistributedDB::KvStoreNbDelegate *delegate_ = nullptr; - ObjectDataListener *objectDataListener_ = nullptr; - sptr objectAssetsRecvListener_ = nullptr; - sptr objectAssetsSendListener_ = nullptr; - uint32_t syncCount_ = 0; - std::string userId_; - std::atomic isSyncing_ = false; - ConcurrentMap callbacks_; - std::shared_ptr executors_; - DistributedData::AssetBindInfo ConvertBindInfo(ObjectStore::AssetBindInfo& bindInfo); - VBucket ConvertVBucket(ObjectStore::ValuesBucket &vBucket); - ConcurrentMap> snapshots_; // key:bundleName_sessionId - ConcurrentMap bindSnapshots_; // key:bundleName_storeName - ConcurrentMap restoreStatus_; // key:bundleName+sessionId - ConcurrentMap objectTimer_; // key:bundleName+sessionId -}; -} // namespace DistributedObject -} // namespace OHOS -#endif // DISTRIBUTEDDATAMGR_OBJECT_MANAGER_H +/* + * Copyright (c) 2022 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 DISTRIBUTEDDATAMGR_OBJECT_MANAGER_H +#define DISTRIBUTEDDATAMGR_OBJECT_MANAGER_H + +#include + +#include "concurrent_map.h" +#include "device_manager_adapter.h" +#include "kv_store_delegate_manager.h" +#include "kvstore_sync_callback.h" +#include "object_asset_loader.h" +#include "object_callback.h" +#include "object_callback_proxy.h" +#include "object_common.h" +#include "object_data_listener.h" +#include "object_snapshot.h" +#include "object_types.h" +#include "serializable/serializable.h" +#include "types.h" +#include "value_proxy.h" +namespace OHOS { +namespace DistributedObject { +using SyncCallBack = std::function &results)>; +using ObjectRecord = std::map>; +class SequenceSyncManager { +public: + enum Result { + SUCCESS_USER_IN_USE, + SUCCESS_USER_HAS_FINISHED, + ERR_SID_NOT_EXIST + }; + static SequenceSyncManager *GetInstance() + { + static SequenceSyncManager sequenceSyncManager; + return &sequenceSyncManager; + } + + uint64_t AddNotifier(const std::string &userId, SyncCallBack &callback); + Result DeleteNotifier(uint64_t sequenceId, std::string &userId); + Result Process( + uint64_t sequenceId, const std::map &results, std::string &userId); + +private: + Result DeleteNotifierNoLock(uint64_t sequenceId, std::string &userId); + std::mutex notifierLock_; + std::map> userIdSeqIdRelations_; + std::map seqIdCallbackRelations_; +}; + +class ObjectStoreManager { +public: + using DmAdaper = OHOS::DistributedData::DeviceManagerAdapter; + using UriToSnapshot = std::shared_ptr>>; + + enum RestoreStatus : int32_t { + NONE = 0, + DATA_READY, + DATA_NOTIFIED, + ASSETS_READY, + ALL_READY, + STATUS_BUTT + }; + + ObjectStoreManager(); + ~ObjectStoreManager(); + static ObjectStoreManager *GetInstance() + { + static ObjectStoreManager *manager = new ObjectStoreManager(); + return manager; + } + int32_t Save(const std::string &appId, const std::string &sessionId, const ObjectRecord &data, + const std::string &deviceId, sptr callback); + int32_t RevokeSave( + const std::string &appId, const std::string &sessionId, sptr callback); + int32_t Retrieve(const std::string &bundleName, const std::string &sessionId, + sptr callback, uint32_t tokenId); + void SetData(const std::string &dataDir, const std::string &userId); + int32_t Clear(); + int32_t DeleteByAppId(const std::string &appId, int32_t user); + void RegisterRemoteCallback(const std::string &bundleName, const std::string &sessionId, + pid_t pid, uint32_t tokenId, + sptr callback); + void UnregisterRemoteCallback(const std::string &bundleName, pid_t pid, uint32_t tokenId, + const std::string &sessionId = ""); + void NotifyChange(ObjectRecord &changedData); + void NotifyAssetsReady(const std::string& objectKey, const std::string& bundleName, + const std::string& srcNetworkId = ""); + void NotifyAssetsStart(const std::string& objectKey, const std::string& srcNetworkId = ""); + void CloseAfterMinute(); + int32_t Open(); + void SetThreadPool(std::shared_ptr executors); + UriToSnapshot GetSnapShots(const std::string &bundleName, const std::string &storeName); + int32_t BindAsset(const uint32_t tokenId, const std::string& appId, const std::string& sessionId, + ObjectStore::Asset& asset, ObjectStore::AssetBindInfo& bindInfo); + int32_t OnAssetChanged(const uint32_t tokenId, const std::string& appId, const std::string& sessionId, + const std::string& deviceId, const ObjectStore::Asset& asset); + void DeleteSnapshot(const std::string &bundleName, const std::string &sessionId); +private: + constexpr static const char *SEPERATOR = "_"; + constexpr static const char *TIME_REGEX = "_\\d{10}_p_"; + constexpr static int BUNDLE_NAME_INDEX = 0; + constexpr static int SESSION_ID_INDEX = 1; + constexpr static int SOURCE_DEVICE_UDID_INDEX = 2; + constexpr static int TIME_INDEX = 4; + constexpr static int PROPERTY_NAME_INDEX = 5; + constexpr static const char *LOCAL_DEVICE = "local"; + constexpr static const char *USERID = "USERID"; + constexpr static int8_t MAX_OBJECT_SIZE_PER_APP = 16; + constexpr static int8_t DECIMAL_BASE = 10; + constexpr static int WAIT_TIME = 60; + static constexpr size_t TIME_TASK_NUM = 1; + static constexpr int64_t INTERVAL = 1; + struct CallbackInfo { + pid_t pid; + std::map> observers_; + bool operator<(const CallbackInfo &it_) const + { + if (pid < it_.pid) { + return true; + } + return false; + } + }; + struct SaveInfo : DistributedData::Serializable { + std::string bundleName; + std::string sessionId; + std::string sourceDeviceId; + std::string targetDeviceId; + std::string timestamp; + SaveInfo() = default; + SaveInfo(const std::string &bundleName, const std::string &sessionId, const std::string &sourceDeviceId, + const std::string &targetDeviceId, const std::string ×tamp); + bool Marshal(json &node) const override; + bool Unmarshal(const json &node) override; + std::string ToPropertyPrefix(); + }; + DistributedDB::KvStoreNbDelegate *OpenObjectKvStore(); + void FlushClosedStore(); + void Close(); + int32_t SetSyncStatus(bool status); + int32_t SaveToStore(const std::string &appId, const std::string &sessionId, const std::string &toDeviceId, + const ObjectRecord &data); + int32_t SyncOnStore(const std::string &prefix, const std::vector &deviceList, SyncCallBack &callback); + int32_t RevokeSaveToStore(const std::string &prefix); + int32_t RetrieveFromStore(const std::string &appId, const std::string &sessionId, ObjectRecord &results); + void SyncCompleted(const std::map &results, uint64_t sequenceId); + std::vector SplitEntryKey(const std::string &key); + void ProcessOldEntry(const std::string &appId); + void ProcessSyncCallback(const std::map &results, const std::string &appId, + const std::string &sessionId, const std::string &deviceId); + void SaveUserToMeta(); + std::string GetCurrentUser(); + void DoNotify(uint32_t tokenId, const CallbackInfo& value, const std::map& data, + bool allReady); + void DoNotifyAssetsReady(uint32_t tokenId, const CallbackInfo& value, const std::string& objectKey, bool allReady); + void DoNotifyWaitAssetTimeout(const std::string &objectKey); + std::map> GetAssetsFromStore(const ObjectRecord& changedData); + static bool IsAssetKey(const std::string& key); + static bool IsAssetComplete(const ObjectRecord& result, const std::string& assetPrefix); + Assets GetAssetsFromDBRecords(const ObjectRecord& result); + bool RegisterAssetsLister(); + void ComputeStatus(const std::string& objectKey, const SaveInfo& saveInfo, + const std::map& data); + void NotifyDataChanged(const std::map& data, const SaveInfo& saveInfo); + int32_t PushAssets(const std::string &srcBundleName, const std::string &dstBundleName, const std::string &sessionId, + const ObjectRecord &data, const std::string &deviceId); + int32_t WaitAssets(const std::string& objectKey, const SaveInfo& saveInfo, + const std::map& data); + void PullAssets(const std::map& data, const SaveInfo& saveInfo); + std::map GetObjectData(const ObjectRecord& changedData, SaveInfo& saveInfo, + bool& hasAsset); + inline std::string GetPropertyPrefix(const std::string &appId, const std::string &sessionId) + { + return appId + SEPERATOR + sessionId + SEPERATOR + DmAdaper::GetInstance().GetLocalDevice().udid + SEPERATOR; + }; + inline std::string GetPropertyPrefix( + const std::string &appId, const std::string &sessionId, const std::string &toDeviceId) + { + return appId + SEPERATOR + sessionId + SEPERATOR + DmAdaper::GetInstance().GetLocalDevice().udid + + SEPERATOR + toDeviceId + SEPERATOR; + }; + inline std::string GetPrefixWithoutDeviceId(const std::string &appId, const std::string &sessionId) + { + return appId + SEPERATOR + sessionId + SEPERATOR; + }; + inline std::string GetMetaUserIdKey(const std::string &userId, const std::string &appId) + { + return std::string(USERID) + SEPERATOR + userId + SEPERATOR + appId + SEPERATOR + + DmAdaper::GetInstance().GetLocalDevice().udid; + }; + std::recursive_mutex kvStoreMutex_; + std::mutex mutex_; + DistributedDB::KvStoreDelegateManager *kvStoreDelegateManager_ = nullptr; + DistributedDB::KvStoreNbDelegate *delegate_ = nullptr; + ObjectDataListener *objectDataListener_ = nullptr; + sptr objectAssetsRecvListener_ = nullptr; + sptr objectAssetsSendListener_ = nullptr; + uint32_t syncCount_ = 0; + std::string userId_; + std::atomic isSyncing_ = false; + ConcurrentMap callbacks_; + std::shared_ptr executors_; + DistributedData::AssetBindInfo ConvertBindInfo(ObjectStore::AssetBindInfo& bindInfo); + VBucket ConvertVBucket(ObjectStore::ValuesBucket &vBucket); + ConcurrentMap> snapshots_; // key:bundleName_sessionId + ConcurrentMap bindSnapshots_; // key:bundleName_storeName + ConcurrentMap restoreStatus_; // key:bundleName+sessionId + ConcurrentMap objectTimer_; // key:bundleName+sessionId +}; +} // namespace DistributedObject +} // namespace OHOS +#endif // DISTRIBUTEDDATAMGR_OBJECT_MANAGER_H diff --git a/datamgr_service/services/distributeddataservice/service/object/object_service_impl.h b/datamgr_service/services/distributeddataservice/service/object/include/object_service_impl.h similarity index 100% rename from datamgr_service/services/distributeddataservice/service/object/object_service_impl.h rename to datamgr_service/services/distributeddataservice/service/object/include/object_service_impl.h diff --git a/datamgr_service/services/distributeddataservice/service/object/object_service_stub.h b/datamgr_service/services/distributeddataservice/service/object/include/object_service_stub.h similarity index 100% rename from datamgr_service/services/distributeddataservice/service/object/object_service_stub.h rename to datamgr_service/services/distributeddataservice/service/object/include/object_service_stub.h diff --git a/datamgr_service/services/distributeddataservice/service/object/object_snapshot.h b/datamgr_service/services/distributeddataservice/service/object/include/object_snapshot.h similarity index 100% rename from datamgr_service/services/distributeddataservice/service/object/object_snapshot.h rename to datamgr_service/services/distributeddataservice/service/object/include/object_snapshot.h diff --git a/datamgr_service/services/distributeddataservice/service/object/object_types_utils.h b/datamgr_service/services/distributeddataservice/service/object/include/object_types_utils.h similarity index 100% rename from datamgr_service/services/distributeddataservice/service/object/object_types_utils.h rename to datamgr_service/services/distributeddataservice/service/object/include/object_types_utils.h diff --git a/datamgr_service/services/distributeddataservice/service/object/object_asset_loader.cpp b/datamgr_service/services/distributeddataservice/service/object/src/object_asset_loader.cpp similarity index 100% rename from datamgr_service/services/distributeddataservice/service/object/object_asset_loader.cpp rename to datamgr_service/services/distributeddataservice/service/object/src/object_asset_loader.cpp diff --git a/datamgr_service/services/distributeddataservice/service/object/object_asset_machine.cpp b/datamgr_service/services/distributeddataservice/service/object/src/object_asset_machine.cpp similarity index 100% rename from datamgr_service/services/distributeddataservice/service/object/object_asset_machine.cpp rename to datamgr_service/services/distributeddataservice/service/object/src/object_asset_machine.cpp diff --git a/datamgr_service/services/distributeddataservice/service/object/object_callback_proxy.cpp b/datamgr_service/services/distributeddataservice/service/object/src/object_callback_proxy.cpp similarity index 100% rename from datamgr_service/services/distributeddataservice/service/object/object_callback_proxy.cpp rename to datamgr_service/services/distributeddataservice/service/object/src/object_callback_proxy.cpp diff --git a/datamgr_service/services/distributeddataservice/service/object/object_data_listener.cpp b/datamgr_service/services/distributeddataservice/service/object/src/object_data_listener.cpp similarity index 97% rename from datamgr_service/services/distributeddataservice/service/object/object_data_listener.cpp rename to datamgr_service/services/distributeddataservice/service/object/src/object_data_listener.cpp index 1c58fb4934c315ffb37f25faddceaf7815418497..e7a7a5d0abcd44de8af8b2ac9b582c17ab887a3b 100644 --- a/datamgr_service/services/distributeddataservice/service/object/object_data_listener.cpp +++ b/datamgr_service/services/distributeddataservice/service/object/src/object_data_listener.cpp @@ -1,75 +1,75 @@ -/* - * Copyright (c) 2022 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 "ObjectDataListener" - -#include "object_data_listener.h" -#include "log_print.h" -#include "object_manager.h" -#include "object_radar_reporter.h" -#include "utils/anonymous.h" -namespace OHOS { -namespace DistributedObject { -ObjectDataListener::ObjectDataListener() -{ -} - -ObjectDataListener::~ObjectDataListener() -{ -} - -void ObjectDataListener::OnChange(const DistributedDB::KvStoreChangedData &data) -{ - const auto &insertedDatas = data.GetEntriesInserted(); - const auto &updatedDatas = data.GetEntriesUpdated(); - std::map> changedData {}; - for (const auto &entry : insertedDatas) { - std::string key(entry.key.begin(), entry.key.end()); - changedData.insert_or_assign(std::move(key), entry.value); - } - for (const auto &entry : updatedDatas) { - std::string key(entry.key.begin(), entry.key.end()); - changedData.insert_or_assign(std::move(key), entry.value); - } - DistributedObject::ObjectStoreManager::GetInstance()->NotifyChange(changedData); -} - -int32_t ObjectAssetsRecvListener::OnStart(const std::string &srcNetworkId, const std::string &dstNetworkId, - const std::string &sessionId, const std::string &dstBundleName) -{ - auto objectKey = dstBundleName + sessionId; - ZLOGI("OnStart, objectKey:%{public}s", objectKey.c_str()); - ObjectStoreManager::GetInstance()->NotifyAssetsStart(objectKey, srcNetworkId); - return OBJECT_SUCCESS; -} - -int32_t ObjectAssetsRecvListener::OnFinished(const std::string &srcNetworkId, const sptr &assetObj, - int32_t result) -{ - if (assetObj == nullptr) { - ZLOGE("OnFinished error! status:%{public}d, srcNetworkId:%{public}s", result, - DistributedData::Anonymous::Change(srcNetworkId).c_str()); - ObjectStore::RadarReporter::ReportStageError(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, - ObjectStore::ASSETS_RECV, ObjectStore::RADAR_FAILED, result); - return result; - } - auto objectKey = assetObj->dstBundleName_+assetObj->sessionId_; - ZLOGI("OnFinished, status:%{public}d objectKey:%{public}s, asset size:%{public}zu", result, objectKey.c_str(), - assetObj->uris_.size()); - ObjectStoreManager::GetInstance()->NotifyAssetsReady(objectKey, assetObj->dstBundleName_, srcNetworkId); - return OBJECT_SUCCESS; -} -} // namespace DistributedObject -} // namespace OHOS +/* + * Copyright (c) 2022 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 "ObjectDataListener" + +#include "object_data_listener.h" +#include "log_print.h" +#include "object_manager.h" +#include "object_radar_reporter.h" +#include "utils/anonymous.h" +namespace OHOS { +namespace DistributedObject { +ObjectDataListener::ObjectDataListener() +{ +} + +ObjectDataListener::~ObjectDataListener() +{ +} + +void ObjectDataListener::OnChange(const DistributedDB::KvStoreChangedData &data) +{ + const auto &insertedDatas = data.GetEntriesInserted(); + const auto &updatedDatas = data.GetEntriesUpdated(); + std::map> changedData {}; + for (const auto &entry : insertedDatas) { + std::string key(entry.key.begin(), entry.key.end()); + changedData.insert_or_assign(std::move(key), entry.value); + } + for (const auto &entry : updatedDatas) { + std::string key(entry.key.begin(), entry.key.end()); + changedData.insert_or_assign(std::move(key), entry.value); + } + DistributedObject::ObjectStoreManager::GetInstance()->NotifyChange(changedData); +} + +int32_t ObjectAssetsRecvListener::OnStart(const std::string &srcNetworkId, const std::string &dstNetworkId, + const std::string &sessionId, const std::string &dstBundleName) +{ + auto objectKey = dstBundleName + sessionId; + ZLOGI("OnStart, objectKey:%{public}s", objectKey.c_str()); + ObjectStoreManager::GetInstance()->NotifyAssetsStart(objectKey, srcNetworkId); + return OBJECT_SUCCESS; +} + +int32_t ObjectAssetsRecvListener::OnFinished(const std::string &srcNetworkId, const sptr &assetObj, + int32_t result) +{ + if (assetObj == nullptr) { + ZLOGE("OnFinished error! status:%{public}d, srcNetworkId:%{public}s", result, + DistributedData::Anonymous::Change(srcNetworkId).c_str()); + ObjectStore::RadarReporter::ReportStageError(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, + ObjectStore::ASSETS_RECV, ObjectStore::RADAR_FAILED, result); + return result; + } + auto objectKey = assetObj->dstBundleName_+assetObj->sessionId_; + ZLOGI("OnFinished, status:%{public}d objectKey:%{public}s, asset size:%{public}zu", result, objectKey.c_str(), + assetObj->uris_.size()); + ObjectStoreManager::GetInstance()->NotifyAssetsReady(objectKey, assetObj->dstBundleName_, srcNetworkId); + return OBJECT_SUCCESS; +} +} // namespace DistributedObject +} // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/service/object/object_dms_handler.cpp b/datamgr_service/services/distributeddataservice/service/object/src/object_dms_handler.cpp similarity index 100% rename from datamgr_service/services/distributeddataservice/service/object/object_dms_handler.cpp rename to datamgr_service/services/distributeddataservice/service/object/src/object_dms_handler.cpp diff --git a/datamgr_service/services/distributeddataservice/service/object/object_manager.cpp b/datamgr_service/services/distributeddataservice/service/object/src/object_manager.cpp similarity index 97% rename from datamgr_service/services/distributeddataservice/service/object/object_manager.cpp rename to datamgr_service/services/distributeddataservice/service/object/src/object_manager.cpp index d1353a9bcceb246557655baadbb40cb7cb661752..feab5574285c9167d1d7886a06bfd9178d38bde6 100644 --- a/datamgr_service/services/distributeddataservice/service/object/object_manager.cpp +++ b/datamgr_service/services/distributeddataservice/service/object/src/object_manager.cpp @@ -1,1269 +1,1268 @@ -/* - * Copyright (c) 2022 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 "ObjectStoreManager" - -#include "object_manager.h" - -#include - -#include "accesstoken_kit.h" -#include "account/account_delegate.h" -#include "block_data.h" -#include "bootstrap.h" -#include "common/bytes.h" -#include "common/string_utils.h" -#include "datetime_ex.h" -#include "distributed_file_daemon_manager.h" -#include "kvstore_utils.h" -#include "log_print.h" -#include "metadata/meta_data_manager.h" -#include "metadata/store_meta_data.h" -#include "object_dms_handler.h" -#include "object_radar_reporter.h" -#include "utils/anonymous.h" - -namespace OHOS { -namespace DistributedObject { -using namespace OHOS::DistributedKv; -using namespace Security::AccessToken; -using StoreMetaData = OHOS::DistributedData::StoreMetaData; -using AccountDelegate = DistributedKv::AccountDelegate; -using Account = OHOS::DistributedKv::AccountDelegate; -using AccessTokenKit = Security::AccessToken::AccessTokenKit; -using ValueProxy = OHOS::DistributedData::ValueProxy; -using DistributedFileDaemonManager = Storage::DistributedFile::DistributedFileDaemonManager; -constexpr const char *SAVE_INFO = "p_###SAVEINFO###"; -ObjectStoreManager::ObjectStoreManager() -{ - ZLOGI("ObjectStoreManager construct"); - RegisterAssetsLister(); -} - -ObjectStoreManager::~ObjectStoreManager() -{ - ZLOGI("ObjectStoreManager destroy"); - if (objectAssetsRecvListener_ != nullptr) { - auto status = DistributedFileDaemonManager::GetInstance().UnRegisterAssetCallback(objectAssetsRecvListener_); - if (status != DistributedDB::DBStatus::OK) { - ZLOGE("UnRegister assetsRecvListener err %{public}d", status); - } - } -} - -DistributedDB::KvStoreNbDelegate *ObjectStoreManager::OpenObjectKvStore() -{ - DistributedDB::KvStoreNbDelegate *store = nullptr; - DistributedDB::KvStoreNbDelegate::Option option; - option.createDirByStoreIdOnly = true; - option.syncDualTupleMode = true; - option.secOption = { DistributedDB::S1, DistributedDB::ECE }; - if (objectDataListener_ == nullptr) { - objectDataListener_ = new ObjectDataListener(); - } - ZLOGD("start GetKvStore"); - kvStoreDelegateManager_->GetKvStore(ObjectCommon::OBJECTSTORE_DB_STOREID, option, - [&store, this](DistributedDB::DBStatus dbStatus, DistributedDB::KvStoreNbDelegate *kvStoreNbDelegate) { - if (dbStatus != DistributedDB::DBStatus::OK) { - ZLOGE("GetKvStore fail %{public}d", dbStatus); - return; - } - ZLOGI("GetKvStore successsfully"); - store = kvStoreNbDelegate; - std::vector tmpKey; - DistributedDB::DBStatus status = store->RegisterObserver(tmpKey, - DistributedDB::ObserverMode::OBSERVER_CHANGES_FOREIGN, - objectDataListener_); - if (status != DistributedDB::DBStatus::OK) { - ZLOGE("RegisterObserver err %{public}d", status); - } - }); - return store; -} - -bool ObjectStoreManager::RegisterAssetsLister() -{ - if (objectAssetsSendListener_ == nullptr) { - objectAssetsSendListener_ = new ObjectAssetsSendListener(); - } - if (objectAssetsRecvListener_ == nullptr) { - objectAssetsRecvListener_ = new ObjectAssetsRecvListener(); - } - auto status = DistributedFileDaemonManager::GetInstance().RegisterAssetCallback(objectAssetsRecvListener_); - if (status != DistributedDB::DBStatus::OK) { - ZLOGE("Register assetsRecvListener err %{public}d", status); - return false; - } - return true; -} - -void ObjectStoreManager::ProcessSyncCallback(const std::map &results, const std::string &appId, - const std::string &sessionId, const std::string &deviceId) -{ - if (results.empty() || results.find(LOCAL_DEVICE) != results.end()) { - return; - } - int32_t result = Open(); - if (result != OBJECT_SUCCESS) { - ZLOGE("Open failed, errCode = %{public}d", result); - return; - } - // delete local data - result = RevokeSaveToStore(GetPropertyPrefix(appId, sessionId, deviceId)); - if (result != OBJECT_SUCCESS) { - ZLOGE("Save failed, status = %{public}d", result); - } - Close(); - return; -} - -int32_t ObjectStoreManager::Save(const std::string &appId, const std::string &sessionId, - const ObjectRecord &data, const std::string &deviceId, sptr callback) -{ - auto proxy = iface_cast(callback); - if (deviceId.size() == 0) { - ZLOGE("DeviceId empty, appId: %{public}s, sessionId: %{public}s", appId.c_str(), sessionId.c_str()); - proxy->Completed(std::map()); - return INVALID_ARGUMENT; - } - int32_t result = Open(); - if (result != OBJECT_SUCCESS) { - ZLOGE("Open object kvstore failed, result: %{public}d", result); - ObjectStore::RadarReporter::ReportStateError(std::string(__FUNCTION__), ObjectStore::SAVE, - ObjectStore::SAVE_TO_STORE, ObjectStore::RADAR_FAILED, ObjectStore::GETKV_FAILED, ObjectStore::FINISHED); - proxy->Completed(std::map()); - return STORE_NOT_OPEN; - } - SaveUserToMeta(); - std::string dstBundleName = ObjectDmsHandler::GetInstance().GetDstBundleName(appId, deviceId); - result = SaveToStore(dstBundleName, sessionId, deviceId, data); - if (result != OBJECT_SUCCESS) { - ZLOGE("Save to store failed, result: %{public}d", result); - ObjectStore::RadarReporter::ReportStateError(std::string(__FUNCTION__), ObjectStore::SAVE, - ObjectStore::SAVE_TO_STORE, ObjectStore::RADAR_FAILED, result, ObjectStore::FINISHED); - Close(); - proxy->Completed(std::map()); - return result; - } - ZLOGI("Sync data, bundleName: %{public}s, sessionId: %{public}s, deviceId: %{public}s", dstBundleName.c_str(), - sessionId.c_str(), Anonymous::Change(deviceId).c_str()); - SyncCallBack syncCallback = - [proxy, dstBundleName, sessionId, deviceId, this](const std::map &results) { - ProcessSyncCallback(results, dstBundleName, sessionId, deviceId); - proxy->Completed(results); - }; - result = SyncOnStore(GetPropertyPrefix(dstBundleName, sessionId, deviceId), {deviceId}, syncCallback); - if (result != OBJECT_SUCCESS) { - ZLOGE("Sync data failed, result: %{public}d", result); - ObjectStore::RadarReporter::ReportStateError(std::string(__FUNCTION__), ObjectStore::SAVE, - ObjectStore::SYNC_DATA, ObjectStore::RADAR_FAILED, result, ObjectStore::FINISHED); - Close(); - proxy->Completed(std::map()); - return result; - } - Close(); - return PushAssets(appId, dstBundleName, sessionId, data, deviceId); -} - -int32_t ObjectStoreManager::PushAssets(const std::string &srcBundleName, const std::string &dstBundleName, - const std::string &sessionId, const ObjectRecord &data, const std::string &deviceId) -{ - Assets assets = GetAssetsFromDBRecords(data); - if (assets.empty() || data.find(ObjectStore::FIELDS_PREFIX + ObjectStore::DEVICEID_KEY) == data.end()) { - return OBJECT_SUCCESS; - } - sptr assetObj = new AssetObj(); - assetObj->dstBundleName_ = dstBundleName; - assetObj->srcBundleName_ = srcBundleName; - assetObj->dstNetworkId_ = deviceId; - assetObj->sessionId_ = sessionId; - for (const auto& asset : assets) { - assetObj->uris_.push_back(asset.uri); - } - if (objectAssetsSendListener_ == nullptr) { - objectAssetsSendListener_ = new ObjectAssetsSendListener(); - } - int userId = std::atoi(GetCurrentUser().c_str()); - auto status = ObjectAssetLoader::GetInstance()->PushAsset(userId, assetObj, objectAssetsSendListener_); - return status; -} - -int32_t ObjectStoreManager::RevokeSave( - const std::string &appId, const std::string &sessionId, sptr callback) -{ - auto proxy = iface_cast(callback); - int32_t result = Open(); - if (result != OBJECT_SUCCESS) { - ZLOGE("Open failed, errCode = %{public}d", result); - proxy->Completed(STORE_NOT_OPEN); - return STORE_NOT_OPEN; - } - - result = RevokeSaveToStore(GetPrefixWithoutDeviceId(appId, sessionId)); - if (result != OBJECT_SUCCESS) { - ZLOGE("RevokeSave failed, errCode = %{public}d", result); - Close(); - proxy->Completed(result); - return result; - } - std::vector deviceList; - auto deviceInfos = DmAdaper::GetInstance().GetRemoteDevices(); - std::for_each(deviceInfos.begin(), deviceInfos.end(), - [&deviceList](AppDistributedKv::DeviceInfo info) { deviceList.emplace_back(info.networkId); }); - if (!deviceList.empty()) { - SyncCallBack tmp = [proxy](const std::map &results) { - ZLOGI("revoke save finished"); - proxy->Completed(OBJECT_SUCCESS); - }; - result = SyncOnStore(GetPropertyPrefix(appId, sessionId), deviceList, tmp); - if (result != OBJECT_SUCCESS) { - ZLOGE("sync failed, errCode = %{public}d", result); - proxy->Completed(result); - } - } else { - proxy->Completed(OBJECT_SUCCESS); - }; - Close(); - return result; -} - -int32_t ObjectStoreManager::Retrieve( - const std::string &bundleName, const std::string &sessionId, sptr callback, uint32_t tokenId) -{ - auto proxy = iface_cast(callback); - int32_t result = Open(); - if (result != OBJECT_SUCCESS) { - ZLOGE("Open object kvstore failed, result: %{public}d", result); - proxy->Completed(ObjectRecord(), false); - return ObjectStore::GETKV_FAILED; - } - ObjectRecord results{}; - int32_t status = RetrieveFromStore(bundleName, sessionId, results); - if (status != OBJECT_SUCCESS) { - ZLOGI("Retrieve from store failed, status: %{public}d", status); - Close(); - proxy->Completed(ObjectRecord(), false); - return status; - } - bool allReady = false; - Assets assets = GetAssetsFromDBRecords(results); - if (assets.empty() || results.find(ObjectStore::FIELDS_PREFIX + ObjectStore::DEVICEID_KEY) == results.end()) { - allReady = true; - } else { - auto objectKey = bundleName + sessionId; - restoreStatus_.ComputeIfPresent(objectKey, [&allReady](const auto &key, auto &value) { - if (value == RestoreStatus::ALL_READY) { - allReady = true; - return false; - } - if (value == RestoreStatus::DATA_READY) { - value = RestoreStatus::DATA_NOTIFIED; - } - return true; - }); - } - status = RevokeSaveToStore(GetPrefixWithoutDeviceId(bundleName, sessionId)); - if (status != OBJECT_SUCCESS) { - ZLOGE("Revoke save failed, status: %{public}d", status); - Close(); - proxy->Completed(ObjectRecord(), false); - return status; - } - Close(); - proxy->Completed(results, allReady); - if (allReady) { - ObjectStore::RadarReporter::ReportStateFinished(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, - ObjectStore::NOTIFY, ObjectStore::RADAR_SUCCESS, ObjectStore::FINISHED); - } - return status; -} - -int32_t ObjectStoreManager::Clear() -{ - ZLOGI("enter"); - std::string userId = GetCurrentUser(); - if (userId.empty()) { - return OBJECT_INNER_ERROR; - } - std::vector metaData; - std::string appId = DistributedData::Bootstrap::GetInstance().GetProcessLabel(); - std::string metaKey = GetMetaUserIdKey(userId, appId); - if (!DistributedData::MetaDataManager::GetInstance().LoadMeta(metaKey, metaData, true)) { - ZLOGE("no store of %{public}s", appId.c_str()); - return OBJECT_STORE_NOT_FOUND; - } - for (const auto &storeMeta : metaData) { - if (storeMeta.storeType < StoreMetaData::StoreType::STORE_OBJECT_BEGIN - || storeMeta.storeType > StoreMetaData::StoreType::STORE_OBJECT_END) { - continue; - } - if (storeMeta.user == userId) { - ZLOGI("user is same, not need to change, mate user:%{public}s::user:%{public}s.", - storeMeta.user.c_str(), userId.c_str()); - return OBJECT_SUCCESS; - } - } - ZLOGD("user is change, need to change"); - int32_t result = Open(); - if (result != OBJECT_SUCCESS) { - ZLOGE("Open failed, errCode = %{public}d", result); - return STORE_NOT_OPEN; - } - result = RevokeSaveToStore(""); - Close(); - return result; -} - -int32_t ObjectStoreManager::DeleteByAppId(const std::string &appId, int32_t user) -{ - int32_t result = Open(); - if (result != OBJECT_SUCCESS) { - ZLOGE("Open store failed, result: %{public}d, appId: %{public}s, user: %{public}d", result, - appId.c_str(), user); - return STORE_NOT_OPEN; - } - result = RevokeSaveToStore(appId); - if (result != OBJECT_SUCCESS) { - ZLOGE("Revoke save failed, result: %{public}d, appId: %{public}s, user: %{public}d", result, - appId.c_str(), user); - } - Close(); - std::string userId = std::to_string(user); - std::string metaKey = GetMetaUserIdKey(userId, appId); - auto status = DistributedData::MetaDataManager::GetInstance().DelMeta(metaKey, true); - if (!status) { - ZLOGE("Delete meta failed, userId: %{public}s, appId: %{public}s", userId.c_str(), appId.c_str()); - } - return result; -} - -void ObjectStoreManager::RegisterRemoteCallback(const std::string &bundleName, const std::string &sessionId, - pid_t pid, uint32_t tokenId, - sptr callback) -{ - if (bundleName.empty() || sessionId.empty()) { - ZLOGD("ObjectStoreManager::RegisterRemoteCallback empty"); - return; - } - ZLOGD("ObjectStoreManager::RegisterRemoteCallback start"); - auto proxy = iface_cast(callback); - std::string prefix = bundleName + sessionId; - callbacks_.Compute(tokenId, ([pid, &proxy, &prefix](const uint32_t key, CallbackInfo &value) { - if (value.pid != pid) { - value = CallbackInfo { pid }; - } - value.observers_.insert_or_assign(prefix, proxy); - return !value.observers_.empty(); - })); -} - -void ObjectStoreManager::UnregisterRemoteCallback(const std::string &bundleName, pid_t pid, uint32_t tokenId, - const std::string &sessionId) -{ - if (bundleName.empty()) { - ZLOGD("bundleName is empty"); - return; - } - callbacks_.Compute(tokenId, ([pid, &sessionId, &bundleName](const uint32_t key, CallbackInfo &value) { - if (value.pid != pid) { - return true; - } - if (sessionId.empty()) { - return false; - } - std::string prefix = bundleName + sessionId; - for (auto it = value.observers_.begin(); it != value.observers_.end();) { - if ((*it).first == prefix) { - it = value.observers_.erase(it); - } else { - ++it; - } - } - return true; - })); -} - -void ObjectStoreManager::NotifyChange(ObjectRecord &changedData) -{ - ZLOGI("OnChange start, size:%{public}zu", changedData.size()); - bool hasAsset = false; - SaveInfo saveInfo; - for (const auto &[key, value] : changedData) { - if (key.find(SAVE_INFO) != std::string::npos) { - DistributedData::Serializable::Unmarshall(std::string(value.begin(), value.end()), saveInfo); - break; - } - } - auto data = GetObjectData(changedData, saveInfo, hasAsset); - if (!hasAsset) { - ObjectStore::RadarReporter::ReportStateStart(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, - ObjectStore::DATA_RECV, ObjectStore::RADAR_SUCCESS, ObjectStore::START, saveInfo.bundleName); - callbacks_.ForEach([this, &data](uint32_t tokenId, const CallbackInfo& value) { - DoNotify(tokenId, value, data, true); // no asset, data ready means all ready - return false; - }); - return; - } - NotifyDataChanged(data, saveInfo); - SaveUserToMeta(); -} - -std::map ObjectStoreManager::GetObjectData(const ObjectRecord& changedData, - SaveInfo& saveInfo, bool& hasAsset) -{ - std::map data; - std::string keyPrefix = saveInfo.ToPropertyPrefix(); - if (!keyPrefix.empty()) { - std::string observerKey = saveInfo.bundleName + saveInfo.sessionId; - for (const auto &[key, value] : changedData) { - if (key.size() < keyPrefix.size() || key.find(SAVE_INFO) != std::string::npos) { - continue; - } - std::string propertyName = key.substr(keyPrefix.size()); - data[observerKey].insert_or_assign(propertyName, value); - if (!hasAsset && IsAssetKey(propertyName)) { - hasAsset = true; - } - } - } else { - for (const auto &item : changedData) { - std::vector splitKeys = SplitEntryKey(item.first); - if (splitKeys.size() <= PROPERTY_NAME_INDEX) { - continue; - } - if (saveInfo.sourceDeviceId.empty() || saveInfo.bundleName.empty()) { - saveInfo.sourceDeviceId = splitKeys[SOURCE_DEVICE_UDID_INDEX]; - saveInfo.bundleName = splitKeys[BUNDLE_NAME_INDEX]; - saveInfo.sessionId = splitKeys[SESSION_ID_INDEX]; - saveInfo.timestamp = splitKeys[TIME_INDEX]; - } - std::string prefix = splitKeys[BUNDLE_NAME_INDEX] + splitKeys[SESSION_ID_INDEX]; - std::string propertyName = splitKeys[PROPERTY_NAME_INDEX]; - data[prefix].insert_or_assign(propertyName, item.second); - if (IsAssetKey(propertyName)) { - hasAsset = true; - } - } - } - return data; -} - -void ObjectStoreManager::ComputeStatus(const std::string& objectKey, const SaveInfo& saveInfo, - const std::map& data) -{ - restoreStatus_.Compute(objectKey, [this, &data, saveInfo] (const auto &key, auto &value) { - if (value == RestoreStatus::ASSETS_READY) { - value = RestoreStatus::ALL_READY; - ObjectStore::RadarReporter::ReportStage(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, - ObjectStore::DATA_RECV, ObjectStore::RADAR_SUCCESS); - callbacks_.ForEach([this, &data](uint32_t tokenId, const CallbackInfo& value) { - DoNotify(tokenId, value, data, true); - return false; - }); - } else { - value = RestoreStatus::DATA_READY; - ObjectStore::RadarReporter::ReportStateStart(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, - ObjectStore::DATA_RECV, ObjectStore::RADAR_SUCCESS, ObjectStore::START, saveInfo.bundleName); - callbacks_.ForEach([this, &data](uint32_t tokenId, const CallbackInfo& value) { - DoNotify(tokenId, value, data, false); - return false; - }); - WaitAssets(key, saveInfo, data); - } - return true; - }); -} - -void ObjectStoreManager::NotifyDataChanged(const std::map& data, const SaveInfo& saveInfo) -{ - for (auto const& [objectKey, results] : data) { - restoreStatus_.ComputeIfAbsent( - objectKey, [](const std::string& key) -> auto { - return RestoreStatus::NONE; - }); - ComputeStatus(objectKey, saveInfo, data); - } -} - -int32_t ObjectStoreManager::WaitAssets(const std::string& objectKey, const SaveInfo& saveInfo, - const std::map& data) -{ - auto taskId = executors_->Schedule(std::chrono::seconds(WAIT_TIME), [this, objectKey, data, saveInfo]() { - ZLOGE("wait assets finisehd timeout, try pull assets, objectKey:%{public}s", objectKey.c_str()); - PullAssets(data, saveInfo); - DoNotifyWaitAssetTimeout(objectKey); - }); - - objectTimer_.ComputeIfAbsent( - objectKey, [taskId](const std::string& key) -> auto { - return taskId; - }); - return OBJECT_SUCCESS; -} - -void ObjectStoreManager::PullAssets(const std::map& data, const SaveInfo& saveInfo) -{ - std::map changedAssets; - for (auto const& [objectId, result] : data) { - changedAssets[objectId] = GetAssetsFromDBRecords(result); - } - for (const auto& [objectId, assets] : changedAssets) { - std::string networkId = DmAdaper::GetInstance().ToNetworkID(saveInfo.sourceDeviceId); - auto block = std::make_shared>>(WAIT_TIME, std::tuple{ true, true }); - ObjectAssetLoader::GetInstance()->TransferAssetsAsync(std::stoi(GetCurrentUser()), - saveInfo.bundleName, networkId, assets, [this, block](bool success) { - block->SetValue({ false, success }); - }); - auto [timeout, success] = block->GetValue(); - ZLOGI("Pull assets end, timeout: %{public}d, success: %{public}d, size:%{public}zu, deviceId: %{public}s", - timeout, success, assets.size(), DistributedData::Anonymous::Change(networkId).c_str()); - } -} - -void ObjectStoreManager::NotifyAssetsReady(const std::string& objectKey, const std::string& bundleName, - const std::string& srcNetworkId) -{ - restoreStatus_.ComputeIfAbsent( - objectKey, [](const std::string& key) -> auto { - return RestoreStatus::NONE; - }); - restoreStatus_.Compute(objectKey, [this, &bundleName] (const auto &key, auto &value) { - if (value == RestoreStatus::DATA_NOTIFIED) { - value = RestoreStatus::ALL_READY; - ObjectStore::RadarReporter::ReportStage(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, - ObjectStore::ASSETS_RECV, ObjectStore::RADAR_SUCCESS); - callbacks_.ForEach([this, key](uint32_t tokenId, const CallbackInfo& value) { - DoNotifyAssetsReady(tokenId, value, key, true); - return false; - }); - } else if (value == RestoreStatus::DATA_READY) { - value = RestoreStatus::ALL_READY; - ObjectStore::RadarReporter::ReportStage(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, - ObjectStore::ASSETS_RECV, ObjectStore::RADAR_SUCCESS); - auto [has, taskId] = objectTimer_.Find(key); - if (has) { - executors_->Remove(taskId); - objectTimer_.Erase(key); - } - } else { - value = RestoreStatus::ASSETS_READY; - ObjectStore::RadarReporter::ReportStateStart(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, - ObjectStore::ASSETS_RECV, ObjectStore::RADAR_SUCCESS, ObjectStore::START, bundleName); - } - return true; - }); -} - -void ObjectStoreManager::NotifyAssetsStart(const std::string& objectKey, const std::string& srcNetworkId) -{ - restoreStatus_.ComputeIfAbsent( - objectKey, [](const std::string& key) -> auto { - return RestoreStatus::NONE; - }); -} - -bool ObjectStoreManager::IsAssetKey(const std::string& key) -{ - return key.find(ObjectStore::ASSET_DOT) != std::string::npos; -} - -bool ObjectStoreManager::IsAssetComplete(const ObjectRecord& result, const std::string& assetPrefix) -{ - if (result.find(assetPrefix + ObjectStore::NAME_SUFFIX) == result.end() || - result.find(assetPrefix + ObjectStore::URI_SUFFIX) == result.end() || - result.find(assetPrefix + ObjectStore::PATH_SUFFIX) == result.end() || - result.find(assetPrefix + ObjectStore::CREATE_TIME_SUFFIX) == result.end() || - result.find(assetPrefix + ObjectStore::MODIFY_TIME_SUFFIX) == result.end() || - result.find(assetPrefix + ObjectStore::SIZE_SUFFIX) == result.end()) { - return false; - } - return true; -} - -Assets ObjectStoreManager::GetAssetsFromDBRecords(const ObjectRecord& result) -{ - Assets assets{}; - std::set assetKey; - for (const auto& [key, value] : result) { - std::string assetPrefix = key.substr(0, key.find(ObjectStore::ASSET_DOT)); - if (!IsAssetKey(key) || assetKey.find(assetPrefix) != assetKey.end() || - result.find(assetPrefix + ObjectStore::NAME_SUFFIX) == result.end() || - result.find(assetPrefix + ObjectStore::URI_SUFFIX) == result.end()) { - continue; - } - Asset asset; - ObjectStore::StringUtils::BytesToStrWithType( - result.find(assetPrefix + ObjectStore::NAME_SUFFIX)->second, asset.name); - if (asset.name.find(ObjectStore::STRING_PREFIX) != std::string::npos) { - asset.name = asset.name.substr(ObjectStore::STRING_PREFIX_LEN); - } - ObjectStore::StringUtils::BytesToStrWithType( - result.find(assetPrefix + ObjectStore::URI_SUFFIX)->second, asset.uri); - if (asset.uri.find(ObjectStore::STRING_PREFIX) != std::string::npos) { - asset.uri = asset.uri.substr(ObjectStore::STRING_PREFIX_LEN); - } - ObjectStore::StringUtils::BytesToStrWithType( - result.find(assetPrefix + ObjectStore::MODIFY_TIME_SUFFIX)->second, asset.modifyTime); - if (asset.modifyTime.find(ObjectStore::STRING_PREFIX) != std::string::npos) { - asset.modifyTime = asset.modifyTime.substr(ObjectStore::STRING_PREFIX_LEN); - } - ObjectStore::StringUtils::BytesToStrWithType( - result.find(assetPrefix + ObjectStore::SIZE_SUFFIX)->second, asset.size); - if (asset.size.find(ObjectStore::STRING_PREFIX) != std::string::npos) { - asset.size = asset.size.substr(ObjectStore::STRING_PREFIX_LEN); - } - asset.hash = asset.modifyTime + "_" + asset.size; - assets.push_back(asset); - assetKey.insert(assetPrefix); - } - return assets; -} - -void ObjectStoreManager::DoNotify(uint32_t tokenId, const CallbackInfo& value, - const std::map& data, bool allReady) -{ - for (const auto& observer : value.observers_) { - auto it = data.find(observer.first); - if (it == data.end()) { - continue; - } - observer.second->Completed((*it).second, allReady); - if (allReady) { - restoreStatus_.Erase(observer.first); - ObjectStore::RadarReporter::ReportStateFinished(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, - ObjectStore::NOTIFY, ObjectStore::RADAR_SUCCESS, ObjectStore::FINISHED); - } else { - restoreStatus_.ComputeIfPresent(observer.first, [](const auto &key, auto &value) { - value = RestoreStatus::DATA_NOTIFIED; - return true; - }); - } - } -} - -void ObjectStoreManager::DoNotifyAssetsReady(uint32_t tokenId, const CallbackInfo& value, - const std::string& objectKey, bool allReady) -{ - for (const auto& observer : value.observers_) { - if (objectKey != observer.first) { - continue; - } - observer.second->Completed(ObjectRecord(), allReady); - if (allReady) { - restoreStatus_.Erase(objectKey); - ObjectStore::RadarReporter::ReportStateFinished(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, - ObjectStore::NOTIFY, ObjectStore::RADAR_SUCCESS, ObjectStore::FINISHED); - } - auto [has, taskId] = objectTimer_.Find(objectKey); - if (has) { - executors_->Remove(taskId); - objectTimer_.Erase(objectKey); - } - } -} - -void ObjectStoreManager::DoNotifyWaitAssetTimeout(const std::string &objectKey) -{ - ObjectStore::RadarReporter::ReportStageError(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, - ObjectStore::ASSETS_RECV, ObjectStore::RADAR_FAILED, ObjectStore::TIMEOUT); - callbacks_.ForEach([this, &objectKey](uint32_t tokenId, const CallbackInfo &value) { - for (const auto& observer : value.observers_) { - if (objectKey != observer.first) { - continue; - } - observer.second->Completed(ObjectRecord(), true); - restoreStatus_.Erase(objectKey); - auto [has, taskId] = objectTimer_.Find(objectKey); - if (has) { - executors_->Remove(taskId); - objectTimer_.Erase(objectKey); - } - ObjectStore::RadarReporter::ReportStateError(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, - ObjectStore::NOTIFY, ObjectStore::RADAR_FAILED, ObjectStore::TIMEOUT, ObjectStore::FINISHED); - } - return false; - }); -} - -void ObjectStoreManager::SetData(const std::string &dataDir, const std::string &userId) -{ - ZLOGI("enter %{public}s", dataDir.c_str()); - kvStoreDelegateManager_ = - new DistributedDB::KvStoreDelegateManager(DistributedData::Bootstrap::GetInstance().GetProcessLabel(), userId); - DistributedDB::KvStoreConfig kvStoreConfig { dataDir }; - kvStoreDelegateManager_->SetKvStoreConfig(kvStoreConfig); - userId_ = userId; -} - -int32_t ObjectStoreManager::Open() -{ - if (kvStoreDelegateManager_ == nullptr) { - ZLOGE("Kvstore delegate manager not init"); - return OBJECT_INNER_ERROR; - } - std::lock_guard lock(kvStoreMutex_); - if (delegate_ == nullptr) { - delegate_ = OpenObjectKvStore(); - if (delegate_ == nullptr) { - ZLOGE("Open object kvstore failed"); - return OBJECT_DBSTATUS_ERROR; - } - syncCount_ = 1; - ZLOGI("Open object kvstore success"); - } else { - syncCount_++; - ZLOGI("Object kvstore syncCount: %{public}d", syncCount_); - } - return OBJECT_SUCCESS; -} - -void ObjectStoreManager::Close() -{ - std::lock_guard lock(kvStoreMutex_); - if (delegate_ == nullptr) { - return; - } - int32_t taskCount = delegate_->GetTaskCount(); - if (taskCount > 0 && syncCount_ == 1) { - CloseAfterMinute(); - ZLOGW("Store is busy, close after a minute, task count: %{public}d", taskCount); - return; - } - syncCount_--; - ZLOGI("closed a store, syncCount = %{public}d", syncCount_); - FlushClosedStore(); -} - -void ObjectStoreManager::SyncCompleted( - const std::map &results, uint64_t sequenceId) -{ - std::string userId; - SequenceSyncManager::Result result = SequenceSyncManager::GetInstance()->Process(sequenceId, results, userId); - if (result == SequenceSyncManager::SUCCESS_USER_HAS_FINISHED && userId == userId_) { - std::lock_guard lock(kvStoreMutex_); - SetSyncStatus(false); - FlushClosedStore(); - } - for (const auto &item : results) { - if (item.second == DistributedDB::DBStatus::OK) { - ZLOGI("Sync data success, sequenceId: 0x%{public}" PRIx64 "", sequenceId); - ObjectStore::RadarReporter::ReportStateFinished(std::string(__FUNCTION__), ObjectStore::SAVE, - ObjectStore::SYNC_DATA, ObjectStore::RADAR_SUCCESS, ObjectStore::FINISHED); - } else { - ZLOGE("Sync data failed, sequenceId: 0x%{public}" PRIx64 ", status: %{public}d", sequenceId, item.second); - ObjectStore::RadarReporter::ReportStateError(std::string(__FUNCTION__), ObjectStore::SAVE, - ObjectStore::SYNC_DATA, ObjectStore::RADAR_FAILED, item.second, ObjectStore::FINISHED); - } - } -} - -void ObjectStoreManager::FlushClosedStore() -{ - std::lock_guard lock(kvStoreMutex_); - if (!isSyncing_ && syncCount_ == 0 && delegate_ != nullptr) { - ZLOGD("close store"); - auto status = kvStoreDelegateManager_->CloseKvStore(delegate_); - if (status != DistributedDB::DBStatus::OK) { - int timeOut = 1000; - executors_->Schedule(std::chrono::milliseconds(timeOut), [this]() { - FlushClosedStore(); - }); - ZLOGE("GetEntries fail %{public}d", status); - return; - } - delegate_ = nullptr; - if (objectDataListener_ != nullptr) { - delete objectDataListener_; - objectDataListener_ = nullptr; - } - } -} - -void ObjectStoreManager::ProcessOldEntry(const std::string &appId) -{ - std::vector entries; - auto status = delegate_->GetEntries(std::vector(appId.begin(), appId.end()), entries); - if (status != DistributedDB::DBStatus::NOT_FOUND) { - ZLOGI("Get old entries empty, bundleName: %{public}s", appId.c_str()); - return; - } - if (status != DistributedDB::DBStatus::OK) { - ZLOGE("Get old entries failed, bundleName: %{public}s, status %{public}d", appId.c_str(), status); - return; - } - std::map sessionIds; - int64_t oldestTime = 0; - std::string deleteKey; - for (auto &item : entries) { - std::string key(item.key.begin(), item.key.end()); - std::vector splitKeys = SplitEntryKey(key); - if (splitKeys.empty()) { - continue; - } - std::string bundleName = splitKeys[BUNDLE_NAME_INDEX]; - std::string sessionId = splitKeys[SESSION_ID_INDEX]; - if (sessionIds.count(sessionId) == 0) { - char *end = nullptr; - sessionIds[sessionId] = strtol(splitKeys[TIME_INDEX].c_str(), &end, DECIMAL_BASE); - } - if (oldestTime == 0 || oldestTime > sessionIds[sessionId]) { - oldestTime = sessionIds[sessionId]; - deleteKey = GetPrefixWithoutDeviceId(bundleName, sessionId); - } - } - if (sessionIds.size() < MAX_OBJECT_SIZE_PER_APP) { - return; - } - int32_t result = RevokeSaveToStore(deleteKey); - if (result != OBJECT_SUCCESS) { - ZLOGE("Delete old entries failed, deleteKey: %{public}s, status: %{public}d", deleteKey.c_str(), result); - return; - } - ZLOGI("Delete old entries success, deleteKey: %{public}s", deleteKey.c_str()); -} - -int32_t ObjectStoreManager::SaveToStore(const std::string &appId, const std::string &sessionId, - const std::string &toDeviceId, const ObjectRecord &data) -{ - ProcessOldEntry(appId); - RevokeSaveToStore(GetPropertyPrefix(appId, sessionId, toDeviceId)); - std::string timestamp = std::to_string(GetSecondsSince1970ToNow()); - std::string prefix = GetPropertyPrefix(appId, sessionId, toDeviceId) + timestamp + SEPERATOR; - DistributedDB::Entry saveInfoEntry; - std::string saveInfoKey = prefix + SAVE_INFO; - saveInfoEntry.key = std::vector(saveInfoKey.begin(), saveInfoKey.end()); - SaveInfo saveInfo(appId, sessionId, DmAdaper::GetInstance().GetLocalDevice().udid, toDeviceId, timestamp); - std::string saveInfoValue = DistributedData::Serializable::Marshall(saveInfo); - saveInfoEntry.value = std::vector(saveInfoValue.begin(), saveInfoValue.end()); - std::vector entries; - entries.emplace_back(saveInfoEntry); - for (auto &item : data) { - DistributedDB::Entry entry; - std::string key = GetPropertyPrefix(appId, sessionId, toDeviceId) + timestamp + SEPERATOR + item.first; - entry.key = std::vector(key.begin(), key.end()); - entry.value = item.second; - entries.emplace_back(entry); - } - auto status = delegate_->PutBatch(entries); - if (status != DistributedDB::DBStatus::OK) { - ZLOGE("PutBatch failed, bundleName: %{public}s, sessionId: %{public}s, dstNetworkId: %{public}s, " - "status: %{public}d", appId.c_str(), sessionId.c_str(), Anonymous::Change(toDeviceId).c_str(), status); - return status; - } - ZLOGI("PutBatch success, bundleName: %{public}s, sessionId: %{public}s, dstNetworkId: %{public}s, " - "count: %{public}zu", appId.c_str(), sessionId.c_str(), Anonymous::Change(toDeviceId).c_str(), entries.size()); - return OBJECT_SUCCESS; -} - -int32_t ObjectStoreManager::SyncOnStore( - const std::string &prefix, const std::vector &deviceList, SyncCallBack &callback) -{ - std::vector syncDevices; - for (auto &device : deviceList) { - if (device == LOCAL_DEVICE) { - ZLOGI("Save to local, do not need sync, prefix: %{public}s", prefix.c_str()); - callback({{LOCAL_DEVICE, OBJECT_SUCCESS}}); - return OBJECT_SUCCESS; - } - syncDevices.emplace_back(DmAdaper::GetInstance().GetUuidByNetworkId(device)); - } - if (syncDevices.empty()) { - ZLOGI("Device list is empty, prefix: %{public}s", Anonymous::Change(prefix).c_str()); - callback(std::map()); - return OBJECT_SUCCESS; - } - uint64_t sequenceId = SequenceSyncManager::GetInstance()->AddNotifier(userId_, callback); - DistributedDB::Query dbQuery = DistributedDB::Query::Select(); - dbQuery.PrefixKey(std::vector(prefix.begin(), prefix.end())); - ZLOGI("Start sync data, sequenceId: 0x%{public}" PRIx64 "", sequenceId); - auto status = delegate_->Sync(syncDevices, DistributedDB::SyncMode::SYNC_MODE_PUSH_ONLY, - [this, sequenceId](const std::map &devicesMap) { - ZLOGI("Sync data finished, sequenceId: 0x%{public}" PRIx64 "", sequenceId); - std::map result; - for (auto &item : devicesMap) { - result[DmAdaper::GetInstance().ToNetworkID(item.first)] = item.second; - } - SyncCompleted(result, sequenceId); - }, dbQuery, false); - if (status != DistributedDB::DBStatus::OK) { - ZLOGE("Sync data failed, prefix: %{public}s, sequenceId: 0x%{public}" PRIx64 ", status: %{public}d", - Anonymous::Change(prefix).c_str(), sequenceId, status); - std::string tmp; - SequenceSyncManager::GetInstance()->DeleteNotifier(sequenceId, tmp); - return status; - } - SetSyncStatus(true); - return OBJECT_SUCCESS; -} - -int32_t ObjectStoreManager::SetSyncStatus(bool status) -{ - std::lock_guard lock(kvStoreMutex_); - isSyncing_ = status; - return OBJECT_SUCCESS; -} - -int32_t ObjectStoreManager::RevokeSaveToStore(const std::string &prefix) -{ - std::vector entries; - auto status = delegate_->GetEntries(std::vector(prefix.begin(), prefix.end()), entries); - if (status == DistributedDB::DBStatus::NOT_FOUND) { - ZLOGI("Get entries empty, prefix: %{public}s", Anonymous::Change(prefix).c_str()); - return OBJECT_SUCCESS; - } - if (status != DistributedDB::DBStatus::OK) { - ZLOGE("Get entries failed, prefix: %{public}s, status: %{public}d", Anonymous::Change(prefix).c_str(), status); - return DB_ERROR; - } - std::vector> keys; - std::for_each(entries.begin(), entries.end(), [&keys](const DistributedDB::Entry &entry) { - keys.emplace_back(entry.key); - }); - if (keys.empty()) { - return OBJECT_SUCCESS; - } - status = delegate_->DeleteBatch(keys); - if (status != DistributedDB::DBStatus::OK) { - ZLOGE("Delete entries failed, prefix: %{public}s, status: %{public}d", Anonymous::Change(prefix).c_str(), - status); - return DB_ERROR; - } - ZLOGI("Delete entries success, prefix: %{public}s, count: %{public}zu", Anonymous::Change(prefix).c_str(), - keys.size()); - return OBJECT_SUCCESS; -} - -int32_t ObjectStoreManager::RetrieveFromStore(const std::string &appId, const std::string &sessionId, - ObjectRecord &results) -{ - std::vector entries; - std::string prefix = GetPrefixWithoutDeviceId(appId, sessionId); - auto status = delegate_->GetEntries(std::vector(prefix.begin(), prefix.end()), entries); - if (status == DistributedDB::DBStatus::NOT_FOUND) { - ZLOGI("Get entries empty, prefix: %{public}s, status: %{public}d", prefix.c_str(), status); - return KEY_NOT_FOUND; - } - if (status != DistributedDB::DBStatus::OK) { - ZLOGE("Get entries failed, prefix: %{public}s, status: %{public}d", prefix.c_str(), status); - return DB_ERROR; - } - ZLOGI("Get entries success, prefix: %{public}s, count: %{public}zu", prefix.c_str(), entries.size()); - for (const auto &entry : entries) { - std::string key(entry.key.begin(), entry.key.end()); - if (key.find(SAVE_INFO) != std::string::npos) { - continue; - } - auto splitKeys = SplitEntryKey(key); - if (!splitKeys.empty()) { - results[splitKeys[PROPERTY_NAME_INDEX]] = entry.value; - } - } - return OBJECT_SUCCESS; -} - -ObjectStoreManager::SaveInfo::SaveInfo(const std::string &bundleName, const std::string &sessionId, - const std::string &sourceDeviceId, const std::string &targetDeviceId, const std::string ×tamp) - : bundleName(bundleName), sessionId(sessionId), sourceDeviceId(sourceDeviceId), targetDeviceId(targetDeviceId), - timestamp(timestamp) {} - -bool ObjectStoreManager::SaveInfo::Marshal(json &node) const -{ - SetValue(node[GET_NAME(bundleName)], bundleName); - SetValue(node[GET_NAME(sessionId)], sessionId); - SetValue(node[GET_NAME(sourceDeviceId)], sourceDeviceId); - SetValue(node[GET_NAME(targetDeviceId)], targetDeviceId); - SetValue(node[GET_NAME(timestamp)], timestamp); - return true; -} - -bool ObjectStoreManager::SaveInfo::Unmarshal(const json &node) -{ - GetValue(node, GET_NAME(bundleName), bundleName); - GetValue(node, GET_NAME(sessionId), sessionId); - GetValue(node, GET_NAME(sourceDeviceId), sourceDeviceId); - GetValue(node, GET_NAME(targetDeviceId), targetDeviceId); - GetValue(node, GET_NAME(timestamp), timestamp); - return true; -} - -std::string ObjectStoreManager::SaveInfo::ToPropertyPrefix() -{ - if (bundleName.empty() || sessionId.empty() || sourceDeviceId.empty() || targetDeviceId.empty() || - timestamp.empty()) { - return ""; - } - return bundleName + SEPERATOR + sessionId + SEPERATOR + sourceDeviceId + SEPERATOR + targetDeviceId + SEPERATOR + - timestamp + SEPERATOR; -} - -std::vector ObjectStoreManager::SplitEntryKey(const std::string &key) -{ - std::smatch match; - std::regex timeRegex(TIME_REGEX); - if (!std::regex_search(key, match, timeRegex)) { - ZLOGW("Format error, key.size = %{public}zu", key.size()); - return {}; - } - auto timePos = match.position(); - std::string fromTime = key.substr(timePos + 1); - std::string beforeTime = key.substr(0, timePos); - - size_t targetDevicePos = beforeTime.find_last_of(SEPERATOR); - if (targetDevicePos == std::string::npos) { - ZLOGW("Format error, key.size = %{public}zu", key.size()); - return {}; - } - std::string targetDevice = beforeTime.substr(targetDevicePos + 1); - std::string beforeTargetDevice = beforeTime.substr(0, targetDevicePos); - - size_t sourceDeviceUdidPos = beforeTargetDevice.find_last_of(SEPERATOR); - if (sourceDeviceUdidPos == std::string::npos) { - ZLOGW("Format error, key.size = %{public}zu", key.size()); - return {}; - } - std::string sourceDeviceUdid = beforeTargetDevice.substr(sourceDeviceUdidPos + 1); - std::string beforeSourceDeviceUdid = beforeTargetDevice.substr(0, sourceDeviceUdidPos); - - size_t sessionIdPos = beforeSourceDeviceUdid.find_last_of(SEPERATOR); - if (sessionIdPos == std::string::npos) { - ZLOGW("Format error, key.size = %{public}zu", key.size()); - return {}; - } - std::string sessionId = beforeSourceDeviceUdid.substr(sessionIdPos + 1); - std::string bundleName = beforeSourceDeviceUdid.substr(0, sessionIdPos); - - size_t propertyNamePos = fromTime.find_first_of(SEPERATOR); - if (propertyNamePos == std::string::npos) { - ZLOGW("Format error, key.size = %{public}zu", key.size()); - return {}; - } - std::string propertyName = fromTime.substr(propertyNamePos + 1); - std::string time = fromTime.substr(0, propertyNamePos); - - return { bundleName, sessionId, sourceDeviceUdid, targetDevice, time, propertyName }; -} - -std::string ObjectStoreManager::GetCurrentUser() -{ - std::vector users; - AccountDelegate::GetInstance()->QueryUsers(users); - if (users.empty()) { - return ""; - } - return std::to_string(users[0]); -} - -void ObjectStoreManager::SaveUserToMeta() -{ - ZLOGD("start."); - std::string userId = GetCurrentUser(); - if (userId.empty()) { - return; - } - std::string appId = DistributedData::Bootstrap::GetInstance().GetProcessLabel(); - StoreMetaData userMeta; - userMeta.storeId = DistributedObject::ObjectCommon::OBJECTSTORE_DB_STOREID; - userMeta.user = userId; - userMeta.storeType = ObjectDistributedType::OBJECT_SINGLE_VERSION; - std::string userMetaKey = GetMetaUserIdKey(userId, appId); - auto saved = DistributedData::MetaDataManager::GetInstance().SaveMeta(userMetaKey, userMeta, true); - if (!saved) { - ZLOGE("userMeta save failed"); - } -} - -void ObjectStoreManager::CloseAfterMinute() -{ - executors_->Schedule(std::chrono::minutes(INTERVAL), std::bind(&ObjectStoreManager::Close, this)); -} - -void ObjectStoreManager::SetThreadPool(std::shared_ptr executors) -{ - executors_ = executors; -} - -uint64_t SequenceSyncManager::AddNotifier(const std::string &userId, SyncCallBack &callback) -{ - std::lock_guard lock(notifierLock_); - uint64_t sequenceId = KvStoreUtils::GenerateSequenceId(); - userIdSeqIdRelations_[userId].emplace_back(sequenceId); - seqIdCallbackRelations_[sequenceId] = callback; - return sequenceId; -} - -SequenceSyncManager::Result SequenceSyncManager::Process( - uint64_t sequenceId, const std::map &results, std::string &userId) -{ - std::lock_guard lock(notifierLock_); - if (seqIdCallbackRelations_.count(sequenceId) == 0) { - ZLOGE("not exist"); - return ERR_SID_NOT_EXIST; - } - std::map syncResults; - for (auto &item : results) { - syncResults[item.first] = item.second == DistributedDB::DBStatus::OK ? 0 : -1; - } - seqIdCallbackRelations_[sequenceId](syncResults); - ZLOGD("end complete"); - return DeleteNotifierNoLock(sequenceId, userId); -} - -SequenceSyncManager::Result SequenceSyncManager::DeleteNotifier(uint64_t sequenceId, std::string &userId) -{ - std::lock_guard lock(notifierLock_); - if (seqIdCallbackRelations_.count(sequenceId) == 0) { - ZLOGE("not exist"); - return ERR_SID_NOT_EXIST; - } - return DeleteNotifierNoLock(sequenceId, userId); -} - -SequenceSyncManager::Result SequenceSyncManager::DeleteNotifierNoLock(uint64_t sequenceId, std::string &userId) -{ - seqIdCallbackRelations_.erase(sequenceId); - auto userIdIter = userIdSeqIdRelations_.begin(); - while (userIdIter != userIdSeqIdRelations_.end()) { - auto sIdIter = std::find(userIdIter->second.begin(), userIdIter->second.end(), sequenceId); - if (sIdIter != userIdIter->second.end()) { - userIdIter->second.erase(sIdIter); - if (userIdIter->second.empty()) { - ZLOGD("finished user callback, userId = %{public}s", userIdIter->first.c_str()); - userId = userIdIter->first; - userIdSeqIdRelations_.erase(userIdIter); - return SUCCESS_USER_HAS_FINISHED; - } else { - ZLOGD(" finished a callback but user not finished, userId = %{public}s", userIdIter->first.c_str()); - return SUCCESS_USER_IN_USE; - } - } - userIdIter++; - } - return SUCCESS_USER_HAS_FINISHED; -} - -int32_t ObjectStoreManager::BindAsset(const uint32_t tokenId, const std::string& appId, const std::string& sessionId, - ObjectStore::Asset& asset, ObjectStore::AssetBindInfo& bindInfo) -{ - auto snapshotKey = appId + SEPERATOR + sessionId; - snapshots_.ComputeIfAbsent( - snapshotKey, [](const std::string& key) -> auto { - return std::make_shared(); - }); - auto storeKey = appId + SEPERATOR + bindInfo.storeName; - bindSnapshots_.ComputeIfAbsent( - storeKey, [](const std::string& key) -> auto { - return std::make_shared>>(); - }); - auto snapshots = snapshots_.Find(snapshotKey).second; - bindSnapshots_.Compute(storeKey, [this, &asset, snapshots] (const auto &key, auto &value) { - value->emplace(std::pair{asset.uri, snapshots}); - return true; - }); - - HapTokenInfo tokenInfo; - auto status = AccessTokenKit::GetHapTokenInfo(tokenId, tokenInfo); - if (status != RET_SUCCESS) { - ZLOGE("token:0x%{public}x, result:%{public}d, bundleName:%{public}s", tokenId, status, appId.c_str()); - return GeneralError::E_ERROR; - } - StoreInfo storeInfo; - storeInfo.bundleName = appId; - storeInfo.tokenId = tokenId; - storeInfo.instanceId = tokenInfo.instIndex; - storeInfo.user = tokenInfo.userID; - storeInfo.storeName = bindInfo.storeName; - - snapshots_.Compute(snapshotKey, [this, &asset, &bindInfo, &storeInfo] (const auto &key, auto &value) { - value->BindAsset(ValueProxy::Convert(std::move(asset)), ConvertBindInfo(bindInfo), storeInfo); - return true; - }); - return OBJECT_SUCCESS; -} - -DistributedData::AssetBindInfo ObjectStoreManager::ConvertBindInfo(ObjectStore::AssetBindInfo& bindInfo) -{ - return DistributedData::AssetBindInfo{ - .storeName = std::move(bindInfo.storeName), - .tableName = std::move(bindInfo.tableName), - .primaryKey = ValueProxy::Convert(std::move(bindInfo.primaryKey)), - .field = std::move(bindInfo.field), - .assetName = std::move(bindInfo.assetName), - }; -} - -int32_t ObjectStoreManager::OnAssetChanged(const uint32_t tokenId, const std::string& appId, - const std::string& sessionId, const std::string& deviceId, const ObjectStore::Asset& asset) -{ - const int32_t userId = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(tokenId); - auto objectAsset = asset; - Asset dataAsset = ValueProxy::Convert(std::move(objectAsset)); - auto snapshotKey = appId + SEPERATOR + sessionId; - int32_t res = OBJECT_SUCCESS; - bool exist = snapshots_.ComputeIfPresent(snapshotKey, - [&res, &dataAsset, &deviceId](const std::string &key, std::shared_ptr snapshot) { - if (snapshot != nullptr) { - res = snapshot->OnDataChanged(dataAsset, deviceId); // needChange - } - return snapshot != nullptr; - }); - if (exist) { - return res; - } - - auto block = std::make_shared>>(WAIT_TIME, std::tuple{ true, true }); - ObjectAssetLoader::GetInstance()->TransferAssetsAsync(userId, appId, deviceId, { dataAsset }, [block](bool ret) { - block->SetValue({ false, ret }); - }); - auto [timeout, success] = block->GetValue(); - if (timeout || !success) { - ZLOGE("transfer failed, timeout: %{public}d, success: %{public}d, name: %{public}s, deviceId: %{public}s ", - timeout, success, asset.name.c_str(), DistributedData::Anonymous::Change(deviceId).c_str()); - return OBJECT_INNER_ERROR; - } - return OBJECT_SUCCESS; -} - -ObjectStoreManager::UriToSnapshot ObjectStoreManager::GetSnapShots(const std::string& bundleName, - const std::string& storeName) -{ - auto storeKey = bundleName + SEPERATOR + storeName; - bindSnapshots_.ComputeIfAbsent( - storeKey, [](const std::string& key) -> auto { - return std::make_shared>>(); - }); - return bindSnapshots_.Find(storeKey).second; -} - -void ObjectStoreManager::DeleteSnapshot(const std::string& bundleName, const std::string& sessionId) -{ - auto snapshotKey = bundleName + SEPERATOR + sessionId; - auto snapshot = snapshots_.Find(snapshotKey).second; - if (snapshot == nullptr) { - ZLOGD("Not find snapshot, don't need delete"); - return; - } - bindSnapshots_.ForEach([snapshot](auto& key, auto& value) { - for (auto pos = value->begin(); pos != value->end();) { - if (pos->second == snapshot) { - pos = value->erase(pos); - } else { - ++pos; - } - } - return true; - }); - snapshots_.Erase(snapshotKey); -} -} // namespace DistributedObject -} // namespace OHOS +/* + * Copyright (c) 2022 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 "ObjectStoreManager" + +#include "object_manager.h" + +#include + +#include "accesstoken_kit.h" +#include "account/account_delegate.h" +#include "block_data.h" +#include "bootstrap.h" +#include "common/bytes.h" +#include "common/string_utils.h" +#include "datetime_ex.h" +#include "distributed_file_daemon_manager.h" +#include "kvstore_utils.h" +#include "log_print.h" +#include "metadata/meta_data_manager.h" +#include "metadata/store_meta_data.h" +#include "object_dms_handler.h" +#include "object_radar_reporter.h" +#include "utils/anonymous.h" + +namespace OHOS { +namespace DistributedObject { +using namespace OHOS::DistributedKv; +using namespace Security::AccessToken; +using StoreMetaData = OHOS::DistributedData::StoreMetaData; +using Account = OHOS::DistributedData::AccountDelegate; +using AccessTokenKit = Security::AccessToken::AccessTokenKit; +using ValueProxy = OHOS::DistributedData::ValueProxy; +using DistributedFileDaemonManager = Storage::DistributedFile::DistributedFileDaemonManager; +constexpr const char *SAVE_INFO = "p_###SAVEINFO###"; +ObjectStoreManager::ObjectStoreManager() +{ + ZLOGI("ObjectStoreManager construct"); + RegisterAssetsLister(); +} + +ObjectStoreManager::~ObjectStoreManager() +{ + ZLOGI("ObjectStoreManager destroy"); + if (objectAssetsRecvListener_ != nullptr) { + auto status = DistributedFileDaemonManager::GetInstance().UnRegisterAssetCallback(objectAssetsRecvListener_); + if (status != DistributedDB::DBStatus::OK) { + ZLOGE("UnRegister assetsRecvListener err %{public}d", status); + } + } +} + +DistributedDB::KvStoreNbDelegate *ObjectStoreManager::OpenObjectKvStore() +{ + DistributedDB::KvStoreNbDelegate *store = nullptr; + DistributedDB::KvStoreNbDelegate::Option option; + option.createDirByStoreIdOnly = true; + option.syncDualTupleMode = true; + option.secOption = { DistributedDB::S1, DistributedDB::ECE }; + if (objectDataListener_ == nullptr) { + objectDataListener_ = new ObjectDataListener(); + } + ZLOGD("start GetKvStore"); + kvStoreDelegateManager_->GetKvStore(ObjectCommon::OBJECTSTORE_DB_STOREID, option, + [&store, this](DistributedDB::DBStatus dbStatus, DistributedDB::KvStoreNbDelegate *kvStoreNbDelegate) { + if (dbStatus != DistributedDB::DBStatus::OK) { + ZLOGE("GetKvStore fail %{public}d", dbStatus); + return; + } + ZLOGI("GetKvStore successsfully"); + store = kvStoreNbDelegate; + std::vector tmpKey; + DistributedDB::DBStatus status = store->RegisterObserver(tmpKey, + DistributedDB::ObserverMode::OBSERVER_CHANGES_FOREIGN, + objectDataListener_); + if (status != DistributedDB::DBStatus::OK) { + ZLOGE("RegisterObserver err %{public}d", status); + } + }); + return store; +} + +bool ObjectStoreManager::RegisterAssetsLister() +{ + if (objectAssetsSendListener_ == nullptr) { + objectAssetsSendListener_ = new ObjectAssetsSendListener(); + } + if (objectAssetsRecvListener_ == nullptr) { + objectAssetsRecvListener_ = new ObjectAssetsRecvListener(); + } + auto status = DistributedFileDaemonManager::GetInstance().RegisterAssetCallback(objectAssetsRecvListener_); + if (status != DistributedDB::DBStatus::OK) { + ZLOGE("Register assetsRecvListener err %{public}d", status); + return false; + } + return true; +} + +void ObjectStoreManager::ProcessSyncCallback(const std::map &results, const std::string &appId, + const std::string &sessionId, const std::string &deviceId) +{ + if (results.empty() || results.find(LOCAL_DEVICE) != results.end()) { + return; + } + int32_t result = Open(); + if (result != OBJECT_SUCCESS) { + ZLOGE("Open failed, errCode = %{public}d", result); + return; + } + // delete local data + result = RevokeSaveToStore(GetPropertyPrefix(appId, sessionId, deviceId)); + if (result != OBJECT_SUCCESS) { + ZLOGE("Save failed, status = %{public}d", result); + } + Close(); + return; +} + +int32_t ObjectStoreManager::Save(const std::string &appId, const std::string &sessionId, + const ObjectRecord &data, const std::string &deviceId, sptr callback) +{ + auto proxy = iface_cast(callback); + if (deviceId.size() == 0) { + ZLOGE("DeviceId empty, appId: %{public}s, sessionId: %{public}s", appId.c_str(), sessionId.c_str()); + proxy->Completed(std::map()); + return INVALID_ARGUMENT; + } + int32_t result = Open(); + if (result != OBJECT_SUCCESS) { + ZLOGE("Open object kvstore failed, result: %{public}d", result); + ObjectStore::RadarReporter::ReportStateError(std::string(__FUNCTION__), ObjectStore::SAVE, + ObjectStore::SAVE_TO_STORE, ObjectStore::RADAR_FAILED, ObjectStore::GETKV_FAILED, ObjectStore::FINISHED); + proxy->Completed(std::map()); + return STORE_NOT_OPEN; + } + SaveUserToMeta(); + std::string dstBundleName = ObjectDmsHandler::GetInstance().GetDstBundleName(appId, deviceId); + result = SaveToStore(dstBundleName, sessionId, deviceId, data); + if (result != OBJECT_SUCCESS) { + ZLOGE("Save to store failed, result: %{public}d", result); + ObjectStore::RadarReporter::ReportStateError(std::string(__FUNCTION__), ObjectStore::SAVE, + ObjectStore::SAVE_TO_STORE, ObjectStore::RADAR_FAILED, result, ObjectStore::FINISHED); + Close(); + proxy->Completed(std::map()); + return result; + } + ZLOGI("Sync data, bundleName: %{public}s, sessionId: %{public}s, deviceId: %{public}s", dstBundleName.c_str(), + sessionId.c_str(), Anonymous::Change(deviceId).c_str()); + SyncCallBack syncCallback = + [proxy, dstBundleName, sessionId, deviceId, this](const std::map &results) { + ProcessSyncCallback(results, dstBundleName, sessionId, deviceId); + proxy->Completed(results); + }; + result = SyncOnStore(GetPropertyPrefix(dstBundleName, sessionId, deviceId), {deviceId}, syncCallback); + if (result != OBJECT_SUCCESS) { + ZLOGE("Sync data failed, result: %{public}d", result); + ObjectStore::RadarReporter::ReportStateError(std::string(__FUNCTION__), ObjectStore::SAVE, + ObjectStore::SYNC_DATA, ObjectStore::RADAR_FAILED, result, ObjectStore::FINISHED); + Close(); + proxy->Completed(std::map()); + return result; + } + Close(); + return PushAssets(appId, dstBundleName, sessionId, data, deviceId); +} + +int32_t ObjectStoreManager::PushAssets(const std::string &srcBundleName, const std::string &dstBundleName, + const std::string &sessionId, const ObjectRecord &data, const std::string &deviceId) +{ + Assets assets = GetAssetsFromDBRecords(data); + if (assets.empty() || data.find(ObjectStore::FIELDS_PREFIX + ObjectStore::DEVICEID_KEY) == data.end()) { + return OBJECT_SUCCESS; + } + sptr assetObj = new AssetObj(); + assetObj->dstBundleName_ = dstBundleName; + assetObj->srcBundleName_ = srcBundleName; + assetObj->dstNetworkId_ = deviceId; + assetObj->sessionId_ = sessionId; + for (const auto& asset : assets) { + assetObj->uris_.push_back(asset.uri); + } + if (objectAssetsSendListener_ == nullptr) { + objectAssetsSendListener_ = new ObjectAssetsSendListener(); + } + int userId = std::atoi(GetCurrentUser().c_str()); + auto status = ObjectAssetLoader::GetInstance()->PushAsset(userId, assetObj, objectAssetsSendListener_); + return status; +} + +int32_t ObjectStoreManager::RevokeSave( + const std::string &appId, const std::string &sessionId, sptr callback) +{ + auto proxy = iface_cast(callback); + int32_t result = Open(); + if (result != OBJECT_SUCCESS) { + ZLOGE("Open failed, errCode = %{public}d", result); + proxy->Completed(STORE_NOT_OPEN); + return STORE_NOT_OPEN; + } + + result = RevokeSaveToStore(GetPrefixWithoutDeviceId(appId, sessionId)); + if (result != OBJECT_SUCCESS) { + ZLOGE("RevokeSave failed, errCode = %{public}d", result); + Close(); + proxy->Completed(result); + return result; + } + std::vector deviceList; + auto deviceInfos = DmAdaper::GetInstance().GetRemoteDevices(); + std::for_each(deviceInfos.begin(), deviceInfos.end(), + [&deviceList](AppDistributedKv::DeviceInfo info) { deviceList.emplace_back(info.networkId); }); + if (!deviceList.empty()) { + SyncCallBack tmp = [proxy](const std::map &results) { + ZLOGI("revoke save finished"); + proxy->Completed(OBJECT_SUCCESS); + }; + result = SyncOnStore(GetPropertyPrefix(appId, sessionId), deviceList, tmp); + if (result != OBJECT_SUCCESS) { + ZLOGE("sync failed, errCode = %{public}d", result); + proxy->Completed(result); + } + } else { + proxy->Completed(OBJECT_SUCCESS); + }; + Close(); + return result; +} + +int32_t ObjectStoreManager::Retrieve( + const std::string &bundleName, const std::string &sessionId, sptr callback, uint32_t tokenId) +{ + auto proxy = iface_cast(callback); + int32_t result = Open(); + if (result != OBJECT_SUCCESS) { + ZLOGE("Open object kvstore failed, result: %{public}d", result); + proxy->Completed(ObjectRecord(), false); + return ObjectStore::GETKV_FAILED; + } + ObjectRecord results{}; + int32_t status = RetrieveFromStore(bundleName, sessionId, results); + if (status != OBJECT_SUCCESS) { + ZLOGI("Retrieve from store failed, status: %{public}d", status); + Close(); + proxy->Completed(ObjectRecord(), false); + return status; + } + bool allReady = false; + Assets assets = GetAssetsFromDBRecords(results); + if (assets.empty() || results.find(ObjectStore::FIELDS_PREFIX + ObjectStore::DEVICEID_KEY) == results.end()) { + allReady = true; + } else { + auto objectKey = bundleName + sessionId; + restoreStatus_.ComputeIfPresent(objectKey, [&allReady](const auto &key, auto &value) { + if (value == RestoreStatus::ALL_READY) { + allReady = true; + return false; + } + if (value == RestoreStatus::DATA_READY) { + value = RestoreStatus::DATA_NOTIFIED; + } + return true; + }); + } + status = RevokeSaveToStore(GetPrefixWithoutDeviceId(bundleName, sessionId)); + if (status != OBJECT_SUCCESS) { + ZLOGE("Revoke save failed, status: %{public}d", status); + Close(); + proxy->Completed(ObjectRecord(), false); + return status; + } + Close(); + proxy->Completed(results, allReady); + if (allReady) { + ObjectStore::RadarReporter::ReportStateFinished(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, + ObjectStore::NOTIFY, ObjectStore::RADAR_SUCCESS, ObjectStore::FINISHED); + } + return status; +} + +int32_t ObjectStoreManager::Clear() +{ + ZLOGI("enter"); + std::string userId = GetCurrentUser(); + if (userId.empty()) { + return OBJECT_INNER_ERROR; + } + std::vector metaData; + std::string appId = DistributedData::Bootstrap::GetInstance().GetProcessLabel(); + std::string metaKey = GetMetaUserIdKey(userId, appId); + if (!DistributedData::MetaDataManager::GetInstance().LoadMeta(metaKey, metaData, true)) { + ZLOGE("no store of %{public}s", appId.c_str()); + return OBJECT_STORE_NOT_FOUND; + } + for (const auto &storeMeta : metaData) { + if (storeMeta.storeType < StoreMetaData::StoreType::STORE_OBJECT_BEGIN + || storeMeta.storeType > StoreMetaData::StoreType::STORE_OBJECT_END) { + continue; + } + if (storeMeta.user == userId) { + ZLOGI("user is same, not need to change, mate user:%{public}s::user:%{public}s.", + storeMeta.user.c_str(), userId.c_str()); + return OBJECT_SUCCESS; + } + } + ZLOGD("user is change, need to change"); + int32_t result = Open(); + if (result != OBJECT_SUCCESS) { + ZLOGE("Open failed, errCode = %{public}d", result); + return STORE_NOT_OPEN; + } + result = RevokeSaveToStore(""); + Close(); + return result; +} + +int32_t ObjectStoreManager::DeleteByAppId(const std::string &appId, int32_t user) +{ + int32_t result = Open(); + if (result != OBJECT_SUCCESS) { + ZLOGE("Open store failed, result: %{public}d, appId: %{public}s, user: %{public}d", result, + appId.c_str(), user); + return STORE_NOT_OPEN; + } + result = RevokeSaveToStore(appId); + if (result != OBJECT_SUCCESS) { + ZLOGE("Revoke save failed, result: %{public}d, appId: %{public}s, user: %{public}d", result, + appId.c_str(), user); + } + Close(); + std::string userId = std::to_string(user); + std::string metaKey = GetMetaUserIdKey(userId, appId); + auto status = DistributedData::MetaDataManager::GetInstance().DelMeta(metaKey, true); + if (!status) { + ZLOGE("Delete meta failed, userId: %{public}s, appId: %{public}s", userId.c_str(), appId.c_str()); + } + return result; +} + +void ObjectStoreManager::RegisterRemoteCallback(const std::string &bundleName, const std::string &sessionId, + pid_t pid, uint32_t tokenId, + sptr callback) +{ + if (bundleName.empty() || sessionId.empty()) { + ZLOGD("ObjectStoreManager::RegisterRemoteCallback empty"); + return; + } + ZLOGD("ObjectStoreManager::RegisterRemoteCallback start"); + auto proxy = iface_cast(callback); + std::string prefix = bundleName + sessionId; + callbacks_.Compute(tokenId, ([pid, &proxy, &prefix](const uint32_t key, CallbackInfo &value) { + if (value.pid != pid) { + value = CallbackInfo { pid }; + } + value.observers_.insert_or_assign(prefix, proxy); + return !value.observers_.empty(); + })); +} + +void ObjectStoreManager::UnregisterRemoteCallback(const std::string &bundleName, pid_t pid, uint32_t tokenId, + const std::string &sessionId) +{ + if (bundleName.empty()) { + ZLOGD("bundleName is empty"); + return; + } + callbacks_.Compute(tokenId, ([pid, &sessionId, &bundleName](const uint32_t key, CallbackInfo &value) { + if (value.pid != pid) { + return true; + } + if (sessionId.empty()) { + return false; + } + std::string prefix = bundleName + sessionId; + for (auto it = value.observers_.begin(); it != value.observers_.end();) { + if ((*it).first == prefix) { + it = value.observers_.erase(it); + } else { + ++it; + } + } + return true; + })); +} + +void ObjectStoreManager::NotifyChange(ObjectRecord &changedData) +{ + ZLOGI("OnChange start, size:%{public}zu", changedData.size()); + bool hasAsset = false; + SaveInfo saveInfo; + for (const auto &[key, value] : changedData) { + if (key.find(SAVE_INFO) != std::string::npos) { + DistributedData::Serializable::Unmarshall(std::string(value.begin(), value.end()), saveInfo); + break; + } + } + auto data = GetObjectData(changedData, saveInfo, hasAsset); + if (!hasAsset) { + ObjectStore::RadarReporter::ReportStateStart(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, + ObjectStore::DATA_RECV, ObjectStore::RADAR_SUCCESS, ObjectStore::START, saveInfo.bundleName); + callbacks_.ForEach([this, &data](uint32_t tokenId, const CallbackInfo& value) { + DoNotify(tokenId, value, data, true); // no asset, data ready means all ready + return false; + }); + return; + } + NotifyDataChanged(data, saveInfo); + SaveUserToMeta(); +} + +std::map ObjectStoreManager::GetObjectData(const ObjectRecord& changedData, + SaveInfo& saveInfo, bool& hasAsset) +{ + std::map data; + std::string keyPrefix = saveInfo.ToPropertyPrefix(); + if (!keyPrefix.empty()) { + std::string observerKey = saveInfo.bundleName + saveInfo.sessionId; + for (const auto &[key, value] : changedData) { + if (key.size() < keyPrefix.size() || key.find(SAVE_INFO) != std::string::npos) { + continue; + } + std::string propertyName = key.substr(keyPrefix.size()); + data[observerKey].insert_or_assign(propertyName, value); + if (!hasAsset && IsAssetKey(propertyName)) { + hasAsset = true; + } + } + } else { + for (const auto &item : changedData) { + std::vector splitKeys = SplitEntryKey(item.first); + if (splitKeys.size() <= PROPERTY_NAME_INDEX) { + continue; + } + if (saveInfo.sourceDeviceId.empty() || saveInfo.bundleName.empty()) { + saveInfo.sourceDeviceId = splitKeys[SOURCE_DEVICE_UDID_INDEX]; + saveInfo.bundleName = splitKeys[BUNDLE_NAME_INDEX]; + saveInfo.sessionId = splitKeys[SESSION_ID_INDEX]; + saveInfo.timestamp = splitKeys[TIME_INDEX]; + } + std::string prefix = splitKeys[BUNDLE_NAME_INDEX] + splitKeys[SESSION_ID_INDEX]; + std::string propertyName = splitKeys[PROPERTY_NAME_INDEX]; + data[prefix].insert_or_assign(propertyName, item.second); + if (IsAssetKey(propertyName)) { + hasAsset = true; + } + } + } + return data; +} + +void ObjectStoreManager::ComputeStatus(const std::string& objectKey, const SaveInfo& saveInfo, + const std::map& data) +{ + restoreStatus_.Compute(objectKey, [this, &data, saveInfo] (const auto &key, auto &value) { + if (value == RestoreStatus::ASSETS_READY) { + value = RestoreStatus::ALL_READY; + ObjectStore::RadarReporter::ReportStage(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, + ObjectStore::DATA_RECV, ObjectStore::RADAR_SUCCESS); + callbacks_.ForEach([this, &data](uint32_t tokenId, const CallbackInfo& value) { + DoNotify(tokenId, value, data, true); + return false; + }); + } else { + value = RestoreStatus::DATA_READY; + ObjectStore::RadarReporter::ReportStateStart(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, + ObjectStore::DATA_RECV, ObjectStore::RADAR_SUCCESS, ObjectStore::START, saveInfo.bundleName); + callbacks_.ForEach([this, &data](uint32_t tokenId, const CallbackInfo& value) { + DoNotify(tokenId, value, data, false); + return false; + }); + WaitAssets(key, saveInfo, data); + } + return true; + }); +} + +void ObjectStoreManager::NotifyDataChanged(const std::map& data, const SaveInfo& saveInfo) +{ + for (auto const& [objectKey, results] : data) { + restoreStatus_.ComputeIfAbsent( + objectKey, [](const std::string& key) -> auto { + return RestoreStatus::NONE; + }); + ComputeStatus(objectKey, saveInfo, data); + } +} + +int32_t ObjectStoreManager::WaitAssets(const std::string& objectKey, const SaveInfo& saveInfo, + const std::map& data) +{ + auto taskId = executors_->Schedule(std::chrono::seconds(WAIT_TIME), [this, objectKey, data, saveInfo]() { + ZLOGE("wait assets finisehd timeout, try pull assets, objectKey:%{public}s", objectKey.c_str()); + PullAssets(data, saveInfo); + DoNotifyWaitAssetTimeout(objectKey); + }); + + objectTimer_.ComputeIfAbsent( + objectKey, [taskId](const std::string& key) -> auto { + return taskId; + }); + return OBJECT_SUCCESS; +} + +void ObjectStoreManager::PullAssets(const std::map& data, const SaveInfo& saveInfo) +{ + std::map changedAssets; + for (auto const& [objectId, result] : data) { + changedAssets[objectId] = GetAssetsFromDBRecords(result); + } + for (const auto& [objectId, assets] : changedAssets) { + std::string networkId = DmAdaper::GetInstance().ToNetworkID(saveInfo.sourceDeviceId); + auto block = std::make_shared>>(WAIT_TIME, std::tuple{ true, true }); + ObjectAssetLoader::GetInstance()->TransferAssetsAsync(std::stoi(GetCurrentUser()), + saveInfo.bundleName, networkId, assets, [this, block](bool success) { + block->SetValue({ false, success }); + }); + auto [timeout, success] = block->GetValue(); + ZLOGI("Pull assets end, timeout: %{public}d, success: %{public}d, size:%{public}zu, deviceId: %{public}s", + timeout, success, assets.size(), DistributedData::Anonymous::Change(networkId).c_str()); + } +} + +void ObjectStoreManager::NotifyAssetsReady(const std::string& objectKey, const std::string& bundleName, + const std::string& srcNetworkId) +{ + restoreStatus_.ComputeIfAbsent( + objectKey, [](const std::string& key) -> auto { + return RestoreStatus::NONE; + }); + restoreStatus_.Compute(objectKey, [this, &bundleName] (const auto &key, auto &value) { + if (value == RestoreStatus::DATA_NOTIFIED) { + value = RestoreStatus::ALL_READY; + ObjectStore::RadarReporter::ReportStage(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, + ObjectStore::ASSETS_RECV, ObjectStore::RADAR_SUCCESS); + callbacks_.ForEach([this, key](uint32_t tokenId, const CallbackInfo& value) { + DoNotifyAssetsReady(tokenId, value, key, true); + return false; + }); + } else if (value == RestoreStatus::DATA_READY) { + value = RestoreStatus::ALL_READY; + ObjectStore::RadarReporter::ReportStage(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, + ObjectStore::ASSETS_RECV, ObjectStore::RADAR_SUCCESS); + auto [has, taskId] = objectTimer_.Find(key); + if (has) { + executors_->Remove(taskId); + objectTimer_.Erase(key); + } + } else { + value = RestoreStatus::ASSETS_READY; + ObjectStore::RadarReporter::ReportStateStart(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, + ObjectStore::ASSETS_RECV, ObjectStore::RADAR_SUCCESS, ObjectStore::START, bundleName); + } + return true; + }); +} + +void ObjectStoreManager::NotifyAssetsStart(const std::string& objectKey, const std::string& srcNetworkId) +{ + restoreStatus_.ComputeIfAbsent( + objectKey, [](const std::string& key) -> auto { + return RestoreStatus::NONE; + }); +} + +bool ObjectStoreManager::IsAssetKey(const std::string& key) +{ + return key.find(ObjectStore::ASSET_DOT) != std::string::npos; +} + +bool ObjectStoreManager::IsAssetComplete(const ObjectRecord& result, const std::string& assetPrefix) +{ + if (result.find(assetPrefix + ObjectStore::NAME_SUFFIX) == result.end() || + result.find(assetPrefix + ObjectStore::URI_SUFFIX) == result.end() || + result.find(assetPrefix + ObjectStore::PATH_SUFFIX) == result.end() || + result.find(assetPrefix + ObjectStore::CREATE_TIME_SUFFIX) == result.end() || + result.find(assetPrefix + ObjectStore::MODIFY_TIME_SUFFIX) == result.end() || + result.find(assetPrefix + ObjectStore::SIZE_SUFFIX) == result.end()) { + return false; + } + return true; +} + +Assets ObjectStoreManager::GetAssetsFromDBRecords(const ObjectRecord& result) +{ + Assets assets{}; + std::set assetKey; + for (const auto& [key, value] : result) { + std::string assetPrefix = key.substr(0, key.find(ObjectStore::ASSET_DOT)); + if (!IsAssetKey(key) || assetKey.find(assetPrefix) != assetKey.end() || + result.find(assetPrefix + ObjectStore::NAME_SUFFIX) == result.end() || + result.find(assetPrefix + ObjectStore::URI_SUFFIX) == result.end()) { + continue; + } + Asset asset; + ObjectStore::StringUtils::BytesToStrWithType( + result.find(assetPrefix + ObjectStore::NAME_SUFFIX)->second, asset.name); + if (asset.name.find(ObjectStore::STRING_PREFIX) != std::string::npos) { + asset.name = asset.name.substr(ObjectStore::STRING_PREFIX_LEN); + } + ObjectStore::StringUtils::BytesToStrWithType( + result.find(assetPrefix + ObjectStore::URI_SUFFIX)->second, asset.uri); + if (asset.uri.find(ObjectStore::STRING_PREFIX) != std::string::npos) { + asset.uri = asset.uri.substr(ObjectStore::STRING_PREFIX_LEN); + } + ObjectStore::StringUtils::BytesToStrWithType( + result.find(assetPrefix + ObjectStore::MODIFY_TIME_SUFFIX)->second, asset.modifyTime); + if (asset.modifyTime.find(ObjectStore::STRING_PREFIX) != std::string::npos) { + asset.modifyTime = asset.modifyTime.substr(ObjectStore::STRING_PREFIX_LEN); + } + ObjectStore::StringUtils::BytesToStrWithType( + result.find(assetPrefix + ObjectStore::SIZE_SUFFIX)->second, asset.size); + if (asset.size.find(ObjectStore::STRING_PREFIX) != std::string::npos) { + asset.size = asset.size.substr(ObjectStore::STRING_PREFIX_LEN); + } + asset.hash = asset.modifyTime + "_" + asset.size; + assets.push_back(asset); + assetKey.insert(assetPrefix); + } + return assets; +} + +void ObjectStoreManager::DoNotify(uint32_t tokenId, const CallbackInfo& value, + const std::map& data, bool allReady) +{ + for (const auto& observer : value.observers_) { + auto it = data.find(observer.first); + if (it == data.end()) { + continue; + } + observer.second->Completed((*it).second, allReady); + if (allReady) { + restoreStatus_.Erase(observer.first); + ObjectStore::RadarReporter::ReportStateFinished(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, + ObjectStore::NOTIFY, ObjectStore::RADAR_SUCCESS, ObjectStore::FINISHED); + } else { + restoreStatus_.ComputeIfPresent(observer.first, [](const auto &key, auto &value) { + value = RestoreStatus::DATA_NOTIFIED; + return true; + }); + } + } +} + +void ObjectStoreManager::DoNotifyAssetsReady(uint32_t tokenId, const CallbackInfo& value, + const std::string& objectKey, bool allReady) +{ + for (const auto& observer : value.observers_) { + if (objectKey != observer.first) { + continue; + } + observer.second->Completed(ObjectRecord(), allReady); + if (allReady) { + restoreStatus_.Erase(objectKey); + ObjectStore::RadarReporter::ReportStateFinished(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, + ObjectStore::NOTIFY, ObjectStore::RADAR_SUCCESS, ObjectStore::FINISHED); + } + auto [has, taskId] = objectTimer_.Find(objectKey); + if (has) { + executors_->Remove(taskId); + objectTimer_.Erase(objectKey); + } + } +} + +void ObjectStoreManager::DoNotifyWaitAssetTimeout(const std::string &objectKey) +{ + ObjectStore::RadarReporter::ReportStageError(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, + ObjectStore::ASSETS_RECV, ObjectStore::RADAR_FAILED, ObjectStore::TIMEOUT); + callbacks_.ForEach([this, &objectKey](uint32_t tokenId, const CallbackInfo &value) { + for (const auto& observer : value.observers_) { + if (objectKey != observer.first) { + continue; + } + observer.second->Completed(ObjectRecord(), true); + restoreStatus_.Erase(objectKey); + auto [has, taskId] = objectTimer_.Find(objectKey); + if (has) { + executors_->Remove(taskId); + objectTimer_.Erase(objectKey); + } + ObjectStore::RadarReporter::ReportStateError(std::string(__FUNCTION__), ObjectStore::DATA_RESTORE, + ObjectStore::NOTIFY, ObjectStore::RADAR_FAILED, ObjectStore::TIMEOUT, ObjectStore::FINISHED); + } + return false; + }); +} + +void ObjectStoreManager::SetData(const std::string &dataDir, const std::string &userId) +{ + ZLOGI("enter %{public}s", dataDir.c_str()); + kvStoreDelegateManager_ = + new DistributedDB::KvStoreDelegateManager(DistributedData::Bootstrap::GetInstance().GetProcessLabel(), userId); + DistributedDB::KvStoreConfig kvStoreConfig { dataDir }; + kvStoreDelegateManager_->SetKvStoreConfig(kvStoreConfig); + userId_ = userId; +} + +int32_t ObjectStoreManager::Open() +{ + if (kvStoreDelegateManager_ == nullptr) { + ZLOGE("Kvstore delegate manager not init"); + return OBJECT_INNER_ERROR; + } + std::lock_guard lock(kvStoreMutex_); + if (delegate_ == nullptr) { + delegate_ = OpenObjectKvStore(); + if (delegate_ == nullptr) { + ZLOGE("Open object kvstore failed"); + return OBJECT_DBSTATUS_ERROR; + } + syncCount_ = 1; + ZLOGI("Open object kvstore success"); + } else { + syncCount_++; + ZLOGI("Object kvstore syncCount: %{public}d", syncCount_); + } + return OBJECT_SUCCESS; +} + +void ObjectStoreManager::Close() +{ + std::lock_guard lock(kvStoreMutex_); + if (delegate_ == nullptr) { + return; + } + int32_t taskCount = delegate_->GetTaskCount(); + if (taskCount > 0 && syncCount_ == 1) { + CloseAfterMinute(); + ZLOGW("Store is busy, close after a minute, task count: %{public}d", taskCount); + return; + } + syncCount_--; + ZLOGI("closed a store, syncCount = %{public}d", syncCount_); + FlushClosedStore(); +} + +void ObjectStoreManager::SyncCompleted( + const std::map &results, uint64_t sequenceId) +{ + std::string userId; + SequenceSyncManager::Result result = SequenceSyncManager::GetInstance()->Process(sequenceId, results, userId); + if (result == SequenceSyncManager::SUCCESS_USER_HAS_FINISHED && userId == userId_) { + std::lock_guard lock(kvStoreMutex_); + SetSyncStatus(false); + FlushClosedStore(); + } + for (const auto &item : results) { + if (item.second == DistributedDB::DBStatus::OK) { + ZLOGI("Sync data success, sequenceId: 0x%{public}" PRIx64 "", sequenceId); + ObjectStore::RadarReporter::ReportStateFinished(std::string(__FUNCTION__), ObjectStore::SAVE, + ObjectStore::SYNC_DATA, ObjectStore::RADAR_SUCCESS, ObjectStore::FINISHED); + } else { + ZLOGE("Sync data failed, sequenceId: 0x%{public}" PRIx64 ", status: %{public}d", sequenceId, item.second); + ObjectStore::RadarReporter::ReportStateError(std::string(__FUNCTION__), ObjectStore::SAVE, + ObjectStore::SYNC_DATA, ObjectStore::RADAR_FAILED, item.second, ObjectStore::FINISHED); + } + } +} + +void ObjectStoreManager::FlushClosedStore() +{ + std::lock_guard lock(kvStoreMutex_); + if (!isSyncing_ && syncCount_ == 0 && delegate_ != nullptr) { + ZLOGD("close store"); + auto status = kvStoreDelegateManager_->CloseKvStore(delegate_); + if (status != DistributedDB::DBStatus::OK) { + int timeOut = 1000; + executors_->Schedule(std::chrono::milliseconds(timeOut), [this]() { + FlushClosedStore(); + }); + ZLOGE("GetEntries fail %{public}d", status); + return; + } + delegate_ = nullptr; + if (objectDataListener_ != nullptr) { + delete objectDataListener_; + objectDataListener_ = nullptr; + } + } +} + +void ObjectStoreManager::ProcessOldEntry(const std::string &appId) +{ + std::vector entries; + auto status = delegate_->GetEntries(std::vector(appId.begin(), appId.end()), entries); + if (status != DistributedDB::DBStatus::NOT_FOUND) { + ZLOGI("Get old entries empty, bundleName: %{public}s", appId.c_str()); + return; + } + if (status != DistributedDB::DBStatus::OK) { + ZLOGE("Get old entries failed, bundleName: %{public}s, status %{public}d", appId.c_str(), status); + return; + } + std::map sessionIds; + int64_t oldestTime = 0; + std::string deleteKey; + for (auto &item : entries) { + std::string key(item.key.begin(), item.key.end()); + std::vector splitKeys = SplitEntryKey(key); + if (splitKeys.empty()) { + continue; + } + std::string bundleName = splitKeys[BUNDLE_NAME_INDEX]; + std::string sessionId = splitKeys[SESSION_ID_INDEX]; + if (sessionIds.count(sessionId) == 0) { + char *end = nullptr; + sessionIds[sessionId] = strtol(splitKeys[TIME_INDEX].c_str(), &end, DECIMAL_BASE); + } + if (oldestTime == 0 || oldestTime > sessionIds[sessionId]) { + oldestTime = sessionIds[sessionId]; + deleteKey = GetPrefixWithoutDeviceId(bundleName, sessionId); + } + } + if (sessionIds.size() < MAX_OBJECT_SIZE_PER_APP) { + return; + } + int32_t result = RevokeSaveToStore(deleteKey); + if (result != OBJECT_SUCCESS) { + ZLOGE("Delete old entries failed, deleteKey: %{public}s, status: %{public}d", deleteKey.c_str(), result); + return; + } + ZLOGI("Delete old entries success, deleteKey: %{public}s", deleteKey.c_str()); +} + +int32_t ObjectStoreManager::SaveToStore(const std::string &appId, const std::string &sessionId, + const std::string &toDeviceId, const ObjectRecord &data) +{ + ProcessOldEntry(appId); + RevokeSaveToStore(GetPropertyPrefix(appId, sessionId, toDeviceId)); + std::string timestamp = std::to_string(GetSecondsSince1970ToNow()); + std::string prefix = GetPropertyPrefix(appId, sessionId, toDeviceId) + timestamp + SEPERATOR; + DistributedDB::Entry saveInfoEntry; + std::string saveInfoKey = prefix + SAVE_INFO; + saveInfoEntry.key = std::vector(saveInfoKey.begin(), saveInfoKey.end()); + SaveInfo saveInfo(appId, sessionId, DmAdaper::GetInstance().GetLocalDevice().udid, toDeviceId, timestamp); + std::string saveInfoValue = DistributedData::Serializable::Marshall(saveInfo); + saveInfoEntry.value = std::vector(saveInfoValue.begin(), saveInfoValue.end()); + std::vector entries; + entries.emplace_back(saveInfoEntry); + for (auto &item : data) { + DistributedDB::Entry entry; + std::string key = GetPropertyPrefix(appId, sessionId, toDeviceId) + timestamp + SEPERATOR + item.first; + entry.key = std::vector(key.begin(), key.end()); + entry.value = item.second; + entries.emplace_back(entry); + } + auto status = delegate_->PutBatch(entries); + if (status != DistributedDB::DBStatus::OK) { + ZLOGE("PutBatch failed, bundleName: %{public}s, sessionId: %{public}s, dstNetworkId: %{public}s, " + "status: %{public}d", appId.c_str(), sessionId.c_str(), Anonymous::Change(toDeviceId).c_str(), status); + return status; + } + ZLOGI("PutBatch success, bundleName: %{public}s, sessionId: %{public}s, dstNetworkId: %{public}s, " + "count: %{public}zu", appId.c_str(), sessionId.c_str(), Anonymous::Change(toDeviceId).c_str(), entries.size()); + return OBJECT_SUCCESS; +} + +int32_t ObjectStoreManager::SyncOnStore( + const std::string &prefix, const std::vector &deviceList, SyncCallBack &callback) +{ + std::vector syncDevices; + for (auto &device : deviceList) { + if (device == LOCAL_DEVICE) { + ZLOGI("Save to local, do not need sync, prefix: %{public}s", prefix.c_str()); + callback({{LOCAL_DEVICE, OBJECT_SUCCESS}}); + return OBJECT_SUCCESS; + } + syncDevices.emplace_back(DmAdaper::GetInstance().GetUuidByNetworkId(device)); + } + if (syncDevices.empty()) { + ZLOGI("Device list is empty, prefix: %{public}s", Anonymous::Change(prefix).c_str()); + callback(std::map()); + return OBJECT_SUCCESS; + } + uint64_t sequenceId = SequenceSyncManager::GetInstance()->AddNotifier(userId_, callback); + DistributedDB::Query dbQuery = DistributedDB::Query::Select(); + dbQuery.PrefixKey(std::vector(prefix.begin(), prefix.end())); + ZLOGI("Start sync data, sequenceId: 0x%{public}" PRIx64 "", sequenceId); + auto status = delegate_->Sync(syncDevices, DistributedDB::SyncMode::SYNC_MODE_PUSH_ONLY, + [this, sequenceId](const std::map &devicesMap) { + ZLOGI("Sync data finished, sequenceId: 0x%{public}" PRIx64 "", sequenceId); + std::map result; + for (auto &item : devicesMap) { + result[DmAdaper::GetInstance().ToNetworkID(item.first)] = item.second; + } + SyncCompleted(result, sequenceId); + }, dbQuery, false); + if (status != DistributedDB::DBStatus::OK) { + ZLOGE("Sync data failed, prefix: %{public}s, sequenceId: 0x%{public}" PRIx64 ", status: %{public}d", + Anonymous::Change(prefix).c_str(), sequenceId, status); + std::string tmp; + SequenceSyncManager::GetInstance()->DeleteNotifier(sequenceId, tmp); + return status; + } + SetSyncStatus(true); + return OBJECT_SUCCESS; +} + +int32_t ObjectStoreManager::SetSyncStatus(bool status) +{ + std::lock_guard lock(kvStoreMutex_); + isSyncing_ = status; + return OBJECT_SUCCESS; +} + +int32_t ObjectStoreManager::RevokeSaveToStore(const std::string &prefix) +{ + std::vector entries; + auto status = delegate_->GetEntries(std::vector(prefix.begin(), prefix.end()), entries); + if (status == DistributedDB::DBStatus::NOT_FOUND) { + ZLOGI("Get entries empty, prefix: %{public}s", Anonymous::Change(prefix).c_str()); + return OBJECT_SUCCESS; + } + if (status != DistributedDB::DBStatus::OK) { + ZLOGE("Get entries failed, prefix: %{public}s, status: %{public}d", Anonymous::Change(prefix).c_str(), status); + return DB_ERROR; + } + std::vector> keys; + std::for_each(entries.begin(), entries.end(), [&keys](const DistributedDB::Entry &entry) { + keys.emplace_back(entry.key); + }); + if (keys.empty()) { + return OBJECT_SUCCESS; + } + status = delegate_->DeleteBatch(keys); + if (status != DistributedDB::DBStatus::OK) { + ZLOGE("Delete entries failed, prefix: %{public}s, status: %{public}d", Anonymous::Change(prefix).c_str(), + status); + return DB_ERROR; + } + ZLOGI("Delete entries success, prefix: %{public}s, count: %{public}zu", Anonymous::Change(prefix).c_str(), + keys.size()); + return OBJECT_SUCCESS; +} + +int32_t ObjectStoreManager::RetrieveFromStore(const std::string &appId, const std::string &sessionId, + ObjectRecord &results) +{ + std::vector entries; + std::string prefix = GetPrefixWithoutDeviceId(appId, sessionId); + auto status = delegate_->GetEntries(std::vector(prefix.begin(), prefix.end()), entries); + if (status == DistributedDB::DBStatus::NOT_FOUND) { + ZLOGI("Get entries empty, prefix: %{public}s, status: %{public}d", prefix.c_str(), status); + return KEY_NOT_FOUND; + } + if (status != DistributedDB::DBStatus::OK) { + ZLOGE("Get entries failed, prefix: %{public}s, status: %{public}d", prefix.c_str(), status); + return DB_ERROR; + } + ZLOGI("Get entries success, prefix: %{public}s, count: %{public}zu", prefix.c_str(), entries.size()); + for (const auto &entry : entries) { + std::string key(entry.key.begin(), entry.key.end()); + if (key.find(SAVE_INFO) != std::string::npos) { + continue; + } + auto splitKeys = SplitEntryKey(key); + if (!splitKeys.empty()) { + results[splitKeys[PROPERTY_NAME_INDEX]] = entry.value; + } + } + return OBJECT_SUCCESS; +} + +ObjectStoreManager::SaveInfo::SaveInfo(const std::string &bundleName, const std::string &sessionId, + const std::string &sourceDeviceId, const std::string &targetDeviceId, const std::string ×tamp) + : bundleName(bundleName), sessionId(sessionId), sourceDeviceId(sourceDeviceId), targetDeviceId(targetDeviceId), + timestamp(timestamp) {} + +bool ObjectStoreManager::SaveInfo::Marshal(json &node) const +{ + SetValue(node[GET_NAME(bundleName)], bundleName); + SetValue(node[GET_NAME(sessionId)], sessionId); + SetValue(node[GET_NAME(sourceDeviceId)], sourceDeviceId); + SetValue(node[GET_NAME(targetDeviceId)], targetDeviceId); + SetValue(node[GET_NAME(timestamp)], timestamp); + return true; +} + +bool ObjectStoreManager::SaveInfo::Unmarshal(const json &node) +{ + GetValue(node, GET_NAME(bundleName), bundleName); + GetValue(node, GET_NAME(sessionId), sessionId); + GetValue(node, GET_NAME(sourceDeviceId), sourceDeviceId); + GetValue(node, GET_NAME(targetDeviceId), targetDeviceId); + GetValue(node, GET_NAME(timestamp), timestamp); + return true; +} + +std::string ObjectStoreManager::SaveInfo::ToPropertyPrefix() +{ + if (bundleName.empty() || sessionId.empty() || sourceDeviceId.empty() || targetDeviceId.empty() || + timestamp.empty()) { + return ""; + } + return bundleName + SEPERATOR + sessionId + SEPERATOR + sourceDeviceId + SEPERATOR + targetDeviceId + SEPERATOR + + timestamp + SEPERATOR; +} + +std::vector ObjectStoreManager::SplitEntryKey(const std::string &key) +{ + std::smatch match; + std::regex timeRegex(TIME_REGEX); + if (!std::regex_search(key, match, timeRegex)) { + ZLOGW("Format error, key.size = %{public}zu", key.size()); + return {}; + } + auto timePos = match.position(); + std::string fromTime = key.substr(timePos + 1); + std::string beforeTime = key.substr(0, timePos); + + size_t targetDevicePos = beforeTime.find_last_of(SEPERATOR); + if (targetDevicePos == std::string::npos) { + ZLOGW("Format error, key.size = %{public}zu", key.size()); + return {}; + } + std::string targetDevice = beforeTime.substr(targetDevicePos + 1); + std::string beforeTargetDevice = beforeTime.substr(0, targetDevicePos); + + size_t sourceDeviceUdidPos = beforeTargetDevice.find_last_of(SEPERATOR); + if (sourceDeviceUdidPos == std::string::npos) { + ZLOGW("Format error, key.size = %{public}zu", key.size()); + return {}; + } + std::string sourceDeviceUdid = beforeTargetDevice.substr(sourceDeviceUdidPos + 1); + std::string beforeSourceDeviceUdid = beforeTargetDevice.substr(0, sourceDeviceUdidPos); + + size_t sessionIdPos = beforeSourceDeviceUdid.find_last_of(SEPERATOR); + if (sessionIdPos == std::string::npos) { + ZLOGW("Format error, key.size = %{public}zu", key.size()); + return {}; + } + std::string sessionId = beforeSourceDeviceUdid.substr(sessionIdPos + 1); + std::string bundleName = beforeSourceDeviceUdid.substr(0, sessionIdPos); + + size_t propertyNamePos = fromTime.find_first_of(SEPERATOR); + if (propertyNamePos == std::string::npos) { + ZLOGW("Format error, key.size = %{public}zu", key.size()); + return {}; + } + std::string propertyName = fromTime.substr(propertyNamePos + 1); + std::string time = fromTime.substr(0, propertyNamePos); + + return { bundleName, sessionId, sourceDeviceUdid, targetDevice, time, propertyName }; +} + +std::string ObjectStoreManager::GetCurrentUser() +{ + std::vector users; + AccountDelegate::GetInstance()->QueryUsers(users); + if (users.empty()) { + return ""; + } + return std::to_string(users[0]); +} + +void ObjectStoreManager::SaveUserToMeta() +{ + ZLOGD("start."); + std::string userId = GetCurrentUser(); + if (userId.empty()) { + return; + } + std::string appId = DistributedData::Bootstrap::GetInstance().GetProcessLabel(); + StoreMetaData userMeta; + userMeta.storeId = DistributedObject::ObjectCommon::OBJECTSTORE_DB_STOREID; + userMeta.user = userId; + userMeta.storeType = ObjectDistributedType::OBJECT_SINGLE_VERSION; + std::string userMetaKey = GetMetaUserIdKey(userId, appId); + auto saved = DistributedData::MetaDataManager::GetInstance().SaveMeta(userMetaKey, userMeta, true); + if (!saved) { + ZLOGE("userMeta save failed"); + } +} + +void ObjectStoreManager::CloseAfterMinute() +{ + executors_->Schedule(std::chrono::minutes(INTERVAL), std::bind(&ObjectStoreManager::Close, this)); +} + +void ObjectStoreManager::SetThreadPool(std::shared_ptr executors) +{ + executors_ = executors; +} + +uint64_t SequenceSyncManager::AddNotifier(const std::string &userId, SyncCallBack &callback) +{ + std::lock_guard lock(notifierLock_); + uint64_t sequenceId = KvStoreUtils::GenerateSequenceId(); + userIdSeqIdRelations_[userId].emplace_back(sequenceId); + seqIdCallbackRelations_[sequenceId] = callback; + return sequenceId; +} + +SequenceSyncManager::Result SequenceSyncManager::Process( + uint64_t sequenceId, const std::map &results, std::string &userId) +{ + std::lock_guard lock(notifierLock_); + if (seqIdCallbackRelations_.count(sequenceId) == 0) { + ZLOGE("not exist"); + return ERR_SID_NOT_EXIST; + } + std::map syncResults; + for (auto &item : results) { + syncResults[item.first] = item.second == DistributedDB::DBStatus::OK ? 0 : -1; + } + seqIdCallbackRelations_[sequenceId](syncResults); + ZLOGD("end complete"); + return DeleteNotifierNoLock(sequenceId, userId); +} + +SequenceSyncManager::Result SequenceSyncManager::DeleteNotifier(uint64_t sequenceId, std::string &userId) +{ + std::lock_guard lock(notifierLock_); + if (seqIdCallbackRelations_.count(sequenceId) == 0) { + ZLOGE("not exist"); + return ERR_SID_NOT_EXIST; + } + return DeleteNotifierNoLock(sequenceId, userId); +} + +SequenceSyncManager::Result SequenceSyncManager::DeleteNotifierNoLock(uint64_t sequenceId, std::string &userId) +{ + seqIdCallbackRelations_.erase(sequenceId); + auto userIdIter = userIdSeqIdRelations_.begin(); + while (userIdIter != userIdSeqIdRelations_.end()) { + auto sIdIter = std::find(userIdIter->second.begin(), userIdIter->second.end(), sequenceId); + if (sIdIter != userIdIter->second.end()) { + userIdIter->second.erase(sIdIter); + if (userIdIter->second.empty()) { + ZLOGD("finished user callback, userId = %{public}s", userIdIter->first.c_str()); + userId = userIdIter->first; + userIdSeqIdRelations_.erase(userIdIter); + return SUCCESS_USER_HAS_FINISHED; + } else { + ZLOGD(" finished a callback but user not finished, userId = %{public}s", userIdIter->first.c_str()); + return SUCCESS_USER_IN_USE; + } + } + userIdIter++; + } + return SUCCESS_USER_HAS_FINISHED; +} + +int32_t ObjectStoreManager::BindAsset(const uint32_t tokenId, const std::string& appId, const std::string& sessionId, + ObjectStore::Asset& asset, ObjectStore::AssetBindInfo& bindInfo) +{ + auto snapshotKey = appId + SEPERATOR + sessionId; + snapshots_.ComputeIfAbsent( + snapshotKey, [](const std::string& key) -> auto { + return std::make_shared(); + }); + auto storeKey = appId + SEPERATOR + bindInfo.storeName; + bindSnapshots_.ComputeIfAbsent( + storeKey, [](const std::string& key) -> auto { + return std::make_shared>>(); + }); + auto snapshots = snapshots_.Find(snapshotKey).second; + bindSnapshots_.Compute(storeKey, [this, &asset, snapshots] (const auto &key, auto &value) { + value->emplace(std::pair{asset.uri, snapshots}); + return true; + }); + + HapTokenInfo tokenInfo; + auto status = AccessTokenKit::GetHapTokenInfo(tokenId, tokenInfo); + if (status != RET_SUCCESS) { + ZLOGE("token:0x%{public}x, result:%{public}d, bundleName:%{public}s", tokenId, status, appId.c_str()); + return GeneralError::E_ERROR; + } + StoreInfo storeInfo; + storeInfo.bundleName = appId; + storeInfo.tokenId = tokenId; + storeInfo.instanceId = tokenInfo.instIndex; + storeInfo.user = tokenInfo.userID; + storeInfo.storeName = bindInfo.storeName; + + snapshots_.Compute(snapshotKey, [this, &asset, &bindInfo, &storeInfo] (const auto &key, auto &value) { + value->BindAsset(ValueProxy::Convert(std::move(asset)), ConvertBindInfo(bindInfo), storeInfo); + return true; + }); + return OBJECT_SUCCESS; +} + +DistributedData::AssetBindInfo ObjectStoreManager::ConvertBindInfo(ObjectStore::AssetBindInfo& bindInfo) +{ + return DistributedData::AssetBindInfo{ + .storeName = std::move(bindInfo.storeName), + .tableName = std::move(bindInfo.tableName), + .primaryKey = ValueProxy::Convert(std::move(bindInfo.primaryKey)), + .field = std::move(bindInfo.field), + .assetName = std::move(bindInfo.assetName), + }; +} + +int32_t ObjectStoreManager::OnAssetChanged(const uint32_t tokenId, const std::string& appId, + const std::string& sessionId, const std::string& deviceId, const ObjectStore::Asset& asset) +{ + const int32_t userId = AccountDelegate::GetInstance()->GetUserByToken(tokenId); + auto objectAsset = asset; + Asset dataAsset = ValueProxy::Convert(std::move(objectAsset)); + auto snapshotKey = appId + SEPERATOR + sessionId; + int32_t res = OBJECT_SUCCESS; + bool exist = snapshots_.ComputeIfPresent(snapshotKey, + [&res, &dataAsset, &deviceId](const std::string &key, std::shared_ptr snapshot) { + if (snapshot != nullptr) { + res = snapshot->OnDataChanged(dataAsset, deviceId); // needChange + } + return snapshot != nullptr; + }); + if (exist) { + return res; + } + + auto block = std::make_shared>>(WAIT_TIME, std::tuple{ true, true }); + ObjectAssetLoader::GetInstance()->TransferAssetsAsync(userId, appId, deviceId, { dataAsset }, [block](bool ret) { + block->SetValue({ false, ret }); + }); + auto [timeout, success] = block->GetValue(); + if (timeout || !success) { + ZLOGE("transfer failed, timeout: %{public}d, success: %{public}d, name: %{public}s, deviceId: %{public}s ", + timeout, success, asset.name.c_str(), DistributedData::Anonymous::Change(deviceId).c_str()); + return OBJECT_INNER_ERROR; + } + return OBJECT_SUCCESS; +} + +ObjectStoreManager::UriToSnapshot ObjectStoreManager::GetSnapShots(const std::string& bundleName, + const std::string& storeName) +{ + auto storeKey = bundleName + SEPERATOR + storeName; + bindSnapshots_.ComputeIfAbsent( + storeKey, [](const std::string& key) -> auto { + return std::make_shared>>(); + }); + return bindSnapshots_.Find(storeKey).second; +} + +void ObjectStoreManager::DeleteSnapshot(const std::string& bundleName, const std::string& sessionId) +{ + auto snapshotKey = bundleName + SEPERATOR + sessionId; + auto snapshot = snapshots_.Find(snapshotKey).second; + if (snapshot == nullptr) { + ZLOGD("Not find snapshot, don't need delete"); + return; + } + bindSnapshots_.ForEach([snapshot](auto& key, auto& value) { + for (auto pos = value->begin(); pos != value->end();) { + if (pos->second == snapshot) { + pos = value->erase(pos); + } else { + ++pos; + } + } + return true; + }); + snapshots_.Erase(snapshotKey); +} +} // namespace DistributedObject +} // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/service/object/object_service_impl.cpp b/datamgr_service/services/distributeddataservice/service/object/src/object_service_impl.cpp similarity index 98% rename from datamgr_service/services/distributeddataservice/service/object/object_service_impl.cpp rename to datamgr_service/services/distributeddataservice/service/object/src/object_service_impl.cpp index 5c32afaaa7794c3d99de0f3d2f1b71709edf420e..fdb08505e7ad12410d938f5807446a5666d7d9fc 100644 --- a/datamgr_service/services/distributeddataservice/service/object/object_service_impl.cpp +++ b/datamgr_service/services/distributeddataservice/service/object/src/object_service_impl.cpp @@ -134,8 +134,8 @@ int32_t ObjectServiceImpl::OnInitialize() return OBJECT_INNER_ERROR; } auto token = IPCSkeleton::GetCallingTokenID(); - const std::string accountId = DistributedKv::AccountDelegate::GetInstance()->GetCurrentAccountId(); - const auto userId = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(token); + const std::string accountId = DistributedData::AccountDelegate::GetInstance()->GetCurrentAccountId(); + const auto userId = DistributedData::AccountDelegate::GetInstance()->GetUserByToken(token); StoreMetaData saveMeta; saveMeta.appType = "default"; saveMeta.deviceId = localDeviceId; @@ -178,7 +178,7 @@ int32_t ObjectServiceImpl::OnInitialize() int32_t ObjectServiceImpl::OnUserChange(uint32_t code, const std::string &user, const std::string &account) { - if (code == static_cast(DistributedKv::AccountStatus::DEVICE_ACCOUNT_SWITCHED)) { + if (code == static_cast(AccountStatus::DEVICE_ACCOUNT_SWITCHED)) { Clear(); } return Feature::OnUserChange(code, user, account); diff --git a/datamgr_service/services/distributeddataservice/service/object/object_service_stub.cpp b/datamgr_service/services/distributeddataservice/service/object/src/object_service_stub.cpp similarity index 100% rename from datamgr_service/services/distributeddataservice/service/object/object_service_stub.cpp rename to datamgr_service/services/distributeddataservice/service/object/src/object_service_stub.cpp diff --git a/datamgr_service/services/distributeddataservice/service/object/object_snapshot.cpp b/datamgr_service/services/distributeddataservice/service/object/src/object_snapshot.cpp similarity index 100% rename from datamgr_service/services/distributeddataservice/service/object/object_snapshot.cpp rename to datamgr_service/services/distributeddataservice/service/object/src/object_snapshot.cpp diff --git a/datamgr_service/services/distributeddataservice/service/object/object_types_utils.cpp b/datamgr_service/services/distributeddataservice/service/object/src/object_types_utils.cpp similarity index 100% rename from datamgr_service/services/distributeddataservice/service/object/object_types_utils.cpp rename to datamgr_service/services/distributeddataservice/service/object/src/object_types_utils.cpp diff --git a/datamgr_service/services/distributeddataservice/service/permission/BUILD.gn b/datamgr_service/services/distributeddataservice/service/permission/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..2795bda98f789384e7e03b76cde5469544eaae2b --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/permission/BUILD.gn @@ -0,0 +1,71 @@ +# Copyright (c) 2024 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. +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +config("permission_public_config") { + visibility = [ ":*" ] + include_dirs = [ "include" ] +} + +ohos_source_set("distributeddata_permit") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + boundary_sanitize = true + ubsan = true + } + sources = [ + "../kvdb/user_delegate.cpp", + "src/permission_validator.cpp", + "src/permit_delegate.cpp", + ] + + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] + + include_dirs = [ + "${data_service_path}/service/crypto/include", + "${data_service_path}/service/kvdb", + "${data_service_path}/adapter/include/communicator", + ] + configs = [ ":permission_public_config" ] + public_configs = [ ":permission_public_config" ] + cflags = [ + "-Werror", + "-Wno-multichar", + "-Wno-c99-designator", + "-D_LIBCPP_HAS_COND_CLOCKWAIT", + "-Oz", + ] + + deps = [ + "${data_service_path}/framework:distributeddatasvcfwk", + "${data_service_path}/service/crypto:distributeddata_crypto", + ] + external_deps = [ + "access_token:libaccesstoken_sdk", + "device_auth:deviceauth_sdk", + "device_manager:devicemanagersdk", + "hilog:libhilog", + "json:nlohmann_json_static", + "kv_store:datamgr_common", + "kv_store:distributeddb", + ] + subsystem_name = "distributeddatamgr" + part_name = "datamgr_service" +} diff --git a/datamgr_service/services/distributeddataservice/service/permission/include/permission_validator.h b/datamgr_service/services/distributeddataservice/service/permission/include/permission_validator.h new file mode 100644 index 0000000000000000000000000000000000000000..322d8b00257603b82440057df5da7488a33601a0 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/permission/include/permission_validator.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 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 PERMISSION_VALIDATOR_H +#define PERMISSION_VALIDATOR_H +#include +#include "types.h" +#include "visibility.h" + +namespace OHOS { +namespace DistributedKv { +class PermissionValidator { +public: + API_EXPORT static PermissionValidator &GetInstance(); + // 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 +#endif // PERMISSION_VALIDATOR_H diff --git a/datamgr_service/services/distributeddataservice/service/permission/src/permission_validator.cpp b/datamgr_service/services/distributeddataservice/service/permission/src/permission_validator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c05e483f60b8332c3e554ce0d6582d55b8c8037d --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/permission/src/permission_validator.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 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 "PermissionValidator" + +#include "permission_validator.h" +#include "accesstoken_kit.h" +#include "log_print.h" + +namespace OHOS { +namespace DistributedKv { +using namespace Security::AccessToken; +PermissionValidator &PermissionValidator::GetInstance() +{ + static PermissionValidator permissionValidator; + return permissionValidator; +} + +// check whether the client process have enough privilege to share data with the other devices. +bool PermissionValidator::CheckSyncPermission(uint32_t tokenId) +{ + auto permit = AccessTokenKit::VerifyAccessToken(tokenId, DISTRIBUTED_DATASYNC); + ZLOGD("sync permit:%{public}d, token:0x%{public}x", permit, tokenId); + return permit == PERMISSION_GRANTED; +} + +bool PermissionValidator::IsCloudConfigPermit(uint32_t tokenId) +{ + auto permit = AccessTokenKit::VerifyAccessToken(tokenId, CLOUD_DATA_CONFIG); + ZLOGD("cloud permit:%{public}d, token:0x%{public}x", permit, tokenId); + return permit == PERMISSION_GRANTED; +} +} // namespace DistributedKv +} // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/service/permission/src/permit_delegate.cpp b/datamgr_service/services/distributeddataservice/service/permission/src/permit_delegate.cpp index 6e9e9cb41e4dbc78e025dba7cfd4de2ec4a50424..d3d020871aa37876f4d22cfe0f885792e3b23a8a 100644 --- a/datamgr_service/services/distributeddataservice/service/permission/src/permit_delegate.cpp +++ b/datamgr_service/services/distributeddataservice/service/permission/src/permit_delegate.cpp @@ -21,7 +21,7 @@ #include "metadata/appid_meta_data.h" #include "metadata/meta_data_manager.h" #include "metadata/strategy_meta_data.h" -#include "permission/permission_validator.h" +#include "permission_validator.h" #include "runtime_config.h" #include "store_types.h" #include "user_delegate.h" diff --git a/datamgr_service/services/distributeddataservice/service/rdb/BUILD.gn b/datamgr_service/services/distributeddataservice/service/rdb/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..e8cd0981655d65aeb450418cf842e0dddf28db73 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/rdb/BUILD.gn @@ -0,0 +1,102 @@ +# Copyright (c) 2024 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. +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") + +config("rdb_public_config") { + visibility = [ ":*" ] + + include_dirs = [ + "${data_service_path}/adapter/include", + "${data_service_path}/service/common", + "${data_service_path}/service/bootstrap/include", + "${data_service_path}/service/kvdb", + "${data_service_path}/service/matrix/include", + "${data_service_path}/service/permission/include", + "${data_service_path}/service/cloud", + "${data_service_path}/framework/include", + "${data_service_path}/adapter/include/utils", + "${data_service_path}/adapter/include/communicator", + "${data_service_path}/adapter/include/dfx", + ] +} + +ohos_source_set("distributeddata_rdb") { + branch_protector_ret = "pac_ret" + sanitize = { + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + sources = [ + "cache_cursor.cpp", + "rdb_asset_loader.cpp", + "rdb_cloud.cpp", + "rdb_cursor.cpp", + "rdb_general_store.cpp", + "rdb_notifier_proxy.cpp", + "rdb_query.cpp", + "rdb_result_set_impl.cpp", + "rdb_result_set_stub.cpp", + "rdb_schema_config.cpp", + "rdb_service_impl.cpp", + "rdb_service_stub.cpp", + "rdb_watcher.cpp", + ] + + configs = [ ":rdb_public_config" ] + + cflags = [ + "-D_LIBCPP_HAS_COND_CLOCKWAIT", + "-Werror", + "-Oz", + ] + + deps = [ + "${data_service_path}/service/bootstrap:distributeddata_bootstrap", + "${data_service_path}/service/common:distributeddata_common", + "${data_service_path}/service/crypto:distributeddata_crypto", + "${data_service_path}/service/matrix:distributeddata_matrix", + "${data_service_path}/service/permission:distributeddata_permit", + ] + + external_deps = [ + "access_token:libaccesstoken_sdk", + "access_token:libtokenid_sdk", + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "device_auth:deviceauth_sdk", + "device_manager:devicemanagersdk", + "dmsfwk:distributed_sdk", + "hicollie:libhicollie", + "hilog:libhilog", + "hisysevent:libhisysevent", + "huks:libhukssdk", + "ipc:ipc_core", + "kv_store:datamgr_common", + "kv_store:distributeddb", + "relational_store:native_rdb", + "resource_management:global_resmgr", + "samgr:samgr_proxy", + ] + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] + subsystem_name = "distributeddatamgr" + + part_name = "datamgr_service" +} diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_asset_loader.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_asset_loader.cpp index f65d51a9afc1722b13485e87afdc5ef699820852..93cd875b678c24c789360482774617fd3ead15b2 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_asset_loader.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_asset_loader.cpp @@ -107,9 +107,10 @@ DBStatus RdbAssetLoader::ConvertStatus(AssetStatus error) { switch (error) { case AssetStatus::STATUS_NORMAL: - return DBStatus::OK; case AssetStatus::STATUS_DOWNLOADING: return DBStatus::OK; + case AssetStatus::STATUS_SKIP_ASSET: + return DBStatus::SKIP_ASSET; default: ZLOGE("error:0x%{public}x", error); break; @@ -124,6 +125,16 @@ DBStatus RdbAssetLoader::RemoveLocalAssets(const std::vector &assets) return RdbCloud::ConvertStatus(static_cast(error)); } +DBStatus RdbAssetLoader::CancelDownload() +{ + if (assetLoader_ == nullptr) { + ZLOGE("assetLoader is nullptr"); + return DBStatus::DB_ERROR; + } + auto error = assetLoader_->CancelDownload(); + return RdbCloud::ConvertStatus(static_cast(error)); +} + void RdbAssetLoader::PostEvent(std::set &skipAssets, std::vector &assetsRecords, DistributedData::AssetEvent eventId, std::set &deleteAssets) { diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_asset_loader.h b/datamgr_service/services/distributeddataservice/service/rdb/rdb_asset_loader.h index a8a90d914aa8b5ac9a8415d951997cb271914aea..1eb7b3e759c0146286eca196c37f8533d0debc1a 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_asset_loader.h +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_asset_loader.h @@ -45,6 +45,8 @@ public: DBStatus RemoveLocalAssets(const std::vector &assets) override; + DBStatus CancelDownload() override; + private: static std::vector Convert(std::vector &&assetsRecords); static std::vector Convert(std::vector &&assetRecords); diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud.cpp index a26a6dbf73bbb8905eaf518168ab59247c33f532..0a0726079f857ccfc3eb8c92431d0be84d47bcfa 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud.cpp @@ -198,6 +198,10 @@ DBStatus RdbCloud::ConvertStatus(DistributedData::GeneralError error) return DBStatus::LOCAL_ASSET_NOT_FOUND; case GeneralError::E_TIME_OUT: return DBStatus::TIME_OUT; + case GeneralError::E_CLOUD_DISABLED: + return DBStatus::CLOUD_DISABLED; + case GeneralError::E_SKIP_ASSET: + return DBStatus::SKIP_ASSET; default: ZLOGI("error:0x%{public}x", error); break; diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud.h b/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud.h index ac93e253d3c22618ea75faad8164d3b935bbbda9..1a3f37e50aa9f8c49657065bf11939a2607d4c48 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud.h +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_cloud.h @@ -81,4 +81,4 @@ private: GeneralError InnerUnLock(FLAG flag); }; } // namespace OHOS::DistributedRdb -#endif // OHOS_DISTRIBUTED_DATA_DATAMGR_SERVICE_RDB_CLOUD_H +#endif // OHOS_DISTRIBUTED_DATA_DATAMGR_SERVICE_RDB_CLOUD_H \ No newline at end of file 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 a102573e878ea5999bbaaaa2a2bec75d67633ad8..203eec5d08f835a7db564a41a2f5f5f527629d8b 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.cpp @@ -29,6 +29,7 @@ #include "commonevent/data_sync_event.h" #include "communicator/device_manager_adapter.h" #include "crypto_manager.h" +#include "dfx_types.h" #include "device_manager_adapter.h" #include "eventcenter/event_center.h" #include "log_print.h" @@ -39,6 +40,7 @@ #include "rdb_query.h" #include "rdb_result_set_impl.h" #include "relational_store_manager.h" +#include "reporter.h" #include "snapshot/bind_event.h" #include "utils/anonymous.h" #include "value_proxy.h" @@ -48,13 +50,21 @@ using namespace DistributedDB; using namespace NativeRdb; using namespace CloudData; using namespace std::chrono; +using namespace DistributedDataDfx; using DBField = DistributedDB::Field; using DBTable = DistributedDB::TableSchema; using DBSchema = DistributedDB::DataBaseSchema; using ClearMode = DistributedDB::ClearMode; using DBStatus = DistributedDB::DBStatus; using DmAdapter = OHOS::DistributedData::DeviceManagerAdapter; - +constexpr uint32_t EXECUTE_TIMEOUT = 1000; // ms +#define TIME_STATISTIC(timeout) \ +// DdsTrace(std::string(LOG_TAG "::") + std::string(__FUNCTION__), API_PERFORMANCE_TRACE_ON, \ +// [](const std::string &value, uint64_t delta) { \ +// if (delta > timeout) { \ +// ZLOGW("actual cost:%{public}lu ms, expected cost:%{public}lu ms", delta, timeout); \ +// } \ +// }); constexpr const char *INSERT = "INSERT INTO "; constexpr const char *REPLACE = "REPLACE INTO "; constexpr const char *VALUES = " VALUES "; @@ -65,6 +75,8 @@ constexpr const LockAction LOCK_ACTION = constexpr uint32_t CLOUD_SYNC_FLAG = 1; constexpr uint32_t SEARCHABLE_FLAG = 2; constexpr uint32_t LOCK_TIMEOUT = 3600; // second +static constexpr const char *FT_OPEN_STORE = "OPEN_STORE"; +static constexpr const char *FT_CLOUD_SYNC = "CLOUD_SYNC"; static DBSchema GetDBSchema(const Database &database) { @@ -87,12 +99,74 @@ static DBSchema GetDBSchema(const Database &database) return schema; } +static bool IsExistence(const std::string &col, const std::vector &cols) +{ + for (auto &column : cols) { + if (col == column) { + return true; + } + } + return false; +} + +static DistributedSchema GetGaussDistributedSchema(const Database &database) +{ + DistributedSchema distributedSchema; + distributedSchema.version = database.version; + distributedSchema.tables.resize(database.tables.size()); + for (size_t i = 0; i < database.tables.size(); i++) { + const Table &table = database.tables[i]; + DistributedTable &dbTable = distributedSchema.tables[i]; + dbTable.tableName = table.name; + for (auto &field : table.fields) { + DistributedField dbField; + dbField.colName = field.colName; + dbField.isP2pSync = IsExistence(field.colName, table.deviceSyncFields); + dbTable.fields.push_back(std::move(dbField)); + } + } + return distributedSchema; +} + +static std::pair GetDistributedSchema(const StoreMetaData &meta) +{ + std::pair tableData; + Database database; + database.bundleName = meta.bundleName; + database.name = meta.storeId; + database.user = meta.user; + database.deviceId = meta.deviceId; + tableData.first = MetaDataManager::GetInstance().LoadMeta(database.GetKey(), database, true); + tableData.second = database; + return tableData; +} + +void RdbGeneralStore::InitStoreInfo(const StoreMetaData &meta) +{ + storeInfo_.tokenId = meta.tokenId; + storeInfo_.bundleName = meta.bundleName; + storeInfo_.storeName = meta.storeId; + storeInfo_.instanceId = meta.instanceId; + storeInfo_.user = std::stoi(meta.user); + storeInfo_.deviceId = DeviceManagerAdapter::GetInstance().GetLocalDevice().uuid; +} + +RelationalStoreDelegate::Option GetOption(const StoreMetaData &meta) +{ + RelationalStoreDelegate::Option option; + option.syncDualTupleMode = true; + if (GetDistributedSchema(meta).first) { + option.tableMode = DistributedTableMode::COLLABORATION; + } + return option; +} + RdbGeneralStore::RdbGeneralStore(const StoreMetaData &meta) : manager_(meta.appId, meta.user, meta.instanceId), tasks_(std::make_shared>()) { observer_.storeId_ = meta.storeId; observer_.meta_ = meta; - RelationalStoreDelegate::Option option; + RelationalStoreDelegate::Option option = GetOption(meta); option.observer = &observer_; if (meta.isEncrypt) { std::string key = meta.GetSecretKey(); @@ -120,22 +194,18 @@ RdbGeneralStore::RdbGeneralStore(const StoreMetaData &meta) delegate_ = nullptr; } } - - storeInfo_.tokenId = meta.tokenId; - storeInfo_.bundleName = meta.bundleName; - storeInfo_.storeName = meta.storeId; - storeInfo_.instanceId = meta.instanceId; - storeInfo_.user = std::stoi(meta.user); - storeInfo_.deviceId = DeviceManagerAdapter::GetInstance().GetLocalDevice().uuid; + InitStoreInfo(meta); if (meta.isSearchable) { syncNotifyFlag_ |= SEARCHABLE_FLAG; } - if (delegate_ != nullptr && meta.isManualClean) { - PragmaData data = - static_cast(const_cast(static_cast(&meta.isManualClean))); + PragmaData data = static_cast(const_cast(static_cast(&meta.isManualClean))); delegate_->Pragma(PragmaCmd::LOGIC_DELETE_SYNC_DATA, data); } + std::pair tableData = GetDistributedSchema(meta); + if (delegate_ != nullptr && tableData.first) { + delegate_->SetDistributedSchema(GetGaussDistributedSchema(tableData.second)); + } ZLOGI("Get rdb store, tokenId:%{public}u, bundleName:%{public}s, storeName:%{public}s, user:%{public}s," "isEncrypt:%{public}d, isManualClean:%{public}d, isSearchable:%{public}d", meta.tokenId, meta.bundleName.c_str(), Anonymous::Change(meta.storeId).c_str(), meta.user.c_str(), @@ -144,6 +214,8 @@ RdbGeneralStore::RdbGeneralStore(const StoreMetaData &meta) RdbGeneralStore::~RdbGeneralStore() { + ZLOGI("Destruct. BundleName: %{public}s. StoreName: %{public}s. user: %{public}d", + storeInfo_.bundleName.c_str(), Anonymous::Change(storeInfo_.storeName).c_str(), storeInfo_.user); manager_.CloseStore(delegate_); delegate_ = nullptr; bindInfo_.loader_ = nullptr; @@ -166,9 +238,10 @@ int32_t RdbGeneralStore::BindSnapshots(std::shared_ptr &bindInfos, +int32_t RdbGeneralStore::Bind(const Database &database, const std::map &bindInfos, const CloudConfig &config) { + TIME_STATISTIC(EXECUTE_TIMEOUT); if (bindInfos.empty()) { return GeneralError::E_OK; } @@ -223,6 +296,7 @@ bool RdbGeneralStore::IsBound(uint32_t user) int32_t RdbGeneralStore::Close(bool isForce) { + TIME_STATISTIC(EXECUTE_TIMEOUT); { std::unique_lock lock(rwMutex_, std::chrono::seconds(isForce ? LOCK_TIMEOUT : 0)); if (!lock) { @@ -232,12 +306,10 @@ int32_t RdbGeneralStore::Close(bool isForce) if (delegate_ == nullptr) { return GeneralError::E_OK; } - if (!isForce && delegate_->GetCloudSyncTaskCount() > 0) { + auto [dbStatus, downloadCount] = delegate_->GetDownloadingAssetsCount(); + if (!isForce && (delegate_->GetCloudSyncTaskCount() > 0 || downloadCount > 0)) { return GeneralError::E_BUSY; } - if (isForce && bindInfo_.loader_ != nullptr) { - bindInfo_.loader_->Cancel(); - } auto status = manager_.CloseStore(delegate_); if (status != DBStatus::OK) { return status; @@ -260,6 +332,7 @@ int32_t RdbGeneralStore::Close(bool isForce) int32_t RdbGeneralStore::Execute(const std::string &table, const std::string &sql) { + TIME_STATISTIC(EXECUTE_TIMEOUT); std::shared_lock lock(rwMutex_); if (delegate_ == nullptr) { ZLOGE("Database already closed! database:%{public}s, table:%{public}s, sql:%{public}s", @@ -270,8 +343,11 @@ int32_t RdbGeneralStore::Execute(const std::string &table, const std::string &sq std::vector changedData; auto status = delegate_->ExecuteSql({ sql, {}, false }, changedData); if (status != DBStatus::OK) { - ZLOGE("Failed! ret:%{public}d, sql:%{public}s, data size:%{public}zu", status, Anonymous::Change(sql).c_str(), - changedData.size()); + ZLOGE("Execute failed! ret:%{public}d, sql:%{public}s, data size:%{public}zu", status, + Anonymous::Change(sql).c_str(), changedData.size()); + if (status == DBStatus::BUSY) { + return GeneralError::E_BUSY; + } return GeneralError::E_ERROR; } return GeneralError::E_OK; @@ -297,6 +373,7 @@ size_t RdbGeneralStore::SqlConcatenate(VBucket &value, std::string &strColumnSql int32_t RdbGeneralStore::Insert(const std::string &table, VBuckets &&values) { + TIME_STATISTIC(EXECUTE_TIMEOUT); if (table.empty() || values.size() == 0) { ZLOGE("Insert:table maybe empty:%{public}d,value size is:%{public}zu", table.empty(), values.size()); return GeneralError::E_INVALID_ARGS; @@ -368,6 +445,7 @@ bool RdbGeneralStore::IsPrintLog(DBStatus status) int32_t RdbGeneralStore::Update(const std::string &table, const std::string &setSql, Values &&values, const std::string &whereSql, Values &&conditions) { + TIME_STATISTIC(EXECUTE_TIMEOUT); if (table.empty()) { ZLOGE("Update: table can't be empty!"); return GeneralError::E_INVALID_ARGS; @@ -409,6 +487,7 @@ int32_t RdbGeneralStore::Update(const std::string &table, const std::string &set int32_t RdbGeneralStore::Replace(const std::string &table, VBucket &&value) { + TIME_STATISTIC(EXECUTE_TIMEOUT); if (table.empty() || value.size() == 0) { return GeneralError::E_INVALID_ARGS; } @@ -433,6 +512,9 @@ int32_t RdbGeneralStore::Replace(const std::string &table, VBucket &&value) if (status != DBStatus::OK) { ZLOGE("Replace failed! ret:%{public}d, table:%{public}s, sql:%{public}s, fields:%{public}s", status, Anonymous::Change(table).c_str(), Anonymous::Change(sql).c_str(), columnSql.c_str()); + if (status == DBStatus::BUSY) { + return GeneralError::E_BUSY; + } return GeneralError::E_ERROR; } return GeneralError::E_OK; @@ -446,6 +528,7 @@ int32_t RdbGeneralStore::Delete(const std::string &table, const std::string &sql std::pair> RdbGeneralStore::Query(__attribute__((unused))const std::string &table, const std::string &sql, Values &&args) { + TIME_STATISTIC(EXECUTE_TIMEOUT); std::shared_lock lock(rwMutex_); if (delegate_ == nullptr) { ZLOGE("Database already closed! database:%{public}s", Anonymous::Change(storeInfo_.storeName).c_str()); @@ -457,6 +540,7 @@ std::pair> RdbGeneralStore::Query(__attribute__ std::pair> RdbGeneralStore::Query(const std::string &table, GenQuery &query) { + TIME_STATISTIC(EXECUTE_TIMEOUT); RdbQuery *rdbQuery = nullptr; auto ret = query.QueryInterface(rdbQuery); if (ret != GeneralError::E_OK || rdbQuery == nullptr) { @@ -482,6 +566,7 @@ std::pair> RdbGeneralStore::Query(const std::st int32_t RdbGeneralStore::MergeMigratedData(const std::string &tableName, VBuckets &&values) { + TIME_STATISTIC(EXECUTE_TIMEOUT); std::shared_lock lock(rwMutex_); if (delegate_ == nullptr) { ZLOGE("Database already closed! database:%{public}s, table:%{public}s", @@ -495,6 +580,7 @@ int32_t RdbGeneralStore::MergeMigratedData(const std::string &tableName, VBucket int32_t RdbGeneralStore::CleanTrackerData(const std::string &tableName, int64_t cursor) { + TIME_STATISTIC(EXECUTE_TIMEOUT); std::shared_lock lock(rwMutex_); if (delegate_ == nullptr) { ZLOGE("Database already closed! database:%{public}s, table:%{public}s", @@ -506,9 +592,49 @@ int32_t RdbGeneralStore::CleanTrackerData(const std::string &tableName, int64_t return status == DistributedDB::OK ? GeneralError::E_OK : GeneralError::E_ERROR; } +std::pair RdbGeneralStore::DoCloudSync(const Devices &devices, const DistributedDB::Query &dbQuery, + const SyncParam &syncParam, bool isPriority, DetailAsync async) +{ + auto syncMode = GeneralStore::GetSyncMode(syncParam.mode); + auto highMode = GetHighMode(static_cast(syncParam.mode)); + SyncId syncId = ++syncTaskId_; + auto callback = GetDBProcessCB(std::move(async), syncMode, syncId, highMode); + if (executor_ != nullptr && tasks_ != nullptr) { + auto id = executor_->Schedule(std::chrono::minutes(INTERVAL), GetFinishTask(syncId)); + tasks_->Insert(syncId, { id, callback }); + } + CloudSyncOption option; + option.devices = devices; + option.mode = DistributedDB::SyncMode(syncMode); + option.query = dbQuery; + option.waitTime = syncParam.wait; + option.priorityTask = isPriority || highMode == MANUAL_SYNC_MODE; + option.priorityLevel = GetPriorityLevel(highMode); + option.compensatedSyncOnly = syncParam.isCompensation; + option.merge = highMode == AUTO_SYNC_MODE; + option.lockAction = LOCK_ACTION; + option.prepareTraceId = syncParam.prepareTraceId; + option.asyncDownloadAssets = syncParam.asyncDownloadAsset; + auto dbStatus = DistributedDB::INVALID_ARGS; + dbStatus = delegate_->Sync(option, tasks_ != nullptr ? GetCB(syncId) : callback, syncId); + if (dbStatus == DBStatus::OK || tasks_ == nullptr) { + return { ConvertStatus(dbStatus), dbStatus }; + } + Report(FT_CLOUD_SYNC, static_cast(Fault::CSF_GS_CLOUD_SYNC), + "Cloud sync ret=" + std::to_string(static_cast(dbStatus))); + tasks_->ComputeIfPresent(syncId, [executor = executor_](SyncId syncId, const FinishTask &task) { + if (executor != nullptr) { + executor->Remove(task.taskId); + } + return false; + }); + return { ConvertStatus(dbStatus), dbStatus }; +} + std::pair RdbGeneralStore::Sync(const Devices &devices, GenQuery &query, DetailAsync async, const SyncParam &syncParam) { + TIME_STATISTIC(EXECUTE_TIMEOUT); DistributedDB::Query dbQuery; RdbQuery *rdbQuery = nullptr; bool isPriority = false; @@ -528,36 +654,18 @@ std::pair RdbGeneralStore::Sync(const Devices &devices, GenQue devices.empty() ? "null" : Anonymous::Change(*devices.begin()).c_str(), syncParam.mode, syncParam.wait); return { GeneralError::E_ALREADY_CLOSED, DBStatus::OK }; } - auto highMode = GetHighMode(static_cast(syncParam.mode)); - SyncId syncId = ++syncTaskId_; auto dbStatus = DistributedDB::INVALID_ARGS; if (syncMode < NEARBY_END) { dbStatus = delegate_->Sync(devices, dbMode, dbQuery, GetDBBriefCB(std::move(async)), syncParam.wait != 0); } else if (syncMode > NEARBY_END && syncMode < CLOUD_END) { - auto callback = GetDBProcessCB(std::move(async), syncMode, syncId, highMode); - if (executor_ != nullptr && tasks_ != nullptr) { - auto id = executor_->Schedule(std::chrono::minutes(INTERVAL), GetFinishTask(syncId)); - tasks_->Insert(syncId, { id, callback }); - } - dbStatus = delegate_->Sync({ devices, dbMode, dbQuery, syncParam.wait, - (isPriority || highMode == MANUAL_SYNC_MODE), syncParam.isCompensation, {}, - highMode == AUTO_SYNC_MODE, LOCK_ACTION, syncParam.prepareTraceId }, - tasks_ != nullptr ? GetCB(syncId) : callback, syncId); - if (dbStatus == DBStatus::OK || tasks_ == nullptr) { - return { ConvertStatus(dbStatus), dbStatus }; - } - tasks_->ComputeIfPresent(syncId, [executor = executor_](SyncId syncId, const FinishTask &task) { - if (executor != nullptr) { - executor->Remove(task.taskId); - } - return false; - }); + return DoCloudSync(devices, dbQuery, syncParam, isPriority, async); } return { ConvertStatus(dbStatus), dbStatus }; } std::pair> RdbGeneralStore::PreSharing(GenQuery &query) { + TIME_STATISTIC(EXECUTE_TIMEOUT); RdbQuery *rdbQuery = nullptr; auto ret = query.QueryInterface(rdbQuery); if (ret != GeneralError::E_OK || rdbQuery == nullptr) { @@ -634,6 +742,7 @@ std::string RdbGeneralStore::BuildSql( int32_t RdbGeneralStore::Clean(const std::vector &devices, int32_t mode, const std::string &tableName) { + TIME_STATISTIC(EXECUTE_TIMEOUT); if (mode < 0 || mode > CLEAN_MODE_BUTT) { return GeneralError::E_INVALID_ARGS; } @@ -800,6 +909,17 @@ int32_t RdbGeneralStore::AddRef() return ++ref_; } +void RdbGeneralStore::Report(const std::string &faultType, int32_t errCode, const std::string &appendix) +{ + ArkDataFaultMsg msg = { .faultType = faultType, + .bundleName = storeInfo_.bundleName, + .moduleName = ModuleName::RDB_STORE, + .storeName = storeInfo_.storeName, + .errorType = errCode + GeneralStore::CLOUD_ERR_OFFSET, + .appendixMsg = appendix }; + Reporter::GetInstance()->CloudSyncFault()->Report(msg); +} + int32_t RdbGeneralStore::SetDistributedTables(const std::vector &tables, int32_t type, const std::vector &references) { @@ -815,6 +935,8 @@ int32_t RdbGeneralStore::SetDistributedTables(const std::vector &ta if (dBStatus != DistributedDB::DBStatus::OK) { ZLOGE("create distributed table failed, table:%{public}s, err:%{public}d", Anonymous::Change(table).c_str(), dBStatus); + Report(FT_OPEN_STORE, static_cast(Fault::CSF_GS_CREATE_DISTRIBUTED_TABLE), + "SetDistributedTables ret=" + std::to_string(static_cast(dBStatus))); return GeneralError::E_ERROR; } } @@ -884,6 +1006,8 @@ RdbGeneralStore::GenErr RdbGeneralStore::ConvertStatus(DistributedDB::DBStatus s return GenErr::E_BUSY; case DBStatus::CLOUD_SYNC_TASK_MERGED: return GenErr::E_SYNC_TASK_MERGED; + case DBStatus::CLOUD_DISABLED: + return GeneralError::E_CLOUD_DISABLED; default: ZLOGI("status:0x%{public}x", status); break; @@ -916,18 +1040,16 @@ std::pair RdbGeneralStore::QuerySql(const std::string &sql, V std::vector bindArgs = ValueProxy::Convert(std::move(args)); auto status = delegate_->ExecuteSql({ sql, std::move(bindArgs), true }, changedData); if (status != DBStatus::OK) { - ZLOGE("Failed! ret:%{public}d, sql:%{public}s, data size:%{public}zu", status, Anonymous::Change(sql).c_str(), - changedData.size()); + ZLOGE("Query failed! ret:%{public}d, sql:%{public}s, data size:%{public}zu", status, + Anonymous::Change(sql).c_str(), changedData.size()); + if (status == DBStatus::BUSY) { + return { GenErr::E_BUSY, {} }; + } return { GenErr::E_ERROR, {} }; } return { GenErr::E_OK, ValueProxy::Convert(std::move(changedData)) }; } -std::vector RdbGeneralStore::GetWaterVersion(const std::string &deviceId) -{ - return {}; -} - void RdbGeneralStore::OnSyncStart(const StoreInfo &storeInfo, uint32_t flag, uint32_t syncMode, uint32_t traceId, uint32_t syncCount) { @@ -1070,6 +1192,7 @@ void RdbGeneralStore::ObserverProxy::OnChange(DBOrigin origin, const std::string std::pair RdbGeneralStore::LockCloudDB() { + TIME_STATISTIC(EXECUTE_TIMEOUT); auto rdbCloud = GetRdbCloud(); if (rdbCloud == nullptr) { return { GeneralError::E_ERROR, 0 }; @@ -1079,6 +1202,7 @@ std::pair RdbGeneralStore::LockCloudDB() int32_t RdbGeneralStore::UnLockCloudDB() { + TIME_STATISTIC(EXECUTE_TIMEOUT); auto rdbCloud = GetRdbCloud(); if (rdbCloud == nullptr) { return GeneralError::E_ERROR; @@ -1094,6 +1218,7 @@ std::shared_ptr RdbGeneralStore::GetRdbCloud() const bool RdbGeneralStore::IsFinished(SyncId syncId) const { + TIME_STATISTIC(EXECUTE_TIMEOUT); std::shared_lock lock(rwMutex_); if (delegate_ == nullptr) { ZLOGE("database already closed! database:%{public}s", Anonymous::Change(storeInfo_.storeName).c_str()); @@ -1155,17 +1280,24 @@ void RdbGeneralStore::RemoveTasks() taskIds.push_back(task.taskId); return true; }); + auto func = [](const std::list &cbs) { + std::map result; + result.insert({ "", { DistributedDB::FINISHED, DBStatus::DB_ERROR } }); + for (auto &cb : cbs) { + if (cb != nullptr) { + cb(result); + } + } + }; if (executor_ != nullptr) { - for (auto taskId : taskIds) { + for (auto taskId: taskIds) { executor_->Remove(taskId, true); } - } - std::map result; - result.insert({ "", { DistributedDB::FINISHED, DBStatus::DB_ERROR } }); - for (auto &cb : cbs) { - if (cb != nullptr) { - cb(result); - } + executor_->Execute([cbs, func]() { + func(cbs); + }); + } else { + func(cbs); } } diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.h b/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.h index 51cfc5f0c65269131397cacca88063c6cc525891..8d2a40790e0160ccb0f87021ba0adaa576a23595 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.h +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.h @@ -54,7 +54,7 @@ public: static void OnSyncFinish(const DistributedData::StoreInfo &storeInfo, uint32_t flag, uint32_t syncMode, uint32_t traceId); void SetExecutor(std::shared_ptr executor) override; - int32_t Bind(Database &database, const std::map &bindInfos, + int32_t Bind(const Database &database, const std::map &bindInfos, const CloudConfig &config) override; bool IsBound(uint32_t user) override; bool IsValid(); @@ -85,7 +85,6 @@ public: int32_t BindSnapshots(std::shared_ptr>> bindAssets) override; int32_t MergeMigratedData(const std::string &tableName, VBuckets&& values) override; int32_t CleanTrackerData(const std::string &tableName, int64_t cursor) override; - std::vector GetWaterVersion(const std::string &deviceId) override; std::pair LockCloudDB() override; int32_t UnLockCloudDB() override; @@ -101,6 +100,7 @@ private: using Time = std::chrono::steady_clock::time_point; using SyncId = uint64_t; static GenErr ConvertStatus(DistributedDB::DBStatus status); + void InitStoreInfo(const StoreMetaData &meta); // GetIntersection and return results in the order of collecter1 static std::vector GetIntersection(std::vector &&syncTables, const std::set &localTables); @@ -153,6 +153,9 @@ private: std::shared_ptr GetRdbCloud() const; bool IsFinished(uint64_t syncId) const; void RemoveTasks(); + std::pair DoCloudSync(const Devices &devices, const DistributedDB::Query &dbQuery, + const DistributedData::SyncParam &syncParam, bool isPriority, DetailAsync async); + void Report(const std::string &faultType, int32_t errCode, const std::string &appendix); ObserverProxy observer_; RdbManager manager_; @@ -184,4 +187,4 @@ private: std::shared_ptr> tasks_; }; } // namespace OHOS::DistributedRdb -#endif // OHOS_DISTRIBUTED_DATA_DATAMGR_SERVICE_RDB_GENERAL_STORE_H +#endif // OHOS_DISTRIBUTED_DATA_DATAMGR_SERVICE_RDB_GENERAL_STORE_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_query.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_query.cpp index 5c47d453478811cc63f4bff77f31078afda4ff7b..298e099874f1adec1d7f9b5281234579c1eb0fd7 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_query.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_query.cpp @@ -15,6 +15,7 @@ #define LOG_TAG "RdbQuery" #include "rdb_query.h" +#include "asset_value.h" #include "log_print.h" #include "utils/anonymous.h" #include "value_proxy.h" @@ -69,6 +70,11 @@ void RdbQuery::MakeQuery(const PredicatesMemo &predicates) tables_ = predicates.tables_; } +void RdbQuery::MakeQuery(const std::string &table) +{ + query_ = DistributedDB::Query::Select(table); +} + void RdbQuery::MakeCloudQuery(const PredicatesMemo& predicates) { ZLOGD("table size:%{public}zu, device size:%{public}zu, op size:%{public}zu", predicates.tables_.size(), @@ -342,4 +348,37 @@ std::vector RdbQuery::GetColumns() const { return columns_; } + +void RdbQuery::NotContains(const RdbPredicateOperation &operation) +{ + return; +} + +void RdbQuery::NotLike(const RdbPredicateOperation &operation) +{ + if (operation.values_.empty()) { + return; + } + query_.NotLike(operation.field_, operation.values_[0]); + predicates_->NotLike(operation.field_, operation.values_[0]); +} + +void RdbQuery::AssetsOnly(const RdbPredicateOperation &operation) +{ + if (operation.values_.empty()) { + return; + } + DistributedDB::AssetsMap assetsMap; + std::vector assets; + std::set names; + for (const auto &value : operation.values_) { + names.insert(value); + NativeRdb::AssetValue asset{ .name = value }; + assets.push_back(std::move(asset)); + } + NativeRdb::ValueObject object(assets); + assetsMap[operation.field_] = names; + query_.AssetsOnly(assetsMap); + predicates_->EqualTo(operation.field_, object); +} } // namespace OHOS::DistributedRdb diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_query.h b/datamgr_service/services/distributeddataservice/service/rdb/rdb_query.h index bf8cd381aa6a44842cb0229d76cffa2a47719d3a..5f985a28bf6a71db9947006f50fcf9a7da520ba4 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_query.h +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_query.h @@ -41,6 +41,7 @@ public: bool IsRemoteQuery(); bool IsPriority(); void MakeQuery(const PredicatesMemo &predicates); + void MakeQuery(const std::string &table); void MakeRemoteQuery(const std::string &devices, const std::string &sql, DistributedData::Values &&args); void MakeCloudQuery(const PredicatesMemo &predicates); @@ -70,6 +71,9 @@ private: void IndexedBy(const RdbPredicateOperation& operation); void BeginGroup(const RdbPredicateOperation& operation); void EndGroup(const RdbPredicateOperation& operation); + void NotContains(const RdbPredicateOperation& operation); + void NotLike(const RdbPredicateOperation& operation); + void AssetsOnly(const RdbPredicateOperation& operation); using PredicateHandle = void (RdbQuery::*)(const RdbPredicateOperation &operation); static constexpr inline PredicateHandle HANDLES[OPERATOR_MAX] = { &RdbQuery::EqualTo, @@ -96,6 +100,9 @@ private: &RdbQuery::LessThan, &RdbQuery::LessThanOrEqual, &RdbQuery::Distinct, + &RdbQuery::NotContains, + &RdbQuery::NotLike, + &RdbQuery::AssetsOnly, &RdbQuery::IndexedBy }; static constexpr inline uint32_t DECIMAL_BASE = 10; diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_result_set_stub.h b/datamgr_service/services/distributeddataservice/service/rdb/rdb_result_set_stub.h index 4c2d62108091b4ef4eabeaa87200b701c522b93c..9931418f6a86f39f0fb8494b2dc8ea6f580ca659 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_result_set_stub.h +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_result_set_stub.h @@ -17,6 +17,7 @@ #define DISTRIBUTED_RDB_RDB_RESULT_SET_STUB_H #include + #include "irdb_result_set.h" #include "result_set.h" @@ -72,4 +73,4 @@ private: std::shared_ptr resultSet_; }; } // namespace OHOS::DistributedRdb -#endif // DISTRIBUTED_RDB_RDB_RESULT_SET_STUB_H +#endif // DISTRIBUTED_RDB_RDB_RESULT_SET_STUB_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_schema_config.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_schema_config.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1f5557f95a185f648d0ee26f4299f0fa5b953347 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_schema_config.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2024 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 "RdbSchemaConfig" + +#include "rdb_schema_config.h" +#include +#include +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" +#include "metadata/meta_data_manager.h" +#include "iremote_broker.h" +#include "iremote_object.h" +#include "refbase.h" +#include "resource_manager.h" +#include "log_print.h" + +namespace OHOS::DistributedRdb { +using namespace OHOS::Global::Resource; +using namespace OHOS::DistributedData; +using Serializable = DistributedData::Serializable; +constexpr const char *SCHEMA_PATH = "arkdata/schema/schema.json"; + +bool RdbSchemaConfig::GetDistributedSchema(const StoreMetaData &meta, Database &database) +{ + OHOS::AppExecFwk::BundleInfo bundleInfo; + if (!InitBundleInfo(meta.bundleName, std::atoi(meta.user.c_str()), bundleInfo)) { + return false; + } + std::string storeName = meta.storeId; + auto ret = GetSchemaFromHap(bundleInfo, meta.storeId, database); + if (ret) { + database.user = meta.user; + database.deviceId = meta.deviceId; + return true; + } + return false; +} + +bool RdbSchemaConfig::InitBundleInfo( + const std::string &bundleName, int32_t userId, OHOS::AppExecFwk::BundleInfo &bundleInfo) +{ + OHOS::sptr systemAbilityManager = + OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (systemAbilityManager == nullptr) { + ZLOGE("Fail to get ststem ability mgr, bundleName: %{public}s.", bundleName.c_str()); + return false; + } + + OHOS::sptr remoteObject = + systemAbilityManager->GetSystemAbility(OHOS::BUNDLE_MGR_SERVICE_SYS_ABILITY_ID); + if (remoteObject == nullptr) { + ZLOGE("Fail to get bundle manager proxy, bundleName: %{public}s.", bundleName.c_str()); + return false; + } + + auto bundleMgrProxy = iface_cast(remoteObject); + if (bundleMgrProxy == nullptr) { + ZLOGE("Fail to cast proxy, bundleName: %{public}s.", bundleName.c_str()); + return false; + } + bool ret = bundleMgrProxy->GetBundleInfo( + bundleName, OHOS::AppExecFwk::BundleFlag::GET_BUNDLE_WITH_EXTENSION_INFO, bundleInfo, userId); + if (!ret || bundleInfo.moduleDirs.size() == 0) { + ZLOGE("Get bundle info failed, bundleName: %{public}s.", bundleName.c_str()); + return false; + } + return true; +} + +bool RdbSchemaConfig::GetSchemaFromHap( + const OHOS::AppExecFwk::BundleInfo &bundleInfo, const std::string &storeName, Database &database) +{ + for (auto &hapInfo : bundleInfo.hapModuleInfos) { + std::shared_ptr resMgr(CreateResourceManager()); + if (resMgr == nullptr) { + ZLOGE("Create resourceManager failed"); + return {}; + } + resMgr->AddResource(hapInfo.hapPath.c_str()); + size_t length = 0; + std::unique_ptr fileContent; +// int err = resMgr->GetRawFileFromHap(SCHEMA_PATH, length, fileContent); +// if (err != 0) { +// continue; +// } + std::string jsonData(fileContent.get(), fileContent.get() + length); + DbSchema databases; + databases.Unmarshall(jsonData); + for (auto &schema : databases.databases) { + if (schema.name == storeName) { + database = schema; + return true; + } + } + } + return false; +} +} // namespace OHOS::DistributedRdb \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_schema_config.h b/datamgr_service/services/distributeddataservice/service/rdb/rdb_schema_config.h new file mode 100644 index 0000000000000000000000000000000000000000..16d995dd2062065cc6e6f1b7600ae36933d252a4 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_schema_config.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 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_RDB_SCHEMA_CONFIG_H +#define OHOS_DISTRIBUTED_DATA_DATAMGR_SERVICE_RDB_RDB_SCHEMA_CONFIG_H +#include +#include +#include "bundlemgr/bundle_mgr_proxy.h" +#include "metadata/store_meta_data.h" +#include "serializable/serializable.h" +#include "cloud/schema_meta.h" +namespace OHOS::DistributedRdb { +using Database = DistributedData::Database; +using DbSchema = DistributedData::SchemaMeta; +using StoreMetaData = OHOS::DistributedData::StoreMetaData; +class RdbSchemaConfig { +public: + static bool GetDistributedSchema(const StoreMetaData &meta, Database &database); + +private: + static bool InitBundleInfo(const std::string &bundleName, int32_t userId, OHOS::AppExecFwk::BundleInfo &bundleInfo); + static bool GetSchemaFromHap( + const OHOS::AppExecFwk::BundleInfo &bundleInfo, const std::string &storeName, Database &database); +}; +} // namespace OHOS::DistributedRdb +#endif // OHOS_DISTRIBUTED_DATA_DATAMGR_SERVICE_RDB_RDB_SCHEMA_CONFIG_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_impl.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_impl.cpp index 36016b652017a33b5caaaf41eca430c3efc16e47..7c0181c9f97c38017d7db37c17c87bec312f2a55 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_impl.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_impl.cpp @@ -43,6 +43,7 @@ #include "rdb_general_store.h" #include "rdb_notifier_proxy.h" #include "rdb_query.h" +#include "rdb_schema_config.h" #include "rdb_result_set_impl.h" #include "rdb_watcher.h" #include "store/general_store.h" @@ -53,19 +54,23 @@ #include "utils/converter.h" #include "xcollie.h" #include "permit_delegate.h" +#include "bootstrap.h" using OHOS::DistributedData::Anonymous; using OHOS::DistributedData::CheckerManager; using OHOS::DistributedData::MetaDataManager; using OHOS::DistributedData::StoreMetaData; -using OHOS::DistributedKv::AccountDelegate; +using OHOS::DistributedData::AccountDelegate; using namespace OHOS::DistributedData; using namespace OHOS::Security::AccessToken; using DistributedDB::RelationalStoreManager; using DmAdapter = OHOS::DistributedData::DeviceManagerAdapter; +using RdbSchemaConfig = OHOS::DistributedRdb::RdbSchemaConfig; using DumpManager = OHOS::DistributedData::DumpManager; using system_clock = std::chrono::system_clock; constexpr uint32_t ITERATE_TIMES = 10000; +constexpr uint32_t ALLOW_ONLINE_AUTO_SYNC = 8; +const size_t KEY_COUNT = 2; namespace OHOS::DistributedRdb { __attribute__((used)) RdbServiceImpl::Factory RdbServiceImpl::factory_; RdbServiceImpl::Factory::Factory() @@ -99,6 +104,7 @@ RdbServiceImpl::RdbServiceImpl() [this](const std::string &identifier, DistributedDB::AutoLaunchParam ¶m) { return ResolveAutoLaunch(identifier, param); }); + RegisterEvent(); } int32_t RdbServiceImpl::ResolveAutoLaunch(const std::string &identifier, DistributedDB::AutoLaunchParam ¶m) @@ -118,7 +124,7 @@ int32_t RdbServiceImpl::ResolveAutoLaunch(const std::string &identifier, Distrib } auto aIdentifier = DistributedDB::RelationalStoreManager::GetRelationalStoreIdentifier( - entry.user, entry.appId, entry.storeId); + "", entry.appId, entry.storeId, true); ZLOGD("%{public}s %{public}s %{public}s", entry.user.c_str(), entry.appId.c_str(), Anonymous::Change(entry.storeId).c_str()); if (aIdentifier != identifier) { @@ -232,6 +238,19 @@ std::shared_ptr RdbServiceImpl::GetStore(const Rd return store; } +void RdbServiceImpl::UpdateSyncMeta(const StoreMetaData &meta, const StoreMetaData &localMeta) +{ + StoreMetaData syncMeta; + bool isCreatedSync = MetaDataManager::GetInstance().LoadMeta(meta.GetKey(), syncMeta); + if (!isCreatedSync || localMeta != syncMeta) { + ZLOGI("save sync meta. bundle:%{public}s store:%{public}s type:%{public}d->%{public}d " + "encrypt:%{public}d->%{public}d , area:%{public}d->%{public}d", + meta.bundleName.c_str(), meta.GetStoreAlias().c_str(), syncMeta.storeType, meta.storeType, + syncMeta.isEncrypt, meta.isEncrypt, syncMeta.area, meta.area); + MetaDataManager::GetInstance().SaveMeta(meta.GetKey(), localMeta); + } +} + int32_t RdbServiceImpl::SetDistributedTables(const RdbSyncerParam ¶m, const std::vector &tables, const std::vector &references, bool isRebuild, int32_t type) { @@ -240,29 +259,32 @@ int32_t RdbServiceImpl::SetDistributedTables(const RdbSyncerParam ¶m, const Anonymous::Change(param.storeName_).c_str()); return RDB_ERROR; } - if (type == DistributedRdb::DistributedTableType::DISTRIBUTED_SEARCH) { + if (type == DistributedTableType::DISTRIBUTED_SEARCH) { DistributedData::SetSearchableEvent::EventInfo eventInfo; eventInfo.isRebuild = isRebuild; return PostSearchEvent(CloudEvent::SET_SEARCH_TRIGGER, param, eventInfo); } auto meta = GetStoreMetaData(param); - - if (type == DistributedRdb::DistributedTableType::DISTRIBUTED_DEVICE) { - StoreMetaData localMeta; - bool isCreatedLocal = MetaDataManager::GetInstance().LoadMeta(meta.GetKey(), localMeta, true); - if (!isCreatedLocal) { - ZLOGE("no meta. bundleName:%{public}s, storeName:%{public}s. GetStore failed", param.bundleName_.c_str(), - Anonymous::Change(param.storeName_).c_str()); - return RDB_ERROR; + StoreMetaData localMeta; + bool isCreatedLocal = MetaDataManager::GetInstance().LoadMeta(meta.GetKey(), localMeta, true); + if (!isCreatedLocal) { + ZLOGE("no meta. bundleName:%{public}s, storeName:%{public}s. GetStore failed", param.bundleName_.c_str(), + Anonymous::Change(param.storeName_).c_str()); + return RDB_ERROR; + } + if (type == DistributedTableType::DISTRIBUTED_DEVICE) { + UpdateSyncMeta(meta, localMeta); + Database dataBase; + if (RdbSchemaConfig::GetDistributedSchema(localMeta, dataBase) && !dataBase.name.empty() && + !dataBase.bundleName.empty()) { + MetaDataManager::GetInstance().SaveMeta(dataBase.GetKey(), dataBase, true); } - StoreMetaData syncMeta; - bool isCreatedSync = MetaDataManager::GetInstance().LoadMeta(meta.GetKey(), syncMeta); - if (!isCreatedSync || localMeta != syncMeta) { - ZLOGI("save sync meta. bundle:%{public}s store:%{public}s type:%{public}d->%{public}d " - "encrypt:%{public}d->%{public}d , area:%{public}d->%{public}d", - meta.bundleName.c_str(), meta.GetStoreAlias().c_str(), syncMeta.storeType, meta.storeType, - syncMeta.isEncrypt, meta.isEncrypt, syncMeta.area, meta.area); - MetaDataManager::GetInstance().SaveMeta(meta.GetKey(), localMeta); + } else if (type == DistributedTableType::DISTRIBUTED_CLOUD) { + if (localMeta.asyncDownloadAsset != param.asyncDownloadAsset_) { + localMeta.asyncDownloadAsset = param.asyncDownloadAsset_; + ZLOGI("update meta, bundleName:%{public}s, storeName:%{public}s, asyncDownloadAsset?[%{public}d]", + param.bundleName_.c_str(), Anonymous::Change(param.storeName_).c_str(), localMeta.asyncDownloadAsset); + MetaDataManager::GetInstance().SaveMeta(localMeta.GetKey(), localMeta, true); } } auto store = GetStore(param); @@ -512,9 +534,12 @@ void RdbServiceImpl::DoCloudSync(const RdbSyncerParam ¶m, const RdbService:: async(HandleGenDetails(details)); } }; - auto mixMode = static_cast(GeneralStore::MixMode(option.mode, - option.isAutoSync ? GeneralStore::AUTO_SYNC_MODE : GeneralStore::MANUAL_SYNC_MODE)); + auto highMode = (!predicates.tables_.empty() && option.mode == DistributedData::GeneralStore::CLOUD_ClOUD_FIRST) + ? GeneralStore::ASSETS_SYNC_MODE + : (option.isAutoSync ? GeneralStore::AUTO_SYNC_MODE : GeneralStore::MANUAL_SYNC_MODE); + auto mixMode = static_cast(GeneralStore::MixMode(option.mode, highMode)); SyncParam syncParam = { mixMode, (option.isAsync ? 0 : static_cast(WAIT_TIME)), option.isCompensation }; + syncParam.asyncDownloadAsset = param.asyncDownloadAsset_; auto info = ChangeEvent::EventInfo(syncParam, option.isAutoSync, query, option.isAutoSync ? nullptr : option.isAsync ? asyncCallback @@ -643,6 +668,7 @@ int32_t RdbServiceImpl::Delete(const RdbSyncerParam ¶m) MetaDataManager::GetInstance().DelMeta(storeMeta.GetBackupSecretKey(), true); MetaDataManager::GetInstance().DelMeta(storeMeta.GetAutoLaunchKey(), true); MetaDataManager::GetInstance().DelMeta(storeMeta.GetDebugInfoKey(), true); + MetaDataManager::GetInstance().DelMeta(storeMeta.GetCloneSecretKey(), true); return RDB_OK; } @@ -693,9 +719,16 @@ std::pair> RdbServiceImpl::AllocResource(StoreI int32_t RdbServiceImpl::BeforeOpen(RdbSyncerParam ¶m) { XCollie xcollie(__FUNCTION__, HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_RECOVERY); + if (!CheckAccess(param.bundleName_, param.storeName_)) { + ZLOGE("bundleName:%{public}s, storeName:%{public}s. Permission error", param.bundleName_.c_str(), + Anonymous::Change(param.storeName_).c_str()); + return RDB_ERROR; + } auto meta = GetStoreMetaData(param); auto isCreated = MetaDataManager::GetInstance().LoadMeta(meta.GetKey(), meta, true); if (!isCreated) { + ZLOGW("bundleName:%{public}s, storeName:%{public}s. no meta", param.bundleName_.c_str(), + Anonymous::Change(param.storeName_).c_str()); return RDB_NO_META; } SetReturnParam(meta, param); @@ -813,6 +846,7 @@ StoreMetaData RdbServiceImpl::GetStoreMetaData(const RdbSyncerParam ¶m) metaData.isManualClean = !param.isAutoClean_; metaData.isSearchable = param.isSearchable_; metaData.haMode = param.haMode_; + metaData.asyncDownloadAsset = param.asyncDownloadAsset_; return metaData; } @@ -912,6 +946,118 @@ int32_t RdbServiceImpl::OnBind(const BindInfo &bindInfo) return 0; } +StoreMetaData RdbServiceImpl::GetStoreMetaData(const Database &dataBase) +{ + StoreMetaData storeMetaData; + storeMetaData.storeId = dataBase.name; + storeMetaData.bundleName = dataBase.bundleName; + storeMetaData.user = dataBase.user; + storeMetaData.deviceId = DmAdapter::GetInstance().GetLocalDevice().uuid; + auto tokenId = IPCSkeleton::GetCallingTokenID(); + storeMetaData.tokenId = tokenId; + auto [instanceId, user] = GetInstIndexAndUser(storeMetaData.tokenId, storeMetaData.bundleName); + storeMetaData.instanceId = instanceId; + MetaDataManager::GetInstance().LoadMeta(storeMetaData.GetKey(), storeMetaData, true); + return storeMetaData; +} + + +std::shared_ptr RdbServiceImpl::GetStore(const StoreMetaData &storeMetaData) +{ + auto watchers = GetWatchers(storeMetaData.tokenId, storeMetaData.storeId); + auto store = AutoCache::GetInstance().GetStore(storeMetaData, watchers); + return store; +} + +std::vector RdbServiceImpl::GetReuseDevice(const std::vector &devices) +{ + std::vector onDevices; + auto instance = AppDistributedKv::ProcessCommunicatorImpl::GetInstance(); + for (auto &device : devices) { + if (instance->ReuseConnect({device}) == Status::SUCCESS) { + onDevices.push_back(device); + } + } + return onDevices; +} + +int RdbServiceImpl::DoAutoSync( + const std::vector &devices, const Database &dataBase, std::vector tables) +{ + StoreMetaData storeMetaData = GetStoreMetaData(dataBase); + auto tokenId = storeMetaData.tokenId; + auto store = GetStore(storeMetaData); + if (store == nullptr) { + ZLOGE("autosync store null, storeId:%{public}s", storeMetaData.GetStoreAlias().c_str()); + return RDB_ERROR; + } + SyncParam syncParam = {0, 0}; + auto pid = IPCSkeleton::GetCallingPid(); + DetailAsync async; + if (executors_ == nullptr) { + ZLOGE("autosync executors_ null, storeId:%{public}s", storeMetaData.GetStoreAlias().c_str()); + return RDB_ERROR; + } + for (auto &table : tables) { + executors_->Execute([this, table, store, pid, syncParam, tokenId, async, + devices, storeMetaData]() { + RdbQuery rdbQuery; + rdbQuery.MakeQuery(table); + std::vector onDevices = GetReuseDevice(devices); + if (onDevices.empty()) { + ZLOGE("autosync ondevices null, storeId:%{public}s", storeMetaData.GetStoreAlias().c_str()); + return; + } + auto complete = [this, rdbQuery, store, pid, syncParam, tokenId, async, seq = 0]( + const auto &results) mutable { + auto ret = ProcessResult(results); + store->Sync(ret.first, rdbQuery, async, syncParam); + }; + if (IsNeedMetaSync(storeMetaData, onDevices)) { + MetaDataManager::GetInstance().Sync(onDevices, complete); + return; + } + (void)store->Sync(onDevices, rdbQuery, async, syncParam).first; + return; + }); + } + return RDB_OK; +} + +int RdbServiceImpl::DoOnlineSync(const std::vector &devices, const Database &dataBase) +{ + std::vector tableNames; + for (auto &table : dataBase.tables) { + if (!table.deviceSyncFields.empty()) { + tableNames.push_back(table.name); + } + } + return DoAutoSync(devices, dataBase, tableNames); +} + +int32_t RdbServiceImpl::OnReady(const std::string &device) +{ + int index = ALLOW_ONLINE_AUTO_SYNC; + Database dataBase; + std::string prefix = dataBase.GetPrefix({}); + std::vector dataBases; + if (!MetaDataManager::GetInstance().LoadMeta(prefix, dataBases, true)) { + return 0; + } + for (auto dataBase : dataBases) { + if ((dataBase.autoSyncType == AutoSyncType::SYNC_ON_READY || + dataBase.autoSyncType == AutoSyncType::SYNC_ON_CHANGE_READY) && + index > 0) { + std::vector devices = {device}; + if (!DoOnlineSync(devices, dataBase)) { + ZLOGE("store online sync fail, storeId:%{public}s", dataBase.name.c_str()); + } + index--; + } + } + return 0; +} + void RdbServiceImpl::SyncAgent::SetNotifier(sptr notifier) { notifier_ = notifier; @@ -968,11 +1114,25 @@ int32_t RdbServiceImpl::RdbStatic::CloseStore(const std::string &bundleName, int int32_t RdbServiceImpl::RdbStatic::OnAppUninstall(const std::string &bundleName, int32_t user, int32_t index) { + std::string prefix = Database::GetPrefix({std::to_string(user), "default", bundleName}); + std::vector dataBase; + if (MetaDataManager::GetInstance().LoadMeta(prefix, dataBase, true)) { + for (const auto &dataBase : dataBase) { + MetaDataManager::GetInstance().DelMeta(dataBase.GetKey(), true); + } + } return CloseStore(bundleName, user, index); } int32_t RdbServiceImpl::RdbStatic::OnAppUpdate(const std::string &bundleName, int32_t user, int32_t index) { + std::string prefix = Database::GetPrefix({std::to_string(user), "default", bundleName}); + std::vector dataBase; + if (MetaDataManager::GetInstance().LoadMeta(prefix, dataBase, true)) { + for (const auto &dataBase : dataBase) { + MetaDataManager::GetInstance().DelMeta(dataBase.GetKey(), true); + } + } return CloseStore(bundleName, user, index); } @@ -1009,22 +1169,40 @@ int32_t RdbServiceImpl::OnInitialize() { RegisterRdbServiceInfo(); RegisterHandler(); - RegisterEvent(); return RDB_OK; } RdbServiceImpl::~RdbServiceImpl() { DumpManager::GetInstance().RemoveHandler("FEATURE_INFO", uintptr_t(this)); - EventCenter::GetInstance().Unsubscribe(CloudEvent::CLOUD_SYNC); - EventCenter::GetInstance().Unsubscribe(CloudEvent::CLEAN_DATA); - EventCenter::GetInstance().Unsubscribe(CloudEvent::MAKE_QUERY); - EventCenter::GetInstance().Unsubscribe(BindEvent::COMPENSATE_SYNC); - EventCenter::GetInstance().Unsubscribe(BindEvent::RECOVER_SYNC); } -int32_t RdbServiceImpl::NotifyDataChange(const RdbSyncerParam ¶m, const RdbChangedData &rdbChangedData, - const RdbNotifyConfig &rdbNotifyConfig) +int RdbServiceImpl::DoDataChangeSync(const StoreInfo &storeInfo, const RdbChangedData &rdbChangedData) +{ + std::vector tableNames; + Database dataBase; + dataBase.bundleName = storeInfo.bundleName; + dataBase.name = storeInfo.storeName; + dataBase.user = std::to_string(storeInfo.user); + dataBase.deviceId = storeInfo.deviceId; + for (const auto &[key, value] : rdbChangedData.tableData) { + if (value.isP2pSyncDataChange) { + tableNames.push_back(key); + } + } + if (MetaDataManager::GetInstance().LoadMeta(dataBase.GetKey(), dataBase, true)) { + std::vector devices = DmAdapter::ToUUID(DmAdapter::GetInstance().GetRemoteDevices()); + if ((dataBase.autoSyncType == AutoSyncType::SYNC_ON_CHANGE || + dataBase.autoSyncType == AutoSyncType::SYNC_ON_CHANGE_READY) && + !devices.empty()) { + return DoAutoSync(devices, dataBase, tableNames); + } + } + return RDB_OK; +} + +int32_t RdbServiceImpl::NotifyDataChange( + const RdbSyncerParam ¶m, const RdbChangedData &rdbChangedData, const RdbNotifyConfig &rdbNotifyConfig) { XCollie xcollie(__FUNCTION__, HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_RECOVERY); if (!CheckAccess(param.bundleName_, param.storeName_)) { @@ -1036,23 +1214,25 @@ int32_t RdbServiceImpl::NotifyDataChange(const RdbSyncerParam ¶m, const RdbC storeInfo.tokenId = IPCSkeleton::GetCallingTokenID(); storeInfo.bundleName = param.bundleName_; storeInfo.storeName = RemoveSuffix(param.storeName_); - auto [instanceId, user]= GetInstIndexAndUser(storeInfo.tokenId, param.bundleName_); + auto [instanceId, user] = GetInstIndexAndUser(storeInfo.tokenId, param.bundleName_); storeInfo.instanceId = instanceId; storeInfo.user = user; storeInfo.deviceId = DmAdapter::GetInstance().GetLocalDevice().uuid; - DataChangeEvent::EventInfo eventInfo; eventInfo.isFull = rdbNotifyConfig.isFull_; - for (const auto& [key, value] : rdbChangedData.tableData) { - DataChangeEvent::TableChangeProperties tableChangeProperties = {value.isTrackedDataChange}; - eventInfo.tableProperties.insert_or_assign(key, std::move(tableChangeProperties)); + if (!DoDataChangeSync(storeInfo, rdbChangedData)) { + ZLOGE("store datachange sync fail, storeId:%{public}s", storeInfo.storeName.c_str()); + } + for (const auto &[key, value] : rdbChangedData.tableData) { + if (value.isTrackedDataChange) { + DataChangeEvent::TableChangeProperties tableChangeProperties = {value.isTrackedDataChange}; + eventInfo.tableProperties.insert_or_assign(key, std::move(tableChangeProperties)); + } } - if (IsPostImmediately(IPCSkeleton::GetCallingPid(), rdbNotifyConfig, storeInfo, eventInfo, param.storeName_)) { auto evt = std::make_unique(std::move(storeInfo), std::move(eventInfo)); EventCenter::GetInstance().PostEvent(std::move(evt)); } - return RDB_OK; } @@ -1139,7 +1319,7 @@ int32_t RdbServiceImpl::Enable(const RdbSyncerParam ¶m) return RDB_OK; } -int32_t RdbServiceImpl::GetPassword(const RdbSyncerParam ¶m, std::vector &password) +int32_t RdbServiceImpl::GetPassword(const RdbSyncerParam ¶m, std::vector> &password) { if (!CheckAccess(param.bundleName_, param.storeName_)) { ZLOGE("bundleName:%{public}s, storeName:%{public}s. Permission error", param.bundleName_.c_str(), @@ -1147,16 +1327,24 @@ int32_t RdbServiceImpl::GetPassword(const RdbSyncerParam ¶m, std::vector> &)>; using StoreInfo = DistributedData::StoreInfo; RdbServiceImpl(); @@ -85,6 +88,8 @@ public: int32_t OnBind(const BindInfo &bindInfo) override; + int32_t OnReady(const std::string &device) override; + int32_t OnInitialize() override; int32_t NotifyDataChange(const RdbSyncerParam ¶m, const RdbChangedData &rdbChangedData, @@ -97,7 +102,7 @@ public: int32_t AfterOpen(const RdbSyncerParam ¶m) override; - int32_t GetPassword(const RdbSyncerParam ¶m, std::vector &password) override; + int32_t GetPassword(const RdbSyncerParam ¶m, std::vector> &password) override; std::pair LockCloudContainer(const RdbSyncerParam ¶m) override; @@ -164,6 +169,14 @@ private: int DoSync(const RdbSyncerParam ¶m, const Option &option, const PredicatesMemo &predicates, const AsyncDetail &async); + + int DoAutoSync( + const std::vector &devices, const Database &dataBase, std::vector tableNames); + + std::vector GetReuseDevice(const std::vector &devices); + int DoOnlineSync(const std::vector &devices, const Database &dataBase); + + int DoDataChangeSync(const StoreInfo &storeInfo, const RdbChangedData &rdbChangedData); Watchers GetWatchers(uint32_t tokenId, const std::string &storeName); @@ -172,11 +185,15 @@ private: bool CheckAccess(const std::string& bundleName, const std::string& storeName); std::shared_ptr GetStore(const RdbSyncerParam& param); + + std::shared_ptr GetStore(const StoreMetaData &storeMetaData); void OnAsyncComplete(uint32_t tokenId, pid_t pid, uint32_t seqNum, Details &&result); StoreMetaData GetStoreMetaData(const RdbSyncerParam ¶m); + StoreMetaData GetStoreMetaData(const Database &dataBase); + int32_t SetSecretKey(const RdbSyncerParam ¶m, const StoreMetaData &meta); int32_t Upgrade(const RdbSyncerParam ¶m, const StoreMetaData &old); @@ -214,6 +231,8 @@ private: bool IsPostImmediately(const int32_t callingPid, const RdbNotifyConfig &rdbNotifyConfig, StoreInfo &storeInfo, DistributedData::DataChangeEvent::EventInfo &eventInfo, const std::string &storeName); + void UpdateSyncMeta(const StoreMetaData &meta, const StoreMetaData &localMeta); + static Factory factory_; ConcurrentMap syncAgents_; std::shared_ptr executors_; diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.cpp index d30125b91792f1463bcf049ee9e89ac9ab68bc09..c6daa96acca1f28083594485c0e31da0be44e212 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.cpp @@ -383,14 +383,18 @@ int32_t RdbServiceStub::OnGetPassword(MessageParcel &data, MessageParcel &reply) return IPC_STUB_INVALID_DATA_ERR; } - std::vector key; - auto status = GetPassword(param, key); - if (!ITypesUtil::Marshal(reply, status, key)) { - key.assign(key.size(), 0); + std::vector> keys; + auto status = GetPassword(param, keys); + if (!ITypesUtil::Marshal(reply, status, keys)) { + for (auto &key : keys) { + key.assign(key.size(), 0); + } ZLOGE("Marshal status:0x%{public}x", status); return IPC_STUB_WRITE_PARCEL_ERR; } - key.assign(key.size(), 0); + for (auto &key : keys) { + key.assign(key.size(), 0); + } return RDB_OK; } diff --git a/datamgr_service/services/distributeddataservice/service/test/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/BUILD.gn index 5ed1d319f673f96a276b782b49ce6a0decdb54a6..77e9151464e3695e34bbc5f1087e46f0e30daa33 100644 --- a/datamgr_service/services/distributeddataservice/service/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/test/BUILD.gn @@ -34,22 +34,25 @@ config("module_private_config") { "${data_service_path}/service/directory/include/", "${data_service_path}/service/data_share/common", "${data_service_path}/service/data_share/data", + "${data_service_path}/service/data_share/dfx", "${data_service_path}/service/data_share/strategies", "${data_service_path}/service/data_share/subscriber_managers", "${data_service_path}/service/data_share", "${data_service_path}/service/matrix/include/", + "${data_service_path}/service/network", "${data_service_path}/service/kvdb", - "${data_service_path}/service/object/", + "${data_service_path}/service/object/include", "${data_service_path}/service/permission/include", "${data_service_path}/service/rdb/", "${data_service_path}/service/test/mock", - "${data_service_path}/service/waterversion", "${dataobject_path}/interfaces/innerkits", "${dataobject_path}/frameworks/innerkitsimpl/include", "${kv_store_distributeddb_path}/interfaces/include/", "${kv_store_distributeddb_path}/include/", "${relational_store_path}/interfaces/inner_api/cloud_data/include", "${relational_store_path}/interfaces/inner_api/common_type/include", + "${data_service_path}/adapter/include/communicator", + "${data_service_path}/adapter/include/dfx", ] cflags = [ "-Werror" ] defines = [ @@ -68,6 +71,7 @@ ohos_unittest("CloudDataTest") { sources = [ "${data_service_path}/service/backup/src/backup_manager.cpp", "${data_service_path}/service/bootstrap/src/bootstrap.cpp", + "${data_service_path}/service/cloud/cloud_data_translate.cpp", "${data_service_path}/service/cloud/cloud_service_impl.cpp", "${data_service_path}/service/cloud/cloud_service_stub.cpp", "${data_service_path}/service/cloud/cloud_types_util.cpp", @@ -87,26 +91,29 @@ ohos_unittest("CloudDataTest") { "${data_service_path}/service/config/src/model/global_config.cpp", "${data_service_path}/service/config/src/model/network_config.cpp", "${data_service_path}/service/config/src/model/protocol_config.cpp", + "${data_service_path}/service/config/src/model/thread_config.cpp", "${data_service_path}/service/crypto/src/crypto_manager.cpp", + "${data_service_path}/service/kvdb/user_delegate.cpp", "${data_service_path}/service/matrix/src/device_matrix.cpp", "${data_service_path}/service/matrix/src/matrix_event.cpp", + "${data_service_path}/service/permission/src/permission_validator.cpp", "${data_service_path}/service/permission/src/permit_delegate.cpp", "${data_service_path}/service/rdb/cache_cursor.cpp", "${data_service_path}/service/rdb/rdb_asset_loader.cpp", "${data_service_path}/service/rdb/rdb_cloud.cpp", - "${data_service_path}/service/rdb/rdb_cloud_data_translate.cpp", "${data_service_path}/service/rdb/rdb_cursor.cpp", "${data_service_path}/service/rdb/rdb_general_store.cpp", "${data_service_path}/service/rdb/rdb_notifier_proxy.cpp", "${data_service_path}/service/rdb/rdb_query.cpp", "${data_service_path}/service/rdb/rdb_result_set_impl.cpp", "${data_service_path}/service/rdb/rdb_result_set_stub.cpp", + "${data_service_path}/service/rdb/rdb_schema_config.cpp", "${data_service_path}/service/rdb/rdb_service_impl.cpp", "${data_service_path}/service/rdb/rdb_service_stub.cpp", "${data_service_path}/service/rdb/rdb_watcher.cpp", "${data_service_path}/service/test/mock/checker_mock.cpp", - "${data_service_path}/service/waterversion/water_version_manager.cpp", "cloud_data_test.cpp", + "network_adapter_test.cpp", ] configs = [ ":module_private_config" ] @@ -117,6 +124,8 @@ ohos_unittest("CloudDataTest") { "access_token:libaccesstoken_sdk", "access_token:libtoken_setproc", "access_token:libtokenid_sdk", + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", "c_utils:utils", "hicollie:libhicollie", "hilog:libhilog", @@ -125,10 +134,14 @@ ohos_unittest("CloudDataTest") { "kv_store:distributeddata_inner", "kv_store:distributeddb", "relational_store:native_rdb", + "resource_management:global_resmgr", + "samgr:samgr_proxy", ] deps = [ - "../../adapter:distributeddata_adapter", + "${data_service_path}/adapter/account:distributeddata_account", + "${data_service_path}/adapter/communicator:distributeddata_communicator", + "${data_service_path}/service/network:distributeddata_network", "../../framework:distributeddatasvcfwk", "mock:distributeddata_mock_static", "//third_party/googletest:gtest_main", @@ -151,6 +164,7 @@ ohos_unittest("CloudServiceImplTest") { sources = [ "${data_service_path}/service/backup/src/backup_manager.cpp", "${data_service_path}/service/bootstrap/src/bootstrap.cpp", + "${data_service_path}/service/cloud/cloud_data_translate.cpp", "${data_service_path}/service/cloud/cloud_service_impl.cpp", "${data_service_path}/service/cloud/cloud_service_stub.cpp", "${data_service_path}/service/cloud/cloud_types_util.cpp", @@ -170,25 +184,27 @@ ohos_unittest("CloudServiceImplTest") { "${data_service_path}/service/config/src/model/global_config.cpp", "${data_service_path}/service/config/src/model/network_config.cpp", "${data_service_path}/service/config/src/model/protocol_config.cpp", + "${data_service_path}/service/config/src/model/thread_config.cpp", "${data_service_path}/service/crypto/src/crypto_manager.cpp", + "${data_service_path}/service/kvdb/user_delegate.cpp", "${data_service_path}/service/matrix/src/device_matrix.cpp", "${data_service_path}/service/matrix/src/matrix_event.cpp", + "${data_service_path}/service/permission/src/permission_validator.cpp", "${data_service_path}/service/permission/src/permit_delegate.cpp", "${data_service_path}/service/rdb/cache_cursor.cpp", "${data_service_path}/service/rdb/rdb_asset_loader.cpp", "${data_service_path}/service/rdb/rdb_cloud.cpp", - "${data_service_path}/service/rdb/rdb_cloud_data_translate.cpp", "${data_service_path}/service/rdb/rdb_cursor.cpp", "${data_service_path}/service/rdb/rdb_general_store.cpp", "${data_service_path}/service/rdb/rdb_notifier_proxy.cpp", "${data_service_path}/service/rdb/rdb_query.cpp", "${data_service_path}/service/rdb/rdb_result_set_impl.cpp", "${data_service_path}/service/rdb/rdb_result_set_stub.cpp", + "${data_service_path}/service/rdb/rdb_schema_config.cpp", "${data_service_path}/service/rdb/rdb_service_impl.cpp", "${data_service_path}/service/rdb/rdb_service_stub.cpp", "${data_service_path}/service/rdb/rdb_watcher.cpp", "${data_service_path}/service/test/mock/checker_mock.cpp", - "${data_service_path}/service/waterversion/water_version_manager.cpp", "cloud_service_impl_test.cpp", ] @@ -200,6 +216,8 @@ ohos_unittest("CloudServiceImplTest") { "access_token:libaccesstoken_sdk", "access_token:libtoken_setproc", "access_token:libtokenid_sdk", + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", "c_utils:utils", "hicollie:libhicollie", "hilog:libhilog", @@ -208,10 +226,14 @@ ohos_unittest("CloudServiceImplTest") { "kv_store:distributeddata_inner", "kv_store:distributeddb", "relational_store:native_rdb", + "resource_management:global_resmgr", + "samgr:samgr_proxy", ] deps = [ - "../../adapter:distributeddata_adapter", + "${data_service_path}/adapter/account:distributeddata_account", + "${data_service_path}/adapter/communicator:distributeddata_communicator", + "${data_service_path}/service/network:distributeddata_network", "../../framework:distributeddatasvcfwk", "mock:distributeddata_mock_static", "//third_party/googletest:gtest_main", @@ -241,7 +263,6 @@ ohos_unittest("CloudTest") { ] deps = [ - "../../adapter:distributeddata_adapter", "../../framework:distributeddatasvcfwk", "../../service:distributeddatasvc", "mock:distributeddata_mock_static", @@ -282,7 +303,6 @@ ohos_unittest("ValueProxyServiceTest") { deps = [ "${kv_store_distributeddb_path}:distributeddb", "${relational_store_inner_api_path}:native_rdb_static", - "../../adapter:distributeddata_adapter", "../../framework:distributeddatasvcfwk", "../../service:distributeddatasvc", "//third_party/googletest:gtest_main", @@ -304,7 +324,6 @@ ohos_unittest("ConfigFactoryTest") { ] deps = [ - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter:distributeddata_adapter", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/framework:distributeddatasvcfwk", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/service:distributeddatasvc", "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddata:distributeddata_inner", @@ -330,7 +349,6 @@ ohos_unittest("DirectoryManagerTest") { ] deps = [ - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter:distributeddata_adapter", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/framework:distributeddatasvcfwk", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/service:distributeddatasvc", "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddata:distributeddata_inner", @@ -355,7 +373,6 @@ ohos_unittest("CryptoManagerTest") { ] deps = [ - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter:distributeddata_adapter", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/framework:distributeddatasvcfwk", "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/service:distributeddatasvc", "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddata:distributeddata_inner", @@ -385,7 +402,6 @@ ohos_unittest("DeviceMatrixTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb:distributeddb", @@ -395,13 +411,13 @@ ohos_unittest("DeviceMatrixTest") { } ohos_unittest("KVDBGeneralStoreTest") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } module_out_path = module_output_path sources = [ - "../common/value_proxy.cpp", - "../kvdb/kvdb_general_store.cpp", - "../rdb/rdb_cloud.cpp", - "../rdb/rdb_query.cpp", - "../waterversion/water_version_manager.cpp", "kvdb_general_store_test.cpp", "mock/db_change_data_mock.cpp", "mock/db_store_mock.cpp", @@ -412,7 +428,7 @@ ohos_unittest("KVDBGeneralStoreTest") { include_dirs = [ "${data_service_path}/service/common", "${data_service_path}/service/rdb", - "${data_service_path}/service/waterversion", + "${data_service_path}/service/kvdb", "${relational_store_path}/interfaces/innerapi/clouddata/include", "${relational_store_path}/interfaces/inner_api/rdb/include", "${relational_store_path}/interfaces/inner_api/common_type/include", @@ -437,9 +453,10 @@ ohos_unittest("KVDBGeneralStoreTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", + "${data_service_path}/adapter/account:distributeddata_account", + "${data_service_path}/adapter/communicator:distributeddata_communicator", "${data_service_path}/framework:distributeddatasvcfwk", - "${data_service_path}/service:distributeddatasvc", + "${data_service_path}/service/kvdb:distributeddata_kvdb", "${kv_store_distributeddb_path}:distributeddb", "//third_party/googletest:gtest_main", ] @@ -452,7 +469,6 @@ ohos_unittest("KVDBGeneralStoreAbnormalTest") { "../kvdb/kvdb_general_store.cpp", "../rdb/rdb_cloud.cpp", "../rdb/rdb_query.cpp", - "../waterversion/water_version_manager.cpp", "kvdb_general_store_abnormal_test.cpp", "mock/db_change_data_mock.cpp", "mock/db_store_mock.cpp", @@ -464,7 +480,6 @@ ohos_unittest("KVDBGeneralStoreAbnormalTest") { include_dirs = [ "${data_service_path}/service/common", "${data_service_path}/service/rdb", - "${data_service_path}/service/waterversion", "${data_service_path}/adapter/include", "${data_service_path}/app/src", "${data_service_path}/framework/include", @@ -481,9 +496,11 @@ ohos_unittest("KVDBGeneralStoreAbnormalTest") { "${data_service_path}/service/data_share", "${data_service_path}/service/matrix/include/", "${data_service_path}/service/kvdb", - "${data_service_path}/service/object/", + "${data_service_path}/service/object/include", "${data_service_path}/service/permission/include", "${data_service_path}/service/test/mock", + "${data_service_path}/adapter/include/communicator", + "${data_service_path}/adapter/include/dfx", ] configs = [] @@ -499,6 +516,7 @@ ohos_unittest("KVDBGeneralStoreAbnormalTest") { "access_token:libaccesstoken_sdk", "access_token:libnativetoken", "c_utils:utils", + "device_manager:devicemanagersdk", "googletest:gmock_main", "googletest:gtest_main", "hilog:libhilog", @@ -509,7 +527,6 @@ ohos_unittest("KVDBGeneralStoreAbnormalTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", ] @@ -552,8 +569,7 @@ ohos_unittest("RdbResultSetImplTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", - "${data_service_path}/adapter/utils:distributeddata_utils_static", + "${data_service_path}/adapter/utils:distributeddata_utils", "${data_service_path}/framework:distributeddatasvcfwk", "${kv_store_distributeddb_path}:distributeddb", "${relational_store_inner_api_path}:native_rdb_static", @@ -568,7 +584,6 @@ ohos_unittest("RdbServiceTest") { "${data_service_path}/service/rdb/cache_cursor.cpp", "${data_service_path}/service/rdb/rdb_asset_loader.cpp", "${data_service_path}/service/rdb/rdb_cloud.cpp", - "${data_service_path}/service/rdb/rdb_cloud_data_translate.cpp", "${data_service_path}/service/rdb/rdb_cursor.cpp", "${data_service_path}/service/rdb/rdb_general_store.cpp", "${data_service_path}/service/rdb/rdb_notifier_proxy.cpp", @@ -615,8 +630,7 @@ ohos_unittest("RdbServiceTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", - "${data_service_path}/adapter/utils:distributeddata_utils_static", + "${data_service_path}/adapter/utils:distributeddata_utils", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", "${kv_store_distributeddb_path}:distributeddb", @@ -628,9 +642,9 @@ ohos_unittest("RdbServiceTest") { ohos_unittest("ObjectAssetLoaderTest") { module_out_path = module_output_path sources = [ - "../object/object_asset_loader.cpp", - "../object/object_asset_machine.cpp", - "../object/object_snapshot.cpp", + "../object/src/object_asset_loader.cpp", + "../object/src/object_asset_machine.cpp", + "../object/src/object_snapshot.cpp", "object_asset_loader_test.cpp", ] @@ -653,7 +667,6 @@ ohos_unittest("ObjectAssetLoaderTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", "//third_party/googletest:gtest_main", @@ -668,8 +681,8 @@ ohos_unittest("ObjectAssetLoaderTest") { ohos_unittest("ObjectAssetMachineTest") { module_out_path = module_output_path sources = [ - "../object/object_asset_loader.cpp", - "../object/object_asset_machine.cpp", + "../object/src/object_asset_loader.cpp", + "../object/src/object_asset_machine.cpp", "object_asset_machine_test.cpp", ] @@ -692,7 +705,6 @@ ohos_unittest("ObjectAssetMachineTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", "//third_party/googletest:gtest_main", @@ -700,9 +712,14 @@ ohos_unittest("ObjectAssetMachineTest") { } ohos_unittest("ObjectDmsHandlerTest") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } module_out_path = module_output_path sources = [ - "../object/object_dms_handler.cpp", + "../object/src/object_dms_handler.cpp", "object_dms_handler_test.cpp", ] @@ -719,7 +736,7 @@ ohos_unittest("ObjectDmsHandlerTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", + "${data_service_path}/adapter/communicator:distributeddata_communicator", "${data_service_path}/framework:distributeddatasvcfwk", "//third_party/googletest:gtest_main", ] @@ -734,12 +751,12 @@ ohos_unittest("ObjectManagerTest") { module_out_path = module_output_path sources = [ "${data_service_path}/service/common/value_proxy.cpp", - "../object/object_asset_loader.cpp", - "../object/object_asset_machine.cpp", - "../object/object_callback_proxy.cpp", - "../object/object_data_listener.cpp", - "../object/object_manager.cpp", - "../object/object_snapshot.cpp", + "../object/src/object_asset_loader.cpp", + "../object/src/object_asset_machine.cpp", + "../object/src/object_callback_proxy.cpp", + "../object/src/object_data_listener.cpp", + "../object/src/object_manager.cpp", + "../object/src/object_snapshot.cpp", "mock/kv_store_nb_delegate_mock.cpp", "object_manager_test.cpp", ] @@ -749,6 +766,7 @@ ohos_unittest("ObjectManagerTest") { "${data_service_path}/service/common", "${dataobject_path}/frameworks/innerkitsimpl/include/common", "${dataobject_path}/interfaces/innerkits", + "${data_service_path}/adapter/include/utils", ] configs = [ ":module_private_config" ] @@ -757,6 +775,7 @@ ohos_unittest("ObjectManagerTest") { "access_token:libaccesstoken_sdk", "access_token:libtokenid_sdk", "c_utils:utils", + "data_object:distributeddataobject_impl", "dfs_service:cloudsync_asset_kit_inner", "dfs_service:distributed_file_daemon_kit_inner", "dmsfwk:distributed_sdk", @@ -769,7 +788,6 @@ ohos_unittest("ObjectManagerTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", "//third_party/googletest:gtest_main", @@ -784,9 +802,9 @@ ohos_unittest("ObjectManagerTest") { ohos_unittest("ObjectSnapshotTest") { module_out_path = module_output_path sources = [ - "../object/object_asset_loader.cpp", - "../object/object_asset_machine.cpp", - "../object/object_snapshot.cpp", + "../object/src/object_asset_loader.cpp", + "../object/src/object_asset_machine.cpp", + "../object/src/object_snapshot.cpp", "object_snapshot_test.cpp", ] @@ -809,7 +827,6 @@ ohos_unittest("ObjectSnapshotTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", "//third_party/googletest:gtest_main", @@ -836,6 +853,8 @@ ohos_unittest("MetaDataTest") { "${kv_store_path}/frameworks/innerkitsimpl/kvdb/include", "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/include", "${kv_store_path}/frameworks/innerkitsimpl/distributeddatasvc/include", + "${data_service_path}/adapter/include/communicator", + "${data_service_path}/adapter/include/dfx", ] configs = [ ":module_private_config" ] @@ -849,13 +868,15 @@ ohos_unittest("MetaDataTest") { "hilog:libhilog", "hisysevent:libhisysevent", "ipc:ipc_core", + "json:nlohmann_json_static", "kv_store:distributeddata_inner", ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", + "${data_service_path}/adapter/account:distributeddata_account", + "${data_service_path}/adapter/communicator:distributeddata_communicator", "${data_service_path}/framework:distributeddatasvcfwk", - "${data_service_path}/service:distributeddatasvc", + "${data_service_path}/service/kvdb:distributeddata_kvdb", "${kv_store_path}/frameworks/libs/distributeddb:distributeddb", "//third_party/googletest:gtest_main", ] @@ -877,6 +898,7 @@ ohos_unittest("UdmfRunTimeStoreTest") { "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/include", "${kv_store_path}/frameworks/innerkitsimpl/distributeddatasvc/include", "${kv_store_path}/frameworks/innerkitsimpl/kvdb/include", + "${data_service_path}/adapter/include/dfx", ] configs = [ ":module_private_config" ] @@ -899,8 +921,7 @@ ohos_unittest("UdmfRunTimeStoreTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", - "${data_service_path}/adapter/communicator:distributeddata_communicator_static", + "${data_service_path}/adapter/communicator:distributeddata_communicator", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", "${data_service_path}/service/udmf:udmf_server", @@ -910,82 +931,12 @@ ohos_unittest("UdmfRunTimeStoreTest") { ] } -ohos_unittest("WaterVersionManagerTest") { - module_out_path = module_output_path +ohos_unittest("DataShareServiceImplTest") { sanitize = { cfi = true cfi_cross_dso = true debug = false } - sources = [ - "${data_service_path}/service/backup/src/backup_manager.cpp", - "${data_service_path}/service/bootstrap/src/bootstrap.cpp", - "${data_service_path}/service/config/src/config_factory.cpp", - "${data_service_path}/service/config/src/model/app_id_mapping_config.cpp", - "${data_service_path}/service/config/src/model/backup_config.cpp", - "${data_service_path}/service/config/src/model/checker_config.cpp", - "${data_service_path}/service/config/src/model/cloud_config.cpp", - "${data_service_path}/service/config/src/model/component_config.cpp", - "${data_service_path}/service/config/src/model/directory_config.cpp", - "${data_service_path}/service/config/src/model/global_config.cpp", - "${data_service_path}/service/config/src/model/network_config.cpp", - "${data_service_path}/service/config/src/model/protocol_config.cpp", - "${data_service_path}/service/waterversion/water_version_manager.cpp", - "mock/checker_mock.cpp", - "mock/db_change_data_mock.cpp", - "mock/db_store_mock.cpp", - "water_version_manager_test.cpp", - ] - - include_dirs = [ - "${data_service_path}/service/backup/include", - "${data_service_path}/service/bootstrap/include", - "${data_service_path}/service/cloud", - "${data_service_path}/service/common", - "${data_service_path}/service/config/include", - "${data_service_path}/service/crypto/include", - "${data_service_path}/service/dumper/include", - "${data_service_path}/service/kvdb", - "${data_service_path}/service/matrix/include", - "${data_service_path}/service/object", - "${data_service_path}/service/permission/include", - "${data_service_path}/service/rdb", - "${data_service_path}/service/waterversion", - "${data_service_path}/adapter/include/communicator", - "${data_service_path}/adapter/include", - "${data_service_path}/app/src", - "${data_service_path}/framework/include", - ] - - configs = [ ":module_private_config" ] - - external_deps = [ - "access_token:libaccesstoken_sdk", - "access_token:libnativetoken", - "access_token:libtoken_setproc", - "access_token:libtokenid_sdk", - "c_utils:utils", - "device_auth:deviceauth_sdk", - "device_manager:devicemanagersdk", - "dfs_service:cloudsync_asset_kit_inner", - "dfs_service:distributed_file_daemon_kit_inner", - "dsoftbus:softbus_client", - "hilog:libhilog", - "ipc:ipc_core", - "kv_store:distributeddata_inner", - ] - - deps = [ - "${data_service_path}/adapter:distributeddata_adapter", - "${data_service_path}/framework:distributeddatasvcfwk", - "${data_service_path}/service:distributeddatasvc", - "${kv_store_distributeddb_path}:distributeddb", - "//third_party/googletest:gtest_main", - "//third_party/openssl:libcrypto_shared", - ] -} - -ohos_unittest("DataShareServiceImplTest") { module_out_path = module_output_path include_dirs = [ @@ -999,7 +950,6 @@ ohos_unittest("DataShareServiceImplTest") { "${data_service_path}/service/common/xcollie.cpp", "${data_service_path}/service/crypto/src/crypto_manager.cpp", "${data_service_path}/service/data_share/common/app_connect_manager.cpp", - "${data_service_path}/service/data_share/common/base64_utils.cpp", "${data_service_path}/service/data_share/common/bundle_mgr_proxy.cpp", "${data_service_path}/service/data_share/common/db_delegate.cpp", "${data_service_path}/service/data_share/common/div_strategy.cpp", @@ -1022,6 +972,8 @@ ohos_unittest("DataShareServiceImplTest") { "${data_service_path}/service/data_share/data_share_service_stub.cpp", "${data_service_path}/service/data_share/data_share_silent_config.cpp", "${data_service_path}/service/data_share/data_share_types_util.cpp", + "${data_service_path}/service/data_share/dfx/hiview_adapter.cpp", + "${data_service_path}/service/data_share/dfx/hiview_fault_adapter.cpp", "${data_service_path}/service/data_share/strategies/data_proxy/load_config_from_data_proxy_node_strategy.cpp", "${data_service_path}/service/data_share/strategies/data_share/load_config_from_data_share_bundle_info_strategy.cpp", "${data_service_path}/service/data_share/strategies/general/check_is_data_proxy_strategy.cpp", @@ -1040,6 +992,7 @@ ohos_unittest("DataShareServiceImplTest") { "${data_service_path}/service/data_share/subscriber_managers/rdb_subscriber_manager.cpp", "${data_service_path}/service/data_share/sys_event_subscriber.cpp", "${data_service_path}/service/kvdb/user_delegate.cpp", + "${data_service_path}/service/permission/src/permission_validator.cpp", "${data_service_path}/service/permission/src/permit_delegate.cpp", "data_share_obs_proxy_test.cpp", "data_share_profile_config_test.cpp", @@ -1082,6 +1035,7 @@ ohos_unittest("DataShareServiceImplTest") { "hisysevent:libhisysevent", "huks:libhukssdk", "ipc:ipc_core", + "kv_store:distributeddata_inner", "kv_store:distributeddb", "relational_store:native_rdb", "relational_store:rdb_data_share_adapter", @@ -1091,11 +1045,9 @@ ohos_unittest("DataShareServiceImplTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", - "${data_service_path}/adapter/utils:distributeddata_utils_static", + "${data_service_path}/adapter/utils:distributeddata_utils", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", - "${data_service_path}/service/data_share:data_share_service", "${kv_store_distributeddb_path}:distributeddb", "//third_party/googletest:gtest_main", ] @@ -1105,17 +1057,6 @@ ohos_unittest("KvdbServiceImplTest") { module_out_path = module_output_path sources = [ "${data_service_path}/app/src/kvstore_meta_manager.cpp", - "${data_service_path}/service/common/value_proxy.cpp", - "${data_service_path}/service/kvdb/auth_delegate.cpp", - "${data_service_path}/service/kvdb/kvdb_general_store.cpp", - "${data_service_path}/service/kvdb/kvdb_notifier_proxy.cpp", - "${data_service_path}/service/kvdb/kvdb_watcher.cpp", - "${data_service_path}/service/kvdb/query_helper.cpp", - "${data_service_path}/service/kvdb/upgrade.cpp", - "${data_service_path}/service/kvdb/user_delegate.cpp", - "${data_service_path}/service/rdb/rdb_cloud.cpp", - "${data_service_path}/service/rdb/rdb_query.cpp", - "${data_service_path}/service/waterversion/water_version_manager.cpp", "kvdb_service_impl_test.cpp", "kvdb_service_test.cpp", ] @@ -1127,6 +1068,8 @@ ohos_unittest("KvdbServiceImplTest") { "${kv_store_path}/frameworks/innerkitsimpl/kvdb/include", "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/include", "${kv_store_path}/frameworks/innerkitsimpl/distributeddatasvc/include", + "${data_service_path}/adapter/include/communicator", + "${data_service_path}/adapter/include/dfx", ] configs = [ ":module_private_config" ] @@ -1151,9 +1094,10 @@ ohos_unittest("KvdbServiceImplTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", + "${data_service_path}/adapter/account:distributeddata_account", + "${data_service_path}/adapter/communicator:distributeddata_communicator", "${data_service_path}/framework:distributeddatasvcfwk", - "${data_service_path}/service:distributeddatasvc", + "${data_service_path}/service/kvdb:distributeddata_kvdb", "${kv_store_path}/frameworks/libs/distributeddb:distributeddb", "//third_party/googletest:gtest_main", ] @@ -1229,6 +1173,88 @@ ohos_unittest("UdmfServiceImplTest") { ] } +ohos_unittest("UdmfCheckerManagerTest") { + module_out_path = module_output_path + sources = [ + "${data_service_path}/service/udmf/permission/checker_manager.cpp", + "udmf_checker_manager_test.cpp", + ] + + include_dirs = [ + "${data_service_path}/adapter/include/account", + "${data_service_path}/adapter/include/communicator", + "${data_service_path}/app/src", + "${data_service_path}/service/kvdb", + "${data_service_path}/service/udmf", + "${data_service_path}/service/udmf/lifecycle", + "${data_service_path}/service/udmf/permission", + "${data_service_path}/service/udmf/store", + ] + + cflags = [ + "-Dprivate=public", + "-Dprotected=public", + ] + + deps = [ + "${data_service_path}/adapter/communicator:distributeddata_communicator", + "${data_service_path}/framework:distributeddatasvcfwk", + "${data_service_path}/service:distributeddatasvc", + ] + + external_deps = [ + "ability_base:base", + "ability_base:want", + "ability_runtime:uri_permission_mgr", + "access_token:libaccesstoken_sdk", + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "app_file_service:fileuri_native", + "app_file_service:remote_file_share_native", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "dataclassification:data_transit_mgr", + "dsoftbus:softbus_client", + "googletest:gtest_main", + "hilog:libhilog", + "hisysevent:libhisysevent", + "image_framework:image", + "ipc:ipc_core", + "kv_store:distributeddata_inner", + "openssl:libcrypto_shared", + "udmf:udmf_client", + "udmf:utd_client", + ] +} + +ohos_unittest("PermissionValidatorTest") { + module_out_path = module_output_path + + include_dirs = [ + "${data_service_path}/service/permission/include", + "${data_service_path}/framework/include", + ] + + sources = [ + "${data_service_path}/service/permission/src/permission_validator.cpp", + "permission_validator_test.cpp", + ] + + deps = [ + "${data_service_path}/adapter/utils:distributeddata_utils", + "${data_service_path}/framework:distributeddatasvcfwk", + ] + + external_deps = [ + "access_token:libaccesstoken_sdk", + "c_utils:utils", + "googletest:gtest_main", + "hilog:libhilog", + "kv_store:distributeddata_inner", + ] + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] +} + ############################################################################### group("unittest") { testonly = true @@ -1239,30 +1265,59 @@ group("unittest") { deps += [ ":ConfigFactoryTest" ] } + if (datamgr_service_cloud) { + deps += [ + ":CloudDataTest", + ":CloudServiceImplTest", + ":CloudTest", + ] + } + + if (datamgr_service_udmf) { + deps += [ + ":UdmfCheckerManagerTest", + ":UdmfRunTimeStoreTest", + ":UdmfServiceImplTest", + ] + } + + if (datamgr_service_object) { + deps += [ + ":ObjectAssetLoaderTest", + ":ObjectAssetMachineTest", + ":ObjectDmsHandlerTest", + ":ObjectManagerTest", + ":ObjectSnapshotTest", + ] + } + + if (datamgr_service_rdb) { + deps += [ + ":RdbResultSetImplTest", + ":RdbServiceTest", + ] + } + + if (datamgr_service_kvdb) { + deps += [ + ":KVDBGeneralStoreAbnormalTest", + ":KVDBGeneralStoreTest", + ":KvdbServiceImplTest", + ] + } + + if (datamgr_service_data_share) { + deps += [ ":DataShareServiceImplTest" ] + } + deps += [ - ":CloudDataTest", - ":CloudServiceImplTest", - ":CloudTest", ":CryptoManagerTest", - ":DataShareServiceImplTest", ":DeviceMatrixTest", ":DirectoryManagerTest", ":DumpHelperTest", - ":KVDBGeneralStoreAbnormalTest", - ":KVDBGeneralStoreTest", - ":KvdbServiceImplTest", ":MetaDataTest", - ":ObjectAssetLoaderTest", - ":ObjectAssetMachineTest", - ":ObjectDmsHandlerTest", - ":ObjectManagerTest", - ":ObjectSnapshotTest", - ":RdbResultSetImplTest", - ":RdbServiceTest", - ":UdmfRunTimeStoreTest", - ":UdmfServiceImplTest", + ":PermissionValidatorTest", ":ValueProxyServiceTest", - ":WaterVersionManagerTest", ] } ############################################################################### 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 29932a6d3d4bd873567fc3c1dad3081f1b895121..7b9d2acf753a2da508fed0e387157d91093dabe7 100644 --- a/datamgr_service/services/distributeddataservice/service/test/cloud_data_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/cloud_data_test.cpp @@ -27,6 +27,7 @@ #include "cloud/cloud_share_event.h" #include "cloud/make_query_event.h" #include "cloud/schema_meta.h" +#include "cloud_data_translate.h" #include "cloud_service_impl.h" #include "cloud_types.h" #include "cloud_types_util.h" @@ -42,6 +43,7 @@ #include "metadata/store_meta_data_local.h" #include "mock/db_store_mock.h" #include "mock/general_store_mock.h" +#include "network_adapter.h" #include "rdb_query.h" #include "rdb_service.h" #include "rdb_service_impl.h" @@ -62,6 +64,7 @@ using SharingCfm = OHOS::CloudData::SharingUtil::SharingCfm; using Confirmation = OHOS::CloudData::Confirmation; using CenterCode = OHOS::DistributedData::SharingCenter::SharingCode; using Status = OHOS::CloudData::CloudService::Status; +using CloudSyncScene = OHOS::CloudData::CloudServiceImpl::CloudSyncScene; using GenErr = OHOS::DistributedData::GeneralError; uint64_t g_selfTokenID = 0; @@ -84,12 +87,14 @@ static constexpr const char *TEST_CLOUD_BUNDLE = "test_cloud_bundleName"; static constexpr const char *TEST_CLOUD_APPID = "test_cloud_appid"; static constexpr const char *TEST_CLOUD_STORE = "test_cloud_store"; static constexpr const char *TEST_CLOUD_ID = "test_cloud_id"; +static constexpr const char *TEST_CLOUD_TABLE = "teat_cloud_table"; static constexpr const char *TEST_CLOUD_DATABASE_ALIAS_1 = "test_cloud_database_alias_1"; static constexpr const char *TEST_CLOUD_DATABASE_ALIAS_2 = "test_cloud_database_alias_2"; static constexpr const char *PERMISSION_CLOUDDATA_CONFIG = "ohos.permission.CLOUDDATA_CONFIG"; static constexpr const char *PERMISSION_GET_NETWORK_INFO = "ohos.permission.GET_NETWORK_INFO"; static constexpr const char *PERMISSION_DISTRIBUTED_DATASYNC = "ohos.permission.DISTRIBUTED_DATASYNC"; static constexpr const char *PERMISSION_ACCESS_SERVICE_DM = "ohos.permission.ACCESS_SERVICE_DM"; +static constexpr const char *PERMISSION_MANAGE_LOCAL_ACCOUNTS = "ohos.permission.MANAGE_LOCAL_ACCOUNTS"; PermissionDef GetPermissionDef(const std::string &permission) { PermissionDef def = { .permissionName = permission, @@ -134,7 +139,7 @@ protected: class CloudServerMock : public CloudServer { public: - CloudInfo GetServerInfo(int32_t userId, bool needSpaceInfo) override; + std::pair GetServerInfo(int32_t userId, bool needSpaceInfo) override; std::pair GetAppSchema(int32_t userId, const std::string &bundleName) override; virtual ~CloudServerMock() = default; static constexpr uint64_t REMAINSPACE = 1000; @@ -142,7 +147,7 @@ public: static constexpr int32_t INVALID_USER_ID = -1; }; -CloudInfo CloudServerMock::GetServerInfo(int32_t userId, bool needSpaceInfo) +std::pair CloudServerMock::GetServerInfo(int32_t userId, bool needSpaceInfo) { CloudInfo cloudInfo; cloudInfo.user = userId; @@ -158,7 +163,7 @@ CloudInfo CloudServerMock::GetServerInfo(int32_t userId, bool needSpaceInfo) appInfo.cloudSwitch = true; cloudInfo.apps[TEST_CLOUD_BUNDLE] = std::move(appInfo); - return cloudInfo; + return { E_OK, cloudInfo }; } std::pair CloudServerMock::GetAppSchema(int32_t userId, const std::string &bundleName) @@ -188,7 +193,7 @@ void CloudDataTest::InitMetaData() metaData_.appId = TEST_CLOUD_APPID; metaData_.bundleName = TEST_CLOUD_BUNDLE; metaData_.tokenId = OHOS::IPCSkeleton::GetCallingTokenID(); - metaData_.user = std::to_string(DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(metaData_.tokenId)); + metaData_.user = std::to_string(AccountDelegate::GetInstance()->GetUserByToken(metaData_.tokenId)); metaData_.area = OHOS::DistributedKv::EL1; metaData_.instanceId = 0; metaData_.isAutoSync = true; @@ -227,7 +232,7 @@ void CloudDataTest::InitSchemaMeta() void CloudDataTest::InitCloudInfo() { - cloudInfo_.user = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(IPCSkeleton::GetCallingTokenID()); + cloudInfo_.user = AccountDelegate::GetInstance()->GetUserByToken(IPCSkeleton::GetCallingTokenID()); cloudInfo_.id = TEST_CLOUD_ID; cloudInfo_.enableCloud = true; @@ -242,7 +247,7 @@ void CloudDataTest::InitCloudInfo() void CloudDataTest::SetUpTestCase(void) { - MetaDataManager::GetInstance().Initialize(dbStoreMock_, nullptr); + MetaDataManager::GetInstance().Initialize(dbStoreMock_, nullptr, ""); MetaDataManager::GetInstance().SetSyncer([](const auto &, auto) { DeviceMatrix::GetInstance().OnChanged(DeviceMatrix::META_STORE_MASK); }); @@ -252,11 +257,13 @@ void CloudDataTest::SetUpTestCase(void) HapPolicyParams policy = { .apl = APL_SYSTEM_BASIC, .domain = "test.domain", .permList = { GetPermissionDef(PERMISSION_CLOUDDATA_CONFIG), GetPermissionDef(PERMISSION_GET_NETWORK_INFO), - GetPermissionDef(PERMISSION_DISTRIBUTED_DATASYNC), GetPermissionDef(PERMISSION_ACCESS_SERVICE_DM) }, + GetPermissionDef(PERMISSION_DISTRIBUTED_DATASYNC), GetPermissionDef(PERMISSION_ACCESS_SERVICE_DM), + GetPermissionDef(PERMISSION_MANAGE_LOCAL_ACCOUNTS) }, .permStateList = { GetPermissionStateFull(PERMISSION_CLOUDDATA_CONFIG), GetPermissionStateFull(PERMISSION_GET_NETWORK_INFO), GetPermissionStateFull(PERMISSION_DISTRIBUTED_DATASYNC), - GetPermissionStateFull(PERMISSION_ACCESS_SERVICE_DM) } }; + GetPermissionStateFull(PERMISSION_ACCESS_SERVICE_DM), + GetPermissionStateFull(PERMISSION_MANAGE_LOCAL_ACCOUNTS)} }; g_selfTokenID = GetSelfTokenID(); AllocHapToken(policy); size_t max = 12; @@ -271,7 +278,7 @@ void CloudDataTest::SetUpTestCase(void) InitCloudInfo(); InitMetaData(); InitSchemaMeta(); - DeviceManagerAdapter::GetInstance().SetNet(DeviceManagerAdapter::WIFI); + NetworkAdapter::GetInstance().SetNet(NetworkAdapter::WIFI); } void CloudDataTest::TearDownTestCase() @@ -288,6 +295,7 @@ void CloudDataTest::SetUp() void CloudDataTest::TearDown() { + EventCenter::GetInstance().Unsubscribe(CloudEvent::LOCAL_CHANGE); MetaDataManager::GetInstance().DelMeta(cloudInfo_.GetKey(), true); MetaDataManager::GetInstance().DelMeta(metaData_.GetKey(), true); MetaDataManager::GetInstance().DelMeta(cloudInfo_.GetSchemaKey(TEST_CLOUD_BUNDLE), true); @@ -302,10 +310,9 @@ void CloudDataTest::TearDown() */ HWTEST_F(CloudDataTest, GetSchema, TestSize.Level0) { - ZLOGI("CloudDataTest start"); auto cloudServerMock = std::make_shared(); - auto user = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(OHOS::IPCSkeleton::GetCallingTokenID()); - auto cloudInfo = cloudServerMock->GetServerInfo(user, true); + auto user = AccountDelegate::GetInstance()->GetUserByToken(OHOS::IPCSkeleton::GetCallingTokenID()); + auto [status, cloudInfo] = cloudServerMock->GetServerInfo(user, true); ASSERT_TRUE(MetaDataManager::GetInstance().DelMeta(cloudInfo.GetSchemaKey(TEST_CLOUD_BUNDLE), true)); SchemaMeta schemaMeta; ASSERT_FALSE(MetaDataManager::GetInstance().LoadMeta(cloudInfo.GetSchemaKey(TEST_CLOUD_BUNDLE), schemaMeta, true)); @@ -324,7 +331,6 @@ HWTEST_F(CloudDataTest, GetSchema, TestSize.Level0) */ HWTEST_F(CloudDataTest, QueryStatistics001, TestSize.Level0) { - ZLOGI("CloudDataTest QueryStatistics001 start"); // prepare MetaDta MetaDataManager::GetInstance().DelMeta(cloudInfo_.GetKey(), true); @@ -341,7 +347,6 @@ HWTEST_F(CloudDataTest, QueryStatistics001, TestSize.Level0) */ HWTEST_F(CloudDataTest, QueryStatistics002, TestSize.Level0) { - ZLOGI("CloudDataTest QueryStatistics002 start"); // prepare MetaDta MetaDataManager::GetInstance().DelMeta(cloudInfo_.GetSchemaKey(TEST_CLOUD_BUNDLE), true); MetaDataManager::GetInstance().SaveMeta(cloudInfo_.GetKey(), cloudInfo_, true); @@ -368,7 +373,6 @@ HWTEST_F(CloudDataTest, QueryStatistics002, TestSize.Level0) */ HWTEST_F(CloudDataTest, QueryStatistics003, TestSize.Level0) { - ZLOGI("CloudDataTest QueryStatistics003 start"); // Construct the statisticInfo data auto creator = [](const StoreMetaData &metaData) -> GeneralStore* { auto store = new (std::nothrow) GeneralStoreMock(); @@ -404,8 +408,6 @@ HWTEST_F(CloudDataTest, QueryStatistics003, TestSize.Level0) */ HWTEST_F(CloudDataTest, QueryStatistics004, TestSize.Level0) { - ZLOGI("CloudDataTest QueryStatistics004 start"); - // Construct the statisticInfo data auto creator = [](const StoreMetaData &metaData) -> GeneralStore* { auto store = new (std::nothrow) GeneralStoreMock(); @@ -439,7 +441,6 @@ HWTEST_F(CloudDataTest, QueryStatistics004, TestSize.Level0) */ HWTEST_F(CloudDataTest, QueryLastSyncInfo001, TestSize.Level0) { - ZLOGI("CloudDataTest QueryLastSyncInfo001 start"); auto [status, result] = cloudServiceImpl_->QueryLastSyncInfo("accountId", TEST_CLOUD_BUNDLE, TEST_CLOUD_DATABASE_ALIAS_1); EXPECT_EQ(status, CloudData::CloudService::SUCCESS); @@ -454,7 +455,6 @@ HWTEST_F(CloudDataTest, QueryLastSyncInfo001, TestSize.Level0) */ HWTEST_F(CloudDataTest, QueryLastSyncInfo002, TestSize.Level0) { - ZLOGI("CloudDataTest QueryLastSyncInfo002 start"); auto [status, result] = cloudServiceImpl_->QueryLastSyncInfo(TEST_CLOUD_ID, "bundleName", TEST_CLOUD_DATABASE_ALIAS_1); EXPECT_EQ(status, CloudData::CloudService::Status::INVALID_ARGUMENT); @@ -469,7 +469,6 @@ HWTEST_F(CloudDataTest, QueryLastSyncInfo002, TestSize.Level0) */ HWTEST_F(CloudDataTest, QueryLastSyncInfo003, TestSize.Level0) { - ZLOGI("CloudDataTest QueryLastSyncInfo003 start"); auto [status, result] = cloudServiceImpl_->QueryLastSyncInfo(TEST_CLOUD_ID, TEST_CLOUD_BUNDLE, "storeId"); EXPECT_EQ(status, CloudData::CloudService::INVALID_ARGUMENT); EXPECT_TRUE(result.empty()); @@ -483,7 +482,6 @@ HWTEST_F(CloudDataTest, QueryLastSyncInfo003, TestSize.Level0) */ HWTEST_F(CloudDataTest, QueryLastSyncInfo004, TestSize.Level0) { - ZLOGI("CloudDataTest QueryLastSyncInfo004 start"); auto ret = cloudServiceImpl_->DisableCloud(TEST_CLOUD_ID); EXPECT_EQ(ret, CloudData::CloudService::SUCCESS); cloudServiceImpl_->OnReady(DeviceManagerAdapter::CLOUD_DEVICE_UUID); @@ -505,7 +503,6 @@ HWTEST_F(CloudDataTest, QueryLastSyncInfo004, TestSize.Level0) */ HWTEST_F(CloudDataTest, QueryLastSyncInfo005, TestSize.Level0) { - ZLOGI("CloudDataTest QueryLastSyncInfo005 start"); std::map switches; switches.emplace(TEST_CLOUD_ID, true); CloudInfo info; @@ -530,7 +527,6 @@ HWTEST_F(CloudDataTest, QueryLastSyncInfo005, TestSize.Level0) */ HWTEST_F(CloudDataTest, QueryLastSyncInfo006, TestSize.Level0) { - ZLOGI("CloudDataTest QueryLastSyncInfo006 start"); MetaDataManager::GetInstance().DelMeta(cloudInfo_.GetSchemaKey(TEST_CLOUD_BUNDLE), true); auto [status, result] = cloudServiceImpl_->QueryLastSyncInfo(TEST_CLOUD_ID, TEST_CLOUD_BUNDLE, TEST_CLOUD_DATABASE_ALIAS_1); @@ -777,7 +773,7 @@ HWTEST_F(CloudDataTest, Clean002, TestSize.Level0) ret = cloudServiceImpl_->Clean(TEST_CLOUD_ID, actions); EXPECT_EQ(ret, CloudData::CloudService::SUCCESS); MetaDataManager::GetInstance().DelMeta(metaData_.GetKey(), true); - metaData_.user = std::to_string(DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(metaData_.tokenId)); + metaData_.user = std::to_string(AccountDelegate::GetInstance()->GetUserByToken(metaData_.tokenId)); MetaDataManager::GetInstance().DelMeta(metaData_.GetKeyLocal(), true); } @@ -888,7 +884,6 @@ HWTEST_F(CloudDataTest, Offline001, TestSize.Level0) */ HWTEST_F(CloudDataTest, CloudShare001, TestSize.Level0) { - ZLOGI("weisx CloudShare start"); StoreInfo storeInfo{ OHOS::IPCSkeleton::GetCallingTokenID(), TEST_CLOUD_BUNDLE, TEST_CLOUD_STORE, 0 }; std::pair> result; CloudShareEvent::Callback asyncCallback = [&result](int32_t status, std::shared_ptr cursor) { @@ -1837,14 +1832,14 @@ HWTEST_F(CloudDataTest, GetAppSchemaFromServer, TestSize.Level0) { int32_t userId = CloudServerMock::INVALID_USER_ID; std::string bundleName; - DeviceManagerAdapter::GetInstance().SetNet(DeviceManagerAdapter::NONE); - DeviceManagerAdapter::GetInstance().expireTime_ = + NetworkAdapter::GetInstance().SetNet(NetworkAdapter::NONE); + NetworkAdapter::GetInstance().expireTime_ = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()) .count() + 1000; auto [status, meta] = cloudServiceImpl_->GetAppSchemaFromServer(userId, bundleName); EXPECT_EQ(status, CloudData::CloudService::NETWORK_ERROR); - DeviceManagerAdapter::GetInstance().SetNet(DeviceManagerAdapter::WIFI); + NetworkAdapter::GetInstance().SetNet(NetworkAdapter::WIFI); std::tie(status, meta) = cloudServiceImpl_->GetAppSchemaFromServer(userId, bundleName); EXPECT_EQ(status, CloudData::CloudService::SCHEMA_INVALID); userId = 100; @@ -1864,7 +1859,6 @@ HWTEST_F(CloudDataTest, GetAppSchemaFromServer, TestSize.Level0) */ HWTEST_F(CloudDataTest, OnAppUninstall, TestSize.Level0) { - ZLOGI("weisx test OnAppUninstall 111"); CloudData::CloudServiceImpl::CloudStatic cloudStatic; int32_t userId = 1001; Subscription sub; @@ -1891,19 +1885,18 @@ HWTEST_F(CloudDataTest, OnAppUninstall, TestSize.Level0) */ HWTEST_F(CloudDataTest, GetCloudInfo001, TestSize.Level0) { - ZLOGI("weisx test OnAppUninstall 111"); int32_t userId = 1000; auto [status, cloudInfo] = cloudServiceImpl_->GetCloudInfo(userId); EXPECT_EQ(status, CloudData::CloudService::ERROR); - DeviceManagerAdapter::GetInstance().SetNet(DeviceManagerAdapter::NONE); - DeviceManagerAdapter::GetInstance().expireTime_ = + NetworkAdapter::GetInstance().SetNet(NetworkAdapter::NONE); + NetworkAdapter::GetInstance().expireTime_ = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()) .count() + 1000; MetaDataManager::GetInstance().DelMeta(cloudInfo_.GetKey(), true); std::tie(status, cloudInfo) = cloudServiceImpl_->GetCloudInfo(cloudInfo_.user); EXPECT_EQ(status, CloudData::CloudService::NETWORK_ERROR); - DeviceManagerAdapter::GetInstance().SetNet(DeviceManagerAdapter::WIFI); + NetworkAdapter::GetInstance().SetNet(NetworkAdapter::WIFI); } /** @@ -1966,23 +1959,22 @@ HWTEST_F(CloudDataTest, InitSubTask, TestSize.Level0) */ HWTEST_F(CloudDataTest, DoSubscribe, TestSize.Level0) { - ZLOGI("CloudServiceImplTest DoSubscribe start"); Subscription sub; sub.userId = cloudInfo_.user; MetaDataManager::GetInstance().SaveMeta(sub.GetKey(), sub, true); int user = cloudInfo_.user; - auto status = cloudServiceImpl_->DoSubscribe(user); + auto status = cloudServiceImpl_->DoSubscribe(user, CloudSyncScene::ENABLE_CLOUD); EXPECT_FALSE(status); sub.id = "testId"; MetaDataManager::GetInstance().SaveMeta(sub.GetKey(), sub, true); - status = cloudServiceImpl_->DoSubscribe(user); + status = cloudServiceImpl_->DoSubscribe(user, CloudSyncScene::ENABLE_CLOUD); EXPECT_FALSE(status); sub.id = TEST_CLOUD_APPID; MetaDataManager::GetInstance().SaveMeta(sub.GetKey(), sub, true); - status = cloudServiceImpl_->DoSubscribe(user); + status = cloudServiceImpl_->DoSubscribe(user, CloudSyncScene::ENABLE_CLOUD); EXPECT_FALSE(status); MetaDataManager::GetInstance().DelMeta(cloudInfo_.GetKey(), true); - status = cloudServiceImpl_->DoSubscribe(user); + status = cloudServiceImpl_->DoSubscribe(user, CloudSyncScene::ENABLE_CLOUD); EXPECT_FALSE(status); } @@ -2013,8 +2005,8 @@ HWTEST_F(CloudDataTest, Report, TestSize.Level0) HWTEST_F(CloudDataTest, IsOn, TestSize.Level0) { auto cloudServerMock = std::make_shared(); - auto user = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(OHOS::IPCSkeleton::GetCallingTokenID()); - auto cloudInfo = cloudServerMock->GetServerInfo(user, true); + auto user = AccountDelegate::GetInstance()->GetUserByToken(OHOS::IPCSkeleton::GetCallingTokenID()); + auto [status, cloudInfo] = cloudServerMock->GetServerInfo(user, true); int32_t instanceId = 0; auto ret = cloudInfo.IsOn("", instanceId); EXPECT_FALSE(ret); @@ -2029,8 +2021,8 @@ HWTEST_F(CloudDataTest, IsOn, TestSize.Level0) HWTEST_F(CloudDataTest, IsAllSwitchOff, TestSize.Level0) { auto cloudServerMock = std::make_shared(); - auto user = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(OHOS::IPCSkeleton::GetCallingTokenID()); - auto cloudInfo = cloudServerMock->GetServerInfo(user, true); + auto user = AccountDelegate::GetInstance()->GetUserByToken(OHOS::IPCSkeleton::GetCallingTokenID()); + auto [status, cloudInfo] = cloudServerMock->GetServerInfo(user, true); auto ret = cloudInfo.IsAllSwitchOff(); EXPECT_FALSE(ret); } @@ -2053,7 +2045,7 @@ HWTEST_F(CloudDataTest, GetMinExpireTime, TestSize.Level0) sub.expiresTime.insert_or_assign("test_cloud_bundleName1", expire); EXPECT_EQ(sub.GetMinExpireTime(), expire); } - + /** * @tc.name: GetTableNames * @tc.desc: Test GetTableNames. @@ -2071,5 +2063,124 @@ HWTEST_F(CloudDataTest, GetTableNames, TestSize.Level0) auto tableNames = database.GetTableNames(); EXPECT_EQ(tableNames.size(), 2); } + +/** +* @tc.name: BlobToAssets +* @tc.desc: cloud_data_translate BlobToAsset error test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(CloudDataTest, BlobToAssets, TestSize.Level1) +{ + CloudData::RdbCloudDataTranslate rdbTranslate; + DistributedDB::Asset asset = { + .name = "", + .assetId = "", + .subpath = "", + .uri = "", + .modifyTime = "", + .createTime = "", + .size = "", + .hash = "" + }; + std::vector blob; + auto result = rdbTranslate.BlobToAsset(blob); + EXPECT_EQ(result, asset); + + DistributedDB::Assets assets; + blob = rdbTranslate.AssetsToBlob(assets); + auto results = rdbTranslate.BlobToAssets(blob); + EXPECT_EQ(results, assets); +} + +/** +* @tc.name: GetPriorityLevel001 +* @tc.desc: GetPriorityLevel test +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(CloudDataTest, GetPriorityLevel001, TestSize.Level1) +{ + EventCenter::GetInstance().Subscribe(CloudEvent::LOCAL_CHANGE, [](const Event &event) { + auto &evt = static_cast(event); + auto mode = evt.GetMode(); + EXPECT_EQ(GeneralStore::GetPriorityLevel(GeneralStore::GetHighMode(static_cast(mode))), 2); + }); + DistributedRdb::RdbServiceImpl rdbServiceImpl; + DistributedRdb::RdbSyncerParam param{ .bundleName_ = TEST_CLOUD_BUNDLE, .storeName_ = TEST_CLOUD_STORE }; + DistributedRdb::RdbService::Option option{ .mode = GeneralStore::SyncMode::CLOUD_ClOUD_FIRST, .isAsync = true }; + DistributedRdb::PredicatesMemo memo; + memo.tables_ = { TEST_CLOUD_TABLE }; + rdbServiceImpl.DoCloudSync(param, option, memo, nullptr); +} + +/** +* @tc.name: GetPriorityLevel002 +* @tc.desc: GetPriorityLevel test +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(CloudDataTest, GetPriorityLevel002, TestSize.Level1) +{ + EventCenter::GetInstance().Subscribe(CloudEvent::LOCAL_CHANGE, [](const Event &event) { + auto &evt = static_cast(event); + auto mode = evt.GetMode(); + EXPECT_EQ(GeneralStore::GetPriorityLevel(GeneralStore::GetHighMode(static_cast(mode))), 0); + }); + DistributedRdb::RdbServiceImpl rdbServiceImpl; + DistributedRdb::RdbSyncerParam param{ .bundleName_ = TEST_CLOUD_BUNDLE, .storeName_ = TEST_CLOUD_STORE }; + DistributedRdb::RdbService::Option option{ .mode = GeneralStore::SyncMode::CLOUD_TIME_FIRST, .isAsync = true }; + DistributedRdb::PredicatesMemo memo; + memo.tables_ = { TEST_CLOUD_TABLE }; + rdbServiceImpl.DoCloudSync(param, option, memo, nullptr); +} + +/** +* @tc.name: GetPriorityLevel003 +* @tc.desc: GetPriorityLevel test +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(CloudDataTest, GetPriorityLevel003, TestSize.Level1) +{ + EventCenter::GetInstance().Subscribe(CloudEvent::LOCAL_CHANGE, [](const Event &event) { + auto &evt = static_cast(event); + auto mode = evt.GetMode(); + EXPECT_EQ(GeneralStore::GetPriorityLevel(GeneralStore::GetHighMode(static_cast(mode))), 0); + }); + DistributedRdb::RdbServiceImpl rdbServiceImpl; + DistributedRdb::RdbSyncerParam param{ .bundleName_ = TEST_CLOUD_BUNDLE, .storeName_ = TEST_CLOUD_STORE }; + DistributedRdb::RdbService::Option option{ .mode = GeneralStore::SyncMode::CLOUD_ClOUD_FIRST, .isAsync = true }; + DistributedRdb::PredicatesMemo memo; + rdbServiceImpl.DoCloudSync(param, option, memo, nullptr); +} + +/** +* @tc.name: GetPriorityLevel004 +* @tc.desc: GetPriorityLevel test +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(CloudDataTest, GetPriorityLevel004, TestSize.Level1) +{ + EventCenter::GetInstance().Subscribe(CloudEvent::LOCAL_CHANGE, [](const Event &event) { + auto &evt = static_cast(event); + auto mode = evt.GetMode(); + EXPECT_EQ(GeneralStore::GetPriorityLevel(GeneralStore::GetHighMode(static_cast(mode))), 1); + }); + DistributedRdb::RdbServiceImpl rdbServiceImpl; + DistributedRdb::RdbSyncerParam param{ .bundleName_ = TEST_CLOUD_BUNDLE, .storeName_ = TEST_CLOUD_STORE }; + DistributedRdb::RdbService::Option option{ .mode = GeneralStore::SyncMode::CLOUD_ClOUD_FIRST, + .seqNum = 0, + .isAsync = true, + .isAutoSync = true }; + DistributedRdb::PredicatesMemo memo; + rdbServiceImpl.DoCloudSync(param, option, memo, nullptr); +} } // namespace DistributedDataTest } // namespace OHOS::Test \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/cloud_service_impl_test.cpp b/datamgr_service/services/distributeddataservice/service/test/cloud_service_impl_test.cpp index c16d535e326a7359fa23dd2dc895686d1c6cfa84..b8fd653ab9db7505950b0b11c378a51d7ef780fd 100644 --- a/datamgr_service/services/distributeddataservice/service/test/cloud_service_impl_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/cloud_service_impl_test.cpp @@ -41,6 +41,7 @@ #include "metadata/store_meta_data_local.h" #include "mock/db_store_mock.h" #include "mock/general_store_mock.h" +#include "network_adapter.h" #include "rdb_query.h" #include "rdb_service.h" #include "rdb_service_impl.h" @@ -54,6 +55,7 @@ using namespace OHOS::DistributedData; using namespace OHOS::Security::AccessToken; using Confirmation = OHOS::CloudData::Confirmation; using Status = OHOS::CloudData::CloudService::Status; +using CloudSyncScene = OHOS::CloudData::CloudServiceImpl::CloudSyncScene; namespace OHOS::Test { namespace DistributedDataTest { @@ -233,7 +235,7 @@ HWTEST_F(CloudServiceImplTest, UpdateSchema001, TestSize.Level0) { ZLOGI("CloudServiceImplTest UpdateSchema001 start"); int user = -1; - auto status = cloudServiceImpl_->UpdateSchema(user); + auto status = cloudServiceImpl_->UpdateSchema(user, CloudSyncScene::ENABLE_CLOUD); EXPECT_FALSE(status); } @@ -246,7 +248,7 @@ HWTEST_F(CloudServiceImplTest, UpdateSchema001, TestSize.Level0) HWTEST_F(CloudServiceImplTest, GetAppSchemaFromServer001, TestSize.Level0) { ZLOGI("CloudServiceImplTest GetAppSchemaFromServer001 start"); - DeviceManagerAdapter::GetInstance().SetNet(DeviceManagerAdapter::WIFI); + NetworkAdapter::GetInstance().SetNet(NetworkAdapter::WIFI); int user = -1; auto [status, result] = cloudServiceImpl_->GetAppSchemaFromServer(user, TEST_CLOUD_BUNDLE); EXPECT_EQ(status, CloudData::CloudService::SERVER_UNAVAILABLE); @@ -261,7 +263,7 @@ HWTEST_F(CloudServiceImplTest, GetAppSchemaFromServer001, TestSize.Level0) HWTEST_F(CloudServiceImplTest, GetCloudInfoFromServer001, TestSize.Level0) { ZLOGI("CloudServiceImplTest GetCloudInfoFromServer001 start"); - DeviceManagerAdapter::GetInstance().SetNet(DeviceManagerAdapter::WIFI); + NetworkAdapter::GetInstance().SetNet(NetworkAdapter::WIFI); int user = -1; auto [status, result] = cloudServiceImpl_->GetCloudInfoFromServer(user); EXPECT_EQ(status, CloudData::CloudService::SERVER_UNAVAILABLE); @@ -277,7 +279,7 @@ HWTEST_F(CloudServiceImplTest, ReleaseUserInfo001, TestSize.Level0) { ZLOGI("CloudServiceImplTest ReleaseUserInfo001 start"); int user = 100; - auto status = cloudServiceImpl_->ReleaseUserInfo(user); + auto status = cloudServiceImpl_->ReleaseUserInfo(user, CloudSyncScene::ENABLE_CLOUD); EXPECT_TRUE(status); } @@ -290,7 +292,7 @@ HWTEST_F(CloudServiceImplTest, ReleaseUserInfo001, TestSize.Level0) HWTEST_F(CloudServiceImplTest, DoSubscribe, TestSize.Level0) { int32_t user = 100; - auto status = cloudServiceImpl_->DoSubscribe(user); + auto status = cloudServiceImpl_->DoSubscribe(user, CloudSyncScene::ENABLE_CLOUD); EXPECT_TRUE(status); } diff --git a/datamgr_service/services/distributeddataservice/service/test/cloud_test.cpp b/datamgr_service/services/distributeddataservice/service/test/cloud_test.cpp index e49c66ca9570cc4e9c025a2300896774cdb90e1f..4a773db97127f543816774b35361d7cbd9180cfc 100644 --- a/datamgr_service/services/distributeddataservice/service/test/cloud_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/cloud_test.cpp @@ -43,7 +43,7 @@ std::shared_ptr CloudTest::dbStoreMock_ = std::make_sharedsize(), 4); + ASSERT_EQ(components->size(), 2); const ComponentConfig &config = (*components)[0]; ASSERT_EQ(config.description, "3rd party adapter"); ASSERT_EQ(config.lib, "libconfigdemo.z.so"); diff --git a/datamgr_service/services/distributeddataservice/service/test/data_share_subscriber_managers_test.cpp b/datamgr_service/services/distributeddataservice/service/test/data_share_subscriber_managers_test.cpp index 7ee102b269f4808595fa331fd75c5d1ba310203c..c5bccacf1a7e49954c7ce1ac0b1500ad974a0cc2 100644 --- a/datamgr_service/services/distributeddataservice/service/test/data_share_subscriber_managers_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/data_share_subscriber_managers_test.cpp @@ -142,7 +142,8 @@ HWTEST_F(DataShareSubscriberManagersTest, Delete, TestSize.Level1) auto context = std::make_shared(DATA_SHARE_URI_TEST); DataShare::Key key(context->uri, TEST_SUB_ID, BUNDLE_NAME_TEST); uint32_t tokenId = AccessTokenKit::GetHapTokenID(USER_TEST, BUNDLE_NAME_TEST, USER_TEST); - RdbSubscriberManager::GetInstance().Delete(tokenId); + uint32_t pid = getpid(); + RdbSubscriberManager::GetInstance().Delete(tokenId, pid); auto result = RdbSubscriberManager::GetInstance().Delete(key, tokenId); EXPECT_EQ(result, E_SUBSCRIBER_NOT_EXIST); } @@ -183,7 +184,11 @@ HWTEST_F(DataShareSubscriberManagersTest, Emit, TestSize.Level1) tpltId.subscriberId_ = TEST_SUB_ID; tpltId.bundleName_ = BUNDLE_NAME_TEST; DataShare::Key key(context->uri, tpltId.subscriberId_, tpltId.bundleName_); - RdbSubscriberManager::GetInstance().EmitByKey(key, USER_TEST, "rdbPath", 1); + DistributedData::StoreMetaData metaData; + metaData.version = 1; + metaData.tokenId = 0; + metaData.dataDir = "rdbPath"; + RdbSubscriberManager::GetInstance().EmitByKey(key, USER_TEST, metaData); DataShare::Key keys("", 0, ""); auto result = RdbSubscriberManager::GetInstance().GetEnableObserverCount(keys); EXPECT_EQ(result, 0); diff --git a/datamgr_service/services/distributeddataservice/service/test/device_matrix_test.cpp b/datamgr_service/services/distributeddataservice/service/test/device_matrix_test.cpp index 43e162a7f6edaebed2e127f29fc5c26c82d91e59..9eb491b171f7a401eae376bf0d50b53e094b83ff 100644 --- a/datamgr_service/services/distributeddataservice/service/test/device_matrix_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/device_matrix_test.cpp @@ -72,7 +72,7 @@ uint32_t DeviceMatrixTest::selfToken_ = 0; CheckerMock DeviceMatrixTest::instance_; void DeviceMatrixTest::SetUpTestCase(void) { - MetaDataManager::GetInstance().Initialize(dbStoreMock_, nullptr); + MetaDataManager::GetInstance().Initialize(dbStoreMock_, nullptr, ""); MetaDataManager::GetInstance().SetCloudSyncer([]() { DeviceMatrix::GetInstance().OnChanged(DeviceMatrix::META_STORE_MASK); }); diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/fuzztest/BUILD.gn index 6686a1d01f9846051d975d02d513ed167b0f5c61..efc92352430c137946660de49280abbe6e5ed71f 100644 --- a/datamgr_service/services/distributeddataservice/service/test/fuzztest/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/BUILD.gn @@ -18,15 +18,31 @@ import("//foundation/distributeddatamgr/datamgr_service/datamgr_service.gni") group("fuzztest") { testonly = true - deps = [ - "cloudservicestub_fuzzer:fuzztest", - "datashareservicestub_fuzzer:fuzztest", - "dumphelper_fuzzer:fuzztest", - "kvdbservicestub_fuzzer:fuzztest", - "objectservicestub_fuzzer:fuzztest", - "rdbresultsetstub_fuzzer:fuzztest", - "rdbservicestub_fuzzer:fuzztest", - ] + deps = [ "dumphelper_fuzzer:fuzztest" ] + + if (datamgr_service_cloud) { + deps += [ "cloudservicestub_fuzzer:fuzztest" ] + } + + if (datamgr_service_object) { + deps += [ "objectservicestub_fuzzer:fuzztest" ] + } + + if (datamgr_service_rdb) { + deps += [ + "rdbresultsetstub_fuzzer:fuzztest", + "rdbservicestub_fuzzer:fuzztest", + ] + } + + if (datamgr_service_kvdb) { + deps += [ "kvdbservicestub_fuzzer:fuzztest" ] + } + + if (datamgr_service_data_share) { + deps += [ "datashareservicestub_fuzzer:fuzztest" ] + } + if (datamgr_service_udmf) { deps += [ "udmfservice_fuzzer:fuzztest" ] } diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/BUILD.gn index 848e5900bbb4e6321aaca06655f6dfc0da99d832..2826516f31be9642a83da5015d136e53f852212c 100644 --- a/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/cloudservicestub_fuzzer/BUILD.gn @@ -31,10 +31,10 @@ ohos_fuzztest("CloudServiceStubFuzzTest") { "${data_service_path}/service/crypto/include", "${data_service_path}/service/kvdb", "${data_service_path}/service/matrix/include", + "${data_service_path}/service/network", "${data_service_path}/service/object", "${data_service_path}/service/permission/include", "${data_service_path}/service/rdb", - "${data_service_path}/service/waterversion", "${kv_store_common_path}", "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/include", "${kv_store_path}/frameworks/innerkitsimpl/distributeddatasvc/include", @@ -48,6 +48,8 @@ ohos_fuzztest("CloudServiceStubFuzzTest") { "${relational_store_path}/interfaces/inner_api/rdb/include", "${relational_store_path}/interfaces/inner_api/common_type/include", "//third_party/json/single_include", + "${data_service_path}/adapter/include/communicator", + "${data_service_path}/adapter/include/dfx", ] fuzz_config_file = @@ -65,6 +67,7 @@ ohos_fuzztest("CloudServiceStubFuzzTest") { "${data_service_path}/app/src/checker/system_checker.cpp", "${data_service_path}/service/backup/src/backup_manager.cpp", "${data_service_path}/service/bootstrap/src/bootstrap.cpp", + "${data_service_path}/service/cloud/cloud_data_translate.cpp", "${data_service_path}/service/cloud/cloud_service_impl.cpp", "${data_service_path}/service/cloud/cloud_service_stub.cpp", "${data_service_path}/service/cloud/cloud_types_util.cpp", @@ -84,29 +87,33 @@ ohos_fuzztest("CloudServiceStubFuzzTest") { "${data_service_path}/service/config/src/model/global_config.cpp", "${data_service_path}/service/config/src/model/network_config.cpp", "${data_service_path}/service/config/src/model/protocol_config.cpp", + "${data_service_path}/service/config/src/model/thread_config.cpp", "${data_service_path}/service/crypto/src/crypto_manager.cpp", + "${data_service_path}/service/kvdb/user_delegate.cpp", + "${data_service_path}/service/permission/src/permission_validator.cpp", + "${data_service_path}/service/permission/src/permit_delegate.cpp", "${data_service_path}/service/rdb/cache_cursor.cpp", "${data_service_path}/service/rdb/rdb_asset_loader.cpp", "${data_service_path}/service/rdb/rdb_cloud.cpp", - "${data_service_path}/service/rdb/rdb_cloud_data_translate.cpp", "${data_service_path}/service/rdb/rdb_cursor.cpp", "${data_service_path}/service/rdb/rdb_general_store.cpp", "${data_service_path}/service/rdb/rdb_notifier_proxy.cpp", "${data_service_path}/service/rdb/rdb_query.cpp", "${data_service_path}/service/rdb/rdb_result_set_impl.cpp", "${data_service_path}/service/rdb/rdb_result_set_stub.cpp", + "${data_service_path}/service/rdb/rdb_schema_config.cpp", "${data_service_path}/service/rdb/rdb_service_impl.cpp", "${data_service_path}/service/rdb/rdb_service_stub.cpp", "${data_service_path}/service/rdb/rdb_watcher.cpp", - "${data_service_path}/service/waterversion/water_version_manager.cpp", "cloudservicestub_fuzzer.cpp", ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", - "${data_service_path}/adapter/utils:distributeddata_utils_static", + "${data_service_path}/adapter/account:distributeddata_account", + "${data_service_path}/adapter/utils:distributeddata_utils", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", + "${data_service_path}/service/network:distributeddata_network", "${kv_store_distributeddb_path}:distributeddb", ] @@ -118,6 +125,8 @@ ohos_fuzztest("CloudServiceStubFuzzTest") { "access_token:libaccesstoken_sdk", "access_token:libtoken_setproc", "access_token:libtokenid_sdk", + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", "c_utils:utils", "device_auth:deviceauth_sdk", "device_manager:devicemanagersdk", @@ -128,6 +137,7 @@ ohos_fuzztest("CloudServiceStubFuzzTest") { "kv_store:distributeddata_inner", "kv_store:distributeddata_mgr", "relational_store:native_rdb", + "resource_management:global_resmgr", "safwk:system_ability_fwk", "samgr:samgr_proxy", ] diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/BUILD.gn index ee4edc63f48f36cd9bfa3ea63b2fb5935431c391..110dc0650ea6a869d7ac8a9a9ccaeddcbdfc0e28 100644 --- a/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/datashareservicestub_fuzzer/BUILD.gn @@ -27,6 +27,7 @@ ohos_fuzztest("DataShareServiceStubFuzzTest") { "${data_service_path}/service/crypto/include", "${data_service_path}/service/data_share/common", "${data_service_path}/service/data_share/data", + "${data_service_path}/service/data_share/dfx", "${data_service_path}/service/data_share/strategies", "${data_service_path}/service/data_share/subscriber_managers", "${data_service_path}/service/data_share", @@ -36,6 +37,7 @@ ohos_fuzztest("DataShareServiceStubFuzzTest") { "${datashare_path}/interfaces/inner_api/common/include", "${datashare_path}/interfaces/inner_api/consumer/include", "//third_party/json/single_include", + "${data_service_path}/adapter/include/communicator", ] fuzz_config_file = @@ -52,7 +54,6 @@ ohos_fuzztest("DataShareServiceStubFuzzTest") { "${data_service_path}/service/common/xcollie.cpp", "${data_service_path}/service/crypto/src/crypto_manager.cpp", "${data_service_path}/service/data_share/common/app_connect_manager.cpp", - "${data_service_path}/service/data_share/common/base64_utils.cpp", "${data_service_path}/service/data_share/common/bundle_mgr_proxy.cpp", "${data_service_path}/service/data_share/common/db_delegate.cpp", "${data_service_path}/service/data_share/common/div_strategy.cpp", @@ -75,6 +76,8 @@ ohos_fuzztest("DataShareServiceStubFuzzTest") { "${data_service_path}/service/data_share/data_share_service_stub.cpp", "${data_service_path}/service/data_share/data_share_silent_config.cpp", "${data_service_path}/service/data_share/data_share_types_util.cpp", + "${data_service_path}/service/data_share/dfx/hiview_adapter.cpp", + "${data_service_path}/service/data_share/dfx/hiview_fault_adapter.cpp", "${data_service_path}/service/data_share/strategies/data_proxy/load_config_from_data_proxy_node_strategy.cpp", "${data_service_path}/service/data_share/strategies/data_share/load_config_from_data_share_bundle_info_strategy.cpp", "${data_service_path}/service/data_share/strategies/general/check_is_data_proxy_strategy.cpp", @@ -98,9 +101,9 @@ ohos_fuzztest("DataShareServiceStubFuzzTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", + "${data_service_path}/adapter/account:distributeddata_account", + "${data_service_path}/adapter/communicator:distributeddata_communicator", "${data_service_path}/framework:distributeddatasvcfwk", - "${data_service_path}/service/data_share:data_share_service", ] external_deps = [ @@ -123,6 +126,7 @@ ohos_fuzztest("DataShareServiceStubFuzzTest") { "hisysevent:libhisysevent", "huks:libhukssdk", "ipc:ipc_core", + "kv_store:distributeddata_inner", "kv_store:distributeddb", "relational_store:native_rdb", "relational_store:rdb_data_share_adapter", diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/dumphelper_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/fuzztest/dumphelper_fuzzer/BUILD.gn index 0416b718132a1e887e5f7a3c2dd2893ea0522429..3e39786a14cb2ef917721b9244cd6e435aa41ee3 100644 --- a/datamgr_service/services/distributeddataservice/service/test/fuzztest/dumphelper_fuzzer/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/dumphelper_fuzzer/BUILD.gn @@ -52,8 +52,8 @@ ohos_fuzztest("DumpHelperFuzzTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", - "${data_service_path}/adapter/utils:distributeddata_utils_static", + "${data_service_path}/adapter/account:distributeddata_account", + "${data_service_path}/adapter/utils:distributeddata_utils", "${data_service_path}/framework:distributeddatasvcfwk", "${kv_store_distributeddb_path}:distributeddb", ] diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/BUILD.gn index 1aad884a216043c86338f0378b24d67295fe54b6..aeedc92b262e618a6b93e9ba50923ef3852bb7dd 100644 --- a/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/kvdbservicestub_fuzzer/BUILD.gn @@ -33,7 +33,6 @@ ohos_fuzztest("KvdbServiceStubFuzzTest") { "${data_service_path}/service/matrix/include", "${data_service_path}/service/permission/include", "${data_service_path}/service/rdb", - "${data_service_path}/service/waterversion", "${kv_store_common_path}", "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/include", "${kv_store_path}/frameworks/innerkitsimpl/distributeddatasvc/include", @@ -44,6 +43,9 @@ ohos_fuzztest("KvdbServiceStubFuzzTest") { "${kv_store_distributeddb_path}/interfaces/include/relational", "${relational_store_path}/interfaces/inner_api/common_type/include", "//third_party/json/single_include", + "${data_service_path}/adapter/include/communicator", + "${data_service_path}/adapter/include/dfx", + "${data_service_path}/adapter/include/utils", ] fuzz_config_file = @@ -72,6 +74,7 @@ ohos_fuzztest("KvdbServiceStubFuzzTest") { "${data_service_path}/service/config/src/model/global_config.cpp", "${data_service_path}/service/config/src/model/network_config.cpp", "${data_service_path}/service/config/src/model/protocol_config.cpp", + "${data_service_path}/service/config/src/model/thread_config.cpp", "${data_service_path}/service/crypto/src/crypto_manager.cpp", "${data_service_path}/service/kvdb/auth_delegate.cpp", "${data_service_path}/service/kvdb/kvdb_exporter.cpp", @@ -86,16 +89,16 @@ ohos_fuzztest("KvdbServiceStubFuzzTest") { "${data_service_path}/service/kvdb/user_delegate.cpp", "${data_service_path}/service/matrix/src/device_matrix.cpp", "${data_service_path}/service/matrix/src/matrix_event.cpp", + "${data_service_path}/service/permission/src/permission_validator.cpp", "${data_service_path}/service/permission/src/permit_delegate.cpp", "${data_service_path}/service/rdb/rdb_cloud.cpp", "${data_service_path}/service/rdb/rdb_query.cpp", - "${data_service_path}/service/waterversion/water_version_manager.cpp", "kvdbservicestub_fuzzer.cpp", ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", - "${data_service_path}/adapter/utils:distributeddata_utils_static", + "${data_service_path}/adapter/account:distributeddata_account", + "${data_service_path}/adapter/utils:distributeddata_utils", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", "${kv_store_distributeddb_path}:distributeddb", diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/BUILD.gn index afb0620045554200756a3a6a215764ac54c74ea3..fb2775fb12c91ae8946641a2dba8e9ef80e24965 100644 --- a/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/objectservicestub_fuzzer/BUILD.gn @@ -28,9 +28,8 @@ ohos_fuzztest("ObjectServiceStubFuzzTest") { "${data_service_path}/service/common", "${data_service_path}/service/config/include", "${data_service_path}/service/crypto/include", - "${data_service_path}/service/object", + "${data_service_path}/service/object/include", "${data_service_path}/service/matrix/include", - "${data_service_path}/service/waterversion", "${kv_store_common_path}", "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/include", "${kv_store_path}/frameworks/innerkitsimpl/distributeddatasvc/include", @@ -44,6 +43,8 @@ ohos_fuzztest("ObjectServiceStubFuzzTest") { "${dataobject_path}/interfaces/innerkits", "//third_party/json/single_include", "${relational_store_path}/interfaces/inner_api/common_type/include", + "${data_service_path}/adapter/include/communicator", + "${data_service_path}/adapter/include/utils", ] fuzz_config_file = @@ -71,24 +72,24 @@ ohos_fuzztest("ObjectServiceStubFuzzTest") { "${data_service_path}/service/config/src/model/global_config.cpp", "${data_service_path}/service/config/src/model/network_config.cpp", "${data_service_path}/service/config/src/model/protocol_config.cpp", + "${data_service_path}/service/config/src/model/thread_config.cpp", "${data_service_path}/service/crypto/src/crypto_manager.cpp", - "${data_service_path}/service/object/object_asset_loader.cpp", - "${data_service_path}/service/object/object_asset_machine.cpp", - "${data_service_path}/service/object/object_callback_proxy.cpp", - "${data_service_path}/service/object/object_data_listener.cpp", - "${data_service_path}/service/object/object_dms_handler.cpp", - "${data_service_path}/service/object/object_manager.cpp", - "${data_service_path}/service/object/object_service_impl.cpp", - "${data_service_path}/service/object/object_service_stub.cpp", - "${data_service_path}/service/object/object_snapshot.cpp", - "${data_service_path}/service/object/object_types_utils.cpp", - "${data_service_path}/service/waterversion/water_version_manager.cpp", + "${data_service_path}/service/object/src/object_asset_loader.cpp", + "${data_service_path}/service/object/src/object_asset_machine.cpp", + "${data_service_path}/service/object/src/object_callback_proxy.cpp", + "${data_service_path}/service/object/src/object_data_listener.cpp", + "${data_service_path}/service/object/src/object_dms_handler.cpp", + "${data_service_path}/service/object/src/object_manager.cpp", + "${data_service_path}/service/object/src/object_service_impl.cpp", + "${data_service_path}/service/object/src/object_service_stub.cpp", + "${data_service_path}/service/object/src/object_snapshot.cpp", + "${data_service_path}/service/object/src/object_types_utils.cpp", "objectservicestub_fuzzer.cpp", ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", - "${data_service_path}/adapter/utils:distributeddata_utils_static", + "${data_service_path}/adapter/account:distributeddata_account", + "${data_service_path}/adapter/utils:distributeddata_utils", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", "${kv_store_distributeddb_path}:distributeddb", @@ -102,6 +103,7 @@ ohos_fuzztest("ObjectServiceStubFuzzTest") { "access_token:libaccesstoken_sdk", "access_token:libtokenid_sdk", "c_utils:utils", + "data_object:distributeddataobject_impl", "device_auth:deviceauth_sdk", "device_manager:devicemanagersdk", "dfs_service:cloudsync_asset_kit_inner", diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/BUILD.gn index 430492810d401b3dd565eaa00b70cd1703808aae..b7dffe3f17867dc5a05fdec07e096a7063ef0b4d 100644 --- a/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbresultsetstub_fuzzer/BUILD.gn @@ -57,8 +57,8 @@ ohos_fuzztest("RdbResultSetStubFuzzTest") { ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", - "${data_service_path}/adapter/utils:distributeddata_utils_static", + "${data_service_path}/adapter/account:distributeddata_account", + "${data_service_path}/adapter/utils:distributeddata_utils", "${data_service_path}/framework:distributeddatasvcfwk", "${kv_store_distributeddb_path}:distributeddb", "${relational_store_inner_api_path}:native_rdb_static", diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/BUILD.gn index a6ffe6bb80601d514d992035cc5f049921cc2111..2253863295dfa00058dd18ad9cd1d9f72664b6a3 100644 --- a/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/rdbservicestub_fuzzer/BUILD.gn @@ -35,7 +35,6 @@ ohos_fuzztest("RdbServiceStubFuzzTest") { "${data_service_path}/service/object", "${data_service_path}/service/permission/include", "${data_service_path}/service/rdb", - "${data_service_path}/service/waterversion", "${kv_store_common_path}", "${kv_store_path}/frameworks/innerkitsimpl/distributeddatafwk/include", "${kv_store_path}/frameworks/innerkitsimpl/distributeddatasvc/include", @@ -49,6 +48,8 @@ ohos_fuzztest("RdbServiceStubFuzzTest") { "${relational_store_path}/interfaces/inner_api/rdb/include", "${relational_store_path}/interfaces/inner_api/common_type/include", "//third_party/json/single_include", + "${data_service_path}/adapter/include/communicator", + "${data_service_path}/adapter/include/dfx", ] fuzz_config_file = @@ -78,27 +79,27 @@ ohos_fuzztest("RdbServiceStubFuzzTest") { "${data_service_path}/service/config/src/model/global_config.cpp", "${data_service_path}/service/config/src/model/network_config.cpp", "${data_service_path}/service/config/src/model/protocol_config.cpp", + "${data_service_path}/service/config/src/model/thread_config.cpp", "${data_service_path}/service/crypto/src/crypto_manager.cpp", "${data_service_path}/service/rdb/cache_cursor.cpp", "${data_service_path}/service/rdb/rdb_asset_loader.cpp", "${data_service_path}/service/rdb/rdb_cloud.cpp", - "${data_service_path}/service/rdb/rdb_cloud_data_translate.cpp", "${data_service_path}/service/rdb/rdb_cursor.cpp", "${data_service_path}/service/rdb/rdb_general_store.cpp", "${data_service_path}/service/rdb/rdb_notifier_proxy.cpp", "${data_service_path}/service/rdb/rdb_query.cpp", "${data_service_path}/service/rdb/rdb_result_set_impl.cpp", "${data_service_path}/service/rdb/rdb_result_set_stub.cpp", + "${data_service_path}/service/rdb/rdb_schema_config.cpp", "${data_service_path}/service/rdb/rdb_service_impl.cpp", "${data_service_path}/service/rdb/rdb_service_stub.cpp", "${data_service_path}/service/rdb/rdb_watcher.cpp", - "${data_service_path}/service/waterversion/water_version_manager.cpp", "rdbservicestub_fuzzer.cpp", ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", - "${data_service_path}/adapter/utils:distributeddata_utils_static", + "${data_service_path}/adapter/account:distributeddata_account", + "${data_service_path}/adapter/utils:distributeddata_utils", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service:distributeddatasvc", "${kv_store_distributeddb_path}:distributeddb", @@ -112,6 +113,8 @@ ohos_fuzztest("RdbServiceStubFuzzTest") { "ability_runtime:dataobs_manager", "access_token:libaccesstoken_sdk", "access_token:libtokenid_sdk", + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", "c_utils:utils", "device_auth:deviceauth_sdk", "device_manager:devicemanagersdk", @@ -122,6 +125,8 @@ ohos_fuzztest("RdbServiceStubFuzzTest") { "kv_store:distributeddata_inner", "kv_store:distributeddata_mgr", "relational_store:native_rdb", + "resource_management:global_resmgr", + "samgr:samgr_proxy", ] } diff --git a/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/BUILD.gn index 82fe2b8671d5cfd82742dcd3cc3e41dfa7f08362..067d82c0e8e9bec54ff2cb93129b97fb4fa35f65 100644 --- a/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/test/fuzztest/udmfservice_fuzzer/BUILD.gn @@ -45,6 +45,8 @@ ohos_fuzztest("UdmfServiceFuzzTest") { sources = [ "udmfservice_fuzzer.cpp" ] deps = [ + "${data_service_path}/adapter/account:distributeddata_account", + "${data_service_path}/adapter/communicator:distributeddata_communicator", "${data_service_path}/framework:distributeddatasvcfwk", "${data_service_path}/service/udmf:udmf_server", ] @@ -59,6 +61,7 @@ ohos_fuzztest("UdmfServiceFuzzTest") { "ipc:ipc_core", "kv_store:distributeddata_inner", "kv_store:distributeddata_mgr", + "kv_store:distributeddb", "udmf:udmf_client", ] } diff --git a/datamgr_service/services/distributeddataservice/service/test/kvdb_general_store_test.cpp b/datamgr_service/services/distributeddataservice/service/test/kvdb_general_store_test.cpp index cd8dd577393d12365d96d0b7922e0fb7bab352a3..8466ecce427bf4c8f933a26aa8d55350c1ffc910 100644 --- a/datamgr_service/services/distributeddataservice/service/test/kvdb_general_store_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/kvdb_general_store_test.cpp @@ -156,7 +156,7 @@ public: HWTEST_F(KVDBGeneralStoreTest, GetDBPasswordTest_001, TestSize.Level0) { ZLOGI("GetDBPasswordTest start"); - MetaDataManager::GetInstance().Initialize(dbStoreMock_, nullptr); + MetaDataManager::GetInstance().Initialize(dbStoreMock_, nullptr, ""); EXPECT_TRUE(MetaDataManager::GetInstance().SaveMeta(metaData_.GetKey(), metaData_, true)); EXPECT_TRUE(MetaDataManager::GetInstance().SaveMeta(metaData_.GetSecretKey(), metaData_, true)); auto dbPassword = KVDBGeneralStore::GetDBPassword(metaData_); @@ -173,7 +173,7 @@ HWTEST_F(KVDBGeneralStoreTest, GetDBPasswordTest_001, TestSize.Level0) HWTEST_F(KVDBGeneralStoreTest, GetDBPasswordTest_002, TestSize.Level0) { ZLOGI("GetDBPasswordTest_002 start"); - MetaDataManager::GetInstance().Initialize(dbStoreMock_, nullptr); + MetaDataManager::GetInstance().Initialize(dbStoreMock_, nullptr, ""); metaData_.isEncrypt = true; EXPECT_TRUE(MetaDataManager::GetInstance().SaveMeta(metaData_.GetKey(), metaData_, true)); @@ -365,7 +365,7 @@ HWTEST_F(KVDBGeneralStoreTest, BindTest, TestSize.Level0) ret = store->Bind(database, bindInfos, config); EXPECT_EQ(ret, GeneralError::E_ALREADY_CLOSED); - store->users_.clear(); + store->bindInfos_.clear(); KvStoreNbDelegateMock mockDelegate; store->delegate_ = &mockDelegate; EXPECT_NE(store->delegate_, nullptr); @@ -670,34 +670,6 @@ HWTEST_F(KVDBGeneralStoreTest, ConvertStatus, TestSize.Level0) EXPECT_EQ(ret, GeneralError::E_DB_ERROR); } -/** -* @tc.name: GetWaterVersion -* @tc.desc: GetWaterVersion test the functionality of different branches. -* @tc.type: FUNC -* @tc.require: -* @tc.author: SQL -*/ -HWTEST_F(KVDBGeneralStoreTest, GetWaterVersion, TestSize.Level0) -{ - auto store = new (std::nothrow) KVDBGeneralStore(metaData_); - ASSERT_NE(store, nullptr); - std::string deviceId = "deviceId"; - std::vector res = {}; - auto ret = store->GetWaterVersion(deviceId); - EXPECT_EQ(ret, res); - KvStoreNbDelegateMock mockDelegate; - store->delegate_ = &mockDelegate; - ret = store->GetWaterVersion(""); - EXPECT_EQ(ret, res); - ret = store->GetWaterVersion("test"); - EXPECT_EQ(ret, res); - ret = store->GetWaterVersion("device"); - EXPECT_EQ(ret, res); - res = { "deviceId" }; - ret = store->GetWaterVersion(deviceId); - EXPECT_EQ(ret, res); -} - /** * @tc.name: OnChange * @tc.desc: OnChange test the functionality of different branches. diff --git a/datamgr_service/services/distributeddataservice/service/test/mock/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/mock/BUILD.gn index 2feaaa791831660d4eb32c5db3ba666dd4364b9e..1f85e3b06cf1e8a09609a1e213102d7a26fe175d 100644 --- a/datamgr_service/services/distributeddataservice/service/test/mock/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/test/mock/BUILD.gn @@ -17,6 +17,7 @@ config("module_private_config") { visibility = [ ":*" ] include_dirs = [ + "${data_service_path}/adapter/include/communicator", "../../../framework/include/", "../../../service/rdb/", ] diff --git a/datamgr_service/services/distributeddataservice/service/test/mock/cloud_server_mock.cpp b/datamgr_service/services/distributeddataservice/service/test/mock/cloud_server_mock.cpp index 3b06746b019c0d8efe0ab42dab89efd78bb26424..558666d590db1dde4bd32ebfbbfd7afc2d240c83 100644 --- a/datamgr_service/services/distributeddataservice/service/test/mock/cloud_server_mock.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/mock/cloud_server_mock.cpp @@ -21,11 +21,11 @@ CloudServerMock::CloudServerMock(const CloudInfo &cloudInfo, const std::map CloudServerMock::GetServerInfo(int32_t userId, bool needSpaceInfo) { auto cloudInfo = cloudInfo_; cloudInfo.user = userId; - return cloudInfo; + return { E_OK, cloudInfo }; } std::pair CloudServerMock::GetAppSchema(int32_t userId, const std::string &bundleName) diff --git a/datamgr_service/services/distributeddataservice/service/test/mock/cloud_server_mock.h b/datamgr_service/services/distributeddataservice/service/test/mock/cloud_server_mock.h index d6b2ebbefe64b1837de58e603788f2a060b1805d..0b3b30729600b970cb314db3c51e62c25f1bb3fa 100644 --- a/datamgr_service/services/distributeddataservice/service/test/mock/cloud_server_mock.h +++ b/datamgr_service/services/distributeddataservice/service/test/mock/cloud_server_mock.h @@ -24,7 +24,7 @@ namespace DistributedData { class CloudServerMock : public CloudServer { public: CloudServerMock(const CloudInfo& cloudInfo, const std::map& schemaMetas); - CloudInfo GetServerInfo(int32_t userId, bool needSpaceInfo = true) override; + std::pair GetServerInfo(int32_t userId, bool needSpaceInfo = true) override; std::pair GetAppSchema(int32_t userId, const std::string &bundleName) override; virtual ~CloudServerMock() = default; diff --git a/datamgr_service/services/distributeddataservice/service/test/mock/db_store_mock.cpp b/datamgr_service/services/distributeddataservice/service/test/mock/db_store_mock.cpp index c89d6d954c41cbc64629183b999cf83308c7ffec..84c31cd22a788bf49a6cd6c1a154607ac8d599b4 100644 --- a/datamgr_service/services/distributeddataservice/service/test/mock/db_store_mock.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/mock/db_store_mock.cpp @@ -13,6 +13,7 @@ * limitations under the License. */ #include "db_store_mock.h" + #include "db_change_data_mock.h" namespace OHOS { namespace DistributedData { @@ -384,11 +385,11 @@ DBStatus DBStoreMock::Sync(const DeviceSyncOption &option, const DeviceSyncProce DBStatus DBStoreMock::CancelSync(uint32_t syncId) { return NOT_SUPPORT; -} +}; KvStoreNbDelegate::DatabaseStatus DBStoreMock::GetDatabaseStatus() const { - return KvStoreNbDelegate::DatabaseStatus(); -}; + return {}; +} } // namespace DistributedData } // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/mock/general_store_mock.cpp b/datamgr_service/services/distributeddataservice/service/test/mock/general_store_mock.cpp index 03ca21d297a752356a097152a827e10c09185ab0..89e80c6e9922544ed16131a492dd397265128d32 100644 --- a/datamgr_service/services/distributeddataservice/service/test/mock/general_store_mock.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/mock/general_store_mock.cpp @@ -15,7 +15,7 @@ #include "general_store_mock.h" namespace OHOS { namespace DistributedData { -GeneralStoreMock::GeneralStoreMock(const StoreMetaData& meta) {} +GeneralStoreMock::GeneralStoreMock(const StoreMetaData &meta) {} GeneralStoreMock::~GeneralStoreMock() {} bool GeneralStoreMock::IsValid() { @@ -25,7 +25,7 @@ StoreMetaData GeneralStoreMock::GetStoreMetaData() { return StoreMetaData(); } -int32_t GeneralStoreMock::Bind(Database &database, const std::map &bindInfos, +int32_t GeneralStoreMock::Bind(const Database &database, const std::map &bindInfos, const CloudConfig &config) { return 0; @@ -41,14 +41,14 @@ int32_t GeneralStoreMock::Execute(const std::string &table, const std::string &s return 0; } -int32_t GeneralStoreMock::SetDistributedTables( - const std::vector &tables, int32_t type, const std::vector &references) +int32_t GeneralStoreMock::SetDistributedTables(const std::vector &tables, int32_t type, + const std::vector &references) { return 0; } -int32_t GeneralStoreMock::SetTrackerTable(const std::string &tableName, - const std::set &trackerColNames, const std::set &extendColNames, bool isForceUpgrade) +int32_t GeneralStoreMock::SetTrackerTable(const std::string &tableName, const std::set &trackerColNames, + const std::set &extendColNames, bool isForceUpgrade) { return 0; } @@ -76,18 +76,18 @@ int32_t GeneralStoreMock::Delete(const std::string &table, const std::string &sq std::pair> GeneralStoreMock::Query(const std::string &table, GenQuery &query) { - return {GeneralError::E_NOT_SUPPORT, nullptr}; + return { GeneralError::E_NOT_SUPPORT, nullptr }; } -std::pair GeneralStoreMock::Sync(const Devices &devices, GenQuery &query, - DetailAsync async, const SyncParam &syncParm) +std::pair GeneralStoreMock::Sync(const Devices &devices, GenQuery &query, DetailAsync async, + const SyncParam &syncParm) { return { GeneralError::E_OK, 0 }; } std::pair> GeneralStoreMock::PreSharing(GenQuery &query) { - return {GeneralError::E_NOT_SUPPORT, nullptr}; + return { GeneralError::E_NOT_SUPPORT, nullptr }; } int32_t GeneralStoreMock::Clean(const std::vector &devices, int32_t mode, const std::string &tableName) @@ -148,12 +148,7 @@ int32_t GeneralStoreMock::CleanTrackerData(const std::string &tableName, int64_t std::pair> GeneralStoreMock::Query(const std::string &table, const std::string &sql, Values &&args) { - return {GeneralError::E_OK, cursor_}; -} - -std::vector GeneralStoreMock::GetWaterVersion(const std::string &deviceId) -{ - return std::vector(); + return { GeneralError::E_OK, cursor_ }; } void GeneralStoreMock::MakeCursor(const std::map &entry) diff --git a/datamgr_service/services/distributeddataservice/service/test/mock/general_store_mock.h b/datamgr_service/services/distributeddataservice/service/test/mock/general_store_mock.h index 3b343c14ff34d9f87e14f8f36f863d0d196f028d..9a2d3c8ae1c3b1cc2215c2a3ccf9f08f184f7589 100644 --- a/datamgr_service/services/distributeddataservice/service/test/mock/general_store_mock.h +++ b/datamgr_service/services/distributeddataservice/service/test/mock/general_store_mock.h @@ -34,7 +34,7 @@ public: GeneralStoreMock(); ~GeneralStoreMock(); bool IsValid(); - int32_t Bind(Database &database, const std::map &bindInfos, + int32_t Bind(const Database &database, const std::map &bindInfos, const CloudConfig &config) override; bool IsBound(uint32_t user) override; int32_t Execute(const std::string &table, const std::string &sql) override; @@ -64,7 +64,6 @@ public: int32_t BindSnapshots(std::shared_ptr>> bindAssets) override; int32_t MergeMigratedData(const std::string &tableName, VBuckets &&values) override; int32_t CleanTrackerData(const std::string &tableName, int64_t cursor) override; - std::vector GetWaterVersion(const std::string &deviceId) override; void SetExecutor(std::shared_ptr executor) override; void MakeCursor(const std::map &entry); std::pair LockCloudDB() override; diff --git a/datamgr_service/services/distributeddataservice/service/test/network_adapter_test.cpp b/datamgr_service/services/distributeddataservice/service/test/network_adapter_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e8c1db111232acacf0d6ca9d55c2f20281941238 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/network_adapter_test.cpp @@ -0,0 +1,102 @@ +/* +* Copyright (c) 2025 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 "NetworkAdapterTest" +#include +#include +#include + +#include "communicator/device_manager_adapter.h" +#include "log_print.h" +#include "network_adapter.h" + +using namespace testing::ext; +using namespace OHOS::DistributedData; +using DmAdapter = OHOS::DistributedData::DeviceManagerAdapter; + +namespace OHOS::Test { +namespace DistributedDataTest { +class NetworkAdapterTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void NetworkAdapterTest::SetUpTestCase(void) +{ + NetworkAdapter::GetInstance().RegOnNetworkChange(); +} + +void NetworkAdapterTest::TearDownTestCase() +{ +} + +void NetworkAdapterTest::SetUp() +{ +} + +void NetworkAdapterTest::TearDown() +{ +} + +/** +* @tc.name: GetInstanceTest +* @tc.desc: GetInstance test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(NetworkAdapterTest, GetInstanceTest, TestSize.Level0) +{ + NetworkAdapter &instance = NetworkAdapter::GetInstance(); + EXPECT_NE(&instance, nullptr); +} + +/** +* @tc.name: SetNetTest +* @tc.desc: SetNet test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(NetworkAdapterTest, SetNetTest, TestSize.Level0) +{ + NetworkAdapter::GetInstance().SetNet(NetworkAdapter::NetworkType::NONE); + auto ret = NetworkAdapter::GetInstance().IsNetworkAvailable(); + EXPECT_EQ(ret, false); + auto type = NetworkAdapter::GetInstance().GetNetworkType(true); + EXPECT_EQ(type, NetworkAdapter::NONE); + type = NetworkAdapter::GetInstance().GetNetworkType(); + EXPECT_EQ(type, NetworkAdapter::NONE); + + NetworkAdapter::GetInstance().SetNet(NetworkAdapter::NetworkType::WIFI); + type = NetworkAdapter::GetInstance().GetNetworkType(); + EXPECT_EQ(type, NetworkAdapter::WIFI); + + NetworkAdapter::GetInstance().SetNet(NetworkAdapter::NetworkType::CELLULAR); + type = NetworkAdapter::GetInstance().GetNetworkType(); + EXPECT_EQ(type, NetworkAdapter::CELLULAR); + + NetworkAdapter::GetInstance().SetNet(NetworkAdapter::NetworkType::ETHERNET); + type = NetworkAdapter::GetInstance().GetNetworkType(); + EXPECT_EQ(type, NetworkAdapter::ETHERNET); + + NetworkAdapter::GetInstance().SetNet(NetworkAdapter::NetworkType::OTHER); + type = NetworkAdapter::GetInstance().GetNetworkType(); + EXPECT_EQ(type, NetworkAdapter::OTHER); +} +} // namespace DistributedDataTest +} // namespace OHOS::Test \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/object_asset_machine_test.cpp b/datamgr_service/services/distributeddataservice/service/test/object_asset_machine_test.cpp index c865cf9e54adbe4f01edeb90da059a45d977e48f..0405b829469e604611e5848df3acb6d1d67d7fea 100644 --- a/datamgr_service/services/distributeddataservice/service/test/object_asset_machine_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/object_asset_machine_test.cpp @@ -204,11 +204,11 @@ HWTEST_F(ObjectAssetMachineTest, StatusUpload002, TestSize.Level0) .assetName = "asset_" + timestamp + ".jpg", }; StoreInfo storeInfo { - .tokenId = static_cast(time), + .tokenId = time, .bundleName = "bundleName_" + timestamp, .storeName = "store_" + timestamp, - .instanceId = static_cast(time), - .user = static_cast(time), + .instanceId = time, + .user = time, }; ChangedAssetInfo changedAssetInfo(asset, bindInfo, storeInfo); std::pair changedAsset{ "device_" + timestamp, asset }; diff --git a/datamgr_service/services/distributeddataservice/service/test/object_manager_test.cpp b/datamgr_service/services/distributeddataservice/service/test/object_manager_test.cpp index 5d25fc0b1d94796dddd8fae403a3b97ccd13a065..0a7eca463c31af09681cf7197558f0ac73d37df7 100644 --- a/datamgr_service/services/distributeddataservice/service/test/object_manager_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/object_manager_test.cpp @@ -313,7 +313,9 @@ HWTEST_F(ObjectManagerTest, NotifyChange001, TestSize.Level0) data = {{ "test_cloud", data_ }}; data1 = {{ "p_###SAVEINFO###001", data1_ }}; manager->NotifyChange(data1); + EXPECT_FALSE(manager->restoreStatus_.Find("p_###SAVEINFO###001").first); manager->NotifyChange(data); + EXPECT_FALSE(manager->restoreStatus_.Find("test_cloud").first); } /** @@ -489,7 +491,9 @@ HWTEST_F(ObjectManagerTest, FlushClosedStore001, TestSize.Level0) manager->syncCount_ = 0; // test syncCount_ manager->FlushClosedStore(); manager->delegate_ = manager->OpenObjectKvStore(); + ASSERT_NE(manager->delegate_, nullptr); manager->FlushClosedStore(); + ASSERT_EQ(manager->delegate_, nullptr); } /** @@ -583,6 +587,7 @@ HWTEST_F(ObjectManagerTest, SyncCompleted001, TestSize.Level0) userId.push_back(99); userId.push_back(100); manager->SyncCompleted(results, sequenceId_); + EXPECT_FALSE(manager->isSyncing_); } /** diff --git a/datamgr_service/services/distributeddataservice/service/test/permission_validator_test.cpp b/datamgr_service/services/distributeddataservice/service/test/permission_validator_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..469348416e431284eb10b4baf1016de29e1f2202 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/permission_validator_test.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2021 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 "permission_validator.h" +#include "utils/crypto.h" + +using namespace testing::ext; +using namespace OHOS::DistributedKv; +using namespace OHOS::DistributedData; + +class PermissionValidatorTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void PermissionValidatorTest::SetUpTestCase(void) +{} + +void PermissionValidatorTest::TearDownTestCase(void) +{} + +void PermissionValidatorTest::SetUp(void) +{} + +void PermissionValidatorTest::TearDown(void) +{} + +/** + * @tc.name: TestPermissionValidate001 + * @tc.desc: test if CheckPermission can return correct permission. + * @tc.type: FUNC + * @tc.require: AR000CQDUT + * @tc.author: liqiao + */ +HWTEST_F(PermissionValidatorTest, TestPermissionValidate001, TestSize.Level0) +{ + uint32_t tokenId = 0; + EXPECT_FALSE(PermissionValidator::GetInstance().CheckSyncPermission(tokenId)); +} + +/** + * @tc.name: TestPermissionValidate003 + * @tc.desc: test if account id sha256. + * @tc.type: FUNC + * @tc.require: AR000DPSH0 AR000DPSEC + * @tc.author: liqiao + */ +HWTEST_F(PermissionValidatorTest, TestPermissionValidate002, TestSize.Level0) +{ + std::string userId = "ohos"; + EXPECT_NE(Crypto::Sha256("ohos"), userId); +} diff --git a/datamgr_service/services/distributeddataservice/service/test/rdb_cloud_test.cpp b/datamgr_service/services/distributeddataservice/service/test/rdb_cloud_test.cpp index 7f945e15ce92877f252523f49b1232c36d81552e..1cfe316a15e565877e26341104df26837a4d2c3f 100644 --- a/datamgr_service/services/distributeddataservice/service/test/rdb_cloud_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/rdb_cloud_test.cpp @@ -18,7 +18,6 @@ #include "gtest/gtest.h" #include "log_print.h" -#include "rdb_cloud_data_translate.h" using namespace testing::ext; using namespace OHOS::DistributedData; @@ -194,36 +193,8 @@ HWTEST_F(RdbCloudTest, ConvertStatus, TestSize.Level1) EXPECT_EQ(result, DBStatus::LOCAL_ASSET_NOT_FOUND); result = rdbCloud.ConvertStatus(GeneralError::E_TIME_OUT); EXPECT_EQ(result, DBStatus::TIME_OUT); -} - -/** -* @tc.name: BlobToAssets -* @tc.desc: rdb_cloud_data_translate BlobToAsset error test. -* @tc.type: FUNC -* @tc.require: -* @tc.author: SQL -*/ -HWTEST_F(RdbCloudTest, BlobToAssets, TestSize.Level1) -{ - RdbCloudDataTranslate rdbTranslate; - DistributedDB::Asset asset = { - .name = "", - .assetId = "", - .subpath = "", - .uri = "", - .modifyTime = "", - .createTime = "", - .size = "", - .hash = "" - }; - std::vector blob; - auto result = rdbTranslate.BlobToAsset(blob); - EXPECT_EQ(result, asset); - - DistributedDB::Assets assets; - blob = rdbTranslate.AssetsToBlob(assets); - auto results = rdbTranslate.BlobToAssets(blob); - EXPECT_EQ(results, assets); + result = rdbCloud.ConvertStatus(GeneralError::E_CLOUD_DISABLED); + EXPECT_EQ(result, DBStatus::CLOUD_DISABLED); } /** diff --git a/datamgr_service/services/distributeddataservice/service/test/rdb_general_store_test.cpp b/datamgr_service/services/distributeddataservice/service/test/rdb_general_store_test.cpp index 488ec36fdc1305cc395e4e2c886fa7faf20e0c61..11ce24868400b23ee86c81bf971e08cbbf5b5a7b 100644 --- a/datamgr_service/services/distributeddataservice/service/test/rdb_general_store_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/rdb_general_store_test.cpp @@ -996,6 +996,8 @@ HWTEST_F(RdbGeneralStoreTest, ConvertStatus, TestSize.Level1) EXPECT_EQ(result, GeneralError::E_BUSY); result = store->ConvertStatus(DBStatus::DB_ERROR); EXPECT_EQ(result, GeneralError::E_ERROR); + result = store->ConvertStatus(DBStatus::CLOUD_DISABLED); + EXPECT_EQ(result, GeneralError::E_CLOUD_DISABLED); } /** @@ -1063,26 +1065,6 @@ HWTEST_F(RdbGeneralStoreTest, BuildSqlWhenParamValid, TestSize.Level1) EXPECT_EQ(resultSql, expectSql); } -/** -* @tc.name: GetWaterVersionTest -* @tc.desc: GetWaterVersion test -* @tc.type: FUNC -* @tc.require: -* @tc.author: SQL -*/ -HWTEST_F(RdbGeneralStoreTest, GetWaterVersionTest, TestSize.Level1) -{ - auto store = new (std::nothrow) RdbGeneralStore(metaData_); - ASSERT_NE(store, nullptr); - std::string deviceId = ""; - std::vector expected = {}; - std::vector actual = store->GetWaterVersion(deviceId); - EXPECT_EQ(expected, actual); - deviceId = "mock_deviceId"; - actual = store->GetWaterVersion(deviceId); - EXPECT_EQ(expected, actual); -} - /** * @tc.name: LockAndUnLockCloudDBTest * @tc.desc: lock and unlock cloudDB test diff --git a/datamgr_service/services/distributeddataservice/service/test/rdb_query_test.cpp b/datamgr_service/services/distributeddataservice/service/test/rdb_query_test.cpp index 72572e9d31296d6c23fc8493c623ac3e5580d6a0..a8f5f270c6ebc2ac129b4adad1a7f3b57866757c 100644 --- a/datamgr_service/services/distributeddataservice/service/test/rdb_query_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/rdb_query_test.cpp @@ -16,6 +16,7 @@ #include "rdb_query.h" +#include "asset_value.h" #include "gtest/gtest.h" #include "log_print.h" #include "utils/anonymous.h" @@ -179,5 +180,67 @@ HWTEST_F(RdbQueryTest, RdbQueryTest004, TestSize.Level1) EXPECT_TRUE(!values.empty()); EXPECT_FALSE(values.size() != 2); } + +/** +* @tc.name: RdbQueryTest005 +* @tc.desc: RdbQuery function operation test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(RdbQueryTest, RdbQueryTest005, TestSize.Level1) +{ + RdbQuery rdbQuery; + DistributedRdb::PredicatesMemo predicates; + predicates.tables_.push_back("table"); + std::vector assets; + NativeRdb::AssetValue asset{ .name = "name1" }; + assets.push_back(asset); + NativeRdb::ValueObject object(assets); + predicates.AddOperation(DistributedRdb::RdbPredicateOperator::EQUAL_TO, "test", object); + rdbQuery.MakeCloudQuery(predicates); + EXPECT_EQ(predicates.operations_.size(), 1); +} + +/** +* @tc.name: RdbQueryTest006 +* @tc.desc: RdbQuery function operation test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(RdbQueryTest, RdbQueryTest006, TestSize.Level1) +{ + RdbQuery rdbQuery; + DistributedRdb::PredicatesMemo predicates; + predicates.tables_.push_back("table"); + std::vector assets; + NativeRdb::AssetValue asset{ .name = "name1" }; + NativeRdb::ValueObject object(asset); + predicates.AddOperation(DistributedRdb::RdbPredicateOperator::EQUAL_TO, "test", object); + rdbQuery.MakeCloudQuery(predicates); + EXPECT_EQ(predicates.operations_.size(), 1); +} + +/** +* @tc.name: RdbQueryTest007 +* @tc.desc: RdbQuery function operation test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(RdbQueryTest, RdbQueryTest007, TestSize.Level1) +{ + RdbQuery rdbQuery; + DistributedRdb::PredicatesMemo predicates; + predicates.tables_.push_back("table"); + std::vector assets; + NativeRdb::AssetValue asset{ .name = "name1" }; + assets.push_back(asset); + NativeRdb::ValueObject object(assets); + predicates.AddOperation(DistributedRdb::RdbPredicateOperator::IN, "test", object); + rdbQuery.MakeCloudQuery(predicates); + EXPECT_EQ(predicates.operations_.size(), 1); +} } // namespace DistributedRDBTest } // namespace OHOS::Test \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/rdb_service_impl_test.cpp b/datamgr_service/services/distributeddataservice/service/test/rdb_service_impl_test.cpp deleted file mode 100644 index 6c3800397df38656afd8530f5b5e0e07c78707e4..0000000000000000000000000000000000000000 --- a/datamgr_service/services/distributeddataservice/service/test/rdb_service_impl_test.cpp +++ /dev/null @@ -1,376 +0,0 @@ -/* -* 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 "rdb_service_impl.h" - -#include -#include -#include - -#include "accesstoken_kit.h" -#include "account/account_delegate.h" -#include "bootstrap.h" -#include "checker/checker_manager.h" -#include "communicator/device_manager_adapter.h" -#include "gtest/gtest.h" -#include "ipc_skeleton.h" -#include "metadata/meta_data_manager.h" -#include "metadata/store_meta_data.h" -#include "mock/db_store_mock.h" -#include "mock/general_store_mock.h" -#include "rdb_notifier_stub.h" -#include "store/auto_cache.h" -#include "token_setproc.h" -#include "types.h" - -using namespace testing::ext; -using namespace OHOS; -using namespace OHOS::DistributedData; -using namespace OHOS::DistributedRdb; -using namespace OHOS::Security::AccessToken; -using DmAdapter = OHOS::DistributedData::DeviceManagerAdapter; -namespace OHOS::Test { -namespace DistributedRDBTest { -constexpr int USER_ID = 100; -constexpr int INST_INDEX = 0; -constexpr int IPC_KEY = 222222; -constexpr size_t IPC_SIZE = 4096 * (sizeof(RdbServiceImpl) / 4096 + 1); -constexpr const char* BUNDLE_NAME = "ohos.RdbServiceImplTest.BundleName"; -constexpr const char* STORE_ID = "RdbServiceImplTestStoreId"; -constexpr const char* CHECK_NAME = "SystemChecker"; - -void AllocAndSetHapToken() -{ - HapInfoParams info = { .userID = USER_ID, - .bundleName = BUNDLE_NAME, - .instIndex = INST_INDEX, - .appIDDesc = BUNDLE_NAME, - .isSystemApp = true }; - - HapPolicyParams policy = { .apl = APL_NORMAL, .domain = "test.domain", .permList = {}, .permStateList = {} }; - auto tokenID = AccessTokenKit::AllocHapToken(info, policy); - SetSelfTokenID(tokenID.tokenIDEx); -} -class TestChecker : public CheckerManager::Checker { -public: - TestChecker() noexcept - { - CheckerManager::GetInstance().RegisterPlugin( - CHECK_NAME, [this]() -> auto { return this; }); - } - ~TestChecker() {} - void Initialize() override {} - bool SetTrustInfo(const CheckerManager::Trust& trust) override - { - return true; - } - std::string GetAppId(const CheckerManager::StoreInfo& info) override - { - return info.bundleName; - } - bool IsValid(const CheckerManager::StoreInfo& info) override - { - return true; - } - bool SetDistrustInfo(const CheckerManager::Distrust& distrust) override - { - return true; - }; - - bool IsDistrust(const CheckerManager::StoreInfo& info) override - { - return true; - } - bool AddDynamicStore(const CheckerManager::StoreInfo& storeInfo) override - { - return false; - } - bool AddStaticStore(const CheckerManager::StoreInfo& storeInfo) override - { - return false; - } - vector GetDynamicStores() override - { - return {}; - } - vector GetStaticStores() override - { - return {}; - } - bool IsDynamic(const CheckerManager::StoreInfo& info) override - { - return false; - } - bool IsStatic(const CheckerManager::StoreInfo& info) override - { - return false; - } - bool SetSwitchesInfo(const CheckerManager::Switches& switches) override - { - return false; - } - bool IsSwitches(const CheckerManager::StoreInfo& info) override - { - return false; - } - -private: - static TestChecker instance_; -}; -__attribute__((used)) TestChecker TestChecker::instance_; -class NotifierMock : public RdbNotifierStub { -public: - NotifierMock(const SyncCompleteHandler& syncCompleteHandler = nullptr, - const AutoSyncCompleteHandler& autoSyncCompleteHandler = nullptr, - const DataChangeHandler& dataChangeHandler = nullptr) - : RdbNotifierStub(syncCompleteHandler, autoSyncCompleteHandler, dataChangeHandler) - { - } - virtual ~NotifierMock() = default; - int OnComplete(uint32_t, Details&&) - { - return RDB_OK; - } - int OnChange(const Origin&, const PrimaryFields&, ChangeInfo&&) - { - times_++; - return RDB_OK; - } - int GetTimes() - { - return times_; - } - -private: - std::atomic_int times_ = 0; -}; - -class RdbServiceImplMock : public RdbServiceImpl { -public: - RdbServiceImplMock() = default; - virtual ~RdbServiceImplMock() = default; -}; - -class RdbServiceImplTest : public testing::Test { -public: - static void SetUpTestCase(void); - static void TearDownTestCase(void); - void SetUp(); - void TearDown(); - // RdbServiceImpl* CreateShareRdbService(int id); - static StoreMetaData GetStoreMetaData(); - static std::shared_ptr dbStoreMock_; -}; - -std::shared_ptr RdbServiceImplTest::dbStoreMock_ = std::make_shared(); - -StoreMetaData RdbServiceImplTest::GetStoreMetaData() -{ - StoreMetaData storeMetaData; - storeMetaData.deviceId = DmAdapter::GetInstance().GetLocalDevice().uuid; - storeMetaData.bundleName = BUNDLE_NAME; - storeMetaData.storeId = STORE_ID; - storeMetaData.appId = BUNDLE_NAME; - storeMetaData.instanceId = 0; - storeMetaData.isAutoSync = true; - storeMetaData.storeType = DistributedRdb::RDB_DEVICE_COLLABORATION; - storeMetaData.area = OHOS::DistributedKv::EL1; - storeMetaData.tokenId = OHOS::IPCSkeleton::GetCallingTokenID(); - storeMetaData.user = - std::to_string(DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(storeMetaData.tokenId)); - return storeMetaData; -} - -void RdbServiceImplTest::SetUpTestCase(void) -{ - AllocAndSetHapToken(); - AutoCache::GetInstance().RegCreator(RDB_DEVICE_COLLABORATION, [](const StoreMetaData& metaData) -> GeneralStore* { - return new (std::nothrow) GeneralStoreMock(metaData); - }); - MetaDataManager::GetInstance().Initialize(dbStoreMock_, nullptr); - std::vector checks{ CHECK_NAME }; - CheckerManager::GetInstance().LoadCheckers(checks); - FeatureSystem::GetInstance().GetCreator("relational_store")(); -} - -void RdbServiceImplTest::TearDownTestCase(void) {} - -void RdbServiceImplTest::SetUp() {} - -void RdbServiceImplTest::TearDown() -{ - AutoCache::GetInstance().CloseStore(OHOS::IPCSkeleton::GetCallingTokenID()); - if (dbStoreMock_ != nullptr) { - dbStoreMock_->Reset(); - } -} -//RdbServiceImpl* RdbServiceImplTest::CreateShareRdbService(int id) { -// auto ptr = static_cast(shmat(id, nullptr, 0)); -// ASSERT_TRUE(reinterpret_cast(ptr) != -1) << "ptr: " << reinterpret_cast(ptr); -// auto rdbService = new (ptr) RdbServiceImpl(); -// ASSERT_NE(rdbService, nullptr); -// return rdbService -//} - -/** -* @tc.name: InitNotifierOnce -* @tc.desc: InitNotifierOnce and be able to notify normally -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ -HWTEST_F(RdbServiceImplTest, InitNotifierOnce, TestSize.Level0) -{ - GTEST_LOG_(INFO) << "RdbServiceImplTest InitNotifierOnce start"; - std::shared_ptr rdbService = std::make_shared(); - RdbSyncerParam param; - param.bundleName_ = BUNDLE_NAME; - param.storeName_ = STORE_ID; - sptr notifierMock{ new NotifierMock() }; - ASSERT_EQ(rdbService->InitNotifier(param, notifierMock), RDB_OK); - SubscribeOption option; - option.mode = CLOUD_DETAIL; - ASSERT_EQ(rdbService->Subscribe(param, option, nullptr), RDB_OK); - auto storeMeta = GetStoreMetaData(); - ASSERT_TRUE(MetaDataManager::GetInstance().SaveMeta(storeMeta.GetKey(), storeMeta)); - auto identifier = DistributedDB::RelationalStoreManager::GetRelationalStoreIdentifier(storeMeta.user, - storeMeta.appId, storeMeta.storeId); - DistributedDB::AutoLaunchParam autoLaunchParam; - ASSERT_TRUE(rdbService->ResolveAutoLaunch(identifier, autoLaunchParam)); - auto store = std::static_pointer_cast(AutoCache::GetInstance().GetStore(storeMeta, {})); - ASSERT_NE(store, nullptr); - ASSERT_EQ(store->OnChange(GeneralWatcher::Origin(), {}, {}), GeneralError::E_OK); - ASSERT_EQ(notifierMock->GetTimes(), 1); - ASSERT_EQ(rdbService->UnSubscribe(param, option, nullptr), RDB_OK); - ASSERT_EQ(store->OnChange(GeneralWatcher::Origin(), {}, {}), GeneralError::E_OK); - ASSERT_EQ(notifierMock->GetTimes(), 1); - GTEST_LOG_(INFO) << "RdbServiceImplTest InitNotifierOnce end"; -} - -/** -* @tc.name: InitNotifierTwiceUsingDifferentPid -* @tc.desc: use of InitNotifier() by different processes with the same tokenID. -* 1). all processes can received notification -* 2). the process can received notification after the other process exit. -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ -HWTEST_F(RdbServiceImplTest, InitNotifierTwiceUsingDifferentPid, TestSize.Level0) -{ - GTEST_LOG_(INFO) << "RdbServiceImplTest InitNotifierTwiceUsingDifferentPid start"; - auto id = shmget(random(), IPC_SIZE, IPC_CREAT | 0666); - ASSERT_TRUE(id > 0) << "IPC_SIZE: " << IPC_SIZE << "errno: " << errno; - pid_t pid = fork(); - ASSERT_NE(pid, -1) << "fork failed"; - RdbServiceImpl* rdbService = nullptr; - if (pid != 0) { - auto ptr = static_cast(shmat(id, nullptr, 0)); - ASSERT_TRUE(reinterpret_cast(ptr) != -1) << "ptr: " << reinterpret_cast(ptr); - rdbService = new (ptr) RdbServiceImplMock(); - ASSERT_NE(rdbService, nullptr); - } else { - sleep(1); - rdbService = static_cast(shmat(id, nullptr, 0)); - ASSERT_TRUE(reinterpret_cast(rdbService) != -1) << "ptr: " << reinterpret_cast(rdbService); - } - RdbSyncerParam param; - param.bundleName_ = BUNDLE_NAME; - param.storeName_ = STORE_ID; - sptr notifierMock = new NotifierMock(); - ASSERT_EQ(rdbService->InitNotifier(param, notifierMock), RDB_OK) << "InitNotifier failed, pid:" << getpid; - SubscribeOption option; - option.mode = CLOUD_DETAIL; - ASSERT_EQ(rdbService->Subscribe(param, option, nullptr), RDB_OK); - if (pid == 0) { - sleep(3); - ASSERT_EQ(notifierMock->GetTimes(), 1); - rdbService->OnAppExit(0, OHOS::IPCSkeleton::GetCallingPid(), OHOS::IPCSkeleton::GetCallingTokenID(), - BUNDLE_NAME); - _exit(0); - } - auto storeMeta = GetStoreMetaData(); - ASSERT_TRUE(MetaDataManager::GetInstance().SaveMeta(storeMeta.GetKey(), storeMeta)); - auto identifier = DistributedDB::RelationalStoreManager::GetRelationalStoreIdentifier(storeMeta.user, - storeMeta.appId, storeMeta.storeId); - DistributedDB::AutoLaunchParam autoLaunchParam; - ASSERT_TRUE(rdbService->ResolveAutoLaunch(identifier, autoLaunchParam)); - auto store = std::static_pointer_cast(AutoCache::GetInstance().GetStore(storeMeta, {})); - ASSERT_NE(store, nullptr); - ASSERT_EQ(store->OnChange(GeneralWatcher::Origin(), {}, {}), GeneralError::E_OK); - EXPECT_EQ(notifierMock->GetTimes(), 1); - int status = 0; - ASSERT_EQ(wait(&status), pid); - ASSERT_EQ(store->OnChange(GeneralWatcher::Origin(), {}, {}), GeneralError::E_OK); - EXPECT_EQ(notifierMock->GetTimes(), 2); - rdbService->~RdbServiceImpl(); - shmdt(rdbService); - shmctl(id, IPC_RMID, nullptr); - GTEST_LOG_(INFO) << "RdbServiceImplTest InitNotifierTwiceUsingDifferentPid end"; -} - -/** -* @tc.name: SubscribeTwoStores -* @tc.desc: Notify twice when a process subscribes to two stores, and notify once when subscribing to one store. -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ -HWTEST_F(RdbServiceImplTest, SubscribeTwoStores, TestSize.Level0) -{ - GTEST_LOG_(INFO) << "RdbServiceImplTest SubscribeTwoStores start"; - std::shared_ptr rdbService = std::make_shared(); - RdbSyncerParam param; - param.bundleName_ = BUNDLE_NAME; - sptr notifierMock{ new NotifierMock() }; - ASSERT_EQ(rdbService->InitNotifier(param, notifierMock), RDB_OK); - SubscribeOption option; - option.mode = REMOTE; - - param.storeName_ = std::string(STORE_ID) + "1"; - ASSERT_EQ(rdbService->Subscribe(param, option, nullptr), RDB_OK); - auto storeMeta = GetStoreMetaData(); - storeMeta.storeId = param.storeName_; - ASSERT_TRUE(MetaDataManager::GetInstance().SaveMeta(storeMeta.GetKey(), storeMeta)); - auto identifier = DistributedDB::RelationalStoreManager::GetRelationalStoreIdentifier(storeMeta.user, - storeMeta.appId, storeMeta.storeId); - DistributedDB::AutoLaunchParam autoLaunchParam; - ASSERT_TRUE(rdbService->ResolveAutoLaunch(identifier, autoLaunchParam)); - auto store1 = std::static_pointer_cast(AutoCache::GetInstance().GetStore(storeMeta, {})); - ASSERT_NE(store1, nullptr); - - param.storeName_ = std::string(STORE_ID) + "2"; - ASSERT_EQ(rdbService->Subscribe(param, option, nullptr), RDB_OK); - storeMeta.storeId = param.storeName_; - MetaDataManager::GetInstance().SaveMeta(storeMeta.GetKey(), storeMeta); - identifier = DistributedDB::RelationalStoreManager::GetRelationalStoreIdentifier(storeMeta.user, storeMeta.appId, - storeMeta.storeId); - ASSERT_TRUE(rdbService->ResolveAutoLaunch(identifier, autoLaunchParam)); - auto store2 = std::static_pointer_cast(AutoCache::GetInstance().GetStore(storeMeta, {})); - ASSERT_NE(store2, nullptr); - - ASSERT_EQ(store1->OnChange(GeneralWatcher::Origin(), {}, {}), GeneralError::E_OK); - ASSERT_EQ(notifierMock->GetTimes(), 1); - ASSERT_EQ(store2->OnChange(GeneralWatcher::Origin(), {}, {}), GeneralError::E_OK); - ASSERT_EQ(notifierMock->GetTimes(), 2); - - ASSERT_EQ(rdbService->UnSubscribe(param, option, nullptr), RDB_OK); - ASSERT_EQ(store1->OnChange(GeneralWatcher::Origin(), {}, {}), GeneralError::E_OK); - ASSERT_EQ(notifierMock->GetTimes(), 3); - ASSERT_EQ(store2->OnChange(GeneralWatcher::Origin(), {}, {}), GeneralError::E_OK); - ASSERT_EQ(notifierMock->GetTimes(), 3); - GTEST_LOG_(INFO) << "RdbServiceImplTest SubscribeTwoStores end"; -} -} // namespace DistributedRDBTest -} // namespace OHOS::Test \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/udmf_checker_manager_test.cpp b/datamgr_service/services/distributeddataservice/service/test/udmf_checker_manager_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..014b07c6240e9f0ba6411264e6e30fef88ebc8d9 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/test/udmf_checker_manager_test.cpp @@ -0,0 +1,72 @@ +/* +* Copyright (c) 2024 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 "UdmfCheckerManagerTest" + +#include "checker_manager.h" +#include "concurrent_map.h" +#include "error_code.h" +#include "gtest/gtest.h" +#include "unified_types.h" +#include "uri.h" + +using namespace OHOS; +using namespace testing::ext; +using namespace OHOS::UDMF; +namespace OHOS::Test { +namespace DistributedDataTest { + +class UdmfCheckerManagerTest : public testing::Test { +public: + static void SetUpTestCase(void){}; + static void TearDownTestCase(void){}; + void SetUp(){}; + void TearDown(){}; +}; + +/** +* @tc.name: IsValid001 +* @tc.desc: CheckerManager is IsValid function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(UdmfCheckerManagerTest, IsValid001, TestSize.Level1) +{ + std::vector privileges; + UDMF::CheckerManager::CheckInfo info; + bool result = UDMF::CheckerManager::GetInstance().IsValid(privileges, info); + EXPECT_EQ(result, true); +} + +/** +* @tc.name: IsValid002 +* @tc.desc: CheckerManager is IsValid function test. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(UdmfCheckerManagerTest, IsValid002, TestSize.Level1) +{ + UDMF::CheckerManager checkerManager; + std::vector privileges; + UDMF::CheckerManager::CheckInfo info; + UDMF::CheckerManager::Checker *checker = nullptr; + checkerManager.checkers_["DataChecker"] = checker; + bool result = checkerManager.IsValid(privileges, info); + EXPECT_EQ(result, false); +} +} // namespace DistributedDataTest +} // namespace OHOS::Test \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/udmf_run_time_store_test.cpp b/datamgr_service/services/distributeddataservice/service/test/udmf_run_time_store_test.cpp index d625d654195d5454c0e7634c12ad5d0e0ff3dfd4..ec7fb210ab6927ec422e01bf588186b7495d885d 100644 --- a/datamgr_service/services/distributeddataservice/service/test/udmf_run_time_store_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/udmf_run_time_store_test.cpp @@ -46,12 +46,13 @@ namespace DistributedDataTest { static void GrantPermissionNative() { - const char **perms = new const char *[2]; + const char **perms = new const char *[3]; perms[0] = "ohos.permission.DISTRIBUTED_DATASYNC"; perms[1] = "ohos.permission.ACCESS_SERVICE_DM"; + perms[2] = "ohos.permission.MONITOR_DEVICE_NETWORK_STATE"; // perms[2] is a permission parameter TokenInfoParams infoInstance = { .dcapsNum = 0, - .permsNum = 2, + .permsNum = 3, .aclsNum = 0, .dcaps = nullptr, .perms = perms, @@ -207,6 +208,9 @@ HWTEST_F(UdmfRunTimeStoreTest, PutEntries003, TestSize.Level1) status = store->GetEntries(KEY_PREFIX, entries); EXPECT_EQ(E_OK, status); EXPECT_EQ(0, entries.size()); + + status = store->Delete(KEY_PREFIX); + EXPECT_EQ(E_OK, status); } /** @@ -240,11 +244,14 @@ HWTEST_F(UdmfRunTimeStoreTest, PutEntries004, TestSize.Level1) EXPECT_EQ(0, entries.size()); status = store->PutEntries(entrysMix2); - EXPECT_EQ(E_DB_ERROR, status); + EXPECT_EQ(E_OK, status); entries.clear(); status = store->GetEntries(KEY_PREFIX, entries); EXPECT_EQ(E_OK, status); - EXPECT_EQ(0, entries.size()); + EXPECT_EQ(1, entries.size()); + + status = store->Delete(KEY_PREFIX); + EXPECT_EQ(E_OK, status); } /** @@ -284,10 +291,13 @@ HWTEST_F(UdmfRunTimeStoreTest, PutEntries005, TestSize.Level1) GetRandomValue(valueInvalid, MAX_VALUE_SIZE + 1); // 4M + 1 entrysRand[128] = { key, valueInvalid }; status = store->PutEntries(entrysRand); - EXPECT_EQ(E_DB_ERROR, status); + EXPECT_EQ(E_OK, status); status = store->GetEntries(KEY_PREFIX, entries); EXPECT_EQ(E_OK, status); - EXPECT_EQ(0, entries.size()); + EXPECT_EQ(129, entries.size()); + + status = store->Delete(KEY_PREFIX); + EXPECT_EQ(E_OK, status); } /** @@ -326,6 +336,9 @@ HWTEST_F(UdmfRunTimeStoreTest, DeleteEntries001, TestSize.Level1) status = store->GetEntries(KEY_PREFIX, entries); EXPECT_EQ(E_OK, status); EXPECT_EQ(0, entries.size()); + + status = store->Delete(KEY_PREFIX); + EXPECT_EQ(E_OK, status); } /** @@ -366,6 +379,9 @@ HWTEST_F(UdmfRunTimeStoreTest, DeleteEntries002, TestSize.Level1) status = store->GetEntries(KEY_PREFIX, entries); EXPECT_EQ(E_OK, status); EXPECT_EQ(0, entries.size()); + + status = store->Delete(KEY_PREFIX); + EXPECT_EQ(E_OK, status); } /** @@ -415,6 +431,9 @@ HWTEST_F(UdmfRunTimeStoreTest, Get001, TestSize.Level1) status = store->Get(KEY_PREFIX, unifiedData); EXPECT_EQ(E_NOT_FOUND, status); + + status = store->Delete(KEY_PREFIX); + EXPECT_EQ(E_OK, status); } /** @@ -445,6 +464,9 @@ HWTEST_F(UdmfRunTimeStoreTest, Get002, TestSize.Level1) UnifiedData data1; status = store->Get(EMPTY_DEVICE_ID, data1); EXPECT_EQ(E_NOT_FOUND, status); + + status = store->Delete(KEY_PREFIX); + EXPECT_EQ(E_OK, status); } /** @@ -481,6 +503,9 @@ HWTEST_F(UdmfRunTimeStoreTest, GetDetailsFromUData, TestSize.Level1) EXPECT_EQ(records.size(), 0); status = store->GetDetailsFromUData(data1, details1); EXPECT_FALSE(status); + + status = store->Delete(KEY_PREFIX); + EXPECT_EQ(E_OK, status); } /** @@ -509,6 +534,8 @@ HWTEST_F(UdmfRunTimeStoreTest, GetDetailsFromUData01, TestSize.Level1) vector entries; status = store->GetEntries(KEY_PREFIX, entries); EXPECT_EQ(E_OK, status); + status = store->Delete(KEY_PREFIX); + EXPECT_EQ(E_OK, status); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); UnifiedData inputData; @@ -540,10 +567,9 @@ HWTEST_F(UdmfRunTimeStoreTest, GetSummary, TestSize.Level1) UnifiedData data; UDDetails details; details.insert({ "udmf_key", "udmf_value" }); - Text text; - text.SetDetails(details); - std::shared_ptr record1 = std::make_shared(text); - data.AddRecord(record1); + auto text = std::make_shared(); + text->SetDetails(details); + data.AddRecord(text); Summary summary; auto status = store->GetSummary(KEY_PREFIX, summary); diff --git a/datamgr_service/services/distributeddataservice/service/test/unittest/cloud/cloud_data_test.cpp b/datamgr_service/services/distributeddataservice/service/test/unittest/cloud/cloud_data_test.cpp index 5180d7d9de3da72639ff4dbbdc1862b7d3c57fe7..9229bd8ad00b488beedaac5f58a904c2578ea059 100644 --- a/datamgr_service/services/distributeddataservice/service/test/unittest/cloud/cloud_data_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/unittest/cloud/cloud_data_test.cpp @@ -78,7 +78,7 @@ void CloudDataTest::InitMetaData() metaData_.appId = TEST_DISTRIBUTED_DATA_BUNDLE; metaData_.bundleName = TEST_DISTRIBUTED_DATA_BUNDLE; metaData_.tokenId = OHOS::IPCSkeleton::GetCallingTokenID(); - metaData_.user = std::to_string(DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(metaData_.tokenId)); + metaData_.user = std::to_string(DistributedData::AccountDelegate::GetInstance()->GetUserByToken(metaData_.tokenId)); metaData_.area = OHOS::DistributedKv::EL1; metaData_.instanceId = 0; metaData_.isAutoSync = true; @@ -141,13 +141,13 @@ StoreMetaData CloudDataTest::GetStoreMetaData() storeMetaData.area = OHOS::DistributedKv::EL1; storeMetaData.tokenId = OHOS::IPCSkeleton::GetCallingTokenID(); storeMetaData.user = - std::to_string(DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(storeMetaData.tokenId)); + std::to_string(DistributedData::AccountDelegate::GetInstance()->GetUserByToken(storeMetaData.tokenId)); return storeMetaData; } void CloudDataTest::SetUpTestCase(void) { - MetaDataManager::GetInstance().Initialize(dbStoreMock_, nullptr); + MetaDataManager::GetInstance().Initialize(dbStoreMock_, nullptr, ""); FeatureSystem::GetInstance().GetCreator("cloud")(); FeatureSystem::GetInstance().GetCreator("relational_store")(); diff --git a/datamgr_service/services/distributeddataservice/service/test/water_version_manager_test.cpp b/datamgr_service/services/distributeddataservice/service/test/water_version_manager_test.cpp deleted file mode 100644 index d520a57ba082315ebe02c9537dd6e822bfc2bb05..0000000000000000000000000000000000000000 --- a/datamgr_service/services/distributeddataservice/service/test/water_version_manager_test.cpp +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright (c) 2024 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 "water_version_manager.h" - -#include "accesstoken_kit.h" -#include "block_data.h" -#include "bootstrap.h" -#include "checker/checker_manager.h" -#include "device_manager_adapter.h" -#include "executor_pool.h" -#include "gtest/gtest.h" -#include "metadata/matrix_meta_data.h" -#include "metadata/meta_data_manager.h" -#include "mock/checker_mock.h" -#include "mock/db_store_mock.h" -#include "nativetoken_kit.h" -#include "serializable/serializable.h" -#include "token_setproc.h" -#include "utils/constant.h" -using namespace testing::ext; -using namespace OHOS::DistributedData; -using namespace DistributedDB; -using namespace OHOS::Security::AccessToken; -using WvManager = WaterVersionManager; -using DMAdapter = DeviceManagerAdapter; -using WaterVersionMetaData = WvManager::WaterVersionMetaData; - -namespace OHOS::Test { -namespace DistributedDataTest { -static std::vector> staticStores_ = { { "bundle0", "store0" }, - { "bundle1", "store0" }, { "bundle2", "store0" } }; -static std::vector> dynamicStores_ = { { "bundle0", "store1" }, - { "bundle3", "store0" }, { "bundle4", "store0" } }; -class WaterVersionManagerTest : public testing::Test { -public: - static void SetUpTestCase(void); - static void TearDownTestCase(void); - void SetUp(); - void TearDown(); - -protected: - static constexpr const char *TEST_DEVICE = "14a0a92a428005db27c40bad46bf145fede38ec37effe0347cd990fcb031f320"; - static void GrantPermissionNative(); - void InitMetaData(); - - static std::shared_ptr dbStoreMock_; - static WaterVersionMetaData dynamicMeta_; - static WaterVersionMetaData staticMeta_; - static CheckerMock instance_; -}; - -void WaterVersionManagerTest::GrantPermissionNative() -{ - const char **perms = new const char *[2]; - perms[0] = "ohos.permission.DISTRIBUTED_DATASYNC"; - perms[1] = "ohos.permission.ACCESS_SERVICE_DM"; - TokenInfoParams infoInstance = { - .dcapsNum = 0, - .permsNum = 2, - .aclsNum = 0, - .dcaps = nullptr, - .perms = perms, - .acls = nullptr, - .processName = "WaterVersionManagerTest", - .aplStr = "system_basic", - }; - uint64_t tokenId = GetAccessTokenId(&infoInstance); - SetSelfTokenID(tokenId); - AccessTokenKit::ReloadNativeTokenInfo(); - delete[] perms; -} -CheckerMock WaterVersionManagerTest::instance_; -std::shared_ptr WaterVersionManagerTest::dbStoreMock_ = std::make_shared(); -WaterVersionMetaData WaterVersionManagerTest::staticMeta_; -WaterVersionMetaData WaterVersionManagerTest::dynamicMeta_; -void WaterVersionManagerTest::SetUpTestCase(void) -{ - size_t max = 12; - size_t min = 5; - DeviceManagerAdapter::GetInstance().Init(std::make_shared(max, min)); - GrantPermissionNative(); - Bootstrap::GetInstance().LoadCheckers(); - std::vector dynamicStores; - for (auto &[bundle, store] : dynamicStores_) { - dynamicStores.push_back({ 0, 0, bundle, store }); - instance_.SetDynamic(dynamicStores); - } - std::vector staticStores; - for (auto &[bundle, store] : staticStores_) { - staticStores.push_back({ 0, 0, bundle, store }); - instance_.SetStatic(staticStores); - } - WaterVersionManager::GetInstance().Init(); - MetaDataManager::GetInstance().Initialize(dbStoreMock_, nullptr); - - staticMeta_.deviceId = TEST_DEVICE; - staticMeta_.version = WvManager::WaterVersionMetaData::DEFAULT_VERSION; - staticMeta_.waterVersion = 0; - staticMeta_.type = WvManager::STATIC; - staticMeta_.keys.clear(); - for (auto &it : staticStores_) { - staticMeta_.keys.push_back(Constant::Join(it.first, Constant::KEY_SEPARATOR, { it.second })); - } - staticMeta_.infos = { staticMeta_.keys.size(), std::vector(staticMeta_.keys.size(), 0) }; - dynamicMeta_ = staticMeta_; - dynamicMeta_.keys.clear(); - for (auto &it : dynamicStores_) { - dynamicMeta_.keys.push_back(Constant::Join(it.first, Constant::KEY_SEPARATOR, { it.second })); - } - dynamicMeta_.infos = { dynamicMeta_.keys.size(), std::vector(dynamicMeta_.keys.size(), 0) }; - dynamicMeta_.type = WvManager::DYNAMIC; -} - -void WaterVersionManagerTest::TearDownTestCase(void) {} - -void WaterVersionManagerTest::SetUp() -{ - InitMetaData(); -} - -void WaterVersionManagerTest::TearDown() -{ - WvManager::GetInstance().DelWaterVersion(TEST_DEVICE); - WvManager::GetInstance().DelWaterVersion(DMAdapter::GetInstance().GetLocalDevice().uuid); - MetaDataManager::GetInstance().DelMeta(staticMeta_.GetKey(), true); - MetaDataManager::GetInstance().DelMeta(dynamicMeta_.GetKey(), true); - MatrixMetaData matrixMetaData; - matrixMetaData.deviceId = DMAdapter::GetInstance().GetLocalDevice().uuid; - MetaDataManager::GetInstance().DelMeta(matrixMetaData.GetKey(), true); -} - -void WaterVersionManagerTest::InitMetaData() -{ - MetaDataManager::GetInstance().SaveMeta(staticMeta_.GetKey(), staticMeta_, true); - MetaDataManager::GetInstance().SaveMeta(dynamicMeta_.GetKey(), dynamicMeta_, true); -} - -/** -* @tc.name: SetWaterVersionTest1 -* @tc.desc: updating remote device water version once; -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ -HWTEST_F(WaterVersionManagerTest, SetWaterVersionTest1, TestSize.Level0) -{ - std::string waterVersion = WvManager::GetInstance().GetWaterVersion(TEST_DEVICE, WvManager::STATIC); - ASSERT_EQ(waterVersion, Serializable::Marshall(staticMeta_)) << "meta: " << waterVersion; - WvManager::WaterVersionMetaData meta; - ASSERT_TRUE(Serializable::Unmarshall(waterVersion, meta)); - meta.infos[0] = { 1, 0, 0 }; - meta.waterVersion = 1; - - EXPECT_TRUE(WvManager::GetInstance().SetWaterVersion(staticStores_[0].first, staticStores_[0].second, - Serializable::Marshall(meta))) - << Serializable::Marshall(meta); - - waterVersion = WvManager::GetInstance().GetWaterVersion(TEST_DEVICE, WvManager::STATIC); - ASSERT_EQ(Serializable::Marshall(meta), waterVersion); - auto [success, version] = WvManager::GetInstance().GetVersion(TEST_DEVICE, WvManager::STATIC); - EXPECT_TRUE(success && version == 1) - << "success:" << success << " version:" << version << " meta: " << meta.ToAnonymousString(); - - // update to matrixMeta - MatrixMetaData matrixMetaData; - matrixMetaData.deviceId = TEST_DEVICE; - EXPECT_TRUE(MetaDataManager::GetInstance().LoadMeta(matrixMetaData.GetConsistentKey(), matrixMetaData, true)); - EXPECT_EQ(matrixMetaData.statics, version << 4); -} - -/** -* @tc.name: SetWaterVersionTest2 -* @tc.desc: Continuously updating remote device water version more than once; -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ -HWTEST_F(WaterVersionManagerTest, SetWaterVersionTest2, TestSize.Level0) -{ - std::string waterVersion = WvManager::GetInstance().GetWaterVersion(TEST_DEVICE, WvManager::STATIC); - ASSERT_EQ(waterVersion, Serializable::Marshall(staticMeta_)) << "meta: " << waterVersion; - WvManager::WaterVersionMetaData meta; - ASSERT_TRUE(Serializable::Unmarshall(waterVersion, meta)); - // first store update - meta.infos[0] = { 1, 0, 0 }; - meta.waterVersion = 1; - EXPECT_TRUE(WvManager::GetInstance().SetWaterVersion(staticStores_[0].first, staticStores_[0].second, - Serializable::Marshall(meta))); - auto [_, version] = WvManager::GetInstance().GetVersion(TEST_DEVICE, WvManager::STATIC); - EXPECT_EQ(version, 1); - - // second store update - meta.infos[1] = { 1, 2, 0 }; - meta.waterVersion = 2; - EXPECT_TRUE(WvManager::GetInstance().SetWaterVersion(staticStores_[1].first, staticStores_[1].second, - Serializable::Marshall(meta))); - std::tie(_, version) = WvManager::GetInstance().GetVersion(TEST_DEVICE, WvManager::STATIC); - EXPECT_EQ(version, 2); - - // update to matrixMeta - MatrixMetaData matrixMetaData; - matrixMetaData.deviceId = TEST_DEVICE; - EXPECT_TRUE(MetaDataManager::GetInstance().LoadMeta(matrixMetaData.GetConsistentKey(), matrixMetaData, true)); - EXPECT_EQ(matrixMetaData.statics, version << 4); -} - -/** -* @tc.name: SetWaterVersionTest3 -* @tc.desc: A updates first, but B synchronizes first -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ -HWTEST_F(WaterVersionManagerTest, SetWaterVersionTest3, TestSize.Level0) -{ - std::string waterVersion = WvManager::GetInstance().GetWaterVersion(TEST_DEVICE, WvManager::DYNAMIC); - ASSERT_EQ(waterVersion, Serializable::Marshall(dynamicMeta_)) << "meta: " << waterVersion; - WvManager::WaterVersionMetaData meta; - ASSERT_TRUE(Serializable::Unmarshall(waterVersion, meta)); - EXPECT_EQ(meta.GetVersion(), 0) << "meta: " << Serializable::Marshall(meta); - - //bundle2 updated later, but sync first. Do not update waterVersion - meta.infos[1] = { 1, 2, 0 }; - meta.waterVersion = 2; - EXPECT_TRUE(WvManager::GetInstance().SetWaterVersion(dynamicStores_[1].first, dynamicStores_[1].second, - Serializable::Marshall(meta))); - auto res = WvManager::GetInstance().GetVersion(TEST_DEVICE, WvManager::STATIC); - EXPECT_TRUE(res.first && res.second == 0) - << "success:" << res.first << " version:" << res.second << " meta: " << meta.ToAnonymousString(); - - //bundle1 updated earlier, but sync later. update waterVersion - meta.infos[0] = { 1, 0, 0 }; - meta.waterVersion = 1; - EXPECT_TRUE(WvManager::GetInstance().SetWaterVersion(dynamicStores_[0].first, dynamicStores_[0].second, - Serializable::Marshall(meta))); - res = WvManager::GetInstance().GetVersion(TEST_DEVICE, WvManager::DYNAMIC); - EXPECT_TRUE(res.first && res.second == 2) - << "success:" << res.first << " version:" << res.second << " meta: " << meta.ToAnonymousString(); - - // update to matrixMeta - MatrixMetaData matrixMetaData; - matrixMetaData.deviceId = TEST_DEVICE; - EXPECT_TRUE(MetaDataManager::GetInstance().LoadMeta(matrixMetaData.GetConsistentKey(), matrixMetaData, true)); - EXPECT_EQ(matrixMetaData.dynamic, res.second << 4); -} - -/** -* @tc.name: SetWaterVersionTest4 -* @tc.desc: updates twice, but sync once -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ -HWTEST_F(WaterVersionManagerTest, SetWaterVersionTest4, TestSize.Level0) -{ - std::string waterVersion = WvManager::GetInstance().GetWaterVersion(TEST_DEVICE, WvManager::STATIC); - ASSERT_EQ(waterVersion, Serializable::Marshall(staticMeta_)) << "meta: " << waterVersion; - WvManager::WaterVersionMetaData meta; - ASSERT_TRUE(Serializable::Unmarshall(waterVersion, meta)); - EXPECT_EQ(meta.GetVersion(), 0) << "meta: " << Serializable::Marshall(meta); - - //bundle1 updated twice, but sync once. update waterVersion - meta.infos[0] = { 2, 0, 0 }; - meta.waterVersion = 2; - EXPECT_TRUE(WvManager::GetInstance().SetWaterVersion(staticStores_[0].first, staticStores_[0].second, - Serializable::Marshall(meta))); - - auto res = WvManager::GetInstance().GetVersion(TEST_DEVICE, WvManager::STATIC); - EXPECT_TRUE(res.first && res.second == 2) - << "success:" << res.first << " version:" << res.second << " meta: " << meta.ToAnonymousString(); -} - -/** -* @tc.name: SetWaterVersionTest5 -* @tc.desc: Update(upload) multiple times, sync(download) fewer times -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ -HWTEST_F(WaterVersionManagerTest, SetWaterVersionTest5, TestSize.Level0) -{ - auto type = WvManager::DYNAMIC; - std::string waterVersion = WvManager::GetInstance().GetWaterVersion(TEST_DEVICE, type); - ASSERT_EQ(waterVersion, Serializable::Marshall(dynamicMeta_)) << "meta: " << waterVersion; - WvManager::WaterVersionMetaData meta; - ASSERT_TRUE(Serializable::Unmarshall(waterVersion, meta)); - EXPECT_EQ(meta.GetVersion(), 0) << "meta: " << Serializable::Marshall(meta); - - //order: 0(u)->1(u)->0(u)->2(u)->1(s)->2(s)->1(u)->1(u)->0(s) - //1 sync - meta.infos[0] = { 1, 0, 0 }; - meta.infos[1] = { 1, 2, 0 }; - meta.infos[2] = { 0, 0, 0 }; - meta.waterVersion = 2; - EXPECT_TRUE(WvManager::GetInstance().SetWaterVersion(dynamicStores_[1].first, dynamicStores_[1].second, - Serializable::Marshall(meta))); - - auto res = WvManager::GetInstance().GetVersion(TEST_DEVICE, type); - EXPECT_TRUE(res.first && res.second == 0) - << "success:" << res.first << " version:" << res.second << " meta: " << meta.ToAnonymousString(); - - //2 sync - meta.infos[0] = { 3, 2, 0 }; - meta.infos[1] = { 1, 2, 0 }; - meta.infos[2] = { 3, 2, 4 }; - meta.waterVersion = 4; - EXPECT_TRUE(WvManager::GetInstance().SetWaterVersion(dynamicStores_[2].first, dynamicStores_[2].second, - Serializable::Marshall(meta))); - res = WvManager::GetInstance().GetVersion(TEST_DEVICE, type); - EXPECT_TRUE(res.first && res.second == 0) - << "success:" << res.first << " version:" << res.second << " meta: " << meta.ToAnonymousString(); - - //0 sync - meta.infos[0] = { 3, 2, 0 }; - meta.infos[1] = { 1, 2, 0 }; - meta.infos[2] = { 0, 0, 0 }; - meta.waterVersion = 3; - EXPECT_TRUE(WvManager::GetInstance().SetWaterVersion(dynamicStores_[0].first, dynamicStores_[0].second, - Serializable::Marshall(meta))); - res = WvManager::GetInstance().GetVersion(TEST_DEVICE, type); - EXPECT_TRUE(res.first && res.second == 4) - << "success:" << res.first << " version:" << res.second << " meta: " << meta.ToAnonymousString(); -} - -/** -* @tc.name: GenerateWaterVersionTest1 -* @tc.desc: GenerateWaterVersion once, add one to the waterVersion -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ -HWTEST_F(WaterVersionManagerTest, GenerateWaterVersionTest1, TestSize.Level0) -{ - std::string waterVersion = - WvManager::GetInstance().GenerateWaterVersion(staticStores_[0].first, staticStores_[0].second); - WvManager::WaterVersionMetaData meta; - ASSERT_TRUE(Serializable::Unmarshall(waterVersion, meta)) << "waterVersion: " << waterVersion; - EXPECT_EQ(meta.waterVersion, 1) << "waterVersion: " << waterVersion; - - waterVersion = WvManager::GetInstance().GenerateWaterVersion(staticStores_[1].first, staticStores_[1].second); - ASSERT_TRUE(Serializable::Unmarshall(waterVersion, meta)) << "waterVersion: " << waterVersion; - EXPECT_EQ(meta.waterVersion, 2) << "waterVersion: " << waterVersion; - - waterVersion = WvManager::GetInstance().GenerateWaterVersion(staticStores_[0].first, staticStores_[0].second); - ASSERT_TRUE(Serializable::Unmarshall(waterVersion, meta)) << "waterVersion: " << waterVersion; - EXPECT_EQ(meta.waterVersion, 3) << "waterVersion: " << waterVersion; - - MatrixMetaData matrixMetaData; - matrixMetaData.deviceId = DMAdapter::GetInstance().GetLocalDevice().uuid; - auto key = matrixMetaData.GetKey(); - ASSERT_TRUE(MetaDataManager::GetInstance().LoadMeta(key, matrixMetaData, true)); - EXPECT_EQ(matrixMetaData.statics & 0xFFF0, 3 << 4); -} - -/** -* @tc.name: GenerateWaterVersionTest2 -* @tc.desc: Multiple threads simultaneously GenerateWaterVersion -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ -HWTEST_F(WaterVersionManagerTest, GenerateWaterVersionTest2, TestSize.Level0) -{ - auto executorPool = std::make_shared(5, 5); - auto len = dynamicStores_.size(); - for (size_t i = 0; i < 10; ++i) { - executorPool->Execute([index = i % len] { - WvManager::GetInstance().GenerateWaterVersion(dynamicStores_[index].first, dynamicStores_[index].second); - }); - } - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - - auto [success, version] = - WvManager::GetInstance().GetVersion(DMAdapter::GetInstance().GetLocalDevice().uuid, WvManager::DYNAMIC); - EXPECT_EQ(version, 10); - - MatrixMetaData matrixMetaData; - matrixMetaData.deviceId = DMAdapter::GetInstance().GetLocalDevice().uuid; - auto key = matrixMetaData.GetKey(); - ASSERT_TRUE(MetaDataManager::GetInstance().LoadMeta(key, matrixMetaData, true)); - EXPECT_EQ(matrixMetaData.dynamic & 0xFFF0, version << 4); -} - -/** -* @tc.name: GetWaterVersionTest1 -* @tc.desc: GetWaterVersion by different key -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ -HWTEST_F(WaterVersionManagerTest, GetWaterVersionTest1, TestSize.Level0) -{ - auto len = staticStores_.size(); - for (size_t i = 0; i < 10; ++i) { - auto bundle = staticStores_[i % len].first; - auto store = staticStores_[i % len].second; - ASSERT_FALSE(WvManager::GetInstance().GenerateWaterVersion(bundle, store).empty()); - } - for (size_t i = 0; i < len; i++) { - auto waterVersion = WvManager::GetInstance().GetWaterVersion(staticStores_[i].first, staticStores_[i].second); - WvManager::WaterVersionMetaData meta; - ASSERT_TRUE(Serializable::Unmarshall(waterVersion, meta)) << "waterVersion: " << waterVersion; - EXPECT_EQ(meta.waterVersion, 10 / len * len + i + 1 - len * (10 % len <= i ? 1 : 0)); - } -} - -/** -* @tc.name: MixCallTest1 -* @tc.desc: use GenerateWaterVersion to SetWaterVersion -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ -HWTEST_F(WaterVersionManagerTest, MixCallTest1, TestSize.Level0) -{ - std::string waterVersion = - WvManager::GetInstance().GenerateWaterVersion(staticStores_[0].first, staticStores_[0].second); - WvManager::WaterVersionMetaData meta; - ASSERT_TRUE(Serializable::Unmarshall(waterVersion, meta)) << "waterVersion: " << waterVersion; - EXPECT_EQ(meta.waterVersion, 1) << "waterVersion: " << waterVersion; - - meta.deviceId = TEST_DEVICE; - EXPECT_TRUE(WvManager::GetInstance().SetWaterVersion(staticStores_[0].first, staticStores_[0].second, - Serializable::Marshall(meta))); - - auto [_, version] = WvManager::GetInstance().GetVersion(TEST_DEVICE, WvManager::STATIC); - EXPECT_EQ(version, 1) << "version: " << version; -} - -/** -* @tc.name: MixCallTest2 -* @tc.desc: use GenerateWaterVersion to SetWaterVersion and GenerateWaterVersion more than once -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ -HWTEST_F(WaterVersionManagerTest, MixCallTest2, TestSize.Level0) -{ - bool success = false; - uint64_t version = 0; - for (int i = 1; i < 11; ++i) { - int index = i % dynamicMeta_.keys.size(); - std::string waterVersion = - WvManager::GetInstance().GenerateWaterVersion(dynamicStores_[index].first, dynamicStores_[index].second); - WvManager::WaterVersionMetaData meta; - ASSERT_TRUE(Serializable::Unmarshall(waterVersion, meta)) << "waterVersion: " << waterVersion; - EXPECT_EQ(meta.waterVersion, i) << "waterVersion: " << waterVersion; - meta.deviceId = TEST_DEVICE; - EXPECT_TRUE(WvManager::GetInstance().SetWaterVersion(dynamicStores_[index].first, dynamicStores_[index].second, - Serializable::Marshall(meta))); - - std::tie(success, version) = WvManager::GetInstance().GetVersion(TEST_DEVICE, WvManager::DYNAMIC); - EXPECT_TRUE(success && version == i) - << "i:" << i << " success:" << success << " version:" << version << " meta: " << meta.ToAnonymousString(); - } -} -} // namespace DistributedDataTest -} // namespace OHOS::Test \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/udmf/BUILD.gn b/datamgr_service/services/distributeddataservice/service/udmf/BUILD.gn index c791f4bfb94332e044959a754932cafe4705373b..15ae27880b355ae79be0c7f88ca00d21b2f752d7 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/udmf/BUILD.gn @@ -34,10 +34,11 @@ config("module_public_config") { "${udmf_path}/framework/common", "${udmf_path}/interfaces/innerkits/common", "${udmf_path}/interfaces/innerkits/data", + "${data_service_path}/adapter/account/src", ] } -ohos_shared_library("udmf_server") { +ohos_source_set("udmf_server") { branch_protector_ret = "pac_ret" sanitize = { ubsan = true @@ -54,7 +55,9 @@ ohos_shared_library("udmf_server") { "permission/checker_manager.cpp", "permission/data_checker.cpp", "permission/uri_permission_manager.cpp", + "preprocess/data_handler.cpp", "preprocess/preprocess_utils.cpp", + "preprocess/udmf_dialog.cpp", "store/runtime_store.cpp", "store/store_account_observer.cpp", "store/store_cache.cpp", @@ -67,25 +70,31 @@ ohos_shared_library("udmf_server") { cflags = [ "-D_LIBCPP_HAS_COND_CLOCKWAIT", "-Werror", + "-Oz", ] deps = [ - "${data_service_path}/adapter:distributeddata_adapter", "${data_service_path}/framework:distributeddatasvcfwk", - "${data_service_path}/service:distributeddatasvc", + "${data_service_path}/service/bootstrap:distributeddata_bootstrap", ] + defines = [] external_deps = [ "ability_base:zuri", + "ability_runtime:ability_manager", "ability_runtime:uri_permission_mgr", + "ability_runtime:wantagent_innerkits", "access_token:libaccesstoken_sdk", "access_token:libtokenid_sdk", "app_file_service:remote_file_share_native", "bundle_framework:appexecfwk_base", "bundle_framework:appexecfwk_core", "c_utils:utils", + "device_manager:devicemanagersdk", "hilog:libhilog", "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", "ipc:ipc_core", "kv_store:distributeddb", "safwk:system_ability_fwk", @@ -93,8 +102,18 @@ ohos_shared_library("udmf_server") { "udmf:udmf_client", "udmf:utd_client", ] - cflags_cc = [ "-fvisibility=hidden" ] + cflags_cc = [ + "-fvisibility=hidden", + "-Oz", + ] subsystem_name = "distributeddatamgr" part_name = "datamgr_service" + + if (window_manager_use_sceneboard) { + external_deps += [ "window_manager:libwm_lite" ] + defines += [ "SCENE_BOARD_ENABLE" ] + } else { + external_deps += [ "window_manager:libwm" ] + } } diff --git a/datamgr_service/services/distributeddataservice/service/udmf/lifecycle/lifecycle_policy.cpp b/datamgr_service/services/distributeddataservice/service/udmf/lifecycle/lifecycle_policy.cpp index 359dc9f409065f743099b5b83e64587752f050a1..2749c3e5ac0968a0e82a1778a7831a772d163d0f 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/lifecycle/lifecycle_policy.cpp +++ b/datamgr_service/services/distributeddataservice/service/udmf/lifecycle/lifecycle_policy.cpp @@ -86,6 +86,10 @@ Status LifeCyclePolicy::GetTimeoutKeys( } auto curTime = PreProcessUtils::GetTimestamp(); for (const auto &data : datas) { + if (data.GetRuntime() == nullptr) { + ZLOGD("Runtime data is null."); + return E_DB_ERROR; + } if (curTime > data.GetRuntime()->createTime + duration_cast(interval).count() || curTime < data.GetRuntime()->createTime) { timeoutKeys.push_back(data.GetRuntime()->key.key); diff --git a/datamgr_service/services/distributeddataservice/service/udmf/permission/uri_permission_manager.cpp b/datamgr_service/services/distributeddataservice/service/udmf/permission/uri_permission_manager.cpp index 4d5281432ce22f5092e3f407cea15bd258bb707e..29dc713201bc43599d9e9120509bc7451b035908 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/permission/uri_permission_manager.cpp +++ b/datamgr_service/services/distributeddataservice/service/udmf/permission/uri_permission_manager.cpp @@ -30,8 +30,8 @@ UriPermissionManager &UriPermissionManager::GetInstance() return instance; } -Status UriPermissionManager::GrantUriPermission( - const std::vector &allUri, uint32_t tokenId, const std::string &queryKey, uint32_t &completeCount) +Status UriPermissionManager::GrantUriPermission(const std::vector &allUri, uint32_t tokenId, + const std::string &queryKey) { std::string bundleName; if (!PreProcessUtils::GetHapBundleNameByToken(tokenId, bundleName)) { @@ -50,71 +50,19 @@ Status UriPermissionManager::GrantUriPermission( for (size_t index = 0; index < allUri.size(); index += GRANT_URI_PERMISSION_MAX_SIZE) { std::vector uriLst( allUri.begin() + index, allUri.begin() + std::min(index + GRANT_URI_PERMISSION_MAX_SIZE, allUri.size())); - auto status = AAFwk::UriPermissionManagerClient::GetInstance().GrantUriPermissionPrivileged( - uriLst, AAFwk::Want::FLAG_AUTH_READ_URI_PERMISSION, bundleName, instIndex); + auto status = AAFwk::UriPermissionManagerClient::GetInstance().GrantUriPermissionPrivileged(uriLst, + AAFwk::Want::FLAG_AUTH_READ_URI_PERMISSION | + AAFwk::Want::FLAG_AUTH_WRITE_URI_PERMISSION | + AAFwk::Want::FLAG_AUTH_PERSISTABLE_URI_PERMISSION, + bundleName, instIndex); if (status != ERR_OK) { ZLOGE("GrantUriPermission failed, status:%{public}d, queryKey:%{public}s, instIndex:%{public}d.", status, queryKey.c_str(), instIndex); return E_NO_PERMISSION; } - completeCount = std::min(allUri.size(), index + GRANT_URI_PERMISSION_MAX_SIZE); - auto time = std::chrono::steady_clock::now() + std::chrono::minutes(INTERVAL); - std::for_each(uriLst.begin(), uriLst.end(), [&](const Uri &uri) { - auto times = std::make_pair(uri.ToString(), tokenId); - uriTimeout_.Insert(times, time); - }); } ZLOGI("GrantUriPermission end, url size:%{public}zu, queryKey:%{public}s.", allUri.size(), queryKey.c_str()); - - std::unique_lock lock(taskMutex_); - if (taskId_ == ExecutorPool::INVALID_TASK_ID && executorPool_ != nullptr) { - taskId_ = executorPool_->Schedule( - std::chrono::minutes(INTERVAL), std::bind(&UriPermissionManager::RevokeUriPermission, this)); - } return E_OK; } - -void UriPermissionManager::RevokeUriPermission() -{ - auto current = std::chrono::steady_clock::now(); - uriTimeout_.EraseIf([&](const auto &key, const Time &time) { - if (time > current) { - return false; - } - Uri uri(key.first); - uint32_t tokenId = key.second; - std::string bundleName; - if (!PreProcessUtils::GetHapBundleNameByToken(tokenId, bundleName)) { - ZLOGE("Get BundleName fail, tokenId:%{public}u.", tokenId); - return true; - } - int32_t instIndex = -1; - if (!PreProcessUtils::GetInstIndex(tokenId, instIndex)) { - ZLOGE("Get InstIndex fail, tokenId:%{public}u.", tokenId); - return true; - } - int status = AAFwk::UriPermissionManagerClient::GetInstance().RevokeUriPermissionManually( - uri, bundleName, instIndex); - if (status != E_OK) { - ZLOGE("RevokeUriPermission error, permissionCode:%{public}d, bundleName:%{public}s, instIndex:%{public}d", - status, bundleName.c_str(), instIndex); - } - return true; - }); - - std::unique_lock lock(taskMutex_); - if (!uriTimeout_.Empty() && executorPool_ != nullptr) { - ZLOGD("RevokeUriPermission, uriTimeout size:%{public}zu", uriTimeout_.Size()); - taskId_ = executorPool_->Schedule( - std::chrono::minutes(INTERVAL), std::bind(&UriPermissionManager::RevokeUriPermission, this)); - } else { - taskId_ = ExecutorPool::INVALID_TASK_ID; - } -} - -void UriPermissionManager::SetThreadPool(std::shared_ptr executors) -{ - executorPool_ = executors; -} } // namespace UDMF } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/service/udmf/permission/uri_permission_manager.h b/datamgr_service/services/distributeddataservice/service/udmf/permission/uri_permission_manager.h index 61dacb660422ff31d93c855324ef6ead79151ec2..4cbc781267df4b44f442ad2396ea4e705c4c8df1 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/permission/uri_permission_manager.h +++ b/datamgr_service/services/distributeddataservice/service/udmf/permission/uri_permission_manager.h @@ -28,25 +28,14 @@ namespace OHOS { namespace UDMF { class UriPermissionManager { public: - using Time = std::chrono::steady_clock::time_point; static UriPermissionManager &GetInstance(); - Status GrantUriPermission(const std::vector &allUri, uint32_t tokenId, - const std::string &queryKey, uint32_t &completeCount); - void SetThreadPool(std::shared_ptr executors); + Status GrantUriPermission(const std::vector &allUri, uint32_t tokenId, const std::string &queryKey); private: UriPermissionManager() {} ~UriPermissionManager() {} UriPermissionManager(const UriPermissionManager &mgr) = delete; UriPermissionManager &operator=(const UriPermissionManager &mgr) = delete; - - void RevokeUriPermission(); - - ConcurrentMap, Time> uriTimeout_; - static constexpr int64_t INTERVAL = 60; // 60 min - ExecutorPool::TaskId taskId_ = ExecutorPool::INVALID_TASK_ID; - std::mutex taskMutex_; - std::shared_ptr executorPool_; }; } // namespace UDMF } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/service/udmf/preprocess/data_handler.cpp b/datamgr_service/services/distributeddataservice/service/udmf/preprocess/data_handler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..273ae73dee47cf4e2dc06a4d60c67c2b53f1adfa --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/udmf/preprocess/data_handler.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2024 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 "DataHandler" + +#include "data_handler.h" +#include "log_print.h" +#include "tlv_object.h" +#include "tlv_util.h" + +namespace OHOS::UDMF { +constexpr const char *UD_KEY_SEPARATOR = "/"; +constexpr const char *UD_KEY_ENTRY_SEPARATOR = "#"; + +Status DataHandler::MarshalToEntries(const UnifiedData &unifiedData, std::vector &entries) +{ + std::string unifiedKey = unifiedData.GetRuntime()->key.GetUnifiedKey(); + std::vector runtimeBytes; + auto runtimeTlv = TLVObject(runtimeBytes); + if (!TLVUtil::Writing(*unifiedData.GetRuntime(), runtimeTlv, TAG::TAG_RUNTIME)) { + ZLOGE("Marshall runtime info failed, dataPrefix: %{public}s.", unifiedKey.c_str()); + return E_WRITE_PARCEL_ERROR; + } + std::vector udKeyBytes = { unifiedKey.begin(), unifiedKey.end() }; + Entry entry = { udKeyBytes, runtimeBytes }; + entries.emplace_back(entry); + return BuildEntries(unifiedData.GetRecords(), unifiedKey, entries); +} + +Status DataHandler::UnmarshalEntries(const std::string &key, const std::vector &entries, + UnifiedData &unifiedData) +{ + std::map> records; + std::map> innerEntries; + auto status = UnmarshalEntryItem(unifiedData, entries, key, records, innerEntries); + if (status != E_OK) { + ZLOGE("UnmarshalEntryItem failed."); + return status; + } + for (auto &[entryKey, entryValue] : innerEntries) { + auto idx = entryKey.rfind(UD_KEY_ENTRY_SEPARATOR); + std::string recordKey = entryKey.substr(0, idx); + std::string entryUtdId = entryKey.substr(idx + 1); + if (records.find(recordKey) != records.end() && entryValue.find(entryUtdId) != entryValue.end()) { + records[recordKey]->AddEntry(entryUtdId, std::move(entryValue[entryUtdId])); + } + } + return E_OK; +} + +Status DataHandler::UnmarshalEntryItem(UnifiedData &unifiedData, const std::vector &entries, + const std::string &key, std::map> &records, + std::map> &innerEntries) +{ + for (const auto &entry : entries) { + std::string keyStr = { entry.key.begin(), entry.key.end() }; + auto data = TLVObject(const_cast &>(entry.value)); + if (keyStr == key) { + Runtime runtime; + if (!TLVUtil::ReadTlv(runtime, data, TAG::TAG_RUNTIME)) { + ZLOGE("Unmarshall runtime info failed."); + return E_READ_PARCEL_ERROR; + } + unifiedData.SetRuntime(runtime); + continue; + } + auto isStartWithKey = keyStr.find(key) == 0; + if (!isStartWithKey) { + continue; + } + auto isEntryItem = keyStr.rfind(UD_KEY_ENTRY_SEPARATOR) != std::string::npos; + if (isStartWithKey && !isEntryItem) { + std::shared_ptr record; + if (!TLVUtil::ReadTlv(record, data, TAG::TAG_UNIFIED_RECORD)) { + ZLOGE("Unmarshall unified record failed."); + return E_READ_PARCEL_ERROR; + } + unifiedData.AddRecord(record); + records.emplace(keyStr, record); + continue; + } + if (isStartWithKey && isEntryItem) { + std::shared_ptr> entryRead = + std::make_shared>(); + if (!TLVUtil::ReadTlv(entryRead, data, TAG::TAG_INNER_ENTRIES)) { + ZLOGE("Unmarshall inner entry failed."); + return E_READ_PARCEL_ERROR; + } + innerEntries.emplace(keyStr, std::move(*entryRead)); + } + } + return E_OK; +} + +Status DataHandler::BuildEntries(const std::vector> &records, + const std::string &unifiedKey, std::vector &entries) +{ + for (const auto &record : records) { + std::string recordKey = unifiedKey + UD_KEY_SEPARATOR + record->GetUid(); + auto recordEntries = record->GetInnerEntries(); + for (auto &recordEntry : *recordEntries) { + std::string key = recordKey + UD_KEY_ENTRY_SEPARATOR + recordEntry.first; + std::vector entryBytes; + auto entryTlv = TLVObject(entryBytes); + const std::shared_ptr> entryMap = + std::make_shared>(); + entryMap->insert_or_assign(recordEntry.first, recordEntry.second); + if (!TLVUtil::Writing(entryMap, entryTlv, TAG::TAG_INNER_ENTRIES)) { + ZLOGI("Marshall inner entry failed."); + return E_WRITE_PARCEL_ERROR; + } + std::vector keyBytes = { key.begin(), key.end() }; + Entry entry = { keyBytes, entryBytes }; + entries.emplace_back(entry); + } + recordEntries->clear(); + std::vector recordBytes; + auto recordTlv = TLVObject(recordBytes); + if (!TLVUtil::Writing(record, recordTlv, TAG::TAG_UNIFIED_RECORD)) { + ZLOGI("Marshall unified record failed."); + return E_WRITE_PARCEL_ERROR; + } + std::vector keyBytes = { recordKey.begin(), recordKey.end() }; + Entry entry = { keyBytes, recordBytes }; + entries.emplace_back(entry); + } + return E_OK; +} +} // namespace UDMF::OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/udmf/preprocess/data_handler.h b/datamgr_service/services/distributeddataservice/service/udmf/preprocess/data_handler.h new file mode 100644 index 0000000000000000000000000000000000000000..c6b3c94e46755c8a344c0903973f9942d4af525c --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/udmf/preprocess/data_handler.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 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 DATA_HANDLER_H +#define DATA_HANDLER_H + +#include "error_code.h" +#include "unified_data.h" +#include "types_export.h" + +namespace OHOS::UDMF { +using namespace DistributedDB; + +class DataHandler { +public: + static Status MarshalToEntries(const UnifiedData &unifiedData, std::vector &entries); + static Status UnmarshalEntries(const std::string &key, const std::vector &entries, + UnifiedData &unifiedData); + +private: + static Status BuildEntries(const std::vector> &records, + const std::string &unifiedKey, std::vector &entries); + static Status UnmarshalEntryItem(UnifiedData &unifiedData, const std::vector &entries, + const std::string &key, std::map> &records, + std::map> &innerEntries); +}; +} // namespace UDMF::OHOS +#endif // DATA_HANDLER_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/udmf/preprocess/preprocess_utils.cpp b/datamgr_service/services/distributeddataservice/service/udmf/preprocess/preprocess_utils.cpp index 0c4062437d3cb2ed075d00516f994f62bf9d93d1..4ce5d1755eaf907cfa9a8599a766282220af4922 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/preprocess/preprocess_utils.cpp +++ b/datamgr_service/services/distributeddataservice/service/udmf/preprocess/preprocess_utils.cpp @@ -19,14 +19,16 @@ #include #include +#include "dds_trace.h" +#include "udmf_radar_reporter.h" #include "accesstoken_kit.h" #include "bundlemgr/bundle_mgr_client_impl.h" #include "device_manager_adapter.h" #include "error_code.h" -#include "file.h" #include "ipc_skeleton.h" #include "log_print.h" #include "udmf_radar_reporter.h" +#include "udmf_utils.h" #include "remote_file_share.h" #include "uri.h" #include "utils/crypto.h" @@ -39,7 +41,9 @@ static constexpr int MINIMUM = 48; static constexpr int MAXIMUM = 121; constexpr char SPECIAL = '^'; constexpr const char *FILE_SCHEME = "file"; +constexpr const char *TAG = "PreProcessUtils::"; static constexpr uint32_t VERIFY_URI_PERMISSION_MAX_SIZE = 500; +using namespace OHOS::DistributedDataDfx; using namespace Security::AccessToken; using namespace OHOS::AppFileService::ModuleRemoteFileShare; using namespace RadarReporter; @@ -89,7 +93,7 @@ time_t PreProcessUtils::GetTimestamp() return timestamp; } -int32_t PreProcessUtils::GetHapUidByToken(uint32_t tokenId) +int32_t PreProcessUtils::GetHapUidByToken(uint32_t tokenId, int &userId) { Security::AccessToken::HapTokenInfo tokenInfo; auto result = Security::AccessToken::AccessTokenKit::GetHapTokenInfo(tokenId, tokenInfo); @@ -97,18 +101,28 @@ int32_t PreProcessUtils::GetHapUidByToken(uint32_t tokenId) ZLOGE("GetHapUidByToken failed, result = %{public}d.", result); return E_ERROR; } - return tokenInfo.userID; + userId = tokenInfo.userID; + return E_OK; } bool PreProcessUtils::GetHapBundleNameByToken(int tokenId, std::string &bundleName) { Security::AccessToken::HapTokenInfo hapInfo; if (Security::AccessToken::AccessTokenKit::GetHapTokenInfo(tokenId, hapInfo) - != Security::AccessToken::AccessTokenKitRet::RET_SUCCESS) { - return false; + == Security::AccessToken::AccessTokenKitRet::RET_SUCCESS) { + bundleName = hapInfo.bundleName; + return true; } - bundleName = hapInfo.bundleName; - return true; + if (UTILS::IsTokenNative()) { + ZLOGD("TypeATokenTypeEnum is TOKEN_HAP"); + std::string processName; + if (GetNativeProcessNameByToken(tokenId, processName)) { + bundleName = processName; + return true; + } + } + ZLOGE("GetHapBundleNameByToken faild"); + return false; } bool PreProcessUtils::GetNativeProcessNameByToken(int tokenId, std::string &processName) @@ -142,45 +156,54 @@ void PreProcessUtils::SetRemoteData(UnifiedData &data) } ZLOGD("is remote data."); auto records = data.GetRecords(); - for (auto record : records) { - auto type = record->GetType(); - if (IsFileType(type)) { - auto file = static_cast(record.get()); - UDDetails details = file->GetDetails(); - details.insert({ "isRemote", "true" }); - file->SetDetails(details); + ProcessFileType(records, [] (std::shared_ptr obj) { + std::shared_ptr detailObj; + obj->GetValue(DETAILS, detailObj); + if (detailObj == nullptr) { + ZLOGE("Not contain details for object!"); + return false; } - } + UDDetails details = ObjectUtils::ConvertToUDDetails(detailObj); + details.insert({ "isRemote", "true" }); + obj->value_[DETAILS] = ObjectUtils::ConvertToObject(details); + return true; + }); } -bool PreProcessUtils::IsFileType(UDType udType) +bool PreProcessUtils::IsFileType(std::shared_ptr record) { - return (udType == UDType::FILE || udType == UDType::IMAGE || udType == UDType::VIDEO || udType == UDType::AUDIO - || udType == UDType::FOLDER); + if (record == nullptr) { + return false; + } + if (!std::holds_alternative>(record->GetOriginValue())) { + return false; + } + auto obj = std::get>(record->GetOriginValue()); + return obj->value_.find(ORI_URI) != obj->value_.end(); } int32_t PreProcessUtils::SetRemoteUri(uint32_t tokenId, UnifiedData &data) { - int32_t userId = GetHapUidByToken(tokenId); std::vector uris; - for (const auto &record : data.GetRecords()) { - if (record != nullptr && IsFileType(record->GetType())) { - auto file = static_cast(record.get()); - if (file->GetUri().empty()) { - ZLOGW("Get uri empty, plase check the uri."); - continue; - } - Uri uri(file->GetUri()); - std::string scheme = uri.GetScheme(); - std::transform(scheme.begin(), scheme.end(), scheme.begin(), ::tolower); - if (uri.GetAuthority().empty() || scheme != FILE_SCHEME) { - ZLOGW("Get uri authority empty or uri scheme not equals to file."); - continue; - } - uris.push_back(file->GetUri()); + ProcessFileType(data.GetRecords(), [&uris](std::shared_ptr obj) { + std::string oriUri; + obj->GetValue(ORI_URI, oriUri); + if (oriUri.empty()) { + ZLOGW("Get uri empty, plase check the uri."); + return false; } - } + Uri uri(oriUri); + std::string scheme = uri.GetScheme(); + std::transform(scheme.begin(), scheme.end(), scheme.begin(), ::tolower); + if (uri.GetAuthority().empty() || scheme != FILE_SCHEME) { + ZLOGW("Get uri authority empty or uri scheme not equals to file."); + return false; + } + uris.push_back(oriUri); + return true; + }); if (!uris.empty()) { + ZLOGI("Read to check uri authorization"); if (!CheckUriAuthorization(uris, tokenId)) { ZLOGE("CheckUriAuthorization failed, bundleName:%{public}s, tokenId: %{public}d, uris size:%{public}zu.", data.GetRuntime()->createPackage.c_str(), tokenId, uris.size()); @@ -191,10 +214,9 @@ int32_t PreProcessUtils::SetRemoteUri(uint32_t tokenId, UnifiedData &data) if (!IsNetworkingEnabled()) { return E_OK; } - int ret = GetDfsUrisFromLocal(uris, userId, data); - if (ret != E_OK) { - ZLOGE("Get remoteUri failed, ret = %{public}d, userId: %{public}d, uri size:%{public}zu.", - ret, userId, uris.size()); + int32_t userId; + if (GetHapUidByToken(tokenId, userId) == E_OK) { + GetDfsUrisFromLocal(uris, userId, data); } } return E_OK; @@ -202,22 +224,32 @@ int32_t PreProcessUtils::SetRemoteUri(uint32_t tokenId, UnifiedData &data) int32_t PreProcessUtils::GetDfsUrisFromLocal(const std::vector &uris, int32_t userId, UnifiedData &data) { + DdsTrace trace( + std::string(TAG) + std::string(__FUNCTION__), TraceSwitch::BYTRACE_ON | TraceSwitch::TRACE_CHAIN_ON); + RadarReporterAdapter::ReportNormal(std::string(__FUNCTION__), + BizScene::SET_DATA, SetDataStage::GERERATE_DFS_URI, StageRes::IDLE, BizState::DFX_BEGIN); std::unordered_map dfsUris; int ret = RemoteFileShare::GetDfsUrisFromLocal(uris, userId, dfsUris); if (ret != 0 || dfsUris.empty()) { + RadarReporterAdapter::ReportFail(std::string(__FUNCTION__), + BizScene::SET_DATA, SetDataStage::GERERATE_DFS_URI, StageRes::FAILED, E_FS_ERROR, BizState::DFX_END); ZLOGE("Get remoteUri failed, ret = %{public}d, userId: %{public}d, uri size:%{public}zu.", ret, userId, uris.size()); return E_FS_ERROR; } - for (const auto &record : data.GetRecords()) { - if (record != nullptr && IsFileType(record->GetType())) { - auto file = static_cast(record.get()); - auto iter = dfsUris.find(file->GetUri()); - if (iter != dfsUris.end()) { - file->SetRemoteUri((iter->second).uriStr); - } + RadarReporterAdapter::ReportNormal(std::string(__FUNCTION__), + BizScene::SET_DATA, SetDataStage::GERERATE_DFS_URI, StageRes::SUCCESS); + ProcessFileType(data.GetRecords(), [&dfsUris] (std::shared_ptr obj) { + std::string oriUri; + obj->GetValue(ORI_URI, oriUri); + auto iter = dfsUris.find(oriUri); + if (iter != dfsUris.end()) { + obj->value_[REMOTE_URI] = (iter->second).uriStr; } - } + return true; + }); + RadarReporterAdapter::ReportNormal(std::string(__FUNCTION__), + BizScene::SET_DATA, SetDataStage::GERERATE_DFS_URI, StageRes::SUCCESS, BizState::DFX_END); return E_OK; } @@ -262,5 +294,26 @@ bool PreProcessUtils::IsNetworkingEnabled() } return true; } + +void PreProcessUtils::ProcessFileType(std::vector> records, + std::function)> callback) +{ + for (auto record : records) { + if (record == nullptr) { + continue; + } + if (!PreProcessUtils::IsFileType(record)) { + continue; + } + auto obj = std::get>(record->GetOriginValue()); + if (obj == nullptr) { + ZLOGE("ValueType is not Object, Not convert to remote uri!"); + continue; + } + if (!callback(obj)) { + continue; + } + } +} } // namespace UDMF } // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/udmf/preprocess/preprocess_utils.h b/datamgr_service/services/distributeddataservice/service/udmf/preprocess/preprocess_utils.h index 11ecccbb6660ee89c1965148cba8846d85aa24b3..9d3770b6502ae250c68cc9b41019fe1715db9dfb 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/preprocess/preprocess_utils.h +++ b/datamgr_service/services/distributeddataservice/service/udmf/preprocess/preprocess_utils.h @@ -30,18 +30,20 @@ public: static int32_t RuntimeDataImputation(UnifiedData &data, CustomOption &option); static std::string GenerateId(); static time_t GetTimestamp(); - static int32_t GetHapUidByToken(uint32_t tokenId); + static int32_t GetHapUidByToken(uint32_t tokenId, int &userId); static bool GetHapBundleNameByToken(int tokenId, std::string &bundleName); static bool GetNativeProcessNameByToken(int tokenId, std::string &processName); static std::string GetLocalDeviceId(); static void SetRemoteData(UnifiedData &data); - static bool IsFileType(UDType udType); static int32_t SetRemoteUri(uint32_t tokenId, UnifiedData &data); static bool GetInstIndex(uint32_t tokenId, int32_t &instIndex); static bool IsNetworkingEnabled(); + static void ProcessFileType(std::vector> records, + std::function)> callback); private: static bool CheckUriAuthorization(const std::vector& uris, uint32_t tokenId); static int32_t GetDfsUrisFromLocal(const std::vector &uris, int32_t userId, UnifiedData &data); + static bool IsFileType(std::shared_ptr record); }; } // namespace UDMF } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/service/udmf/preprocess/udmf_dialog.cpp b/datamgr_service/services/distributeddataservice/service/udmf/preprocess/udmf_dialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c95f78eb0dee66efd2b4f0aa5474d301de9f4133 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/udmf/preprocess/udmf_dialog.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2025 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 "UdmfDialog" + +#include "udmf_dialog.h" + +#include "ability_connect_callback_stub.h" +#include "error_code.h" +#include "in_process_call_wrapper.h" +#include "iservice_registry.h" +#include "log_print.h" +#include "system_ability_definition.h" +#ifdef SCENE_BOARD_ENABLE +#include "window_manager_lite.h" +#else +#include "window_manager.h" +#endif + +namespace OHOS::UDMF { +using namespace OHOS::AAFwk; + +ProgressDialog &ProgressDialog::GetInstance() +{ + static ProgressDialog instance; + return instance; +} + +ProgressDialog::FocusedAppInfo ProgressDialog::GetFocusedAppInfo(void) const +{ + FocusedAppInfo appInfo = { 0 }; + Rosen::FocusChangeInfo info; +#ifdef SCENE_BOARD_ENABLE + Rosen::WindowManagerLite::GetInstance().GetFocusWindowInfo(info); +#else + Rosen::WindowManager::GetInstance().GetFocusWindowInfo(info); +#endif + appInfo.windowId = info.windowId_; + appInfo.abilityToken = info.abilityToken_; + return appInfo; +} + +sptr ProgressDialog::GetAbilityManagerService() +{ + auto systemAbilityManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (systemAbilityManager == nullptr) { + ZLOGE("Failed to get ability manager."); + return nullptr; + } + sptr remoteObject = systemAbilityManager->GetSystemAbility(ABILITY_MGR_SERVICE_ID); + if (!remoteObject) { + ZLOGE("Failed to get ability manager service."); + return nullptr; + } + return iface_cast(remoteObject); +} + +int32_t ProgressDialog::ShowProgress(const ProgressMessageInfo &message) +{ + ZLOGD("Begin."); + auto abilityManager = GetAbilityManagerService(); + if (abilityManager == nullptr) { + ZLOGE("Get ability manager failed."); + return E_ERROR; + } + + Want want; + want.SetElementName(PASTEBOARD_DIALOG_APP, PASTEBOARD_PROGRESS_ABILITY); + want.SetAction(PASTEBOARD_PROGRESS_ABILITY); + want.SetParam("promptText", message.promptText); + want.SetParam("remoteDeviceName", message.remoteDeviceName); + want.SetParam("progressKey", message.progressKey); + want.SetParam("isRemote", message.isRemote); + want.SetParam("windowId", message.windowId); + want.SetParam("ipcCallback", message.clientCallback); + if (message.callerToken != nullptr) { + want.SetParam("tokenKey", message.callerToken); + } else { + ZLOGW("CallerToken is nullptr."); + } + + int32_t status = IN_PROCESS_CALL(abilityManager->StartAbility(want)); + if (status != 0) { + ZLOGE("Start progress failed, status:%{public}d.", status); + } + return status; +} +} // namespace OHOS::UDMF \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/udmf/preprocess/udmf_dialog.h b/datamgr_service/services/distributeddataservice/service/udmf/preprocess/udmf_dialog.h new file mode 100644 index 0000000000000000000000000000000000000000..94a302fe9c7a8e9b5ef48b31a959960ae40c38dd --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/udmf/preprocess/udmf_dialog.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024 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 UDMF_DIALOG_H +#define UDMF_DIALOG_H + +#include "error_code.h" +#include "ability_manager_interface.h" +#include "refbase.h" + +namespace OHOS::UDMF { + +class ProgressDialog { +public: + struct FocusedAppInfo { + int32_t windowId = 0; + sptr abilityToken = nullptr; + }; + struct ProgressMessageInfo { + std::string promptText { DEFAULT_LABEL }; + std::string remoteDeviceName { DEFAULT_LABEL }; + std::string progressKey { DEFAULT_LABEL }; + bool isRemote { false }; + int32_t windowId { 0 }; + sptr callerToken { nullptr }; + sptr clientCallback { nullptr }; + }; + + static ProgressDialog &GetInstance(); + int32_t ShowProgress(const ProgressMessageInfo &message); + FocusedAppInfo GetFocusedAppInfo(void) const; + +private: + static sptr GetAbilityManagerService(); + + static constexpr const char *DEFAULT_LABEL = "unknown"; + static constexpr const char *PASTEBOARD_DIALOG_APP = "com.ohos.pasteboarddialog"; + static constexpr const char *PASTEBOARD_PROGRESS_ABILITY = "PasteboardProgressAbility"; +}; +} // namespace UDMF::OHOS +#endif // UDMF_DIALOG_H \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/udmf/store/runtime_store.cpp b/datamgr_service/services/distributeddataservice/service/udmf/store/runtime_store.cpp index 11ea83507e36c8089263d098447ae8da45ee9b8c..40a580d986d1e923ac79254c269b3d05e5667485 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/store/runtime_store.cpp +++ b/datamgr_service/services/distributeddataservice/service/udmf/store/runtime_store.cpp @@ -21,10 +21,10 @@ #include #include +#include "data_handler.h" #include "log_print.h" #include "ipc_skeleton.h" -#include "file.h" -#include "udmf_conversion.h" +#include "unified_data_helper.h" #include "udmf_radar_reporter.h" #include "unified_meta.h" #include "tlv_util.h" @@ -107,33 +107,11 @@ Status RuntimeStore::Put(const UnifiedData &unifiedData) { UpdateTime(); std::vector entries; - std::string unifiedKey = unifiedData.GetRuntime()->key.GetUnifiedKey(); - // add runtime info - std::vector runtimeBytes; - auto runtimeTlv = TLVObject(runtimeBytes); - if (!TLVUtil::Writing(*unifiedData.GetRuntime(), runtimeTlv, TAG::TAG_RUNTIME)) { - ZLOGE("Marshall runtime info failed, dataPrefix: %{public}s.", unifiedKey.c_str()); - return E_WRITE_PARCEL_ERROR; - } - std::vector udKeyBytes = {unifiedKey.begin(), unifiedKey.end()}; - Entry entry = {udKeyBytes, runtimeBytes}; - entries.push_back(entry); - - // add unified record - for (const auto &record : unifiedData.GetRecords()) { - std::vector recordBytes; - auto recordTlv = TLVObject(recordBytes); - if (!TLVUtil::Writing(record, recordTlv, TAG::TAG_UNIFIED_RECORD)) { - ZLOGI("Marshall unified record failed."); - return E_WRITE_PARCEL_ERROR; - } - std::string recordKey = unifiedKey + "/" + record->GetUid(); - std::vector keyBytes = {recordKey.begin(), recordKey.end() }; - Entry entry = { keyBytes, recordBytes }; - entries.push_back(entry); + auto status = DataHandler::MarshalToEntries(unifiedData, entries); + if (status != E_OK) { + return status; } - auto status = PutEntries(entries); - return status; + return PutEntries(entries); } Status RuntimeStore::Get(const std::string &key, UnifiedData &unifiedData) @@ -148,7 +126,7 @@ Status RuntimeStore::Get(const std::string &key, UnifiedData &unifiedData) ZLOGW("entries is empty, dataPrefix: %{public}s", key.c_str()); return E_NOT_FOUND; } - return UnmarshalEntries(key, entries, unifiedData); + return DataHandler::UnmarshalEntries(key, entries, unifiedData); } bool RuntimeStore::GetDetailsFromUData(UnifiedData &data, UDDetails &details) @@ -160,11 +138,18 @@ bool RuntimeStore::GetDetailsFromUData(UnifiedData &data, UDDetails &details) if (records[0] == nullptr || records[0]->GetType() != UDType::FILE) { return false; } - auto file = static_cast(records[0].get()); - if (file == nullptr) { + auto obj = std::get>(records[0]->GetOriginValue()); + if (obj == nullptr) { + ZLOGE("ValueType is not Object!"); return false; } - auto result = file->GetDetails(); + std::shared_ptr detailObj; + obj->GetValue(DETAILS, detailObj); + if (detailObj == nullptr) { + ZLOGE("Not contain details for object!"); + return false; + } + auto result = ObjectUtils::ConvertToUDDetails(detailObj); if (result.find(TEMP_UNIFIED_DATA_FLAG) == result.end()) { return false; } @@ -200,17 +185,7 @@ Status RuntimeStore::GetSummary(const std::string &key, Summary &summary) if (GetDetailsFromUData(unifiedData, details)) { return GetSummaryFromDetails(details, summary); } - for (const auto &record : unifiedData.GetRecords()) { - int64_t recordSize = record->GetSize(); - auto udType = UtdUtils::GetUtdIdFromUtdEnum(record->GetType()); - auto it = summary.summary.find(udType); - if (it == summary.summary.end()) { - summary.summary[udType] = recordSize; - } else { - summary.summary[udType] += recordSize; - } - summary.totalSize += recordSize; - } + UnifiedDataHelper::GetSummary(unifiedData, summary); return E_OK; } @@ -330,7 +305,7 @@ Status RuntimeStore::Sync(const std::vector &devices, ProcessCallba void RuntimeStore::NotifySyncProcss(const DevSyncProcessMap &processMap, ProcessCallback callback, const DevNameMap &deviceNameMap) { - AsyncProcessInfo processInfo{ASYNC_IDLE, ASYNC_IDLE, "", 0, 0, 0, 0, 0}; + AsyncProcessInfo processInfo; for (const auto &[originDeviceId, syncProcess] : processMap) { // only one device processInfo.srcDevName = deviceNameMap.at(originDeviceId); processInfo.syncId = syncProcess.syncId; @@ -382,7 +357,7 @@ Status RuntimeStore::GetBatchData(const std::string &dataPrefix, std::vector(delegate, release); + uint32_t pragmData = 16 * 1024 * 1024; + PragmaData input = static_cast(&pragmData); + kvStore_->Pragma(SET_MAX_VALUE_SIZE, input); return true; } @@ -444,7 +422,7 @@ bool RuntimeStore::BuildMetaDataParam(DistributedData::StoreMetaData &metaData) } uint32_t token = IPCSkeleton::GetSelfTokenID(); - const std::string userId = std::to_string(DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(token)); + const std::string userId = std::to_string(DistributedData::AccountDelegate::GetInstance()->GetUserByToken(token)); metaData.appType = "harmony"; metaData.deviceId = localDeviceId; metaData.storeId = storeId_; @@ -454,7 +432,7 @@ bool RuntimeStore::BuildMetaDataParam(DistributedData::StoreMetaData &metaData) metaData.bundleName = DistributedData::Bootstrap::GetInstance().GetProcessLabel(); metaData.appId = DistributedData::Bootstrap::GetInstance().GetProcessLabel(); metaData.user = userId; - metaData.account = DistributedKv::AccountDelegate::GetInstance()->GetCurrentAccountId(); + metaData.account = DistributedData::AccountDelegate::GetInstance()->GetCurrentAccountId(); metaData.tokenId = token; metaData.securityLevel = DistributedKv::SecurityLevel::S1; metaData.area = DistributedKv::Area::EL1; @@ -474,7 +452,7 @@ bool RuntimeStore::SaveMetaData() } int foregroundUserId = 0; - bool ret = DistributedKv::AccountDelegate::GetInstance()->QueryForegroundUserId(foregroundUserId); + bool ret = DistributedData::AccountDelegate::GetInstance()->QueryForegroundUserId(foregroundUserId); if (!ret) { ZLOGE("QueryForegroundUserId failed."); return false; @@ -537,23 +515,9 @@ Status RuntimeStore::GetEntries(const std::string &dataPrefix, std::vector &entries) { - DBStatus status = kvStore_->StartTransaction(); - if (status != DBStatus::OK) { - ZLOGE("start transaction failed, status: %{public}d.", status); - return E_DB_ERROR; - } - status = kvStore_->PutBatch(entries); + DBStatus status = kvStore_->PutBatch(entries); if (status != DBStatus::OK) { ZLOGE("putBatch failed, status: %{public}d.", status); - status = kvStore_->Rollback(); - if (status != DBStatus::OK) { - ZLOGE("rollback failed, status: %{public}d.", status); - } - return E_DB_ERROR; - } - status = kvStore_->Commit(); - if (status != DBStatus::OK) { - ZLOGE("commit failed, status: %{public}d.", status); return E_DB_ERROR; } return E_OK; @@ -561,52 +525,13 @@ Status RuntimeStore::PutEntries(const std::vector &entries) Status RuntimeStore::DeleteEntries(const std::vector &keys) { - DBStatus status = kvStore_->StartTransaction(); - if (status != DBStatus::OK) { - ZLOGE("start transaction failed, status: %{public}d.", status); - return E_DB_ERROR; - } - status = kvStore_->DeleteBatch(keys); + DBStatus status = kvStore_->DeleteBatch(keys); if (status != DBStatus::OK) { ZLOGE("deleteBatch failed, status: %{public}d.", status); - status = kvStore_->Rollback(); - if (status != DBStatus::OK) { - ZLOGE("rollback failed, status: %{public}d.", status); - } - return E_DB_ERROR; - } - status = kvStore_->Commit(); - if (status != DBStatus::OK) { - ZLOGE("commit failed, status: %{public}d.", status); return E_DB_ERROR; } return E_OK; } -Status RuntimeStore::UnmarshalEntries(const std::string &key, std::vector &entries, UnifiedData &unifiedData) -{ - for (const auto &entry : entries) { - std::string keyStr = {entry.key.begin(), entry.key.end()}; - if (keyStr == key) { - Runtime runtime; - auto runtimeTlv = TLVObject(const_cast &>(entry.value)); - if (!TLVUtil::ReadTlv(runtime, runtimeTlv, TAG::TAG_RUNTIME)) { - ZLOGE("Unmarshall runtime info failed."); - return E_READ_PARCEL_ERROR; - } - unifiedData.SetRuntime(runtime); - } else if (keyStr.find(key) == 0) { - std::shared_ptr record; - auto recordTlv = TLVObject(const_cast &>(entry.value)); - if (!TLVUtil::ReadTlv(record, recordTlv, TAG::TAG_UNIFIED_RECORD)) { - ZLOGE("Unmarshall unified record failed."); - return E_READ_PARCEL_ERROR; - } - unifiedData.AddRecord(record); - } - } - UdmfConversion::ConvertRecordToSubclass(unifiedData); - return E_OK; -} } // namespace UDMF } // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/udmf/store/runtime_store.h b/datamgr_service/services/distributeddataservice/service/udmf/store/runtime_store.h index e01d6e2dfd505d5ebbbf945975cb5e46c12f15b8..68f32a6b9bade7f1da9f8f7b3a387e4a7b394254 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/store/runtime_store.h +++ b/datamgr_service/services/distributeddataservice/service/udmf/store/runtime_store.h @@ -25,7 +25,7 @@ namespace OHOS { namespace UDMF { using DevNameMap = std::map; using DevSyncProcessMap = std::map; -class API_EXPORT RuntimeStore final : public Store { +class RuntimeStore final : public Store { public: explicit RuntimeStore(const std::string &storeId); ~RuntimeStore(); diff --git a/datamgr_service/services/distributeddataservice/service/udmf/store/store_account_observer.cpp b/datamgr_service/services/distributeddataservice/service/udmf/store/store_account_observer.cpp index 1fa4c362410a14589eddb05d4c76a82c254631cb..f2ba9c72d9d85a2c17b1f26e5c03f243a6313ff2 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/store/store_account_observer.cpp +++ b/datamgr_service/services/distributeddataservice/service/udmf/store/store_account_observer.cpp @@ -26,10 +26,10 @@ namespace OHOS { namespace UDMF { using namespace DistributedKv; using namespace DistributedData; -void RuntimeStoreAccountObserver::OnAccountChanged(const DistributedKv::AccountEventInfo &eventInfo) +void RuntimeStoreAccountObserver::OnAccountChanged(const AccountEventInfo &eventInfo, int32_t timeout) { ZLOGI("account event begin. status is %{public}d.", eventInfo.status); - if (eventInfo.status == DistributedKv::AccountStatus::DEVICE_ACCOUNT_DELETE) { + if (eventInfo.status == AccountStatus::DEVICE_ACCOUNT_DELETE) { DistributedData::StoreMetaData metaData; uint32_t token = IPCSkeleton::GetSelfTokenID(); metaData.bundleName = DistributedData::Bootstrap::GetInstance().GetProcessLabel(); diff --git a/datamgr_service/services/distributeddataservice/service/udmf/store/store_account_observer.h b/datamgr_service/services/distributeddataservice/service/udmf/store/store_account_observer.h index c352fd9cd66c1d403c8e7d4f25202b6554ad777f..f7ebd8f7cc9bda43bbb4bbae4c4e0d356b2608b4 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/store/store_account_observer.h +++ b/datamgr_service/services/distributeddataservice/service/udmf/store/store_account_observer.h @@ -18,8 +18,8 @@ #include "account_delegate.h" namespace OHOS { namespace UDMF { -class RuntimeStoreAccountObserver : public DistributedKv::AccountDelegate::Observer { - void OnAccountChanged(const DistributedKv::AccountEventInfo &eventInfo) override; +class RuntimeStoreAccountObserver : public DistributedData::AccountDelegate::Observer { + void OnAccountChanged(const DistributedData::AccountEventInfo &eventInfo, int32_t timeout) override; // must specify unique name for observer std::string Name() override { diff --git a/datamgr_service/services/distributeddataservice/service/udmf/store/store_cache.cpp b/datamgr_service/services/distributeddataservice/service/udmf/store/store_cache.cpp index f4c11ac569e6c87e217c1c297d3783ac3689f267..aa3c0ec293226ac3fcb3bd6becda9868cff10552 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/store/store_cache.cpp +++ b/datamgr_service/services/distributeddataservice/service/udmf/store/store_cache.cpp @@ -34,7 +34,7 @@ std::shared_ptr StoreCache::GetStore(std::string intention) { std::shared_ptr store; int foregroundUserId = 0; - bool ret = DistributedKv::AccountDelegate::GetInstance()->QueryForegroundUserId(foregroundUserId); + bool ret = DistributedData::AccountDelegate::GetInstance()->QueryForegroundUserId(foregroundUserId); if (!ret) { ZLOGE("QueryForegroundUserId failed."); return nullptr; diff --git a/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_impl.cpp b/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_impl.cpp index 0b237bf2c64debaab8373133ce8c5d418f9a9772..30bb840e9b29c730409373fcc9f2078a8ce3451a 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_impl.cpp +++ b/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_impl.cpp @@ -25,7 +25,6 @@ #include "checker_manager.h" #include "dfx_types.h" #include "distributed_kv_data_manager.h" -#include "file.h" #include "lifecycle/lifecycle_manager.h" #include "log_print.h" #include "preprocess_utils.h" @@ -38,7 +37,11 @@ #include "unified_types.h" #include "device_manager_adapter.h" #include "store_account_observer.h" - +#include "utils/anonymous.h" +#include "bootstrap.h" +#include "metadata/store_meta_data.h" +#include "metadata/meta_data_manager.h" +#include "udmf_dialog.h" namespace OHOS { namespace UDMF { @@ -46,12 +49,16 @@ using namespace Security::AccessToken; using FeatureSystem = DistributedData::FeatureSystem; using UdmfBehaviourMsg = OHOS::DistributedDataDfx::UdmfBehaviourMsg; using Reporter = OHOS::DistributedDataDfx::Reporter; +using DmAdapter = OHOS::DistributedData::DeviceManagerAdapter; +using StoreMetaData = OHOS::DistributedData::StoreMetaData; using namespace RadarReporter; using namespace DistributedKv; constexpr const char *DRAG_AUTHORIZED_PROCESSES[] = {"msdp_sa", "collaboration_service"}; constexpr const char *DATA_PREFIX = "udmf://"; constexpr const char *FILE_SCHEME = "file"; constexpr const char *PRIVILEGE_READ_AND_KEEP = "readAndKeep"; +constexpr const char *MANAGE_UDMF_APP_SHARE_OPTION = "ohos.permission.MANAGE_UDMF_APP_SHARE_OPTION"; +constexpr const char *HAP_LIST[] = {"com.ohos.pasteboarddialog"}; __attribute__((used)) UdmfServiceImpl::Factory UdmfServiceImpl::factory_; UdmfServiceImpl::Factory::Factory() { @@ -63,7 +70,7 @@ UdmfServiceImpl::Factory::Factory() return product_; }, FeatureSystem::BIND_NOW); auto observer = std::make_shared(); - DistributedKv::AccountDelegate::GetInstance()->Subscribe(observer); + DistributedData::AccountDelegate::GetInstance()->Subscribe(observer); } UdmfServiceImpl::Factory::~Factory() @@ -145,12 +152,6 @@ int32_t UdmfServiceImpl::SaveData(CustomOption &option, UnifiedData &unifiedData return E_DB_ERROR; } - if (!UnifiedDataUtils::IsPersist(intention) && store->Clear() != E_OK) { - ZLOGE("Clear store failed, intention: %{public}s.", intention.c_str()); - return E_DB_ERROR; - } - - UdmfConversion::InitValueObject(unifiedData); if (store->Put(unifiedData) != E_OK) { ZLOGE("Put unified data failed, intention: %{public}s.", intention.c_str()); return E_DB_ERROR; @@ -291,10 +292,7 @@ int32_t UdmfServiceImpl::ProcessUri(const QueryOption &query, UnifiedData &unifi ZLOGW("No need to grant uri permissions, queryKey=%{public}s.", query.key.c_str()); return E_OK; } - asyncProcessInfo_.permStatus = ASYNC_RUNNING; - asyncProcessInfo_.permTotal = allUri.size(); - if (UriPermissionManager::GetInstance().GrantUriPermission(allUri, query.tokenId, query.key, - asyncProcessInfo_.permFnished) != E_OK) { + if (UriPermissionManager::GetInstance().GrantUriPermission(allUri, query.tokenId, query.key) != E_OK) { ZLOGE("GrantUriPermission fail, bundleName=%{public}s, key=%{public}s.", bundleName.c_str(), query.key.c_str()); return E_NO_PERMISSION; @@ -311,38 +309,43 @@ int32_t UdmfServiceImpl::ProcessCrossDeviceData(UnifiedData &unifiedData, std::v std::string localDeviceId = PreProcessUtils::GetLocalDeviceId(); std::string sourceDeviceId = unifiedData.GetRuntime()->deviceId; auto records = unifiedData.GetRecords(); - for (auto record : records) { - if (record == nullptr || !PreProcessUtils::IsFileType(record->GetType())) { - continue; + bool hasError = false; + PreProcessUtils::ProcessFileType(records, [&] (std::shared_ptr obj) { + if (hasError) { + return false; } - auto file = static_cast(record.get()); - if (file->GetUri().empty()) { + std::string oriUri; + obj->GetValue(ORI_URI, oriUri); + if (oriUri.empty()) { ZLOGW("Get uri is empty."); - continue; + return false; } - Uri uri(file->GetUri()); + Uri uri(oriUri); std::string scheme = uri.GetScheme(); std::transform(scheme.begin(), scheme.end(), scheme.begin(), ::tolower); - std::string remoteUri = file->GetRemoteUri(); if (localDeviceId != sourceDeviceId) { + std::string remoteUri; + obj->GetValue(REMOTE_URI, remoteUri); if (remoteUri.empty() && scheme == FILE_SCHEME) { ZLOGE("when cross devices, remote uri is required!"); - return E_ERROR; + hasError = true; + return false; } if (!remoteUri.empty()) { - file->SetUri(remoteUri); // cross dev, need dis path. + obj->value_.insert_or_assign(ORI_URI, remoteUri); // cross dev, need dis path. + uri = Uri(remoteUri); + scheme = uri.GetScheme(); + std::transform(scheme.begin(), scheme.end(), scheme.begin(), ::tolower); } } - Uri newUri(file->GetUri()); - scheme = newUri.GetScheme(); - std::transform(scheme.begin(), scheme.end(), scheme.begin(), ::tolower); - if (newUri.GetAuthority().empty() || scheme != FILE_SCHEME) { + if (uri.GetAuthority().empty() || scheme != FILE_SCHEME) { ZLOGW("Get authority is empty or uri scheme not equals to file."); - continue; + return false; } - uris.push_back(newUri); - } - return E_OK; + uris.push_back(uri); + return true; + }); + return hasError ? E_ERROR : E_OK; } int32_t UdmfServiceImpl::GetBatchData(const QueryOption &query, std::vector &unifiedDataSet) @@ -375,7 +378,7 @@ int32_t UdmfServiceImpl::UpdateData(const QueryOption &query, UnifiedData &unifi } std::string bundleName; PreProcessUtils::GetHapBundleNameByToken(query.tokenId, bundleName); - if (key.bundleName != bundleName) { + if (key.bundleName != bundleName && !HasDatahubPriviledge(bundleName)) { ZLOGE("update data failed by %{public}s, key: %{public}s.", bundleName.c_str(), query.key.c_str()); return E_INVALID_PARAMETERS; } @@ -398,7 +401,7 @@ int32_t UdmfServiceImpl::UpdateData(const QueryOption &query, UnifiedData &unifi if (runtime == nullptr) { return E_DB_ERROR; } - if (runtime->tokenId != query.tokenId) { + if (runtime->tokenId != query.tokenId && !HasDatahubPriviledge(bundleName)) { ZLOGE("update data failed, query option tokenId not equals data's tokenId"); return E_INVALID_PARAMETERS; } @@ -407,7 +410,6 @@ int32_t UdmfServiceImpl::UpdateData(const QueryOption &query, UnifiedData &unifi for (auto &record : unifiedData.GetRecords()) { record->SetUid(PreProcessUtils::GenerateId()); } - UdmfConversion::InitValueObject(unifiedData); if (store->Update(unifiedData) != E_OK) { ZLOGE("Update unified data failed, intention: %{public}s.", key.intention.c_str()); return E_DB_ERROR; @@ -521,7 +523,6 @@ int32_t UdmfServiceImpl::AddPrivilege(const QueryOption &query, Privilege &privi return E_DB_ERROR; } data.GetRuntime()->privileges.emplace_back(privilege); - UdmfConversion::InitValueObject(data); if (store->Update(data) != E_OK) { ZLOGE("Update unified data failed, intention: %{public}s.", key.intention.c_str()); return E_DB_ERROR; @@ -541,7 +542,7 @@ int32_t UdmfServiceImpl::Sync(const QueryOption &query, const std::vector 0) { - syncingDevName_ = DistributedData::DeviceManagerAdapter::GetInstance().GetDeviceInfo(devices[0]).deviceName; - } - auto callback = [this](AsyncProcessInfo &syncInfo) { - asyncProcessInfo_.syncId = syncInfo.syncId; - asyncProcessInfo_.syncStatus = syncInfo.syncStatus; - asyncProcessInfo_.syncTotal = syncInfo.syncTotal; - asyncProcessInfo_.syncFinished = syncInfo.syncFinished; - asyncProcessInfo_.srcDevName = syncInfo.srcDevName; - if (asyncProcessInfo_.syncStatus != ASYNC_RUNNING) { - syncingData_ = false; + auto callback = [this, query](AsyncProcessInfo &syncInfo) { + if (query.key.empty()) { + return; } + syncInfo.businessUdKey = query.key; + std::lock_guard lock(mutex_); + asyncProcessInfoMap_.insert_or_assign(syncInfo.businessUdKey, syncInfo); ZLOGD("store.Sync: name=%{public}s, id=%{public}u, status=%{public}u, total=%{public}u, finish=%{public}u", syncInfo.srcDevName.c_str(), syncInfo.syncId, syncInfo.syncStatus, syncInfo.syncTotal, syncInfo.syncFinished); @@ -569,7 +564,6 @@ int32_t UdmfServiceImpl::Sync(const QueryOption &query, const std::vectorSync(devices, callback) != E_OK) { - syncingData_ = false; ZLOGE("Store sync failed, intention: %{public}s.", key.intention.c_str()); RadarReporterAdapter::ReportFail(std::string(__FUNCTION__), BizScene::SYNC_DATA, SyncDataStage::SYNC_END, StageRes::FAILED, E_DB_ERROR, BizState::DFX_END); @@ -620,8 +614,9 @@ int32_t UdmfServiceImpl::SetAppShareOption(const std::string &intention, int32_t uint64_t accessTokenIDEx = IPCSkeleton::GetCallingFullTokenID(); bool isSystemApp = TokenIdKit::IsSystemAppByFullTokenID(accessTokenIDEx); - if (!isSystemApp) { - ZLOGE("no system permission, intention: %{public}s.", intention.c_str()); + bool hasSharePermission = VerifyPermission(MANAGE_UDMF_APP_SHARE_OPTION, IPCSkeleton::GetCallingTokenID()); + if (!isSystemApp && !hasSharePermission) { + ZLOGE("No system permission and no shareOption permission, intention: %{public}s.", intention.c_str()); return E_NO_PERMISSION; } auto store = StoreCache::GetInstance().GetStore(intention); @@ -658,7 +653,7 @@ int32_t UdmfServiceImpl::GetAppShareOption(const std::string &intention, int32_t std::string appShareOption; int32_t ret = store->GetLocal(std::to_string(accessTokenIDEx), appShareOption); if (ret != E_OK) { - ZLOGE("GetAppShareOption empty, intention: %{public}s.", intention.c_str()); + ZLOGW("GetAppShareOption empty, intention: %{public}s.", intention.c_str()); return ret; } ZLOGI("GetAppShareOption, intention: %{public}s, appShareOption:%{public}s.", @@ -675,8 +670,9 @@ int32_t UdmfServiceImpl::RemoveAppShareOption(const std::string &intention) } uint64_t accessTokenIDEx = IPCSkeleton::GetCallingFullTokenID(); bool isSystemApp = TokenIdKit::IsSystemAppByFullTokenID(accessTokenIDEx); - if (!isSystemApp) { - ZLOGE("no system permission, intention: %{public}s.", intention.c_str()); + bool hasSharePermission = VerifyPermission(MANAGE_UDMF_APP_SHARE_OPTION, IPCSkeleton::GetCallingTokenID()); + if (!isSystemApp && !hasSharePermission) { + ZLOGE("No system permission and no shareOption permission, intention: %{public}s.", intention.c_str()); return E_NO_PERMISSION; } auto store = StoreCache::GetInstance().GetStore(intention); @@ -741,24 +737,126 @@ int32_t UdmfServiceImpl::OnBind(const BindInfo &bindInfo) executors_ = bindInfo.executors; StoreCache::GetInstance().SetThreadPool(bindInfo.executors); LifeCycleManager::GetInstance().SetThreadPool(bindInfo.executors); - UriPermissionManager::GetInstance().SetThreadPool(bindInfo.executors); return 0; } int32_t UdmfServiceImpl::ObtainAsynProcess(AsyncProcessInfo &processInfo) { - processInfo = asyncProcessInfo_; - if (syncingData_ && processInfo.syncStatus != ASYNC_RUNNING) { - processInfo.syncStatus = ASYNC_RUNNING; - processInfo.srcDevName = syncingDevName_; + if (processInfo.businessUdKey.empty()) { + return E_INVALID_PARAMETERS; + } + std::lock_guard lock(mutex_); + if (asyncProcessInfoMap_.empty()) { + processInfo.syncStatus = AsyncTaskStatus::ASYNC_SUCCESS; + processInfo.srcDevName = "Local"; + return E_OK; + } + auto it = asyncProcessInfoMap_.find(processInfo.businessUdKey); + if (it == asyncProcessInfoMap_.end()) { + processInfo.syncStatus = AsyncTaskStatus::ASYNC_SUCCESS; + processInfo.srcDevName = "Local"; + return E_OK; + } + auto asyncProcessInfo = asyncProcessInfoMap_.at(processInfo.businessUdKey); + processInfo.syncStatus = asyncProcessInfo.syncStatus; + processInfo.srcDevName = asyncProcessInfo.srcDevName; + return E_OK; +} + +int32_t UdmfServiceImpl::ClearAsynProcessByKey(const std::string & businessUdKey) +{ + ZLOGI("ClearAsynProcessByKey begin."); + std::lock_guard lock(mutex_); + if (asyncProcessInfoMap_.find(businessUdKey) == asyncProcessInfoMap_.end()) { + return E_OK; + } + asyncProcessInfoMap_.erase(businessUdKey); + return E_OK; +} + +int32_t UdmfServiceImpl::ResolveAutoLaunch(const std::string &identifier, DBLaunchParam ¶m) +{ + ZLOGI("user:%{public}s appId:%{public}s storeId:%{public}s identifier:%{public}s", param.userId.c_str(), + param.appId.c_str(), DistributedData::Anonymous::Change(param.storeId).c_str(), + DistributedData::Anonymous::Change(identifier).c_str()); + + std::vector metaData; + auto prefix = StoreMetaData::GetPrefix({ DmAdapter::GetInstance().GetLocalDevice().uuid }); + if (!DistributedData::MetaDataManager::GetInstance().LoadMeta(prefix, metaData)) { + ZLOGE("no meta data appId:%{public}s", param.appId.c_str()); + return E_NOT_FOUND; + } + + for (const auto &storeMeta : metaData) { + if (storeMeta.storeType < StoreMetaData::StoreType::STORE_KV_BEGIN || + storeMeta.storeType > StoreMetaData::StoreType::STORE_KV_END || + storeMeta.appId != DistributedData::Bootstrap::GetInstance().GetProcessLabel()) { + continue; + } + auto identifierTag = DistributedDB::KvStoreDelegateManager::GetKvStoreIdentifier("", storeMeta.appId, + storeMeta.storeId, true); + if (identifier != identifierTag) { + continue; + } + auto store = StoreCache::GetInstance().GetStore(storeMeta.storeId); + if (store == nullptr) { + ZLOGE("GetStore fail, storeId:%{public}s", DistributedData::Anonymous::Change(storeMeta.storeId).c_str()); + continue; + } + ZLOGI("storeId:%{public}s,appId:%{public}s,user:%{public}s", + DistributedData::Anonymous::Change(storeMeta.storeId).c_str(), + storeMeta.appId.c_str(), storeMeta.user.c_str()); + return E_OK; } return E_OK; } -int32_t UdmfServiceImpl::ClearAsynProcess() +bool UdmfServiceImpl::VerifyPermission(const std::string &permission, uint32_t callerTokenId) +{ + if (permission.empty()) { + return true; + } + int status = Security::AccessToken::AccessTokenKit::VerifyAccessToken(callerTokenId, permission); + if (status != Security::AccessToken::PermissionState::PERMISSION_GRANTED) { + ZLOGE("Permission denied. status:%{public}d, token:0x%{public}x, permission:%{public}s", + status, callerTokenId, permission.c_str()); + return false; + } + return true; +} + +bool UdmfServiceImpl::HasDatahubPriviledge(const std::string &bundleName) +{ + uint64_t accessTokenIDEx = IPCSkeleton::GetCallingFullTokenID(); + bool isSystemApp = TokenIdKit::IsSystemAppByFullTokenID(accessTokenIDEx); + return std::find(std::begin(HAP_LIST), std::end(HAP_LIST), bundleName) != std::end(HAP_LIST) && isSystemApp; +} + +void UdmfServiceImpl::RegisterAsyncProcessInfo(const std::string &businessUdKey) { - (void)memset_s(&asyncProcessInfo_, sizeof(asyncProcessInfo_), 0, sizeof(asyncProcessInfo_)); + AsyncProcessInfo info; + std::lock_guard lock(mutex_); + asyncProcessInfoMap_.insert_or_assign(businessUdKey, std::move(info)); +} + +int32_t UdmfServiceImpl::InvokeHap(const std::string &progressKey, const sptr &observer) +{ + ProgressDialog::ProgressMessageInfo message; + message.promptText = "PromptText_PasteBoard_Local"; + message.remoteDeviceName = ""; + message.isRemote = false; + message.progressKey = progressKey; + message.clientCallback = observer; + + ProgressDialog::FocusedAppInfo appInfo = ProgressDialog::GetInstance().GetFocusedAppInfo(); + message.windowId = appInfo.windowId; + message.callerToken = appInfo.abilityToken; + auto status = ProgressDialog::GetInstance().ShowProgress(message); + if (status != E_OK) { + ZLOGE("ShowProgress fail, status:%{public}d", status); + } return E_OK; } + } // namespace UDMF } // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_impl.h b/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_impl.h index 3d096d7f105ec9ae4753eee8fa54453ad4f8799d..012de04fe538be3edad8e68c410e5a2760310503 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_impl.h +++ b/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_impl.h @@ -27,16 +27,17 @@ #include "unified_data.h" #include "unified_types.h" #include "visibility.h" +#include "kv_store_delegate_manager.h" namespace OHOS { namespace UDMF { /* * UDMF server implementation */ -class API_EXPORT UdmfServiceImpl final : public UdmfServiceStub { +class UdmfServiceImpl final : public UdmfServiceStub { public: UdmfServiceImpl(); ~UdmfServiceImpl() = default; - + using DBLaunchParam = DistributedDB::AutoLaunchParam; int32_t SetData(CustomOption &option, UnifiedData &unifiedData, std::string &key) override; int32_t GetData(const QueryOption &query, UnifiedData &unifiedData) override; int32_t GetBatchData(const QueryOption &query, std::vector &unifiedDataSet) override; @@ -52,8 +53,9 @@ public: int32_t OnInitialize() override; int32_t OnBind(const BindInfo &bindInfo) override; int32_t ObtainAsynProcess(AsyncProcessInfo &processInfo) override; - int32_t ClearAsynProcess() override; - + int32_t ClearAsynProcessByKey(const std::string &businessUdKey) override; + int32_t ResolveAutoLaunch(const std::string &identifier, DBLaunchParam ¶m) override; + int32_t InvokeHap(const std::string &progressKey, const sptr &observer) override; private: int32_t SaveData(CustomOption &option, UnifiedData &unifiedData, std::string &key); int32_t RetrieveData(const QueryOption &query, UnifiedData &unifiedData); @@ -62,6 +64,9 @@ private: bool IsPermissionInCache(const QueryOption &query); bool IsReadAndKeep(const std::vector &privileges, const QueryOption &query); int32_t ProcessCrossDeviceData(UnifiedData &unifiedData, std::vector &uris); + bool VerifyPermission(const std::string &permission, uint32_t callerTokenId); + bool HasDatahubPriviledge(const std::string &bundleName); + void RegisterAsyncProcessInfo(const std::string &businessUdKey); class Factory { public: @@ -75,9 +80,8 @@ private: std::map privilegeCache_; std::shared_ptr executors_; - AsyncProcessInfo asyncProcessInfo_{}; - bool syncingData_{false}; - std::string syncingDevName_; + std::mutex mutex_; + std::unordered_map asyncProcessInfoMap_; }; } // namespace UDMF } // namespace OHOS diff --git a/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_stub.cpp b/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_stub.cpp index e8224c93c43d3eb5299528b350f9e8d5f241b327..32651fa73e7b8342ae31eaf746853ed06f0fe838 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_stub.cpp +++ b/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_stub.cpp @@ -63,7 +63,6 @@ int32_t UdmfServiceStub::OnSetData(MessageParcel &data, MessageParcel &reply) customOption.tokenId = token; std::string key; int32_t status = SetData(customOption, unifiedData, key); - UdmfConversion::InitValueObject(unifiedData); if (!ITypesUtil::Marshal(reply, status, key)) { ZLOGE("Marshal status or key failed, status: %{public}d, key: %{public}s", status, key.c_str()); return E_WRITE_PARCEL_ERROR; @@ -83,7 +82,6 @@ int32_t UdmfServiceStub::OnGetData(MessageParcel &data, MessageParcel &reply) query.tokenId = token; UnifiedData unifiedData; int32_t status = GetData(query, unifiedData); - UdmfConversion::InitValueObject(unifiedData); if (!ITypesUtil::Marshal(reply, status, unifiedData)) { ZLOGE("Marshal status or unifiedData failed, status: %{public}d", status); return E_WRITE_PARCEL_ERROR; @@ -103,7 +101,6 @@ int32_t UdmfServiceStub::OnGetBatchData(MessageParcel &data, MessageParcel &repl query.tokenId = token; std::vector unifiedDataSet; int32_t status = GetBatchData(query, unifiedDataSet); - UdmfConversion::InitValueObject(unifiedDataSet); if (!ITypesUtil::Marshal(reply, status, unifiedDataSet)) { ZLOGE("Marshal status or unifiedDataSet failed, status: %{public}d", status); return E_WRITE_PARCEL_ERROR; @@ -142,7 +139,6 @@ int32_t UdmfServiceStub::OnDeleteData(MessageParcel &data, MessageParcel &reply) query.tokenId = token; std::vector unifiedDataSet; int32_t status = DeleteData(query, unifiedDataSet); - UdmfConversion::InitValueObject(unifiedDataSet); if (!ITypesUtil::Marshal(reply, status, unifiedDataSet)) { ZLOGE("Marshal status or unifiedDataSet failed, status: %{public}d", status); return E_WRITE_PARCEL_ERROR; @@ -274,6 +270,10 @@ int32_t UdmfServiceStub::OnObtainAsynProcess(MessageParcel &data, MessageParcel { ZLOGD("start"); AsyncProcessInfo processInfo; + if (!ITypesUtil::Unmarshal(data, processInfo)) { + ZLOGE("Unmarshal processInfo failed"); + return E_READ_PARCEL_ERROR; + } int32_t status = ObtainAsynProcess(processInfo); if (!ITypesUtil::Marshal(reply, status, processInfo)) { ZLOGE("Marshal status or processInfo failed, status: %{public}d", status); @@ -282,10 +282,36 @@ int32_t UdmfServiceStub::OnObtainAsynProcess(MessageParcel &data, MessageParcel return E_OK; } -int32_t UdmfServiceStub::OnClearAsynProcess(MessageParcel &data, MessageParcel &reply) +int32_t UdmfServiceStub::OnClearAsynProcessByKey(MessageParcel &data, MessageParcel &reply) +{ + ZLOGD("start"); + std::string businessUdKey; + if (!ITypesUtil::Unmarshal(data, businessUdKey)) { + ZLOGE("Unmarshal businessUdKey failed!"); + return E_READ_PARCEL_ERROR; + } + int32_t status = ClearAsynProcessByKey(businessUdKey); + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status failed, status: %{public}d", status); + return E_WRITE_PARCEL_ERROR; + } + return E_OK; +} + +int32_t UdmfServiceStub::OnInvokeHap(MessageParcel &data, MessageParcel &reply) { ZLOGD("start"); - int32_t status = ClearAsynProcess(); + std::string progressKey; + sptr callback = nullptr; + if (!ITypesUtil::Unmarshal(data, progressKey, callback)) { + ZLOGE("Unmarshal failed"); + return E_READ_PARCEL_ERROR; + } + if (callback == nullptr) { + ZLOGE("Callback is null"); + return E_ERROR; + } + int32_t status = InvokeHap(progressKey, callback); if (!ITypesUtil::Marshal(reply, status)) { ZLOGE("Marshal status failed, status: %{public}d", status); return E_WRITE_PARCEL_ERROR; diff --git a/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_stub.h b/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_stub.h index e3a66a588f875d877c951f4681b68f746827aca8..fddcaba3de659abf7ecf0502c13ba6d9d8bb3dc7 100644 --- a/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_stub.h +++ b/datamgr_service/services/distributeddataservice/service/udmf/udmf_service_stub.h @@ -49,7 +49,8 @@ private: int32_t OnGetAppShareOption(MessageParcel &data, MessageParcel &reply); int32_t OnRemoveAppShareOption(MessageParcel &data, MessageParcel &reply); int32_t OnObtainAsynProcess(MessageParcel &data, MessageParcel &reply); - int32_t OnClearAsynProcess(MessageParcel &data, MessageParcel &reply); + int32_t OnClearAsynProcessByKey(MessageParcel &data, MessageParcel &reply); + int32_t OnInvokeHap(MessageParcel &data, MessageParcel &reply); using Handler = int32_t (UdmfServiceStub::*)(MessageParcel &data, MessageParcel &reply); static constexpr Handler HANDLERS[static_cast(UdmfServiceInterfaceCode::CODE_BUTT)] = { @@ -66,7 +67,8 @@ private: &UdmfServiceStub::OnGetAppShareOption, &UdmfServiceStub::OnRemoveAppShareOption, &UdmfServiceStub::OnObtainAsynProcess, - &UdmfServiceStub::OnClearAsynProcess + &UdmfServiceStub::OnClearAsynProcessByKey, + &UdmfServiceStub::OnInvokeHap }; }; } // namespace UDMF diff --git a/interface_sdk/api/@ohos.data.relationalStore.d.ts b/interface_sdk/api/@ohos.data.relationalStore.d.ts index c4baa32240cad8658ae4c5ea265f0cbf842e5114..336a72d5d8b36df2f21386e8e091aa667cea5296 100644 --- a/interface_sdk/api/@ohos.data.relationalStore.d.ts +++ b/interface_sdk/api/@ohos.data.relationalStore.d.ts @@ -340,6 +340,16 @@ declare namespace relationalStore { */ customDir?: string; + /** + * Specifies the root directory relative to the database + * + * @type { ?string } + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @crossplatform + * @since 16 + */ + rootDir?: string; + /** * Specifies whether to clean up dirty data that is synchronized to * the local but deleted in the cloud. @@ -374,8 +384,7 @@ declare namespace relationalStore { * * @type { ?boolean } * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core - * @systemapi - * @since 12 + * @since 16 */ vector?: boolean; @@ -416,6 +425,16 @@ declare namespace relationalStore { * @since 14 */ cryptoParam?: CryptoParam; + + /** + * Specifies the tokenizer type when using fts capability. + * + * @type { ?Tokenizer } + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 16 + */ + + tokenizer?: Tokenizer; } /** @@ -607,6 +626,37 @@ declare namespace relationalStore { KDF_SHA512 } + /** + * Enumerates the supported tokenizer when opening a database. + * + * @enum { number } + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 16 + */ + enum Tokenizer { + /** + * NONE_TOKENIZER: not use tokenizer + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 16 + */ + NONE_TOKENIZER = 0, + /** + * ICU_TOKENIZER: native icu tokenizer. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 16 + */ + ICU_TOKENIZER, + /** + * CUSTOM_TOKENIZER: self-developed enhance tokenizer. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 16 + */ + CUSTOM_TOKENIZER + } + /** * The cloud sync progress * @@ -1229,6 +1279,15 @@ declare namespace relationalStore { * @since 11 */ references?: Array; + + /** + * Specifies whether async download assets. + * + * @type { ?boolean } + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 16 + */ + asyncDownloadAsset?: boolean; } /** @@ -3239,6 +3298,39 @@ declare namespace relationalStore { * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @since 12 */ + /** + * Obtains the value of the specified column in the current row. + * The implementation class determines whether to throw an exception if the value of the specified column + * in the current row is null or the specified column is not of the Assets type. + * Inserting an empty blob, after API14 and API14, the obtained value is an empty blob; Before API 14, + * the obtained value was null. + * + * @param { number } columnIndex - Indicates the specified column index, which starts from 0. + * @returns { ValueType } The value of the specified column. + * @throws { BusinessError } 401 - Parameter error. Possible causes: 1. Mandatory parameters are left unspecified; + *
2. Incorrect parameter types. + * @throws { BusinessError } 14800000 - Inner error. + * @throws { BusinessError } 14800011 - Database corrupted. + * @throws { BusinessError } 14800012 - Row out of bounds. + * @throws { BusinessError } 14800013 - Column out of bounds. + * @throws { BusinessError } 14800014 - Already closed. + * @throws { BusinessError } 14800021 - SQLite: Generic error. + * @throws { BusinessError } 14800022 - SQLite: Callback routine requested an abort. + * @throws { BusinessError } 14800023 - SQLite: Access permission denied. + * @throws { BusinessError } 14800024 - SQLite: The database file is locked. + * @throws { BusinessError } 14800025 - SQLite: A table in the database is locked. + * @throws { BusinessError } 14800026 - SQLite: The database is out of memory. + * @throws { BusinessError } 14800027 - SQLite: Attempt to write a readonly database. + * @throws { BusinessError } 14800028 - SQLite: Some kind of disk I/O error occurred. + * @throws { BusinessError } 14800029 - SQLite: The database is full. + * @throws { BusinessError } 14800030 - SQLite: Unable to open the database file. + * @throws { BusinessError } 14800031 - SQLite: TEXT or BLOB exceeds size limit. + * @throws { BusinessError } 14800032 - SQLite: Abort due to constraint violation. + * @throws { BusinessError } 14800033 - SQLite: Data type mismatch. + * @throws { BusinessError } 14800034 - SQLite: Library used incorrectly. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 14 + */ getValue(columnIndex: number): ValueType; /** @@ -3269,8 +3361,7 @@ declare namespace relationalStore { * @throws { BusinessError } 14800033 - SQLite: Data type mismatch. * @throws { BusinessError } 14800034 - SQLite: Library used incorrectly. * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core - * @systemapi - * @since 12 + * @since 16 */ getFloat32Array(columnIndex: number): Float32Array; @@ -3310,8 +3401,66 @@ declare namespace relationalStore { * @crossplatform * @since 12 */ + /** + * Obtains the values of all columns in the specified row. + * Inserting an empty blob, after API14 and API14, the obtained value is an empty blob; Before API 14, + * the obtained value was null. + * + * @returns { ValuesBucket } Indicates the row of data {@link ValuesBucket} to be inserted into the table. + * @throws { BusinessError } 14800000 - Inner error. + * @throws { BusinessError } 14800011 - Database corrupted. + * @throws { BusinessError } 14800012 - Row out of bounds. + * @throws { BusinessError } 14800013 - Column out of bounds. + * @throws { BusinessError } 14800014 - Already closed. + * @throws { BusinessError } 14800021 - SQLite: Generic error. + * @throws { BusinessError } 14800022 - SQLite: Callback routine requested an abort. + * @throws { BusinessError } 14800023 - SQLite: Access permission denied. + * @throws { BusinessError } 14800024 - SQLite: The database file is locked. + * @throws { BusinessError } 14800025 - SQLite: A table in the database is locked. + * @throws { BusinessError } 14800026 - SQLite: The database is out of memory. + * @throws { BusinessError } 14800027 - SQLite: Attempt to write a readonly database. + * @throws { BusinessError } 14800028 - SQLite: Some kind of disk I/O error occurred. + * @throws { BusinessError } 14800029 - SQLite: The database is full. + * @throws { BusinessError } 14800030 - SQLite: Unable to open the database file. + * @throws { BusinessError } 14800031 - SQLite: TEXT or BLOB exceeds size limit. + * @throws { BusinessError } 14800032 - SQLite: Abort due to constraint violation. + * @throws { BusinessError } 14800033 - SQLite: Data type mismatch. + * @throws { BusinessError } 14800034 - SQLite: Library used incorrectly. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @crossplatform + * @since 14 + */ getRow(): ValuesBucket; + /** + * Obtains the values of all columns in the specified rows. + * @param { number } maxCount - Indicates the maximum number of rows. + * @param { number } position - Indicates the start position to obtain the values. + * @returns { Promise> } Promise used to return the values obtained, in an{@link Array}. + * @throws { BusinessError } 401 - Parameter error. Possible causes: 1. Mandatory parameters are left unspecified; + *
2. Incorrect parameter types. + * @throws { BusinessError } 14800000 - Inner error. + * @throws { BusinessError } 14800011 - Database corrupted. + * @throws { BusinessError } 14800012 - Row out of bounds. + * @throws { BusinessError } 14800013 - Column out of bounds. + * @throws { BusinessError } 14800014 - Already closed. + * @throws { BusinessError } 14800021 - SQLite: Generic error. + * @throws { BusinessError } 14800022 - SQLite: Callback routine requested an abort. + * @throws { BusinessError } 14800023 - SQLite: Access permission denied. + * @throws { BusinessError } 14800024 - SQLite: The database file is locked. + * @throws { BusinessError } 14800025 - SQLite: A table in the database is locked. + * @throws { BusinessError } 14800026 - SQLite: The database is out of memory. + * @throws { BusinessError } 14800028 - SQLite: Some kind of disk I/O error occurred. + * @throws { BusinessError } 14800029 - SQLite: The database is full. + * @throws { BusinessError } 14800031 - SQLite: TEXT or BLOB exceeds size limit. + * @throws { BusinessError } 14800032 - SQLite: Abort due to constraint violation. + * @throws { BusinessError } 14800033 - SQLite: Data type mismatch. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @crossplatform + * @since 16 + */ + getRows(maxCount: number, position?: number): Promise>; + /** * Obtains the values of all columns in the specified row. * @@ -3936,6 +4085,74 @@ declare namespace relationalStore { */ batchInsertSync(table: string, values: Array): number; + /** + * Inserts a batch of data into the target table. + * + * @param { string } table - Indicates the target table. + * @param { Array } values - Indicates the rows of data {@link ValuesBucket} to be inserted into the table. + * @param { ConflictResolution } conflict - Indicates the {@link ConflictResolution} to insert data into the table. + * @returns { Promise } The number of values that were inserted if the operation is successful. returns -1 otherwise. + * @throws { BusinessError } 401 - Parameter error. Possible causes: 1. Mandatory parameters are left unspecified; + *
2. Incorrect parameter types. + * @throws { BusinessError } 14800000 - Inner error. + * @throws { BusinessError } 14800011 - Database corrupted. + * @throws { BusinessError } 14800014 - Already closed. + * @throws { BusinessError } 14800015 - The database does not respond. + * @throws { BusinessError } 14800021 - SQLite: Generic error. + * @throws { BusinessError } 14800022 - SQLite: Callback routine requested an abort. + * @throws { BusinessError } 14800023 - SQLite: Access permission denied. + * @throws { BusinessError } 14800024 - SQLite: The database file is locked. + * @throws { BusinessError } 14800025 - SQLite: A table in the database is locked. + * @throws { BusinessError } 14800026 - SQLite: The database is out of memory. + * @throws { BusinessError } 14800027 - SQLite: Attempt to write a readonly database. + * @throws { BusinessError } 14800028 - SQLite: Some kind of disk I/O error occurred. + * @throws { BusinessError } 14800029 - SQLite: The database is full. + * @throws { BusinessError } 14800030 - SQLite: Unable to open the database file. + * @throws { BusinessError } 14800031 - SQLite: TEXT or BLOB exceeds size limit. + * @throws { BusinessError } 14800032 - SQLite: Abort due to constraint violation. + * @throws { BusinessError } 14800033 - SQLite: Data type mismatch. + * @throws { BusinessError } 14800034 - SQLite: Library used incorrectly. + * @throws { BusinessError } 14800047 - The WAL file size exceeds the default limit. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @crossplatform + * @since 16 + */ + batchInsertWithConflictResolution(table: string, values: Array, conflict: ConflictResolution): Promise; + + /** + * Inserts a batch of data into the target table. + * + * @param { string } table - Indicates the target table. + * @param { Array } values - Indicates the rows of data {@link ValuesBucket} to be inserted into the table. + * @returns { Promise } The number of values that were inserted if the operation is successful. returns -1 otherwise. + * @returns { number } The number of values that were inserted if the operation is successful. returns -1 otherwise. + * @throws { BusinessError } 401 - Parameter error. Possible causes: 1. Mandatory parameters are left unspecified; + *
2. Incorrect parameter types. + * @throws { BusinessError } 14800000 - Inner error. + * @throws { BusinessError } 14800011 - Database corrupted. + * @throws { BusinessError } 14800014 - Already closed. + * @throws { BusinessError } 14800015 - The database does not respond. + * @throws { BusinessError } 14800021 - SQLite: Generic error. + * @throws { BusinessError } 14800022 - SQLite: Callback routine requested an abort. + * @throws { BusinessError } 14800023 - SQLite: Access permission denied. + * @throws { BusinessError } 14800024 - SQLite: The database file is locked. + * @throws { BusinessError } 14800025 - SQLite: A table in the database is locked. + * @throws { BusinessError } 14800026 - SQLite: The database is out of memory. + * @throws { BusinessError } 14800027 - SQLite: Attempt to write a readonly database. + * @throws { BusinessError } 14800028 - SQLite: Some kind of disk I/O error occurred. + * @throws { BusinessError } 14800029 - SQLite: The database is full. + * @throws { BusinessError } 14800030 - SQLite: Unable to open the database file. + * @throws { BusinessError } 14800031 - SQLite: TEXT or BLOB exceeds size limit. + * @throws { BusinessError } 14800032 - SQLite: Abort due to constraint violation. + * @throws { BusinessError } 14800033 - SQLite: Data type mismatch. + * @throws { BusinessError } 14800034 - SQLite: Library used incorrectly. + * @throws { BusinessError } 14800047 - The WAL file size exceeds the default limit. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @crossplatform + * @since 16 + */ + batchInsertWithConflictResolutionSync(table: string, values: Array, conflict: ConflictResolution): number; + /** * Updates data in the database based on a specified instance object of RdbPredicates. * @@ -4048,10 +4265,10 @@ declare namespace relationalStore { * @since 12 */ update( - values: ValuesBucket, - predicates: RdbPredicates, - conflict: ConflictResolution, - callback: AsyncCallback + values: ValuesBucket, + predicates: RdbPredicates, + conflict: ConflictResolution, + callback: AsyncCallback ): void; /** @@ -4276,10 +4493,10 @@ declare namespace relationalStore { * @since 12 */ update( - table: string, - values: ValuesBucket, - predicates: dataSharePredicates.DataSharePredicates, - callback: AsyncCallback + table: string, + values: ValuesBucket, + predicates: dataSharePredicates.DataSharePredicates, + callback: AsyncCallback ): void; /** @@ -4823,10 +5040,10 @@ declare namespace relationalStore { * @since 12 */ query( - table: string, - predicates: dataSharePredicates.DataSharePredicates, - columns: Array, - callback: AsyncCallback + table: string, + predicates: dataSharePredicates.DataSharePredicates, + columns: Array, + callback: AsyncCallback ): void; /** @@ -4866,9 +5083,9 @@ declare namespace relationalStore { * @since 12 */ query( - table: string, - predicates: dataSharePredicates.DataSharePredicates, - columns?: Array + table: string, + predicates: dataSharePredicates.DataSharePredicates, + columns?: Array ): Promise; /** @@ -5114,10 +5331,10 @@ declare namespace relationalStore { * @since 12 */ getModifyTime( - table: string, - columnName: string, - primaryKeys: PRIKeyType[], - callback: AsyncCallback + table: string, + columnName: string, + primaryKeys: PRIKeyType[], + callback: AsyncCallback ): void; /** @@ -6271,10 +6488,10 @@ declare namespace relationalStore { * @since 12 */ setDistributedTables( - tables: Array, - type: DistributedType, - config: DistributedConfig, - callback: AsyncCallback + tables: Array, + type: DistributedType, + config: DistributedConfig, + callback: AsyncCallback ): void; /** @@ -6530,10 +6747,10 @@ declare namespace relationalStore { * @since 12 */ cloudSync( - mode: SyncMode, - tables: string[], - progress: Callback, - callback: AsyncCallback + mode: SyncMode, + tables: string[], + progress: Callback, + callback: AsyncCallback ): void; /** @@ -6599,10 +6816,10 @@ declare namespace relationalStore { * @since 12 */ cloudSync( - mode: SyncMode, - predicates: RdbPredicates, - progress: Callback, - callback: AsyncCallback + mode: SyncMode, + predicates: RdbPredicates, + progress: Callback, + callback: AsyncCallback ): void; /** @@ -6672,11 +6889,11 @@ declare namespace relationalStore { * @since 12 */ remoteQuery( - device: string, - table: string, - predicates: RdbPredicates, - columns: Array, - callback: AsyncCallback + device: string, + table: string, + predicates: RdbPredicates, + columns: Array, + callback: AsyncCallback ): void; /** @@ -6790,7 +7007,7 @@ declare namespace relationalStore { * @throws { BusinessError } 401 - Parameter error. Possible causes: 1. Mandatory parameters are left unspecified; *
2. Incorrect parameter types. * @throws { BusinessError } 801 - Capability not supported. - * @throws { BusinessError } 14800050 - Failed to obtain subscription service. + * @throws { BusinessError } 14800050 - Failed to obtain the subscription service. * @throws { BusinessError } 14800000 - Inner error. * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @since 10 @@ -6806,7 +7023,7 @@ declare namespace relationalStore { * @throws { BusinessError } 801 - Capability not supported. * @throws { BusinessError } 14800000 - Inner error. * @throws { BusinessError } 14800014 - Already closed. - * @throws { BusinessError } 14800050 - Failed to obtain subscription service. + * @throws { BusinessError } 14800050 - Failed to obtain the subscription service. * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @since 12 */ @@ -6911,9 +7128,9 @@ declare namespace relationalStore { * @since 12 */ off( - event: 'dataChange', - type: SubscribeType, - observer?: Callback> | Callback> + event: 'dataChange', + type: SubscribeType, + observer?: Callback> | Callback> ): void; /** @@ -6925,7 +7142,7 @@ declare namespace relationalStore { * @throws { BusinessError } 401 - Parameter error. Possible causes: 1. Mandatory parameters are left unspecified; *
2. Incorrect parameter types. * @throws { BusinessError } 801 - Capability not supported. - * @throws { BusinessError } 14800050 - Failed to obtain subscription service. + * @throws { BusinessError } 14800050 - Failed to obtain the subscription service. * @throws { BusinessError } 14800000 - Inner error. * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @since 10 @@ -6941,7 +7158,7 @@ declare namespace relationalStore { * @throws { BusinessError } 801 - Capability not supported. * @throws { BusinessError } 14800000 - Inner error. * @throws { BusinessError } 14800014 - Already closed. - * @throws { BusinessError } 14800050 - Failed to obtain subscription service. + * @throws { BusinessError } 14800050 - Failed to obtain the subscription service. * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @since 12 */ @@ -6992,7 +7209,7 @@ declare namespace relationalStore { * @throws { BusinessError } 401 - Parameter error. Possible causes: 1. Mandatory parameters are left unspecified; *
2. Incorrect parameter types. * @throws { BusinessError } 801 - Capability not supported. - * @throws { BusinessError } 14800050 - Failed to obtain subscription service. + * @throws { BusinessError } 14800050 - Failed to obtain the subscription service. * @throws { BusinessError } 14800000 - Inner error. * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @since 10 @@ -7006,7 +7223,7 @@ declare namespace relationalStore { * @throws { BusinessError } 801 - Capability not supported. * @throws { BusinessError } 14800000 - Inner error. * @throws { BusinessError } 14800014 - Already closed. - * @throws { BusinessError } 14800050 - Failed to obtain subscription service. + * @throws { BusinessError } 14800050 - Failed to obtain the subscription service. * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @since 12 */ @@ -7038,7 +7255,7 @@ declare namespace relationalStore { * @throws { BusinessError } 14800011 - Database corrupted. * @throws { BusinessError } 14800014 - Already closed. * @throws { BusinessError } 14800015 - The database does not respond. - * @throws { BusinessError } 14800016 - The database is already attached. + * @throws { BusinessError } 14800016 - The database alias already exists. * @throws { BusinessError } 14800021 - SQLite: Generic error. * @throws { BusinessError } 14800022 - SQLite: Callback routine requested an abort. * @throws { BusinessError } 14800023 - SQLite: Access permission denied. @@ -7074,9 +7291,9 @@ declare namespace relationalStore { * @throws { BusinessError } 14800011 - Database corrupted. * @throws { BusinessError } 14800014 - Already closed. * @throws { BusinessError } 14800015 - The database does not respond. - * @throws { BusinessError } 14800016 - The database is already attached. - * @throws { BusinessError } 14801001 - Only supported in stage mode. - * @throws { BusinessError } 14801002 - The data group id is not valid. + * @throws { BusinessError } 14800016 - The database alias already exists. + * @throws { BusinessError } 14801001 - The operation is supported in the stage model only. + * @throws { BusinessError } 14801002 - Invalid data ground ID. * @throws { BusinessError } 14800021 - SQLite: Generic error. * @throws { BusinessError } 14800022 - SQLite: Callback routine requested an abort. * @throws { BusinessError } 14800023 - SQLite: Access permission denied. @@ -7428,6 +7645,70 @@ declare namespace relationalStore { */ batchInsertSync(table: string, values: Array): number; + /** + * Inserts a batch of data into the target table. + * + * @param { string } table - Indicates the target table. + * @param { Array } values - Indicates the rows of data {@link ValuesBucket} to be inserted into the table. + * @param { ConflictResolution } conflict - Indicates the {@link ConflictResolution} to insert data into the table. + * @returns { Promise } The number of values that were inserted if the operation is successful. returns -1 otherwise. + * @throws { BusinessError } 401 - Parameter error. Possible causes: 1. Mandatory parameters are left unspecified; + *
2. Incorrect parameter types. + * @throws { BusinessError } 14800000 - Inner error. + * @throws { BusinessError } 14800011 - Database corrupted. + * @throws { BusinessError } 14800014 - Already closed. + * @throws { BusinessError } 14800021 - SQLite: Generic error. + * @throws { BusinessError } 14800022 - SQLite: Callback routine requested an abort. + * @throws { BusinessError } 14800023 - SQLite: Access permission denied. + * @throws { BusinessError } 14800024 - SQLite: The database file is locked. + * @throws { BusinessError } 14800025 - SQLite: A table in the database is locked. + * @throws { BusinessError } 14800026 - SQLite: The database is out of memory. + * @throws { BusinessError } 14800027 - SQLite: Attempt to write a readonly database. + * @throws { BusinessError } 14800028 - SQLite: Some kind of disk I/O error occurred. + * @throws { BusinessError } 14800029 - SQLite: The database is full. + * @throws { BusinessError } 14800031 - SQLite: TEXT or BLOB exceeds size limit. + * @throws { BusinessError } 14800032 - SQLite: Abort due to constraint violation. + * @throws { BusinessError } 14800033 - SQLite: Data type mismatch. + * @throws { BusinessError } 14800034 - SQLite: Library used incorrectly. + * @throws { BusinessError } 14800047 - The WAL file size exceeds the default limit. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @crossplatform + * @since 16 + */ + batchInsertWithConflictResolution(table: string, values: Array, conflict: ConflictResolution): Promise; + + /** + * Inserts a batch of data into the target table. + * + * @param { string } table - Indicates the target table. + * @param { Array } values - Indicates the rows of data {@link ValuesBucket} to be inserted into the table. + * @param { ConflictResolution } conflict - Indicates the {@link ConflictResolution} to insert data into the table. + * @returns { number } The number of values that were inserted if the operation is successful. returns -1 otherwise. + * @throws { BusinessError } 401 - Parameter error. Possible causes: 1. Mandatory parameters are left unspecified; + *
2. Incorrect parameter types. + * @throws { BusinessError } 14800000 - Inner error. + * @throws { BusinessError } 14800011 - Database corrupted. + * @throws { BusinessError } 14800014 - Already closed. + * @throws { BusinessError } 14800021 - SQLite: Generic error. + * @throws { BusinessError } 14800022 - SQLite: Callback routine requested an abort. + * @throws { BusinessError } 14800023 - SQLite: Access permission denied. + * @throws { BusinessError } 14800024 - SQLite: The database file is locked. + * @throws { BusinessError } 14800025 - SQLite: A table in the database is locked. + * @throws { BusinessError } 14800026 - SQLite: The database is out of memory. + * @throws { BusinessError } 14800027 - SQLite: Attempt to write a readonly database. + * @throws { BusinessError } 14800028 - SQLite: Some kind of disk I/O error occurred. + * @throws { BusinessError } 14800029 - SQLite: The database is full. + * @throws { BusinessError } 14800031 - SQLite: TEXT or BLOB exceeds size limit. + * @throws { BusinessError } 14800032 - SQLite: Abort due to constraint violation. + * @throws { BusinessError } 14800033 - SQLite: Data type mismatch. + * @throws { BusinessError } 14800034 - SQLite: Library used incorrectly. + * @throws { BusinessError } 14800047 - The WAL file size exceeds the default limit. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @crossplatform + * @since 16 + */ + batchInsertWithConflictResolutionSync(table: string, values: Array, conflict: ConflictResolution): number; + /** * Updates data in the database based on a specified instance object of RdbPredicates. * @@ -7724,8 +8005,8 @@ declare namespace relationalStore { * @throws { BusinessError } 14800000 - Inner error. * @throws { BusinessError } 14800010 - Failed to open or delete database by invalid database path. * @throws { BusinessError } 14800011 - Failed to open database by database corrupted. - * @throws { BusinessError } 14801001 - Only supported in stage mode. - * @throws { BusinessError } 14801002 - The data group id is not valid. + * @throws { BusinessError } 14801001 - The operation is supported in the stage model only. + * @throws { BusinessError } 14801002 - Invalid data ground ID. * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @crossplatform * @since 10 @@ -7743,8 +8024,8 @@ declare namespace relationalStore { * @throws { BusinessError } 14800000 - Inner error. * @throws { BusinessError } 14800010 - Invalid database path. * @throws { BusinessError } 14800011 - Database corrupted. - * @throws { BusinessError } 14801001 - Only supported in stage mode. - * @throws { BusinessError } 14801002 - The data group id is not valid. + * @throws { BusinessError } 14801001 - The operation is supported in the stage model only. + * @throws { BusinessError } 14801002 - Invalid data ground ID. * @throws { BusinessError } 14800017 - Config changed. * @throws { BusinessError } 14800021 - SQLite: Generic error. * @throws { BusinessError } 14800022 - SQLite: Callback routine requested an abort. @@ -7757,6 +8038,34 @@ declare namespace relationalStore { * @crossplatform * @since 12 */ + /** + * Obtains a RDB store. + * You can set parameters of the RDB store as required. In general, this method is recommended + * to obtain a rdb store. + * + * @param { Context } context - Indicates the context of an application or ability. + * @param { StoreConfig } config - Indicates the {@link StoreConfig} configuration of the database related to this RDB store. + * @param { AsyncCallback } callback - The RDB store {@link RdbStore}. + * @throws { BusinessError } 401 - Parameter error. Possible causes: 1. Mandatory parameters are left unspecified; + *
2. Incorrect parameter types. + * @throws { BusinessError } 14800000 - Inner error. + * @throws { BusinessError } 14800010 - Invalid database path. + * @throws { BusinessError } 14800011 - Database corrupted. + * @throws { BusinessError } 14801001 - The operation is supported in the stage model only. + * @throws { BusinessError } 14801002 - Invalid data ground ID. + * @throws { BusinessError } 14800017 - Config changed. + * @throws { BusinessError } 14800020 - The secret key is corrupted or lost. + * @throws { BusinessError } 14800021 - SQLite: Generic error. + * @throws { BusinessError } 14800022 - SQLite: Callback routine requested an abort. + * @throws { BusinessError } 14800023 - SQLite: Access permission denied. + * @throws { BusinessError } 14800027 - SQLite: Attempt to write a readonly database. + * @throws { BusinessError } 14800028 - SQLite: Some kind of disk I/O error occurred. + * @throws { BusinessError } 14800029 - SQLite: The database is full. + * @throws { BusinessError } 14800030 - SQLite: Unable to open the database file. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @crossplatform + * @since 14 + */ function getRdbStore(context: Context, config: StoreConfig, callback: AsyncCallback): void; /** @@ -7788,8 +8097,8 @@ declare namespace relationalStore { * @throws { BusinessError } 14800000 - Inner error. * @throws { BusinessError } 14800010 - Failed to open or delete database by invalid database path. * @throws { BusinessError } 14800011 - Failed to open database by database corrupted. - * @throws { BusinessError } 14801001 - Only supported in stage mode. - * @throws { BusinessError } 14801002 - The data group id is not valid. + * @throws { BusinessError } 14801001 - The operation is supported in the stage model only. + * @throws { BusinessError } 14801002 - Invalid data ground ID. * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @crossplatform * @since 10 @@ -7807,8 +8116,8 @@ declare namespace relationalStore { * @throws { BusinessError } 14800000 - Inner error. * @throws { BusinessError } 14800010 - Invalid database path. * @throws { BusinessError } 14800011 - Database corrupted. - * @throws { BusinessError } 14801001 - Only supported in stage mode. - * @throws { BusinessError } 14801002 - The data group id is not valid. + * @throws { BusinessError } 14801001 - The operation is supported in the stage model only. + * @throws { BusinessError } 14801002 - Invalid data ground ID. * @throws { BusinessError } 14800017 - Config changed. * @throws { BusinessError } 14800021 - SQLite: Generic error. * @throws { BusinessError } 14800027 - SQLite: Attempt to write a readonly database. @@ -7819,6 +8128,34 @@ declare namespace relationalStore { * @crossplatform * @since 12 */ + /** + * Obtains a RDB store. + * You can set parameters of the RDB store as required. In general, this method is recommended + * to obtain a rdb store. + * + * @param { Context } context - Indicates the context of an application or ability. + * @param { StoreConfig } config - Indicates the {@link StoreConfig} configuration of the database related to this RDB store. + * @returns { Promise } The RDB store {@link RdbStore}. + * @throws { BusinessError } 401 - Parameter error. Possible causes: 1. Mandatory parameters are left unspecified; + *
2. Incorrect parameter types. + * @throws { BusinessError } 14800000 - Inner error. + * @throws { BusinessError } 14800010 - Invalid database path. + * @throws { BusinessError } 14800011 - Database corrupted. + * @throws { BusinessError } 14801001 - The operation is supported in the stage model only. + * @throws { BusinessError } 14801002 - Invalid data ground ID. + * @throws { BusinessError } 14800017 - Config changed. + * @throws { BusinessError } 14800020 - The secret key is corrupted or lost. + * @throws { BusinessError } 14800021 - SQLite: Generic error. + * @throws { BusinessError } 14800022 - SQLite: Callback routine requested an abort. + * @throws { BusinessError } 14800023 - SQLite: Access permission denied. + * @throws { BusinessError } 14800027 - SQLite: Attempt to write a readonly database. + * @throws { BusinessError } 14800028 - SQLite: Some kind of disk I/O error occurred. + * @throws { BusinessError } 14800029 - SQLite: The database is full. + * @throws { BusinessError } 14800030 - SQLite: Unable to open the database file. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @crossplatform + * @since 14 + */ function getRdbStore(context: Context, config: StoreConfig): Promise; /** @@ -7863,8 +8200,8 @@ declare namespace relationalStore { *
2. Incorrect parameter types. * @throws { BusinessError } 14800000 - Inner error. * @throws { BusinessError } 14800010 - Failed to open or delete database by invalid database path. - * @throws { BusinessError } 14801001 - Only supported in stage mode. - * @throws { BusinessError } 14801002 - The data group id is not valid. + * @throws { BusinessError } 14801001 - The operation is supported in the stage model only. + * @throws { BusinessError } 14801002 - Invalid data ground ID. * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @crossplatform * @since 10 @@ -7928,8 +8265,8 @@ declare namespace relationalStore { *
2. Incorrect parameter types. * @throws { BusinessError } 14800000 - Inner error. * @throws { BusinessError } 14800010 - Failed to open or delete database by invalid database path. - * @throws { BusinessError } 14801001 - Only supported in stage mode. - * @throws { BusinessError } 14801002 - The data group id is not valid. + * @throws { BusinessError } 14801001 - The operation is supported in the stage model only. + * @throws { BusinessError } 14801002 - Invalid data ground ID. * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @crossplatform * @since 10 @@ -7946,13 +8283,32 @@ declare namespace relationalStore { * @throws { BusinessError } 801 - Capability not supported. * @throws { BusinessError } 14800000 - Inner error. * @throws { BusinessError } 14800010 - Invalid database path. - * @throws { BusinessError } 14801001 - Only supported in stage mode. - * @throws { BusinessError } 14801002 - The data group id is not valid. + * @throws { BusinessError } 14801001 - The operation is supported in the stage model only. + * @throws { BusinessError } 14801002 - Invalid data ground ID. * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core * @crossplatform * @since 12 */ function deleteRdbStore(context: Context, config: StoreConfig): Promise; + + /** + * Checks whether the vector database is supported. + * + * @returns { boolean } Returns {@code true} if the vector database is supported; returns {@code false} otherwise. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 16 + */ + function isVectorSupported(): boolean; + + /** + * check the {@link Tokenizer} tokenizer type is supported or not on current system. + * @param { tokenizer } type - Indicates Tokenizer which want to check. + * @returns { boolean } Returns {@code true} if the tokenizer is supported; returns {@code false} otherwise. + * @throws { BusinessError } 401 - Parameter error. Possible causes: Incorrect parameter types + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 16 + */ + function isTokenizerSupported(tokenizer: Tokenizer): boolean; } export default relationalStore; diff --git a/kv_store/bundle.json b/kv_store/bundle.json index b69686167551c89728a1b0237fcbf497e4a9d6e1..fda9c229d5eabd87ef67c9ba975f4f05b14e223e 100644 --- a/kv_store/bundle.json +++ b/kv_store/bundle.json @@ -39,7 +39,9 @@ "SystemCapability.DistributedDataManager.KVStore.Core", "SystemCapability.DistributedDataManager.KVStore.DistributedKVStore" ], - "features": [], + "features": [ + "kv_store_cloud" + ], "adapted_system_type": [ "standard" ], @@ -120,6 +122,64 @@ "header_base": "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddata/include" } }, + { + "name": "//foundation/distributeddatamgr/kv_store/frameworks/common:datamgr_common", + "visibility": [ "datamgr_service" ], + "header": { + "header_files": [ + "executor.h", + "executor_pool.h", + "pool.h", + "priority_queue.h", + "types.h" + ], + "header_base": "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddata/include" + } + }, + { + "name": "//foundation/distributeddatamgr/kv_store/frameworks/common:datamgr_common", + "visibility": [ "datamgr_service" ], + "header": { + "header_files": [ + "concurrent_map.h" + ], + "header_base": "//foundation/distributeddatamgr/kv_store/frameworks/common" + } + }, + { + "name": "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddata:kvdb_inner_lite", + "visibility": [ "datamgr_service" ], + "header": { + "header_files": [ + "ikvdb_notifier.h", + "ikvstore_observer.h" + ], + "header_base": "//foundation/distributeddatamgr/kv_store/frameworks/innerkitsimpl/distributeddatafwk/include" + } + }, + { + "name": "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddata:kvdb_inner_lite", + "visibility": [ "datamgr_service" ], + "header": { + "header_files": [ + "distributeddata_kvdb_ipc_interface_code.h", + "kv_types_util.h", + "kvdb_service.h" + ], + "header_base": "//foundation/distributeddatamgr/kv_store/frameworks/innerkitsimpl/kvdb/include" + } + }, + { + "name": "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddata:kvdb_inner_lite", + "visibility": [ "datamgr_service" ], + "header": { + "header_files": [ + "kvstore_sync_callback.h", + "store_errno.h" + ], + "header_base": "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddata/include" + } + }, { "name": "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddatamgr:distributeddata_mgr", "header": { @@ -129,6 +189,15 @@ "header_base": "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddatamgr/include" } }, + { + "name": "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddatamgr:distributeddata_mgr", + "header": { + "header_files": [ + "ikvstore_data_service.h" + ], + "header_base": "//foundation/distributeddatamgr/kv_store/frameworks/innerkitsimpl/distributeddatasvc/include" + } + }, { "name": "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb:distributeddb", "header": { diff --git a/kv_store/databaseutils/src/acl.cpp b/kv_store/databaseutils/src/acl.cpp index 456ceda930ee13df465493b865eba312fb2f5b5c..f220bf378c1007137f8cedf1756b0e73c451502f 100644 --- a/kv_store/databaseutils/src/acl.cpp +++ b/kv_store/databaseutils/src/acl.cpp @@ -156,7 +156,7 @@ void Acl::AclFromDefault() AclFromMode(); } else { hasError_ = true; - ZLOGW("getxattr failed. error %{public}s path %{public}s", std::strerror(errno), path_.c_str()); + ZLOGW("The getxattr failed. error %{public}s path %{public}s", std::strerror(errno), path_.c_str()); } } diff --git a/kv_store/databaseutils/test/BUILD.gn b/kv_store/databaseutils/test/BUILD.gn index 805e13f5764071e2e19d937f8f0b5a696d146396..6fc794d04d2912f61ce86cfd3793b84c1e2982e9 100644 --- a/kv_store/databaseutils/test/BUILD.gn +++ b/kv_store/databaseutils/test/BUILD.gn @@ -38,6 +38,89 @@ ohos_unittest("DataBaseUtilsTest") { ] } +ohos_unittest("DataMgrServiceProxyVirtualTest") { + module_out_path = module_output_path + + sources = [ + "${kv_store_base_path}/frameworks/innerkitsimpl/distributeddatasvc/src/datamgr_service_proxy.cpp", + "datamgr_service_proxy_virtual_test.cpp", + ] + + configs = [ ":database_utils_config" ] + + external_deps = [ + "c_utils:utils", + "googletest:gtest_main", + "hilog:libhilog", + "ipc:ipc_single", + "samgr:samgr_proxy", + ] + + deps = [ + "${kv_store_base_path}/frameworks/libs/distributeddb/:distributeddb", + "${kv_store_base_path}/interfaces/innerkits/distributeddata:distributeddata_inner", + "${kv_store_base_path}/interfaces/innerkits/distributeddatamgr:distributeddata_mgr", + ] +} + +ohos_unittest("BlobVirtualTest") { + module_out_path = module_output_path + + sources = [ + "${kv_store_base_path}/frameworks/innerkitsimpl/distributeddatasvc/src/datamgr_service_proxy.cpp", + "bool_virtual_test.cpp", + ] + + configs = [ ":database_utils_config" ] + + external_deps = [ + "c_utils:utils", + "googletest:gtest_main", + "hilog:libhilog", + "ipc:ipc_single", + "samgr:samgr_proxy", + ] + + deps = [ + "${kv_store_base_path}/frameworks/libs/distributeddb/:distributeddb", + "${kv_store_base_path}/interfaces/innerkits/distributeddata:distributeddata_inner", + "${kv_store_base_path}/interfaces/innerkits/distributeddatamgr:distributeddata_mgr", + ] +} + +ohos_unittest("DataQueryVirtualTest") { + module_out_path = module_output_path + + sources = [ + "${kv_store_base_path}/frameworks/innerkitsimpl/distributeddatasvc/src/datamgr_service_proxy.cpp", + "data_query_virtual_test.cpp", + "delegate_mgr_callback_virtual_test.cpp", + "distributed_kv_data_manager_vritual_test.cpp", + "kv_utils_virtual_test.cpp", + "kvdb_notifier_virtual_test.cpp", + "kvstore_datashare_bridge_virtual_test.cpp", + "local_kv_store_virtual_test.cpp", + "local_subscribe_store_virtual_test.cpp", + "single_kvstore_query_virtual_test.cpp", + ] + + configs = [ ":database_utils_config" ] + + external_deps = [ + "c_utils:utils", + "googletest:gtest_main", + "hilog:libhilog", + "ipc:ipc_single", + "samgr:samgr_proxy", + ] + + deps = [ + "${kv_store_base_path}/frameworks/libs/distributeddb/:distributeddb", + "${kv_store_base_path}/interfaces/innerkits/distributeddata:distributeddata_inner", + "${kv_store_base_path}/interfaces/innerkits/distributeddatamgr:distributeddata_mgr", + ] +} + group("unittest") { testonly = true diff --git a/kv_store/databaseutils/test/acl_test.cpp b/kv_store/databaseutils/test/acl_test.cpp index 5d55f441fbe0325513e0a144c6c9c7375a754421..46e1934a43d464bd316a9e0472941b08c7a9923a 100644 --- a/kv_store/databaseutils/test/acl_test.cpp +++ b/kv_store/databaseutils/test/acl_test.cpp @@ -14,24 +14,25 @@ */ #include "acl.h" +#include "securec.h" +#include "gtest/gtest.h" #include #include #include #include #include -#include "gtest/gtest.h" -#include "securec.h" using namespace testing::ext; namespace OHOS::Test { using namespace DATABASE_UTILS; +static constexpr uint32_t UID = 2024; // 2024 is test uid +static constexpr uint32_t TEST_UID = 2025; // 2025 is test uid class AclTest : public testing::Test { public: static constexpr const char *PATH_ABC = "/data/test/abc"; static constexpr const char *PATH_ABC_XIAOMING = "/data/test/abc/xiaoming"; static constexpr const char *PATH_ABC_XIAOMING_TEST = "/data/test/abc/xiaoming/test.txt"; static constexpr const char *DATA = "SetDefaultUserTest"; - static constexpr uint32_t UID = 2024; - static constexpr uint32_t TESTUID = 2025; + static void SetUpTestCase(void); static void TearDownTestCase(void); void SetUp(); @@ -39,13 +40,9 @@ public: void PreOperation() const; }; -void AclTest::SetUpTestCase(void) -{ -} +void AclTest::SetUpTestCase(void) { } -void AclTest::TearDownTestCase(void) -{ -} +void AclTest::TearDownTestCase(void) { } // input testcase setup step,setup invoked before each testcases void AclTest::SetUp(void) @@ -82,12 +79,12 @@ void AclTest::PreOperation() const } /** -* @tc.name: SetDefaultGroup001 -* @tc.desc: Set default extended properties for groups. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Jiaxing Chang -*/ + * @tc.name: SetDefaultGroup001 + * @tc.desc: Set default extended properties for groups. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Jiaxing Chang + */ HWTEST_F(AclTest, SetDefaultGroup001, TestSize.Level0) { mode_t mode = S_IRWXU | S_IRWXG | S_IXOTH; // 0771 @@ -102,12 +99,12 @@ HWTEST_F(AclTest, SetDefaultGroup001, TestSize.Level0) } /** -* @tc.name: SetDefaultpUser001 -* @tc.desc: Set default extended properties for user. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Jiaxing Chang -*/ + * @tc.name: SetDefaultpUser001 + * @tc.desc: Set default extended properties for user. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Jiaxing Chang + */ HWTEST_F(AclTest, SetDefaultUser001, TestSize.Level0) { mode_t mode = S_IRWXU | S_IRWXG | S_IXOTH; // 0771 @@ -122,13 +119,13 @@ HWTEST_F(AclTest, SetDefaultUser001, TestSize.Level0) } /** -* @tc.name: SetDefaultUser002 -* @tc.desc: After the main process extends the uid attribute, set this uid to the uid and gid of the child process, -* and the child process can access the files created by the main process normally. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Jiaxing Chang -*/ + * @tc.name: SetDefaultUser002 + * @tc.desc: After the main process extends the uid attribute, set this uid to the uid and gid of the child process, + * and the child process can access the files created by the main process normally. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Jiaxing Chang + */ HWTEST_F(AclTest, SetDefaultUser002, TestSize.Level0) { PreOperation(); @@ -181,29 +178,29 @@ HWTEST_F(AclTest, SetDefaultUser002, TestSize.Level0) } /** -* @tc.name: AclXattrEntry001 -* @tc.desc: Test operator. -* @tc.type: FUNC -* @tc.require: -* @tc.author: SQL -*/ + * @tc.name: AclXattrEntry001 + * @tc.desc: Test operator. + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ HWTEST_F(AclTest, AclXattrEntry001, TestSize.Level0) { AclXattrEntry entryA(ACL_TAG::USER, UID, Acl::R_RIGHT | Acl::W_RIGHT); AclXattrEntry entryB(ACL_TAG::USER, UID, Acl::R_RIGHT | Acl::W_RIGHT); EXPECT_TRUE(entryA == entryB); - AclXattrEntry entryC(ACL_TAG::USER, TESTUID, Acl::R_RIGHT | Acl::W_RIGHT); + AclXattrEntry entryC(ACL_TAG::USER, TEST_UID, Acl::R_RIGHT | Acl::W_RIGHT); EXPECT_FALSE(entryA == entryC); } /** -* @tc.name: AclXattrEntry002 -* @tc.desc: Test IsValid(). -* @tc.type: FUNC -* @tc.require: -* @tc.author: SQL -*/ + * @tc.name: AclXattrEntry002 + * @tc.desc: Test IsValid(). + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ HWTEST_F(AclTest, AclXattrEntry002, TestSize.Level0) { AclXattrEntry entryA(ACL_TAG::USER, UID, Acl::R_RIGHT | Acl::W_RIGHT); @@ -220,12 +217,12 @@ HWTEST_F(AclTest, AclXattrEntry002, TestSize.Level0) } /** -* @tc.name: ACL_PERM001 -* @tc.desc: Test ACL_PERM. -* @tc.type: FUNC -* @tc.require: -* @tc.author: SQL -*/ + * @tc.name: ACL_PERM001 + * @tc.desc: Test ACL_PERM. + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ HWTEST_F(AclTest, ACL_PERM001, TestSize.Level0) { ACL_PERM perm1; diff --git a/kv_store/databaseutils/test/bool_virtual_test.cpp b/kv_store/databaseutils/test/bool_virtual_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6f5c0a5f4a0ec9f7064b7accb39de83784b7ecda --- /dev/null +++ b/kv_store/databaseutils/test/bool_virtual_test.cpp @@ -0,0 +1,540 @@ +/* + * Copyright (c) 2024 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 "BlobVirtualTest" + +#include "blob.h" +#include "change_notification.h" +#include "kv_types_util.h" +#include "types.h" +#include +#include +#include + +using namespace OHOS::DistributedKv; +using namespace testing; +using namespace testing::ext; +namespace OHOS::Test { +class BlobVirtualTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void BlobVirtualTest::SetUpTestCase(void) +{} + +void BlobVirtualTest::TearDownTestCase(void) +{} + +void BlobVirtualTest::SetUp(void) +{} + +void BlobVirtualTest::TearDown(void) +{} + +class ChangeNotificationVirtualTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void ChangeNotificationVirtualTest::SetUpTestCase(void) +{} + +void ChangeNotificationVirtualTest::TearDownTestCase(void) +{} + +void ChangeNotificationVirtualTest::SetUp(void) +{} + +void ChangeNotificationVirtualTest::TearDown(void) +{} + +/** + * @tc.name: DefaultConstructor + * @tc.desc: + * @tc.type: DefaultConstructor test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, DefaultConstructor, TestSize.Level0) +{ + ZLOGI("DefaultConstructor begin."); + Blob defaultConstructor; + EXPECT_TRUE(defaultConstructor.Empty()); +} + +/** + * @tc.name: CopyConstructor + * @tc.desc: + * @tc.type: CopyConstructor test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, CopyConstructor, TestSize.Level0) +{ + ZLOGI("CopyConstructor begin."); + Blob copyConstructor1("hello", 5); + Blob copyConstructor2(blob1); + EXPECT_EQ(copyConstructor1, copyConstructor2); +} + +/** + * @tc.name: MoveConstructor + * @tc.desc: + * @tc.type: MoveConstructor test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, MoveConstructor, TestSize.Level0) +{ + ZLOGI("MoveConstructor begin."); + Blob moveConstructor1("hello", 5); + Blob moveConstructor2(std::move(blob1)); + EXPECT_TRUE(moveConstructor1.Empty()); + EXPECT_EQ(std::string(moveConstructor2.Data().begin(), + moveConstructor2.Data().end()), "hello"); +} + +/** + * @tc.name: CopyAssignmentOperator + * @tc.desc: + * @tc.type: CopyAssignmentOperator test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, CopyAssignmentOperator) +{ + ZLOGI("CopyAssignmentOperator begin."); + Blob copyAssignmentOperator1("hello", 5); + Blob copyAssignmentOperator2; + copyAssignmentOperator2 = copyAssignmentOperator1; + EXPECT_EQ(copyAssignmentOperator1, copyAssignmentOperator2); +} + +/** + * @tc.name: MoveAssignmentOperator + * @tc.desc: + * @tc.type: MoveAssignmentOperator test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, MoveAssignmentOperator, TestSize.Level0) +{ + ZLOGI("MoveAssignmentOperator begin."); + Blob moveAssignmentOperator1("hello", 5); + Blob moveAssignmentOperator2; + blob2 = std::move(moveAssignmentOperator1); + EXPECT_TRUE(moveAssignmentOperator1.Empty()); + EXPECT_EQ(std::string(moveAssignmentOperator2.Data().begin(), + moveAssignmentOperator2.Data().end()), "hello"); +} + +/** + * @tc.name: ConstCharConstructorWithSize + * @tc.desc: + * @tc.type: ConstCharConstructorWithSize test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, ConstCharConstructorWithSize, TestSize.Level0) +{ + ZLOGI("ConstCharConstructorWithSize begin."); + Blob constCharConstructorWithSize("hello", 5); + EXPECT_EQ(std::string(constCharConstructorWithSize.Data().begin(), + constCharConstructorWithSize.Data().end()), "hello"); +} + +/** + * @tc.name: ConstCharConstructorWithNullTerminator + * @tc.desc: + * @tc.type: ConstCharConstructorWithNullTerminator test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, ConstCharConstructorWithNullTerminator, TestSize.Level0) +{ + ZLOGI("ConstCharConstructorWithNullTerminator begin."); + Blob blob("ConstCharConstructorWithNullTerminator"); + EXPECT_EQ(std::string(blob.Data().begin(), blob.Data().end()), "ConstCharConstructorWithNullTerminator"); +} + +/** + * @tc.name: StringConstructor + * @tc.desc: + * @tc.type: StringConstructor test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, StringConstructor, TestSize.Level0) +{ + ZLOGI("StringConstructor begin."); + std::string str = "StringConstructor"; + Blob stringConstructor(str); + EXPECT_EQ(std::string(stringConstructor.Data().begin(), + stringConstructor.Data().end()), str); +} + +/** + * @tc.name: StringAssignmentOperator + * @tc.desc: + * @tc.type: StringAssignmentOperator test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, StringAssignmentOperator, TestSize.Level0) +{ + ZLOGI("StringAssignmentOperator begin."); + std::string str = "StringAssignmentOperator"; + Blob stringAssignmentOperator; + stringAssignmentOperator = str; + EXPECT_EQ(std::string(stringAssignmentOperator.Data().begin(), + stringAssignmentOperator.Data().end()), str); +} + +/** + * @tc.name: ConstCharAssignmentOperator + * @tc.desc: + * @tc.type: ConstCharAssignmentOperator test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, ConstCharAssignmentOperator, TestSize.Level0) +{ + ZLOGI("ConstCharAssignmentOperator begin."); + std::string str = "StringAssignmentOperator"; + Blob constCharAssignmentOperator; + constCharAssignmentOperator = str; + EXPECT_EQ(std::string(constCharAssignmentOperator.Data().begin(), + constCharAssignmentOperator.Data().end()), str); +} + +/** + * @tc.name: VectorConstructor + * @tc.desc: + * @tc.type: VectorConstructor test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, VectorConstructor, TestSize.Level0) +{ + ZLOGI("VectorConstructor begin."); + std::vector vec = {'h', 'e', 'l', 'l', 'o'}; + Blob vectorConstructor(vec); + EXPECT_EQ(std::string(vectorConstructor.Data().begin(), + vectorConstructor.Data().end()), "hello"); +} + +/** + * @tc.name: MoveVectorConstructor + * @tc.desc: + * @tc.type: MoveVectorConstructor test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, MoveVectorConstructor, TestSize.Level0) +{ + ZLOGI("MoveVectorConstructor begin."); + std::vector vec = {'h', 'e', 'l', 'l', 'o'}; + Blob moveVectorConstructor(std::move(vec)); + EXPECT_EQ(std::string(moveVectorConstructor.Data().begin(), + moveVectorConstructor.Data().end()), "hello"); + EXPECT_TRUE(vec.empty()); +} + +/** + * @tc.name: DataAccessor + * @tc.desc: + * @tc.type: DataAccessor test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, DataAccessor, TestSize.Level0) +{ + ZLOGI("DataAccessor begin."); + Blob dataAccessor("hello", 5); + const std::vector& data = dataAccessor.Data(); + EXPECT_EQ(data[0], 'h'); + EXPECT_EQ(data[4], 'o'); +} + +/** + * @tc.name: SizeAccessor + * @tc.desc: + * @tc.type: SizeAccessor test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, SizeAccessor, TestSize.Level0) +{ + ZLOGI("SizeAccessor begin."); + Blob sizeAccessor("hello", 5); + EXPECT_EQ(sizeAccessor.Size(), 5u); +} + +/** + * @tc.name: RawSizeAccessor + * @tc.desc: + * @tc.type: RawSizeAccessor test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, RawSizeAccessor, TestSize.Level0) +{ + ZLOGI("RawSizeAccessor begin."); + Blob rawSizeAccessor("hello", 5); + EXPECT_EQ(rawSizeAccessor.RawSize(), 9); // sizeof(int) + 5 +} + +/** + * @tc.name: EmptyAccessor + * @tc.desc: + * @tc.type: EmptyAccessor test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, EmptyAccessor, TestSize.Level0) +{ + ZLOGI("EmptyAccessor begin."); + Blob emptyAccessor; + EXPECT_TRUE(emptyAccessor.Empty()); + Blob emptyAccessor2("hello"); + EXPECT_FALSE(emptyAccessor2.Empty()); +} + +/** + * @tc.name: ElementAccessOperator + * @tc.desc: + * @tc.type: ElementAccessOperator test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, ElementAccessOperator, TestSize.Level0) +{ + ZLOGI("ElementAccessOperator begin."); + Blob elementAccessOperator("hello", 5); + EXPECT_EQ(elementAccessOperator[0], 'h'); + EXPECT_EQ(elementAccessOperator[4], 'o'); + EXPECT_EQ(elementAccessOperator[5], 0); +} + +/** + * @tc.name: EqualityOperator + * @tc.desc: + * @tc.type: EqualityOperator test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, EqualityOperator, TestSize.Level0) +{ + ZLOGI("EqualityOperator begin."); + Blob equalityOperator1("hello", 5); + Blob equalityOperator2("hello", 5); + EXPECT_TRUE(equalityOperator1 == equalityOperator2); + Blob equalityOperator3("world", 5); + EXPECT_FALSE(equalityOperator1 == equalityOperator3); +} + +/** + * @tc.name: Clear + * @tc.desc: + * @tc.type: Clear test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, Clear, TestSize.Level0) +{ + ZLOGI("Clear begin."); + Blob blobClear("hello", 5); + blobClear.Clear(); + EXPECT_TRUE(blobClear.Empty()); +} + +/** + * @tc.name: ToString + * @tc.desc: + * @tc.type: ToString test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, ToString, TestSize.Level0) +{ + ZLOGI("ToString begin."); + Blob blobToString("hello", 5); + EXPECT_EQ(blobToString.ToString(), "hello"); +} + +/** + * @tc.name: Compare + * @tc.desc: + * @tc.type: Compare test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, Compare, TestSize.Level0) +{ + ZLOGI("Compare begin."); + Blob blobCompare1("abc", 3); + Blob blobCompare2("abcd", 4); + Blob blobCompare3("abc", 3); + EXPECT_LT(blobCompare1.Compare(blobCompare2), 0); + EXPECT_EQ(blobCompare1.Compare(blobCompare3), 0); + EXPECT_GT(blobCompare2.Compare(blobCompare1), 0); +} + +/** + * @tc.name: StartsWith + * @tc.desc: + * @tc.type: StartsWith test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, StartsWith, TestSize.Level0) +{ + ZLOGI("StartsWith begin."); + Blob blobStartsWith1("abcdef", 6); + Blob blobStartsWith2("abc", 3); + Blob blobStartsWith3("abcd", 4); + Blob blobStartsWith4("xyz", 3); + EXPECT_TRUE(blobStartsWith1.StartsWith(blobStartsWith2)); + EXPECT_TRUE(blobStartsWith1.StartsWith(blobStartsWith3)); + EXPECT_FALSE(blobStartsWith1.StartsWith(blobStartsWith4)); +} + +/** + * @tc.name: WriteToBuffer + * @tc.desc: + * @tc.type: WriteToBuffer test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, WriteToBuffer, TestSize.Level0) +{ + ZLOGI("WriteToBuffer begin."); + Blob blobWriteToBuffer("hello", 5); + uint8_t buffer[100]; + uint8_t* cursorPtr = buffer; + int bufferLeftSize = sizeof(buffer); + EXPECT_TRUE(blobWriteToBuffer.WriteToBuffer(cursorPtr, bufferLeftSize)); + EXPECT_EQ(*reinterpret_cast(buffer), 5); + EXPECT_EQ(std::string(reinterpret_cast(buffer + sizeof(int)), 5), "hello"); + EXPECT_EQ(bufferLeftSize, sizeof(buffer) - sizeof(int) - 5); +} + +/** + * @tc.name: ReadFromBuffer + * @tc.desc: + * @tc.type: ReadFromBuffer test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(BlobVirtualTest, ReadFromBuffer, TestSize.Level0) +{ + ZLOGI("ReadFromBuffer begin."); + uint8_t buffer[100]; + int blobSize = 5; + *reinterpret_cast(buffer) = blobSize; + std::string str = "hello"; + strncpy_s(reinterpret_cast(buffer + sizeof(int)), blobSize, str, strlen(str)); + const uint8_t* cursorPtr = buffer; + int bufferLeftSize = sizeof(buffer); + Blob blob; + EXPECT_TRUE(blob.ReadFromBuffer(cursorPtr, bufferLeftSize)); + EXPECT_EQ(std::string(blob.Data().begin(), blob.Data().end()), "hello"); + EXPECT_EQ(bufferLeftSize, sizeof(buffer) - sizeof(int) - blobSize); +} + +/** + * @tc.name: ChangeNotificationVirtualTest001 + * @tc.desc: + * @tc.type: test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(ChangeNotificationVirtualTest, ChangeNotificationVirtualTest001, TestSize.Level0) +{ + ZLOGI("ChangeNotificationVirtualTest001 begin."); + std::vector insertEntries = {{"key1", "value1"}, {"key2", "value2"}}; + std::vector updateEntries = {{"key3", "newValue3"}}; + std::vector deleteEntries = {{"key4", ""}}; + std::string deviceId = "device123"; + bool isClear = false; + + OHOS::DistributedKv::ChangeNotification cn(std::move(insertEntries), + std::move(updateEntries), std::move(deleteEntries), deviceId, isClear); + + EXPECT_TRUE(cn.GetInsertEntries().size() == 2); + EXPECT_TRUE(cn.GetUpdateEntries().size() == 1); + EXPECT_TRUE(cn.GetDeleteEntries().size() == 1); + EXPECT_TRUE(cn.GetDeviceId() == deviceId); + EXPECT_TRUE(!cn.IsClear()); +} + +/** + * @tc.name: ChangeNotificationVirtualTest002 + * @tc.desc: + * @tc.type: test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(ChangeNotificationVirtualTest, ChangeNotificationVirtualTest002, TestSize.Level0) +{ + ZLOGI("ChangeNotificationVirtualTest002 begin."); + std::vector insertEntries; + std::vector updateEntries; + std::vector deleteEntries; + std::string deviceId = "device456"; + bool isClear = true; + + OHOS::DistributedKv::ChangeNotification cn(std::move(insertEntries), + std::move(updateEntries), std::move(deleteEntries), deviceId, isClear); + + EXPECT_TRUE(cn.GetInsertEntries().empty()); + EXPECT_TRUE(cn.GetUpdateEntries().empty()); + EXPECT_TRUE(cn.GetDeleteEntries().empty()); + EXPECT_TRUE(cn.GetDeviceId() == deviceId); + EXPECT_TRUE(cn.IsClear()); +} + +/** + * @tc.name: ChangeNotificationVirtualTest003 + * @tc.desc: + * @tc.type: test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(ChangeNotificationVirtualTest, ChangeNotificationVirtualTest003, TestSize.Level0) +{ + ZLOGI("ChangeNotificationVirtualTest003 begin."); + std::vector insertEntries; + std::vector updateEntries = {{"keyUpdated", "newValue"}}; + std::vector deleteEntries; + std::string deviceId = "device789"; + bool isClear = false; + + OHOS::DistributedKv::ChangeNotification cn(std::move(insertEntries), + std::move(updateEntries), std::move(deleteEntries), deviceId, isClear); + + EXPECT_TRUE(cn.GetInsertEntries().empty()); + EXPECT_TRUE(cn.GetUpdateEntries().size() == 1); + EXPECT_TRUE(cn.GetDeleteEntries().empty()); + EXPECT_TRUE(cn.GetDeviceId() == deviceId); + EXPECT_TRUE(!cn.IsClear()); +} +} // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/databaseutils/test/data_query_virtual_test.cpp b/kv_store/databaseutils/test/data_query_virtual_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e20203e76a14d896a7a1c102c80b644e7c68736 --- /dev/null +++ b/kv_store/databaseutils/test/data_query_virtual_test.cpp @@ -0,0 +1,1184 @@ +/* + * Copyright (c) 2024 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 "DataQueryVirtualTest" + +#include "data_query.h" +#include "kv_types_util.h" +#include +#include "types.h" +#include +#include +#include + +using namespace OHOS::DistributedKv; +using namespace testing; +using namespace testing::ext; +namespace OHOS::Test { +class DataQueryVirtualTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void DataQueryVirtualTest::SetUpTestCase(void) +{} + +void DataQueryVirtualTest::TearDownTestCase(void) +{} + +void DataQueryVirtualTest::SetUp(void) +{} + +void DataQueryVirtualTest::TearDown(void) +{} + +class MockQuery { +public: + MOCK_METHOD2(Range, void(const std::vector&, const std::vector&)); + MOCK_METHOD1(IsNull, void(const std::string&)); + MOCK_METHOD1(IsNotNull, void(const std::string&)); +}; + +/** + * @tc.name: Reset + * @tc.desc: + * @tc.type: Reset test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, Reset, TestSize.Level0) +{ + ZLOGI("ResetTest begin."); + DataQuery queryReset; + queryReset.EqualTo("field1", 123); + queryReset.Reset(); + EXPECT_EQ(queryReset.str_, ""); + EXPECT_FALSE(queryReset.hasKeys_); + EXPECT_FALSE(queryReset.hasPrefix_); + EXPECT_EQ(queryReset.deviceId_, ""); + EXPECT_EQ(queryReset.prefix_, ""); +} + +/** + * @tc.name: EqualToInteger + * @tc.desc: + * @tc.type: EqualToInteger test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, EqualToInteger, TestSize.Level0) +{ + ZLOGI("EqualToInteger begin."); + DataQuery queryEqualToInteger; + queryEqualToInteger.EqualTo("field1", 123); + EXPECT_EQ(queryEqualToInteger.str_, + std::string(DataQuery::EQUAL_TO) + " " + DataQuery::TYPE_INTEGER + " field1 123"); +} + +/** + * @tc.name: EqualToLong + * @tc.desc: + * @tc.type: EqualToLong test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, EqualToLong, TestSize.Level0) +{ + ZLOGI("EqualToLong begin."); + DataQuery queryEqualToLong; + queryEqualToLong.EqualTo("field1", 123456789012345LL); + EXPECT_EQ(queryEqualToLong.str_, + std::string(DataQuery::EQUAL_TO) + " " + DataQuery::TYPE_LONG + " field1 123456789012345"); +} + +/** + * @tc.name: EqualToDouble + * @tc.desc: + * @tc.type: EqualToDouble test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, EqualToDouble, TestSize.Level0) +{ + ZLOGI("EqualToDouble begin."); + DataQuery queryEqualToDouble; + queryEqualToDouble.EqualTo("field1", 123.45); + EXPECT_EQ(queryEqualToDouble.str_, + std::string(DataQuery::EQUAL_TO) + " " + DataQuery::TYPE_DOUBLE + " field1 123.45"); +} + +/** + * @tc.name: EqualToString + * @tc.desc: + * @tc.type: EqualToString test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, EqualToString, TestSize.Level0) +{ + ZLOGI("EqualToString begin."); + DataQuery queryEqualToString; + queryEqualToString.EqualTo("field1", "testValue"); + EXPECT_EQ(queryEqualToString.str_, + std::string(DataQuery::EQUAL_TO) + " " + DataQuery::TYPE_STRING + " field1 testValue"); +} + +/** + * @tc.name: EqualToBooleanTrue + * @tc.desc: + * @tc.type: EqualToBooleanTrue test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, EqualToBooleanTrue, TestSize.Level0) +{ + ZLOGI("EqualToBooleanTrue begin."); + DataQuery queryEqualToBooleanTrue; + queryEqualToBooleanTrue.EqualTo("field1", true); + EXPECT_EQ(queryEqualToBooleanTrue.str_, + std::string(DataQuery::EQUAL_TO) + " " + DataQuery::TYPE_BOOLEAN + " field1 true"); +} + +/** + * @tc.name: EqualToBooleanFalse + * @tc.desc: + * @tc.type: EqualToBooleanFalse test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, EqualToBooleanFalse, TestSize.Level0) +{ + ZLOGI("EqualToBooleanFalse begin."); + DataQuery queryEqualToBooleanFalse; + queryEqualToBooleanFalse.EqualTo("field1", false); + EXPECT_EQ(queryEqualToBooleanFalse.str_, + std::string(DataQuery::EQUAL_TO) + " " + DataQuery::TYPE_BOOLEAN + " field1 false"); +} + +/** + * @tc.name: NotEqualToInteger + * @tc.desc: + * @tc.type: NotEqualToInteger test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, NotEqualToInteger, TestSize.Level0) +{ + ZLOGI("NotEqualToInteger begin."); + DataQuery queryNotEqualToInteger; + queryNotEqualToInteger.NotEqualTo("field1", 123); + EXPECT_EQ(queryNotEqualToInteger.str_, + std::string(DataQuery::NOT_EQUAL_TO) + " " + DataQuery::TYPE_INTEGER + " field1 123"); +} + +/** + * @tc.name: NotEqualToLong + * @tc.desc: + * @tc.type: NotEqualToLong test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, NotEqualToLong, TestSize.Level0) +{ + ZLOGI("NotEqualToLong begin."); + DataQuery queryNotEqualToLong; + queryNotEqualToLong.NotEqualTo("field1", 123456789012345LL); + EXPECT_EQ(queryNotEqualToLong.str_, + std::string(DataQuery::NOT_EQUAL_TO) + " " + DataQuery::TYPE_LONG + " field1 123456789012345"); +} + +/** + * @tc.name: NotEqualToDouble + * @tc.desc: + * @tc.type: NotEqualToDouble test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, NotEqualToDouble, TestSize.Level0) +{ + ZLOGI("NotEqualToDouble begin."); + DataQuery queryNotEqualToDouble; + queryNotEqualToDouble.NotEqualTo("field1", 123.45); + EXPECT_EQ(queryNotEqualToDouble.str_, + std::string(DataQuery::NOT_EQUAL_TO) + " " + DataQuery::TYPE_DOUBLE + " field1 123.45"); +} + +/** + * @tc.name: NotEqualToString + * @tc.desc: + * @tc.type: NotEqualToString test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, NotEqualToString, TestSize.Level0) +{ + ZLOGI("NotEqualToString begin."); + DataQuery queryNotEqualToString; + queryNotEqualToString.NotEqualTo("field1", "testValue"); + EXPECT_EQ(queryNotEqualToString.str_, + std::string(DataQuery::NOT_EQUAL_TO) + " " + DataQuery::TYPE_STRING + " field1 testValue"); +} + +/** + * @tc.name: NotEqualToBooleanTrue + * @tc.desc: + * @tc.type: NotEqualToBooleanTrue test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, NotEqualToBooleanTrue, TestSize.Level0) +{ + ZLOGI("NotEqualToBooleanTrue begin."); + DataQuery queryNotEqualToBooleanTrue; + queryNotEqualToBooleanTrue.NotEqualTo("field1", true); + EXPECT_EQ(queryNotEqualToBooleanTrue.str_, + std::string(DataQuery::NOT_EQUAL_TO) + " " + DataQuery::TYPE_BOOLEAN + " field1 true"); +} + +/** + * @tc.name: NotEqualToBooleanFalse + * @tc.desc: + * @tc.type: NotEqualToBooleanFalse test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, NotEqualToBooleanFalse, TestSize.Level0) +{ + ZLOGI("NotEqualToBooleanFalse begin."); + DataQuery queryNotEqualToBooleanFalse; + queryNotEqualToBooleanFalse.NotEqualTo("field1", false); + EXPECT_EQ(queryNotEqualToBooleanFalse.str_, + std::string(DataQuery::NOT_EQUAL_TO) + " " + DataQuery::TYPE_BOOLEAN + " field1 false"); +} + +/** + * @tc.name: GreaterThanInteger + * @tc.desc: + * @tc.type: GreaterThanInteger test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, GreaterThanInteger, TestSize.Level0) +{ + ZLOGI("GreaterThanInteger begin."); + DataQuery queryNotEqualToBooleanFalse; + queryGreaterThanInteger.GreaterThan("field1", 123); + EXPECT_EQ(queryGreaterThanInteger.str_, + std::string(DataQuery::GREATER_THAN) + " " + DataQuery::TYPE_INTEGER + " field1 123"); +} + +/** + * @tc.name: GreaterThanLong + * @tc.desc: + * @tc.type: GreaterThanLong test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, GreaterThanLong, TestSize.Level0) +{ + ZLOGI("GreaterThanLong begin."); + DataQuery queryGreaterThanLong; + queryGreaterThanLong.GreaterThan("field1", 123456789012345LL); + EXPECT_EQ(queryGreaterThanLong.str_, + std::string(DataQuery::GREATER_THAN) + " " + DataQuery::TYPE_LONG + " field1 123456789012345"); +} + +/** + * @tc.name: GreaterThanDouble + * @tc.desc: + * @tc.type: GreaterThanDouble test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, GreaterThanDouble, TestSize.Level0) +{ + ZLOGI("GreaterThanDouble begin."); + DataQuery queryGreaterThanDouble; + queryGreaterThanDouble.GreaterThan("field1", 123.45); + EXPECT_EQ(queryGreaterThanDouble.str_, + std::string(DataQuery::GREATER_THAN) + " " + DataQuery::TYPE_DOUBLE + " field1 123.45"); +} + +/** + * @tc.name: GreaterThanString + * @tc.desc: + * @tc.type: GreaterThanString test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, GreaterThanString, TestSize.Level0) +{ + ZLOGI("GreaterThanString begin."); + DataQuery queryGreaterThanString; + queryGreaterThanString.GreaterThan("field1", "testValue"); + EXPECT_EQ(queryGreaterThanString.str_, + std::string(DataQuery::GREATER_THAN) + " " + DataQuery::TYPE_STRING + " field1 testValue"); +} + +/** + * @tc.name: LessThanInteger + * @tc.desc: + * @tc.type: LessThanInteger test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, LessThanInteger, TestSize.Level0) +{ + ZLOGI("LessThanInteger begin."); + DataQuery queryLessThanInteger; + queryLessThanInteger.LessThan("field1", 123); + EXPECT_EQ(queryLessThanInteger.str_, + std::string(DataQuery::LESS_THAN) + " " + DataQuery::TYPE_INTEGER + " field1 123"); +} + +/** + * @tc.name: LessThanLong + * @tc.desc: + * @tc.type: LessThanLong test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, LessThanLong, TestSize.Level0) +{ + ZLOGI("GreaterThanLong begin."); + DataQuery queryLessThanLong; + queryLessThanLong.LessThan("field1", 123456789012345LL); + EXPECT_EQ(queryLessThanLong.str_, + std::string(DataQuery::LESS_THAN) + " " + DataQuery::TYPE_LONG + " field1 123456789012345"); +} + +/** + * @tc.name: LessThanDouble + * @tc.desc: + * @tc.type: LessThanDouble test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, LessThanDouble, TestSize.Level0) +{ + ZLOGI("LessThanDouble begin."); + DataQuery queryLessThanDouble; + queryLessThanDouble.LessThan("field1", 123.45); + EXPECT_EQ(queryLessThanDouble.str_, + std::string(DataQuery::LESS_THAN) + " " + DataQuery::TYPE_DOUBLE + " field1 123.45"); +} + +/** + * @tc.name: LessThanString + * @tc.desc: + * @tc.type: LessThanString test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, LessThanString, TestSize.Level0) +{ + ZLOGI("LessThanString begin."); + DataQuery queryLessThanString; + queryLessThanString.LessThan("field1", "testValue"); + EXPECT_EQ(queryLessThanString.str_, + std::string(DataQuery::LESS_THAN) + " " + DataQuery::TYPE_STRING + " field1 testValue"); +} + +/** + * @tc.name: GreaterThanOrEqualToInteger + * @tc.desc: + * @tc.type: GreaterThanOrEqualToInteger test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, GreaterThanOrEqualToInteger, TestSize.Level0) +{ + ZLOGI("LessThanInteger begin."); + DataQuery queryGreaterThanOrEqualToInteger; + queryGreaterThanOrEqualToInteger.GreaterThanOrEqualTo("field1", 123); + EXPECT_EQ(queryGreaterThanOrEqualToInteger.str_, + std::string(DataQuery::GREATER_THAN_OR_EQUAL_TO) + " " + DataQuery::TYPE_INTEGER + " field1 123"); +} + +/** + * @tc.name: GreaterThanOrEqualToLong + * @tc.desc: + * @tc.type: GreaterThanOrEqualToLong test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, GreaterThanOrEqualToLong, TestSize.Level0) +{ + ZLOGI("GreaterThanLong begin."); + DataQuery queryGreaterThanOrEqualToLong; + queryGreaterThanOrEqualToLong.GreaterThanOrEqualTo("field1", 123456789012345LL); + EXPECT_EQ(queryGreaterThanOrEqualToLong.str_, + std::string(DataQuery::GREATER_THAN_OR_EQUAL_TO) + " " + DataQuery::TYPE_LONG + " field1 123456789012345"); +} + +/** + * @tc.name: GreaterThanOrEqualToDouble + * @tc.desc: + * @tc.type: GreaterThanOrEqualToDouble test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, GreaterThanOrEqualToDouble, TestSize.Level0) +{ + ZLOGI("LessThanDouble begin."); + DataQuery queryGreaterThanOrEqualToDouble; + queryGreaterThanOrEqualToDouble.GreaterThanOrEqualTo("field1", 123.45); + EXPECT_EQ(queryGreaterThanOrEqualToDouble.str_, + std::string(DataQuery::GREATER_THAN_OR_EQUAL_TO) + " " + DataQuery::TYPE_DOUBLE + " field1 123.45"); +} + +/** + * @tc.name: GreaterThanOrEqualToString + * @tc.desc: + * @tc.type: GreaterThanOrEqualToString test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, GreaterThanOrEqualToString, TestSize.Level0) +{ + ZLOGI("LessThanString begin."); + DataQuery queryGreaterThanOrEqualToString; + queryGreaterThanOrEqualToString.GreaterThanOrEqualTo("field1", "testValue"); + EXPECT_EQ(queryGreaterThanOrEqualToString.str_, + std::string(DataQuery::GREATER_THAN_OR_EQUAL_TO) + " " + DataQuery::TYPE_STRING + " field1 testValue"); +} + +/** + * @tc.name: LessThanOrEqualToInteger + * @tc.desc: + * @tc.type: LessThanOrEqualToInteger test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, LessThanOrEqualToInteger, TestSize.Level0) +{ + ZLOGI("LessThanOrEqualToInteger begin."); + DataQuery queryLessThanOrEqualToInteger; + queryLessThanOrEqualToInteger.LessThanOrEqualTo("field1", 123); + EXPECT_EQ(queryLessThanOrEqualToInteger.str_, + std::string(DataQuery::LESS_THAN_OR_EQUAL_TO) + " " + DataQuery::TYPE_INTEGER + " field1 123"); +} + +/** + * @tc.name: LessThanOrEqualToLong + * @tc.desc: + * @tc.type: LessThanOrEqualToLong test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, LessThanOrEqualToLong, TestSize.Level0) +{ + ZLOGI("LessThanOrEqualToLong begin."); + DataQuery queryLessThanOrEqualToLong; + queryLessThanOrEqualToLong.LessThanOrEqualTo("field1", 123456789012345LL); + EXPECT_EQ(queryLessThanOrEqualToLong.str_, + std::string(DataQuery::LESS_THAN_OR_EQUAL_TO) + " " + DataQuery::TYPE_LONG + " field1 123456789012345"); +} + +/** + * @tc.name: LessThanOrEqualToDouble + * @tc.desc: + * @tc.type: LessThanOrEqualToDouble test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, LessThanOrEqualToDouble, TestSize.Level0) +{ + ZLOGI("LessThanOrEqualToDouble begin."); + DataQuery queryLessThanOrEqualToDouble; + queryLessThanOrEqualToDouble.LessThanOrEqualTo("field1", 123.45); + EXPECT_EQ(queryLessThanOrEqualToDouble.str_, + std::string(DataQuery::LESS_THAN_OR_EQUAL_TO) + " " + DataQuery::TYPE_DOUBLE + " field1 123.45"); +} + +/** + * @tc.name: LessThanOrEqualToString + * @tc.desc: + * @tc.type: LessThanOrEqualToString test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, LessThanOrEqualToString, TestSize.Level0) +{ + ZLOGI("LessThanOrEqualToString begin."); + DataQuery queryLessThanOrEqualToString; + queryLessThanOrEqualToString.LessThanOrEqualTo("field1", "testValue"); + EXPECT_EQ(queryLessThanOrEqualToString.str_, + std::string(DataQuery::LESS_THAN_OR_EQUAL_TO) + " " + DataQuery::TYPE_STRING + " field1 testValue"); +} + +/** + * @tc.name: Between_ValidInputs_CallsRange + * @tc.desc: + * @tc.type: Between_ValidInputs_CallsRange test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, Between_ValidInputs_CallsRange, TestSize.Level0) +{ + ZLOGI("Between_ValidInputs_CallsRange begin."); + MockQuery mockQuery; + DataQuery queryBetween(&mockQuery); + + EXPECT_CALL(mockQuery, Range(ElementsAre('a', 'b'), ElementsAre('c', 'd'))); + + queryBetween.Between("ab", "cd"); +} + +/** + * @tc.name: IsNull_ValidField_UpdatesStringAndCallsIsNull + * @tc.desc: + * @tc.type: IsNull_ValidField_UpdatesStringAndCallsIsNull test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, IsNull_ValidField_UpdatesStringAndCallsIsNull, TestSize.Level0) +{ + ZLOGI("IsNull_ValidField_UpdatesStringAndCallsIsNull begin."); + MockQuery mockQuery; + DataQuery queryIsNull(&mockQuery); + + EXPECT_CALL(mockQuery, IsNull("field")); + + queryIsNull.IsNull("field"); +} + +/** + * @tc.name: IsNull_InvalidField_DoesNotUpdateStringOrCallIsNull + * @tc.desc: + * @tc.type: IsNull_InvalidField_DoesNotUpdateStringOrCallIsNull test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, IsNull_InvalidField_DoesNotUpdateStringOrCallIsNull, TestSize.Level0) +{ + ZLOGI("IsNull_InvalidField_DoesNotUpdateStringOrCallIsNull begin."); + MockQuery mockQuery; + DataQuery queryIsNull(&mockQuery); + + EXPECT_CALL(mockQuery, IsNull(_)).Times(0); + + queryIsNull.IsNull("invalid field"); +} + +/** + * @tc.name: IsNotNull_ValidField_UpdatesStringAndCallsIsNotNull + * @tc.desc: + * @tc.type: IsNotNull_ValidField_UpdatesStringAndCallsIsNotNull test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, IsNotNull_ValidField_UpdatesStringAndCallsIsNotNull, TestSize.Level0) +{ + ZLOGI("IsNotNull_ValidField_UpdatesStringAndCallsIsNotNull begin."); + MockQuery mockQuery; + DataQuery queryIsNotNull(&mockQuery); + + EXPECT_CALL(mockQuery, IsNotNull("field")); + + queryIsNotNull.IsNotNull("field"); +} + +/** + * @tc.name: IsNotNull_InvalidField_DoesNotUpdateStringOrCallIsNotNull + * @tc.desc: + * @tc.type: IsNotNull_InvalidField_DoesNotUpdateStringOrCallIsNotNull test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, IsNotNull_InvalidField_DoesNotUpdateStringOrCallIsNotNull, TestSize.Level0) +{ + ZLOGI("IsNotNull_InvalidField_DoesNotUpdateStringOrCallIsNotNull begin."); + MockQuery mockQuery; + DataQuery queryIsNotNull(&mockQuery); + + EXPECT_CALL(mockQuery, IsNotNull(_)).Times(0); + + query.IsNotNull("invalid field"); +} + +/** + * @tc.name: InInteger + * @tc.desc: + * @tc.type: InInteger test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, InInteger, TestSize.Level0) +{ + ZLOGI("InInteger begin."); + DataQuery queryInInteger; + queryInInteger.In("field1", 123); + EXPECT_EQ(queryInInteger.str_, + std::string(DataQuery::IN) + " " + DataQuery::TYPE_INTEGER + " field1 123"); +} + +/** + * @tc.name: InLong + * @tc.desc: + * @tc.type: InLong test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, InLong, TestSize.Level0) +{ + ZLOGI("InLong begin."); + DataQuery queryInLong; + queryInLong.In("field1", 123456789012345LL); + EXPECT_EQ(queryInLong.str_, + std::string(DataQuery::IN) + " " + DataQuery::TYPE_LONG + " field1 123456789012345"); +} + +/** + * @tc.name: InDouble + * @tc.desc: + * @tc.type: InDouble test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, InDouble, TestSize.Level0) +{ + ZLOGI("InDouble begin."); + DataQuery queryInDouble; + queryInDouble.In("field1", 123.45); + EXPECT_EQ(queryInDouble.str_, + std::string(DataQuery::IN) + " " + DataQuery::TYPE_DOUBLE + " field1 123.45"); +} + +/** + * @tc.name: InString + * @tc.desc: + * @tc.type: InString test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, InString, TestSize.Level0) +{ + ZLOGI("InString begin."); + DataQuery queryInString; + queryInString.In("field1", "testValue"); + EXPECT_EQ(queryInString.str_, + std::string(DataQuery::IN) + " " + DataQuery::TYPE_STRING + " field1 testValue"); +} + +/** + * @tc.name: NotInInteger + * @tc.desc: + * @tc.type: NotInInteger test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, NotInInteger, TestSize.Level0) +{ + ZLOGI("NotInInteger begin."); + DataQuery queryNotInInteger; + queryNotInInteger.NotIn("field1", 123); + EXPECT_EQ(queryNotInInteger.str_, + std::string(DataQuery::NOT_IN) + " " + DataQuery::TYPE_INTEGER + " field1 123"); +} + +/** + * @tc.name: NotInLong + * @tc.desc: + * @tc.type: NotInLong test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, NotInLong, TestSize.Level0) +{ + ZLOGI("NotInLong begin."); + DataQuery queryNotInLong; + queryNotInLong.NotIn("field1", 123456789012345LL); + EXPECT_EQ(queryNotInLong.str_, + std::string(DataQuery::NOT_IN) + " " + DataQuery::TYPE_LONG + " field1 123456789012345"); +} + +/** + * @tc.name: NotInDouble + * @tc.desc: + * @tc.type: NotInDouble test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, NotInDouble, TestSize.Level0) +{ + ZLOGI("InDouble begin."); + DataQuery queryNotInDouble; + queryNotInDouble.NotIn("field1", 123.45); + EXPECT_EQ(queryNotInDouble.str_, + std::string(DataQuery::NOT_IN) + " " + DataQuery::TYPE_DOUBLE + " field1 123.45"); +} + +/** + * @tc.name: NotInString + * @tc.desc: + * @tc.type: NotInString test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, NotInString, TestSize.Level0) +{ + ZLOGI("NotInString begin."); + DataQuery queryNotInString; + queryNotInString.NotIn("field1", "testValue"); + EXPECT_EQ(queryNotInString.str_, + std::string(DataQuery::NOT_IN) + " " + DataQuery::TYPE_STRING + " field1 testValue"); +} + +/** + * @tc.name: Like_ValidFieldAndValue_AppendsToQuery + * @tc.desc: + * @tc.type: Like_ValidFieldAndValue_AppendsToQuery test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, Like_ValidFieldAndValue_AppendsToQuery, TestSize.Level0) +{ + ZLOGI("Like_ValidFieldAndValue_AppendsToQuery begin."); + std::shared_ptr queryLikeMock = std::make_shared(); + DataQuery queryLike; + EXPECT_CALL(*queryLikeMock, Like("field", "value")).Times(1); + queryLike.Like("field", "value"); + EXPECT_EQ(queryLike.ToString(), std::string(DataQuery::LIKE) + " field value"); +} + +/** + * @tc.name: Unlike_ValidFieldAndValue_AppendsToQuery + * @tc.desc: + * @tc.type: Unlike_ValidFieldAndValue_AppendsToQuery test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, Unlike_ValidFieldAndValue_AppendsToQuery, TestSize.Level0) +{ + ZLOGI("Unlike_ValidFieldAndValue_AppendsToQuery begin."); + std::shared_ptr queryUnlikeMock = std::make_shared(); + DataQuery queryUnlike; + EXPECT_CALL(*queryUnlikeMock, NotLike("field", "value")).Times(1); + queryUnlike.Unlike("field", "value"); + EXPECT_EQ(queryUnlike.ToString(), std::string(DataQuery::NOT_LIKE) + " field1 testValue"); +} + +/** + * @tc.name: And_AppendsAndToQuery + * @tc.desc: + * @tc.type: And_AppendsAndToQuery test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, And_AppendsAndToQuery, TestSize.Level0) +{ + ZLOGI("And_AppendsAndToQuery begin."); + std::shared_ptr queryAndMock = std::make_shared(); + DataQuery queryAnd; + EXPECT_CALL(*queryAndMock, And()).Times(1); + queryAnd.And(); + EXPECT_EQ(queryAnd.ToString(), " AND"); +} + +/** + * @tc.name: Or_AppendsOrToQuery + * @tc.desc: + * @tc.type: Or_AppendsOrToQuery test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, Or_AppendsOrToQuery, TestSize.Level0) +{ + ZLOGI("Or_AppendsOrToQuery begin."); + std::shared_ptr queryOrMock = std::make_shared(); + DataQuery queryOr; + EXPECT_CALL(*queryOrMock, Or()).Times(1); + queryOr.Or(); + EXPECT_EQ(queryOr.ToString(), " OR"); +} + +/** + * @tc.name: OrderByAsc_ValidField_AppendsToQuery + * @tc.desc: + * @tc.type: OrderByAsc_ValidField_AppendsToQuery test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, OrderByAsc_ValidField_AppendsToQuery, TestSize.Level0) +{ + ZLOGI("OrderByAsc_ValidField_AppendsToQuery begin."); + std::shared_ptr queryOrderByAscMock = std::make_shared(); + DataQuery queryOrderByAsc; + EXPECT_CALL(*queryOrderByAscMock, OrderBy("field")).Times(1); + queryOrderByAsc.OrderByAsc("field"); + EXPECT_EQ(queryOrderByAsc.ToString(), " ORDER BY ASC field"); +} + +/** + * @tc.name: OrderByDesc_ValidField_AppendsToQuery + * @tc.desc: + * @tc.type: OrderByDesc_ValidField_AppendsToQuery test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, OrderByDesc_ValidField_AppendsToQuery, TestSize.Level0) +{ + ZLOGI("OrderByDesc_ValidField_AppendsToQuery begin."); + std::shared_ptr queryOrderByDescMock = std::make_shared(); + DataQuery queryOrderByDesc; + EXPECT_CALL(*queryOrderByDescMock, OrderBy("field", false)).Times(1); + queryOrderByDesc.OrderByDesc("field"); + EXPECT_EQ(queryOrderByDesc.ToString(), " ORDER BY DESC field"); +} + +/** + * @tc.name: OrderByWriteTime_Ascending_AppendsToQuery + * @tc.desc: + * @tc.type: OrderByWriteTime_Ascending_AppendsToQuery test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, OrderByWriteTime_Ascending_AppendsToQuery, TestSize.Level0) +{ + ZLOGI("OrderByWriteTime_Ascending_AppendsToQuery begin."); + std::shared_ptr queryOrderByWriteTimeMock = std::make_shared(); + DataQuery queryOrderByWriteTime; + EXPECT_CALL(*queryOrderByWriteTimeMock, OrderByWriteTime(true)).Times(1); + queryOrderByWriteTime.OrderByWriteTime(true); + EXPECT_EQ(queryOrderByWriteTime.ToString(), " ORDER BY WRITE_TIME ASC"); +} + +/** + * @tc.name: OrderByWriteTime_Descending_AppendsToQuery + * @tc.desc: + * @tc.type: OrderByWriteTime_Descending_AppendsToQuery test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, OrderByWriteTime_Descending_AppendsToQuery, TestSize.Level0) +{ + ZLOGI("OrderByWriteTime_Descending_AppendsToQuery begin."); + std::shared_ptr queryOrderByWriteTimeMock = std::make_shared(); + DataQuery queryOrderByWriteTime; + EXPECT_CALL(*queryMock, OrderByWriteTime(false)).Times(1); + queryOrderByWriteTime.OrderByWriteTime(false); + EXPECT_EQ(queryOrderByWriteTime.ToString(), " ORDER BY WRITE_TIME DESC"); +} + +/** + * @tc.name: Limit_ValidNumberAndOffset_AppendsToQuery + * @tc.desc: + * @tc.type: Limit_ValidNumberAndOffset_AppendsToQuery test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, Limit_ValidNumberAndOffset_AppendsToQuery, TestSize.Level0) +{ + ZLOGI("Limit_ValidNumberAndOffset_AppendsToQuery begin."); + std::shared_ptr queryLimitMock = std::make_shared(); + DataQuery queryLimit; + EXPECT_CALL(*queryLimitMock, Limit(10, 0)).Times(1); + queryLimit.Limit(10, 0); + EXPECT_EQ(queryLimit.ToString(), " LIMIT 10 0"); +} + +/** + * @tc.name: BeginGroup_AppendsBeginGroupToQuery + * @tc.desc: + * @tc.type: BeginGroup_AppendsBeginGroupToQuery test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, BeginGroup_AppendsBeginGroupToQuery, TestSize.Level0) +{ + ZLOGI("BeginGroup_AppendsBeginGroupToQuery begin."); + std::shared_ptr queryBeginGroupMock = std::make_shared(); + DataQuery queryBeginGroup; + EXPECT_CALL(*queryBeginGroupMock, BeginGroup()).Times(1); + queryBeginGroup.BeginGroup(); + EXPECT_EQ(queryBeginGroup.ToString(), " ("); +} + +/** + * @tc.name: EndGroup_AppendsEndGroupToQuery + * @tc.desc: + * @tc.type: EndGroup_AppendsEndGroupToQuery test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, EndGroup_AppendsEndGroupToQuery, TestSize.Level0) +{ + ZLOGI("EndGroup_AppendsEndGroupToQuery begin."); + std::shared_ptr queryEndGroupMock = std::make_shared(); + DataQuery queryEndGroup; + EXPECT_CALL(*queryEndGroupMock, EndGroup()).Times(1); + queryEndGroup.EndGroup(); + EXPECT_EQ(queryEndGroup.ToString(), " )"); +} + +/** + * @tc.name: KeyPrefix_ValidPrefix_AppendsToQuery + * @tc.desc: + * @tc.type: KeyPrefix_ValidPrefix_AppendsToQuery test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, KeyPrefix_ValidPrefix_AppendsToQuery, TestSize.Level0) +{ + ZLOGI("KeyPrefix_ValidPrefix_AppendsToQuery begin."); + std::shared_ptr queryKeyPrefixMock = std::make_shared(); + DataQuery queryKeyPrefix; + EXPECT_CALL(*queryKeyPrefixMock, KeyPrefix("prefix")).Times(1); + queryKeyPrefix.KeyPrefix("prefix"); + EXPECT_EQ(queryKeyPrefix.ToString(), " KEY_PREFIX prefix"); +} + +/** + * @tc.name: DeviceId_ValidDeviceId_AppendsToQuery + * @tc.desc: + * @tc.type: DeviceId_ValidDeviceId_AppendsToQuery test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, DeviceId_ValidDeviceId_AppendsToQuery, TestSize.Level0) +{ + ZLOGI("DeviceId_ValidDeviceId_AppendsToQuery begin."); + std::shared_ptr queryDeviceIdMock = std::make_shared(); + DataQuery queryDeviceId; + EXPECT_CALL(*queryDeviceIdMock, DeviceId("deviceId")).Times(1); + queryDeviceId.DeviceId("deviceId"); + EXPECT_EQ(queryDeviceId.ToString(), " DEVICE_ID deviceId"); +} + +/** + * @tc.name: SetSuggestIndex_ValidIndex_AppendsToQuery + * @tc.desc: + * @tc.type: SetSuggestIndex_ValidIndex_AppendsToQuery test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, SetSuggestIndex_ValidIndex_AppendsToQuery, TestSize.Level0) +{ + ZLOGI("DeviceId_ValidDeviceId_AppendsToQuery begin."); + std::shared_ptr querySetSuggestIndexMock = std::make_shared(); + DataQuery querySetSuggestIndex; + EXPECT_CALL(*querySetSuggestIndexMock, SuggestIndex("index")).Times(1); + querySetSuggestIndex.SetSuggestIndex("index"); + EXPECT_EQ(querySetSuggestIndex.ToString(), " SUGGEST_INDEX index"); +} + +/** + * @tc.name: InKeys_ValidKeys_AppendsToQuery + * @tc.desc: + * @tc.type: InKeys_ValidKeys_AppendsToQuery test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, InKeys_ValidKeys_AppendsToQuery, TestSize.Level0) +{ + ZLOGI("InKeys_ValidKeys_AppendsToQuery begin."); + std::shared_ptr queryInKeysMock = std::make_shared(); + DataQuery queryInKeys; + std::vector keys = {"key1", "key2"}; + EXPECT_CALL(*queryInKeysMock, InKeys(keys)).Times(1); + queryInKeys.InKeys(keys); + EXPECT_EQ(queryInKeys.ToString(), " IN_KEYS START_IN key1 key2 END_IN"); +} + +/** + * @tc.name: ToString_QueryTooLong_ReturnsEmptyString + * @tc.desc: + * @tc.type: ToString_QueryTooLong_ReturnsEmptyString test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, ToString_QueryTooLong_ReturnsEmptyString, TestSize.Level0) +{ + ZLOGI("ToString_QueryTooLong_ReturnsEmptyString begin."); + DataQuery queryToString; + queryToString.str_.assign(MAX_QUERY_LENGTH + 1, 'a'); + EXPECT_EQ(queryToString.ToString(), ""); +} + +/** + * @tc.name: AppendCommon_ValidInput_CorrectAppending + * @tc.desc: + * @tc.type: AppendCommon_ValidInput_CorrectAppending test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, AppendCommon_ValidInput_CorrectAppending, TestSize.Level0) +{ + ZLOGI("AppendCommon_ValidInput_CorrectAppending begin."); + DataQuery queryAppendCommon; + string keyword = "key"; + string fieldType = "type"; + string field = "field"; + int value = 123; + queryAppendCommon.AppendCommon(keyword, fieldType, field, value); + EXPECT_EQ(queryAppendCommon.GetQuery(), " key type field 123"); +} + +/** + * @tc.name: AppendCommonString_ValidInput_CorrectAppending + * @tc.desc: + * @tc.type: AppendCommonString_ValidInput_CorrectAppending test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, AppendCommonString_ValidInput_CorrectAppending, TestSize.Level0) +{ + ZLOGI("AppendCommonString_ValidInput_CorrectAppending begin."); + DataQuery queryAppendCommonString; + string keyword = "key"; + string fieldType = "type"; + string field = "field"; + string value = "value"; + queryAppendCommonString.AppendCommonString(keyword, fieldType, field, value); + EXPECT_EQ(queryAppendCommonString.GetQuery(), " key type field value"); +} + +/** + * @tc.name: AppendCommonBoolean_ValidInput_CorrectAppending + * @tc.desc: + * @tc.type: AppendCommonBoolean_ValidInput_CorrectAppending test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, AppendCommonBoolean_ValidInput_CorrectAppending, TestSize.Level0) +{ + ZLOGI("AppendCommonBoolean_ValidInput_CorrectAppending begin."); + DataQuery queryAppendCommonBoolean; + string keyword = "key"; + string fieldType = "type"; + string field = "field"; + bool value = true; + queryAppendCommonBoolean.AppendCommonBoolean(keyword, fieldType, field, value); + EXPECT_EQ(queryAppendCommonBoolean.GetQuery(), " key type field true"); +} + +/** + * @tc.name: AppendCommonList_ValidInput_CorrectAppending + * @tc.desc: + * @tc.type: AppendCommonList_ValidInput_CorrectAppending test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, AppendCommonList_ValidInput_CorrectAppending, TestSize.Level0) +{ + ZLOGI("AppendCommonList_ValidInput_CorrectAppending begin."); + DataQuery queryAppendCommonList; + string keyword = "key"; + string fieldType = "type"; + string field = "field"; + vector valueList = {1, 2, 3}; + queryAppendCommonList.AppendCommonList(keyword, fieldType, field, valueList); + EXPECT_EQ(queryAppendCommonList.GetQuery(), " key type field ( 1 2 3 )"); +} + +/** + * @tc.name: AppendCommonListString_ValidInput_CorrectAppending + * @tc.desc: + * @tc.type: AppendCommonListString_ValidInput_CorrectAppending test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, AppendCommonListString_ValidInput_CorrectAppending, TestSize.Level0) +{ + ZLOGI("AppendCommonListString_ValidInput_CorrectAppending begin."); + DataQuery queryAppendCommonListString; + string keyword = "key"; + string fieldType = "type"; + string field = "field"; + vector valueList = {"value1", "value2"}; + queryAppendCommonListString.AppendCommonListString(keyword, fieldType, field, valueList); + EXPECT_EQ(queryAppendCommonListString.GetQuery(), " key type field ( value1 value2 )"); +} + +/** + * @tc.name: EscapeSpace_ValidInput_CorrectEscaping + * @tc.desc: + * @tc.type: EscapeSpace_ValidInput_CorrectEscaping test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, EscapeSpace_ValidInput_CorrectEscaping, TestSize.Level0) +{ + ZLOGI("EscapeSpace_ValidInput_CorrectEscaping begin."); + DataQuery queryEscapeSpace; + string input = "field with space"; + queryEscapeSpace.EscapeSpace(input); + EXPECT_EQ(input, "field\\ with\\ space"); +} + +/** + * @tc.name: ValidateField_ValidField_ReturnsTrue + * @tc.desc: + * @tc.type: ValidateField_ValidField_ReturnsTrue test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, ValidateField_ValidField_ReturnsTrue, TestSize.Level0) +{ + ZLOGI("ValidateField_ValidField_ReturnsTrue begin."); + DataQuery queryValidateField; + string field = "validField"; + EXPECT_TRUE(queryValidateField.ValidateField(field)); +} + +/** + * @tc.name: ValidateField_EmptyField_ReturnsFalse + * @tc.desc: + * @tc.type: ValidateField_EmptyField_ReturnsFalse test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, ValidateField_EmptyField_ReturnsFalse, TestSize.Level0) +{ + ZLOGI("ValidateField_EmptyField_ReturnsFalse begin."); + DataQuery queryValidateField; + string field = ""; + EXPECT_FALSE(queryValidateField.ValidateField(field)); +} + +/** + * @tc.name: ValidateField_FieldWithSpecialChar_ReturnsFalse + * @tc.desc: + * @tc.type: ValidateField_FieldWithSpecialChar_ReturnsFalse test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, ValidateField_FieldWithSpecialChar_ReturnsFalse, TestSize.Level0) +{ + ZLOGI("ValidateField_FieldWithSpecialChar_ReturnsFalse begin."); + DataQuery queryValidateField; + string field = "field with special*char"; + EXPECT_FALSE(queryValidateField.ValidateField(field)); +} + +/** + * @tc.name: BasicToString_ValidInput_CorrectConversion + * @tc.desc: + * @tc.type: BasicToString_ValidInput_CorrectConversion test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, BasicToString_ValidInput_CorrectConversion, TestSize.Level0) +{ + ZLOGI("BasicToString_ValidInput_CorrectConversion begin."); + DataQuery queryBasicToString; + int value = 456; + string result = queryBasicToString.BasicToString(value); + EXPECT_EQ(result, "456"); +} +} // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/databaseutils/test/datamgr_service_proxy_virtual_test.cpp b/kv_store/databaseutils/test/datamgr_service_proxy_virtual_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..94f721585e829131b6b069bdbafb3770e9c07d6f --- /dev/null +++ b/kv_store/databaseutils/test/datamgr_service_proxy_virtual_test.cpp @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2024 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 "DataMgrServiceProxyVirtualTest" + +#include "datamgr_service_proxy.h" +#include "itypes_util.h" +#include "log_print.h" +#include "message_parcel.h" +#include "mock_remote_object.h" +#include "types.h" +#include +#include +#include + +using namespace OHOS::DistributedKv; +using namespace testing; +using namespace testing::ext; +namespace OHOS::Test { +class DataMgrServiceProxyVirtualTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void DataMgrServiceProxyVirtualTest::SetUpTestCase(void) +{} + +void DataMgrServiceProxyVirtualTest::TearDownTestCase(void) +{} + +void DataMgrServiceProxyVirtualTest::SetUp(void) +{} + +void DataMgrServiceProxyVirtualTest::TearDown(void) +{} + +/** + * @tc.name: GetFeatureInterface_Success + * @tc.desc: + * @tc.type: GetFeatureInterface_Success test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataMgrServiceProxyVirtualTest, GetFeatureInterface_Success, TestSize.Level0) +{ + ZLOGI("GetFeatureInterface_Success begin."); + std::shared_ptr mockImpl = std::make_shared(); + DataMgrServiceProxy proxy(mockImpl); + + EXPECT_CALL(*mockImpl, SendRequest(_, _, _, _)) + .WillOnce(Return(0)); // Simulation returns successfully + + auto result = proxy.GetFeatureInterface("GetFeatureInterface_Success"); + ASSERT_NE(result, nullptr); +} + +/** + * @tc.name: GetFeatureInterface_WriteDescriptorFailed + * @tc.desc: + * @tc.type: GetFeatureInterface_WriteDescriptorFailed test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataMgrServiceProxyVirtualTest, GetFeatureInterface_WriteDescriptorFailed, TestSize.Level0) +{ + ZLOGI("GetFeatureInterface_WriteDescriptorFailed begin."); + std::shared_ptr mockImpl = std::make_shared(); + DataMgrServiceProxy proxy(mockImpl); + + EXPECT_CALL(*mockImpl, SendRequest(_, _, _, _)) + .Times(0); // SendRequest is not called + + auto result = proxy.GetFeatureInterface("GetFeatureInterface_WriteDescriptorFailed"); + ASSERT_EQ(result, nullptr); +} + +/** + * @tc.name: GetFeatureInterface_WriteNameFailed + * @tc.desc: + * @tc.type: GetFeatureInterface_WriteNameFailed test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataMgrServiceProxyVirtualTest, GetFeatureInterface_WriteNameFailed, TestSize.Level0) +{ + ZLOGI("GetFeatureInterface_WriteNameFailed begin."); + std::shared_ptr mockImpl = std::make_shared(); + DataMgrServiceProxy proxy(mockImpl); + + EXPECT_CALL(*mockImpl, SendRequest(_, _, _, _)) + .Times(0); // SendRequest is not called + + auto result = proxy.GetFeatureInterface("GetFeatureInterface_WriteNameFailed"); + ASSERT_EQ(result, nullptr); +} + +/** + * @tc.name: GetFeatureInterface_SendRequestError + * @tc.desc: + * @tc.type: GetFeatureInterface_SendRequestError test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataMgrServiceProxyVirtualTest, GetFeatureInterface_SendRequestError, TestSize.Level0) +{ + ZLOGI("GetFeatureInterface_SendRequestError begin."); + std::shared_ptr mockImpl = std::make_shared(); + DataMgrServiceProxy proxy(mockImpl); + + EXPECT_CALL(*mockImpl, SendRequest(_, _, _, _)) + .WillOnce(Return(-1)); // Simulating an error + + auto result = proxy.GetFeatureInterface("GetFeatureInterface_SendRequestError"); + ASSERT_EQ(result, nullptr); +} + +/** + * @tc.name: RegisterClientDeathObserver_Success + * @tc.desc: + * @tc.type: RegisterClientDeathObserver_Success test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataMgrServiceProxyVirtualTest, RegisterClientDeathObserver_Success, TestSize.Level0) +{ + ZLOGI("RegisterClientDeathObserver_Success begin."); + std::shared_ptr mockImpl = std::make_shared(); + DataMgrServiceProxy proxy(mockImpl); + + EXPECT_CALL(*mockImpl, SendRequest(_, _, _, _)) + .WillOnce(Return(0)); // Simulation returns successfully + + AppId appId; + appId.appId = "RegisterClientDeathObserver_Success"; + sptr observer = new MockRemoteObject(); + auto status = proxy.RegisterClientDeathObserver(appId, observer); + ASSERT_EQ(status, Status::SUCCESS); +} + +/** + * @tc.name: RegisterClientDeathObserver_WriteDescriptorFailed + * @tc.desc: + * @tc.type: RegisterClientDeathObserver_WriteDescriptorFailed test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataMgrServiceProxyVirtualTest, RegisterClientDeathObserver_WriteDescriptorFailed, TestSize.Level0) +{ + ZLOGI("RegisterClientDeathObserver_WriteDescriptorFailed begin."); + std::shared_ptr mockImpl = std::make_shared(); + DataMgrServiceProxy proxy(mockImpl); + + EXPECT_CALL(*mockImpl, SendRequest(_, _, _, _)) + .Times(0); // SendRequest is not called + + AppId appId; + appId.appId = "RegisterClientDeathObserver_WriteDescriptorFailed"; + sptr observer = new MockRemoteObject(); + auto status = proxy.RegisterClientDeathObserver(appId, observer); + ASSERT_EQ(status, Status::IPC_ERROR); +} + +/** + * @tc.name: RegisterClientDeathObserver_WriteStringFailed + * @tc.desc: + * @tc.type: RegisterClientDeathObserver_WriteStringFailed test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataMgrServiceProxyVirtualTest, RegisterClientDeathObserver_WriteStringFailed, TestSize.Level0) +{ + ZLOGI("RegisterClientDeathObserver_WriteStringFailed begin."); + std::shared_ptr mockImpl = std::make_shared(); + DataMgrServiceProxy proxy(mockImpl); + + EXPECT_CALL(*mockImpl, SendRequest(_, _, _, _)) + .Times(0); // SendRequest is not called + + AppId appId; + appId.appId = "RegisterClientDeathObserver_WriteStringFailed"; + sptr observer = new MockRemoteObject(); + auto status = proxy.RegisterClientDeathObserver(appId, observer); + ASSERT_EQ(status, Status::IPC_ERROR); +} + +/** + * @tc.name: RegisterClientDeathObserver_NullObserver + * @tc.desc: + * @tc.type: RegisterClientDeathObserver_NullObserver test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataMgrServiceProxyVirtualTest, RegisterClientDeathObserver_NullObserver, TestSize.Level0) +{ + ZLOGI("RegisterClientDeathObserver_NullObserver begin."); + std::shared_ptr mockImpl = std::make_shared(); + DataMgrServiceProxy proxy(mockImpl); + + EXPECT_CALL(*mockImpl, SendRequest(_, _, _, _)) + .Times(0); // SendRequest is not called + + AppId appId; + appId.appId = "RegisterClientDeathObserver_NullObserver"; + auto status = proxy.RegisterClientDeathObserver(appId, nullptr); + ASSERT_EQ(status, Status::INVALID_ARGUMENT); +} + +/** + * @tc.name: RegisterClientDeathObserver_SendRequestError + * @tc.desc: + * @tc.type: RegisterClientDeathObserver_SendRequestError test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataMgrServiceProxyVirtualTest, RegisterClientDeathObserver_SendRequestError, TestSize.Level0) +{ + ZLOGI("RegisterClientDeathObserver_SendRequestError begin."); + std::shared_ptr mockImpl = std::make_shared(); + DataMgrServiceProxy proxy(mockImpl); + + EXPECT_CALL(*mockImpl, SendRequest(_, _, _, _)) + .WillOnce(Return(-1)); // Simulating an error + + AppId appId; + appId.appId = "RegisterClientDeathObserver_SendRequestError"; + sptr observer = new MockRemoteObject(); + auto status = proxy.RegisterClientDeathObserver(appId, observer); + ASSERT_EQ(status, Status::IPC_ERROR); +} + +/** + * @tc.name: ClearAppStorage_Success + * @tc.desc: + * @tc.type: ClearAppStorage_Success test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataMgrServiceProxyVirtualTest, ClearAppStorage_Success, TestSize.Level0) +{ + ZLOGI("ClearAppStorage_Success begin."); + std::shared_ptr mockImpl = std::make_shared(); + DataMgrServiceProxy proxy(mockImpl); + + EXPECT_CALL(*mockImpl, SendRequest(_, _, _, _)) + .WillOnce(Return(0)); // Simulation returns successfully + + auto result = proxy.ClearAppStorage("ClearAppStorage_Success", 1, 1, 1); + ASSERT_EQ(result, Status::SUCCESS); +} + +/** + * @tc.name: ClearAppStorage_WriteDescriptorFailed + * @tc.desc: + * @tc.type: ClearAppStorage_WriteDescriptorFailed test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataMgrServiceProxyVirtualTest, ClearAppStorage_WriteDescriptorFailed, TestSize.Level0) +{ + ZLOGI("ClearAppStorage_WriteDescriptorFailed begin."); + std::shared_ptr mockImpl = std::make_shared(); + DataMgrServiceProxy proxy(mockImpl); + + EXPECT_CALL(*mockImpl, SendRequest(_, _, _, _)) + .Times(0); // SendRequest is not called + + auto result = proxy.ClearAppStorage("ClearAppStorage_WriteDescriptorFailed", 1, 1, 1); + ASSERT_EQ(result, Status::IPC_ERROR); +} + +/** + * @tc.name: ClearAppStorage_WriteDataFailed + * @tc.desc: + * @tc.type: ClearAppStorage_WriteDataFailed test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataMgrServiceProxyVirtualTest, ClearAppStorage_WriteDataFailed, TestSize.Level0) +{ + ZLOGI("ClearAppStorage_WriteDataFailed begin."); + std::shared_ptr mockImpl = std::make_shared(); + DataMgrServiceProxy proxy(mockImpl); + + EXPECT_CALL(*mockImpl, SendRequest(_, _, _, _)) + .Times(0); // SendRequest is not called + + auto result = proxy.ClearAppStorage("ClearAppStorage_WriteDataFailed", 1, 1, 1); + ASSERT_EQ(result, Status::IPC_ERROR); +} + +/** + * @tc.name: ClearAppStorage_SendRequestError + * @tc.desc: + * @tc.type: ClearAppStorage_SendRequestError test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataMgrServiceProxyVirtualTest, ClearAppStorage_SendRequestError, TestSize.Level0) +{ + ZLOGI("ClearAppStorage_SendRequestError begin."); + std::shared_ptr mockImpl = std::make_shared(); + DataMgrServiceProxy proxy(mockImpl); + + EXPECT_CALL(*mockImpl, SendRequest(_, _, _, _)) + .WillOnce(Return(-1)); // Simulating an error + + auto result = proxy.ClearAppStorage("ClearAppStorage_SendRequestError", 1, 1, 1); + ASSERT_EQ(result, Status::IPC_ERROR); +} +} // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/databaseutils/test/delegate_mgr_callback_virtual_test.cpp b/kv_store/databaseutils/test/delegate_mgr_callback_virtual_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3a7ad64304f15d7751d921e929bcf782a9ec50fc --- /dev/null +++ b/kv_store/databaseutils/test/delegate_mgr_callback_virtual_test.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2024 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 "DelegateMgrCallbackVirtualTest" + +#include "kv_types_util.h" +#include "types.h" +#include +#include +#include +#include "distributeddb_kvstore_delegate_manager.h" +#include "delegate_mgr_callback.h" +#include + +using namespace OHOS::DistributedKv; +using namespace testing; +using namespace testing::ext; +namespace OHOS::Test { +class DelegateMgrCallbackVirtualTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void DelegateMgrCallbackVirtualTest::SetUpTestCase(void) +{ +} + +void DelegateMgrCallbackVirtualTest::TearDownTestCase(void) +{ +} + +void DelegateMgrCallbackVirtualTest::SetUp(void) +{ +} + +void DelegateMgrCallbackVirtualTest::TearDown(void) +{ +} + +class MockKvStoreDelegateManager : public KvStoreDelegateManager { +public: + MOCK_METHOD2(GetKvStoreDiskSize, DBStatus(const std::string &, uint64_t &)); +}; + +/** + * @tc.name: GetKvStoreDiskSize_DelegateIsNull_ReturnsFalse + * @tc.desc: + * @tc.type: GetKvStoreDiskSize_DelegateIsNull_ReturnsFalse test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, GetKvStoreDiskSize_DelegateIsNull_ReturnsFalse, TestSize.Level0) +{ + ZLOGI("GetKvStoreDiskSize_DelegateIsNull_ReturnsFalse begin."); + MockKvStoreDelegateManager *mockDelegate1; + DelegateMgrCallback *callback1; + mockDelegate1 = new MockKvStoreDelegateManager(); + callback1 = new DelegateMgrCallback(nullptr); + + uint64_t size = 0; + EXPECT_FALSE(callback1->GetKvStoreDiskSize("storeId", size)); + + delete callback1; + delete mockDelegate1; +} + +/** + * @tc.name: GetKvStoreDiskSize_DelegateReturnsOK_ReturnsTrue + * @tc.desc: + * @tc.type: GetKvStoreDiskSize_DelegateReturnsOK_ReturnsTrue test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, GetKvStoreDiskSize_DelegateReturnsOK_ReturnsTrue, TestSize.Level0) +{ + ZLOGI("GetKvStoreDiskSize_DelegateReturnsOK_ReturnsTrue begin."); + MockKvStoreDelegateManager *mockDelegate2; + DelegateMgrCallback *callback2; + mockDelegate2 = new MockKvStoreDelegateManager(); + callback2 = new DelegateMgrCallback(mockDelegate2); + uint64_t size = 0; + EXPECT_CALL(*mockDelegate2, GetKvStoreDiskSize("storeId", _)).WillOnce(Return(DBStatus::OK)); + EXPECT_TRUE(callback2->GetKvStoreDiskSize("storeId", size)); + + delete callback2; + delete mockDelegate2; +} + +/** + * @tc.name: GetKvStoreDiskSize_DelegateReturnsNonOK_ReturnsFalse + * @tc.desc: + * @tc.type: GetKvStoreDiskSize_DelegateReturnsNonOK_ReturnsFalse test function + * @tc.require: + * @tc.author: + */ +HWTEST_F(DataQueryVirtualTest, GetKvStoreDiskSize_DelegateReturnsNonOK_ReturnsFalse, TestSize.Level0) +{ + ZLOGI("GetKvStoreDiskSize_DelegateReturnsNonOK_ReturnsFalse begin."); + MockKvStoreDelegateManager *mockDelegate3; + DelegateMgrCallback *callback3; + mockDelegate3 = new MockKvStoreDelegateManager(); + callback3 = new DelegateMgrCallback(mockDelegate3); + + uint64_t size = 0; + EXPECT_CALL(*mockDelegate3, GetKvStoreDiskSize("storeId", _)).WillOnce(Return(DBStatus::NOT_FOUND)); + EXPECT_FALSE(callback->GetKvStoreDiskSize("storeId", size)); + + delete callback3; + delete mockDelegate3; +} +} // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/databaseutils/test/distributed_kv_data_manager_vritual_test.cpp b/kv_store/databaseutils/test/distributed_kv_data_manager_vritual_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a7d4f492dc8ca0e48e481e199152d958ca8b8108 --- /dev/null +++ b/kv_store/databaseutils/test/distributed_kv_data_manager_vritual_test.cpp @@ -0,0 +1,863 @@ +/* + * Copyright (c) 2024 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 "DistributedKvDataManagerVirtualTest" + +#include +#include +#include "distributed_kv_data_manager.h" +#include "kv_store_delegate_manager.h" +#include "kv_store_observer.h" +#include "kv_store_death_recipient.h" +#include "process_communication_impl.h" +#include "process_system_api_adapter_impl.h" +#include "store_manager.h" +#include "store_util.h" +#include "runtime_config.h" +#include "kv_store_service_death_notifier.h" +#include "dds_trace.h" +#include "kvstore_service_death_notifier.h" +#include "kv_store_death_recipient.h" +#include "kv_store_observer.h" +#include "kv_store_delegate_manager.h" +#include "process_communication_impl.h" +#include "process_system_api_adapter_impl.h" +#include "store_manager.h" +#include "store_util.h" +#include "runtime_config.h" +#include "kv_store_service_death_notifier.h" +#include "dds_trace.h" + +using namespace OHOS::DistributedKv; +using namespace testing; +using namespace testing::ext; +namespace OHOS::Test { +static constexpr size_t NUM_MIN_V = 5; +static constexpr size_t NUM_MAX_V = 12; +class DistributedKvDataManagerVirtualTest : public testing::Test { +public: + static std::shared_ptr executors; + static DistributedKvDataManager managerVirtual; + static Options createVirtual; + static Options noCreateVirtual; + static UserId userIdVirtual; + static AppId appIdVirtual; + static StoreId storeId64Virtual; + static StoreId storeId65Virtual; + static StoreId storeIdTestVirtual; + static StoreId storeIdEmptyVirtual; + static Entry entryAVirtual; + static Entry entryBVirtual; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; +std::shared_ptr DistributedKvDataManagerTest::executors = + std::make_shared(NUM_MAX_V, NUM_MIN_V); + +void DistributedKvDataManagerVirtualTest::SetUpTestCase(void) +{} + +void DistributedKvDataManagerVirtualTest::TearDownTestCase(void) +{} + +void DistributedKvDataManagerVirtualTest::SetUp(void) +{} + +void DistributedKvDataManagerVirtualTest::TearDown(void) +{} + +class ChangeNotificationVirtualTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void ChangeNotificationVirtualTest::SetUpTestCase(void) +{} + +void ChangeNotificationVirtualTest::TearDownTestCase(void) +{} + +void ChangeNotificationVirtualTest::SetUp(void) +{} + +void ChangeNotificationVirtualTest::TearDown(void) +{} + +/** + * @tc.name: GetKvStore001 + * @tc.desc: Get an exist SingleKvStore + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlGetKvStore001 + */ +HWTEST_F(DistributedKvDataManagerVirtualTest, GetKvStore001, TestSize.Level1) +{ + ZLOGI("GetKvStore001 begin."); + DistributedKvDataManager managerVirtual; + std::shared_ptr notExistKvStoreVirtual; + Status statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeId64Virtual, notExistKvStoreVirtual); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + EXPECT_NE(notExistKvStoreVirtual, nullptr); + + std::shared_ptr existKvStoreVirtual; + statusVirtual = + managerVirtual.GetSingleKvStore(noCreateVirtual, appIdVirtual, storeId64Virtual, existKvStoreVirtual); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + EXPECT_NE(existKvStoreVirtual, nullptr); +} + +/** +* @tc.name: GetKvStore002 +* @tc.desc: Create and get a new SingleKvStore +* @tc.type: FUNC +* @tc.require: GetKvStore002 +* @tc.author: sqlGetKvStore002 +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, GetKvStore002, TestSize.Level1) +{ + ZLOGI("GetKvStore002 begin."); + std::shared_ptr notExistKvStoreVirtual; + Status statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeId64Virtual, notExistKvStoreVirtual); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + EXPECT_NE(notExistKvStoreVirtual, nullptr); + managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + managerVirtual.DeleteKvStore(appIdVirtual, storeId64Virtual); +} + +/** +* @tc.name: GetKvStore003 +* @tc.desc: Get a non-existing SingleKvStore, and the callback function should receive STORE_NOT_FOUND and +* get a nullptr. +* @tc.type: FUNC +* @tc.require: GetKvStore003 +* @tc.author: sqlGetKvStore003 +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, GetKvStore003, TestSize.Level1) +{ + ZLOGI("GetKvStore003 begin."); + std::shared_ptr notExistKvStoreVirtual; + (void)managerVirtual.GetSingleKvStore(noCreateVirtual, appIdVirtual, storeId64Virtual, notExistKvStoreVirtual); + EXPECT_EQ(notExistKvStoreVirtual, nullptr); +} + +/** +* @tc.name: GetKvStore004 +* @tc.desc: Create a SingleKvStore with an empty storeId, and the callback function should receive +* @tc.type: FUNC +* @tc.require: GetKvStore004 +* @tc.author: sqlGetKvStore004 +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, GetKvStore004, TestSize.Level1) +{ + ZLOGI("GetKvStore004 begin."); + std::shared_ptr notExistKvStoreVirtual; + Status statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeIdEmptyVirtual, notExistKvStoreVirtual); + ASSERT_EQ(statusVirtual, Status::INVALID_ARGUMENT); + EXPECT_EQ(notExistKvStoreVirtual, nullptr); +} + +/** +* @tc.name: GetKvStore005 +* @tc.desc: Get a SingleKvStore with an empty storeId, and the callback function should receive INVALID_ARGUMENT +* @tc.type: FUNC +* @tc.require: GetKvStore005 +* @tc.author: sqlGetKvStore005 +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, GetKvStore005, TestSize.Level1) +{ + ZLOGI("GetKvStore005 begin."); + std::shared_ptr notExistKvStoreVirtual; + Status statusVirtual = + managerVirtual.GetSingleKvStore(noCreateVirtual, appIdVirtual, storeIdEmptyVirtual, notExistKvStoreVirtual); + ASSERT_EQ(statusVirtual, Status::INVALID_ARGUMENT); + EXPECT_EQ(notExistKvStoreVirtual, nullptr); +} + +/** +* @tc.name: GetKvStore006 +* @tc.desc: Create a SingleKvStore with a 65-byte storeId, and the callback function should receive INVALID_ARGUMENT +* @tc.type: FUNC +* @tc.require: GetKvStore006 +* @tc.author: sqlGetKvStore006 +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, GetKvStore006, TestSize.Level1) +{ + ZLOGI("GetKvStore006 begin."); + std::shared_ptr notExistKvStoreVirtual; + Status statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeId65Virtual, notExistKvStoreVirtual); + ASSERT_EQ(statusVirtual, Status::INVALID_ARGUMENT); + EXPECT_EQ(notExistKvStoreVirtual, nullptr); +} + +/** +* @tc.name: GetKvStore007 +* @tc.desc: Get a SingleKvStore with a 65-byte storeId, the callback function should receive INVALID_ARGUMENT +* @tc.type: FUNC +* @tc.require: GetKvStore007 +* @tc.author: sqlGetKvStore007 +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, GetKvStore007, TestSize.Level1) +{ + ZLOGI("GetKvStore007 begin."); + std::shared_ptr notExistKvStoreVirtual; + Status statusVirtual = + managerVirtual.GetSingleKvStore(noCreateVirtual, appIdVirtual, storeId65Virtual, notExistKvStoreVirtual); + ASSERT_EQ(statusVirtual, Status::INVALID_ARGUMENT); + EXPECT_EQ(notExistKvStoreVirtual, nullptr); +} + +/** + * @tc.name: GetKvStore008 + * @tc.desc: Get a SingleKvStore which supports cloud sync. + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlGetKvStore008 + */ +HWTEST_F(DistributedKvDataManagerVirtualTest, GetKvStore008, TestSize.Level1) +{ + ZLOGI("GetKvStore008 begin."); + std::shared_ptr cloudKvStore = nullptr; + Options options = createVirtual; + options.isPublic = true; + options.cloudConfig = { + .enableCloud = true, + .autoSync = true + }; + Status statusVirtual = + managerVirtual.GetSingleKvStore(options, appIdVirtual, storeId64Virtual, cloudKvStore); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + EXPECT_NE(cloudKvStore, nullptr); +} + +/** + * @tc.name: GetKvStore009 + * @tc.desc: Get a SingleKvStore which security level upgrade. + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlGetKvStore009 + */ +HWTEST_F(DistributedKvDataManagerVirtualTest, GetKvStore009, TestSize.Level1) +{ + ZLOGI("GetKvStore009 begin."); + std::shared_ptr kvStore = nullptr; + Options options = createVirtual; + options.securityLevel = S1; + Status statusVirtual = + managerVirtual.GetSingleKvStore(options, appIdVirtual, storeId64Virtual, kvStore); + + managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + options.securityLevel = S2; + statusVirtual = + managerVirtual.GetSingleKvStore(options, appIdVirtual, storeId64Virtual, kvStore); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + EXPECT_NE(kvStore, nullptr); + + managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + options.securityLevel = S1; + statusVirtual = + managerVirtual.GetSingleKvStore(options, appIdVirtual, storeId64Virtual, kvStore); + ASSERT_EQ(statusVirtual, Status::STORE_META_CHANGED); + EXPECT_EQ(kvStore, nullptr); +} + +/** +* @tc.name: GetKvStoreInvalidSecurityLevel +* @tc.desc: Get a SingleKvStore with a 64 + * -byte storeId, the callback function should receive INVALID_ARGUMENT +* @tc.type: FUNC +* @tc.require: SR000IIM2J AR000IIMLL +* @tc.author: sqlGetKvStoreInvalidSecurityLevel +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, GetKvStoreInvalidSecurityLevel, TestSize.Level1) +{ + ZLOGI("GetKvStoreInvalidSecurityLevel begin."); + std::shared_ptr notExistKvStoreVirtual; + Options invalidOption = createVirtual; + invalidOption.securityLevel = INVALID_LABEL; + Status statusVirtual = + managerVirtual.GetSingleKvStore(invalidOption, appIdVirtual, storeId64Virtual, notExistKvStoreVirtual); + ASSERT_EQ(statusVirtual, Status::INVALID_ARGUMENT); + EXPECT_EQ(notExistKvStoreVirtual, nullptr); +} + +/** +* @tc.name: GetAllKvStore001 +* @tc.desc: Get all KvStore IDs when no KvStore exists, and the callback function should receive a 0-length vector. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000BVTDM +* @tc.author: sqlGetAllKvStore001 +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, GetAllKvStore001, TestSize.Level1) +{ + ZLOGI("GetAllKvStore001 begin."); + std::vector storeIds; + Status statusVirtual = managerVirtual.GetAllKvStoreId(appIdVirtual, storeIds); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + EXPECT_EQ(storeIds.size(), static_cast(0)); +} + +/** +* @tc.name: GetAllKvStore002 +* @tc.desc: Get all SingleKvStore IDs when no KvStore exists, and the callback function should receive a empty vector. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000BVTDM +* @tc.author: sqlGetAllKvStore002 +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, GetAllKvStore002, TestSize.Level1) +{ + ZLOGI("GetAllKvStore002 begin."); + StoreId id1; + id1.storeId = "id1"; + StoreId id2; + id2.storeId = "id2"; + StoreId id3; + id3.storeId = "id3"; + std::shared_ptr kvStore; + Status statusVirtual = managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, id1, kvStore); + ASSERT_NE(kvStore, nullptr); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + statusVirtual = managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, id2, kvStore); + ASSERT_NE(kvStore, nullptr); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + statusVirtual = managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, id3, kvStore); + ASSERT_NE(kvStore, nullptr); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + std::vector storeIds; + statusVirtual = managerVirtual.GetAllKvStoreId(appIdVirtual, storeIds); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + bool haveId1 = false; + bool haveId2 = false; + bool haveId3 = false; + for (StoreId &id : storeIds) { + if (id.storeId == "id1") { + haveId1 = true; + } else if (id.storeId == "id2") { + haveId2 = true; + } else if (id.storeId == "id3") { + haveId3 = true; + } else { + ZLOGI("got an unknown storeId."); + EXPECT_TRUE(false); + } + } + EXPECT_TRUE(haveId1); + EXPECT_TRUE(haveId2); + EXPECT_TRUE(haveId3); + EXPECT_EQ(storeIds.size(), static_cast(3)); +} + +/** +* @tc.name: CloseKvStore001 +* @tc.desc: Close an opened KVStore, and the callback function should return SUCCESS. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000BVTDM +* @tc.author: sqlCloseKvStore001 +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, CloseKvStore001, TestSize.Level1) +{ + ZLOGI("CloseKvStore001 begin."); + std::shared_ptr kvStore; + Status statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeId64Virtual, kvStore); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + ASSERT_NE(kvStore, nullptr); + + Status stat = managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + EXPECT_EQ(stat, Status::SUCCESS); +} + +/** +* @tc.name: CloseKvStore002 +* @tc.desc: Close a closed SingleKvStore, and the callback function should return SUCCESS. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000BVTDM +* @tc.author: sqlCloseKvStore002 +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, CloseKvStore002, TestSize.Level1) +{ + ZLOGI("CloseKvStore002 begin."); + std::shared_ptr kvStore; + Status statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeId64Virtual, kvStore); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + ASSERT_NE(kvStore, nullptr); + + managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + Status stat = managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + EXPECT_EQ(stat, Status::STORE_NOT_OPEN); +} + +/** +* @tc.name: CloseKvStore003 +* @tc.desc: Close a SingleKvStore with an empty storeId, and the callback function should return INVALID_ARGUMENT. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000BVTDM +* @tc.author: sqlCloseKvStore003 +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, CloseKvStore003, TestSize.Level1) +{ + ZLOGI("CloseKvStore003 begin."); + Status stat = managerVirtual.CloseKvStore(appIdVirtual, storeIdEmptyVirtual); + EXPECT_EQ(stat, Status::INVALID_ARGUMENT); +} + +/** +* @tc.name: CloseKvStore004 +* @tc.desc: Close a SingleKvStore with a 65-byte storeId, and the callback function should return INVALID_ARGUMENT. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000BVTDM +* @tc.author: sqlCloseKvStore004 +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, CloseKvStore004, TestSize.Level1) +{ + ZLOGI("CloseKvStore004 begin."); + Status stat = managerVirtual.CloseKvStore(appIdVirtual, storeId65Virtual); + EXPECT_EQ(stat, Status::INVALID_ARGUMENT); +} + +/** +* @tc.name: CloseKvStore005 +* @tc.desc: Close a non-existing SingleKvStore, and the callback function should return STORE_NOT_OPEN. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000BVTDM +* @tc.author: sqlliqiao +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, CloseKvStore005, TestSize.Level1) +{ + ZLOGI("CloseKvStore005 begin."); + Status stat = managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + EXPECT_EQ(stat, Status::STORE_NOT_OPEN); +} + +/** +* @tc.name: CloseKvStoreMulti001 +* @tc.desc: Open a SingleKvStore several times and close them one by one. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000CSKRU +* @tc.author: sqlliqiao +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, CloseKvStoreMulti001, TestSize.Level1) +{ + ZLOGI("CloseKvStoreMulti001 begin."); + std::shared_ptr notExistKvStoreVirtual; + Status statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeId64Virtual, notExistKvStoreVirtual); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + EXPECT_NE(notExistKvStoreVirtual, nullptr); + + std::shared_ptr existKvStoreVirtual; + managerVirtual.GetSingleKvStore(noCreateVirtual, appIdVirtual, storeId64Virtual, existKvStoreVirtual); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + EXPECT_NE(existKvStoreVirtual, nullptr); + + Status stat = managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + EXPECT_EQ(stat, Status::SUCCESS); + + stat = managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + EXPECT_EQ(stat, Status::SUCCESS); +} + +/** +* @tc.name: CloseKvStoreMulti002 +* @tc.desc: Open a SingleKvStore several times and close them one by one. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000CSKRU +* @tc.author: sqlliqiao +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, CloseKvStoreMulti002, TestSize.Level1) +{ + ZLOGI("CloseKvStoreMulti002 begin."); + std::shared_ptr notExistKvStoreVirtual; + Status statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeId64Virtual, notExistKvStoreVirtual); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + EXPECT_NE(notExistKvStoreVirtual, nullptr); + + std::shared_ptr existKvStore1; + statusVirtual = + managerVirtual.GetSingleKvStore(noCreateVirtual, appIdVirtual, storeId64Virtual, existKvStore1); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + EXPECT_NE(existKvStore1, nullptr); + + std::shared_ptr existKvStore2; + statusVirtual = + managerVirtual.GetSingleKvStore(noCreateVirtual, appIdVirtual, storeId64Virtual, existKvStore2); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + EXPECT_NE(existKvStore2, nullptr); + + Status stat = managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + EXPECT_EQ(stat, Status::SUCCESS); + + stat = managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + EXPECT_EQ(stat, Status::SUCCESS); + + stat = managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + EXPECT_EQ(stat, Status::SUCCESS); + + stat = managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + EXPECT_NE(stat, Status::SUCCESS); +} + +/** +* @tc.name: CloseAllKvStore001 +* @tc.desc: Close all opened KvStores, and the callback function should return SUCCESS. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000BVTDM +* @tc.author: sqlliqiao +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, CloseAllKvStore001, TestSize.Level1) +{ + ZLOGI("CloseAllKvStore001 begin."); + std::shared_ptr kvStore1; + Status statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeId64Virtual, kvStore1); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + ASSERT_NE(kvStore1, nullptr); + + std::shared_ptr kvStore2; + statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeIdTestVirtual, kvStore2); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + ASSERT_NE(kvStore2, nullptr); + + Status stat = managerVirtual.CloseAllKvStore(appIdVirtual); + EXPECT_EQ(stat, Status::SUCCESS); +} + +/** +* @tc.name: CloseAllKvStore002 +* @tc.desc: Close all KvStores which exist but are not opened, and the callback function should return STORE_NOT_OPEN. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000BVTDM +* @tc.author: sqlliqiao +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, CloseAllKvStore002, TestSize.Level1) +{ + ZLOGI("CloseAllKvStore002 begin."); + std::shared_ptr kvStore; + Status statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeId64Virtual, kvStore); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + ASSERT_NE(kvStore, nullptr); + + std::shared_ptr kvStore2; + statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeIdTestVirtual, kvStore2); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + ASSERT_NE(kvStore2, nullptr); + + Status stat = managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + EXPECT_EQ(stat, Status::SUCCESS); + + stat = managerVirtual.CloseAllKvStore(appIdVirtual); + EXPECT_EQ(stat, Status::SUCCESS); +} + +/** +* @tc.name: DeleteKvStore001 +* @tc.desc: Delete a closed KvStore, and the callback function should return SUCCESS. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000BVTDM +* @tc.author: sqlliqiao +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, DeleteKvStore001, TestSize.Level1) +{ + ZLOGI("DeleteKvStore001 begin."); + std::shared_ptr kvStore; + Status statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeId64Virtual, kvStore); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + ASSERT_NE(kvStore, nullptr); + + Status stat = managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + ASSERT_EQ(stat, Status::SUCCESS); + + stat = managerVirtual.DeleteKvStore(appIdVirtual, storeId64Virtual, createVirtual.baseDir); + EXPECT_EQ(stat, Status::SUCCESS); +} + +/** +* @tc.name: DeleteKvStore002 +* @tc.desc: Delete an opened SingleKvStore, and the callback function should return SUCCESS. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000BVTDM +* @tc.author: sqlliqiao +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, DeleteKvStore002, TestSize.Level1) +{ + ZLOGI("DeleteKvStore002 begin."); + std::shared_ptr kvStore; + Status statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeId64Virtual, kvStore); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + ASSERT_NE(kvStore, nullptr); + + // first close it if opened, and then delete it. + Status stat = managerVirtual.DeleteKvStore(appIdVirtual, storeId64Virtual, createVirtual.baseDir); + EXPECT_EQ(stat, Status::SUCCESS); +} + +/** +* @tc.name: DeleteKvStore003 +* @tc.desc: Delete a non-existing KvStore, and the callback function should return DB_ERROR. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000BVTDM +* @tc.author: sqlliqiao +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, DeleteKvStore003, TestSize.Level1) +{ + ZLOGI("DeleteKvStore003 begin."); + Status stat = managerVirtual.DeleteKvStore(appIdVirtual, storeId64Virtual, createVirtual.baseDir); + EXPECT_EQ(stat, Status::STORE_NOT_FOUND); +} + +/** +* @tc.name: DeleteKvStore004 +* @tc.desc: Delete a KvStore with an empty storeId, and the callback function should return INVALID_ARGUMENT. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000BVTDM +* @tc.author: sqlliqiao +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, DeleteKvStore004, TestSize.Level1) +{ + ZLOGI("DeleteKvStore004 begin."); + Status stat = managerVirtual.DeleteKvStore(appIdVirtual, storeIdEmptyVirtual); + EXPECT_EQ(stat, Status::INVALID_ARGUMENT); +} + +/** +* @tc.name: DeleteKvStore005 +* @tc.desc: Delete a KvStore with 65 bytes long storeId (which exceed storeId length limit). Should +* return INVALID_ARGUMENT. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000BVTDM +* @tc.author: sqlliqiao +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, DeleteKvStore005, TestSize.Level1) +{ + ZLOGI("DeleteKvStore005 begin."); + Status stat = managerVirtual.DeleteKvStore(appIdVirtual, storeId65Virtual); + EXPECT_EQ(stat, Status::INVALID_ARGUMENT); +} + +/** +* @tc.name: DeleteAllKvStore001 +* @tc.desc: Delete all KvStores after closing all of them, and the callback function should return SUCCESS. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000BVTDM +* @tc.author: sqlliqiao +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, DeleteAllKvStore001, TestSize.Level1) +{ + ZLOGI("DeleteAllKvStore001 begin."); + std::shared_ptr kvStore1; + Status statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeId64Virtual, kvStore1); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + ASSERT_NE(kvStore1, nullptr); + std::shared_ptr kvStore2; + statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeIdTestVirtual, kvStore2); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + ASSERT_NE(kvStore2, nullptr); + Status stat = managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + EXPECT_EQ(stat, Status::SUCCESS); + stat = managerVirtual.CloseKvStore(appIdVirtual, storeIdTestVirtual); + EXPECT_EQ(stat, Status::SUCCESS); + + stat = managerVirtual.DeleteAllKvStore({""}, createVirtual.baseDir); + EXPECT_NE(stat, Status::SUCCESS); + stat = managerVirtual.DeleteAllKvStore(appIdVirtual, ""); + EXPECT_EQ(stat, Status::INVALID_ARGUMENT); + + stat = managerVirtual.DeleteAllKvStore(appIdVirtual, createVirtual.baseDir); + EXPECT_EQ(stat, Status::SUCCESS); +} + +/** +* @tc.name: DeleteAllKvStore002 +* @tc.desc: Delete all kvstore fail when any kvstore in the appIdVirtual is not closed +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000BVTDM +* @tc.author: sqlliqiao +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, DeleteAllKvStore002, TestSize.Level1) +{ + ZLOGI("DeleteAllKvStore002 begin."); + std::shared_ptr kvStore1; + Status statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeId64Virtual, kvStore1); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + ASSERT_NE(kvStore1, nullptr); + std::shared_ptr kvStore2; + statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeIdTestVirtual, kvStore2); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + ASSERT_NE(kvStore2, nullptr); + Status stat = managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + EXPECT_EQ(stat, Status::SUCCESS); + + stat = managerVirtual.DeleteAllKvStore(appIdVirtual, createVirtual.baseDir); + EXPECT_EQ(stat, Status::SUCCESS); +} + +/** +* @tc.name: DeleteAllKvStore003 +* @tc.desc: Delete all KvStores even if no KvStore exists in the appIdVirtual. +* @tc.type: FUNC +* @tc.require: SR000CQDU0 AR000BVTDM +* @tc.author: sqlliqiao +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, DeleteAllKvStore003, TestSize.Level1) +{ + ZLOGI("DeleteAllKvStore003 begin."); + Status stat = managerVirtual.DeleteAllKvStore(appIdVirtual, createVirtual.baseDir); + EXPECT_EQ(stat, Status::SUCCESS); +} + +/** +* @tc.name: DeleteAllKvStore004 +* @tc.desc: when delete the last active kvstore, the system will remove the app managerVirtual scene +* @tc.type: FUNC +* @tc.require: bugs +* @tc.author: sqlSven Wang +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, DeleteAllKvStore004, TestSize.Level1) +{ + ZLOGI("DeleteAllKvStore004 begin."); + std::shared_ptr kvStore1; + Status statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeId64Virtual, kvStore1); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + ASSERT_NE(kvStore1, nullptr); + std::shared_ptr kvStore2; + statusVirtual = + managerVirtual.GetSingleKvStore(createVirtual, appIdVirtual, storeIdTestVirtual, kvStore2); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + ASSERT_NE(kvStore2, nullptr); + Status stat = managerVirtual.CloseKvStore(appIdVirtual, storeId64Virtual); + EXPECT_EQ(stat, Status::SUCCESS); + stat = managerVirtual.CloseKvStore(appIdVirtual, storeIdTestVirtual); + EXPECT_EQ(stat, Status::SUCCESS); + stat = managerVirtual.DeleteKvStore(appIdVirtual, storeIdTestVirtual, createVirtual.baseDir); + EXPECT_EQ(stat, Status::SUCCESS); + stat = managerVirtual.DeleteAllKvStore(appIdVirtual, createVirtual.baseDir); + EXPECT_EQ(stat, Status::SUCCESS); +} + +/** +* @tc.name: PutSwitchWithEmptyAppId +* @tc.desc: put switch data, but appIdVirtual is empty. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sqlzuojiangjiang +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, PutSwitchWithEmptyAppId, TestSize.Level1) +{ + ZLOGI("PutSwitchWithEmptyAppId begin."); + SwitchData data; + Status statusVirtual = managerVirtual.PutSwitch({ "" }, data); + ASSERT_EQ(statusVirtual, Status::INVALID_ARGUMENT); +} + +/** +* @tc.name: PutSwitchWithInvalidAppId +* @tc.desc: put switch data, but appIdVirtual is not 'distributed_device_profile_service'. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sqlzuojiangjiang +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, PutSwitchWithInvalidAppId, TestSize.Level1) +{ + ZLOGI("PutSwitchWithInvalidAppId begin."); + SwitchData data; + Status statusVirtual = managerVirtual.PutSwitch({ "swicthes_test_appId" }, data); + ASSERT_EQ(statusVirtual, Status::PERMISSION_DENIED); +} + +/** +* @tc.name: GetSwitchWithInvalidArg +* @tc.desc: get switch data, but appIdVirtual is empty, networkId is invalid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sqlzuojiangjiang +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, GetSwitchWithInvalidArg, TestSize.Level1) +{ + ZLOGI("GetSwitchWithInvalidArg begin."); + auto [status1, data1] = managerVirtual.GetSwitch({ "" }, "networkId_test"); + ASSERT_EQ(status1, Status::INVALID_ARGUMENT); + auto [status2, data2] = managerVirtual.GetSwitch({ "switches_test_appId" }, ""); + ASSERT_EQ(status2, Status::INVALID_ARGUMENT); + auto [status3, data3] = managerVirtual.GetSwitch({ "switches_test_appId" }, "networkId_test"); + ASSERT_EQ(status3, Status::INVALID_ARGUMENT); +} + +/** +* @tc.name: GetSwitchWithInvalidAppId +* @tc.desc: get switch data, but appIdVirtual is not 'distributed_device_profile_service'. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sqlzuojiangjiang +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, GetSwitchWithInvalidAppId, TestSize.Level1) +{ + ZLOGI("GetSwitchWithInvalidAppId begin."); + auto devInfo = DevManager::GetInstance().GetLocalDevice(); + EXPECT_NE(devInfo.networkId, ""); + auto [statusVirtual, data] = managerVirtual.GetSwitch({ "switches_test_appId" }, devInfo.networkId); + ASSERT_EQ(statusVirtual, Status::PERMISSION_DENIED); +} + +/** +* @tc.name: SubscribeSwitchesData +* @tc.desc: subscribe switch data. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sqlzuojiangjiang +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, SubscribeSwitchesData, TestSize.Level1) +{ + ZLOGI("SubscribeSwitchesData begin."); + std::shared_ptr observer = std::make_shared(); + auto statusVirtual = managerVirtual.SubscribeSwitchData({ "switches_test_appId" }, observer); + ASSERT_EQ(statusVirtual, Status::PERMISSION_DENIED); +} + +/** +* @tc.name: UnsubscribeSwitchesData +* @tc.desc: unsubscribe switch data. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sqlzuojiangjiang +*/ +HWTEST_F(DistributedKvDataManagerVirtualTest, UnsubscribeSwitchesData, TestSize.Level1) +{ + ZLOGI("UnsubscribeSwitchesData begin."); + std::shared_ptr observer = std::make_shared(); + auto statusVirtual = managerVirtual.SubscribeSwitchData({ "switches_test_appId" }, observer); + ASSERT_EQ(statusVirtual, Status::PERMISSION_DENIED); + statusVirtual = managerVirtual.UnsubscribeSwitchData({ "switches_test_appId" }, observer); + ASSERT_EQ(statusVirtual, Status::PERMISSION_DENIED); +} +} // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/databaseutils/test/kv_utils_virtual_test.cpp b/kv_store/databaseutils/test/kv_utils_virtual_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aec5af978896ab46adb0264c300e4bfd426f3feb --- /dev/null +++ b/kv_store/databaseutils/test/kv_utils_virtual_test.cpp @@ -0,0 +1,1053 @@ +/* + * Copyright (c) 2024 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 "KvUtilVirtualTest" + +#include +#include +#include +#include +#include +#include "kv_utils.h" +#include "data_query.h" +#include "data_share_abs_predicates.h" +#include "data_share_values_bucket.h" +#include "data_share_value_object.h" + +using namespace testing::ext; +using namespace OHOS::DistributedKv; +using namespace OHOS::DataShare; +namespace OHOS::Test { +static constexpr const char *KEY = "key"; +static constexpr const char *VALUE = "value"; +static constexpr const char *VALID_SCHEMA_STRICT_DEFINE = "{\"SCHEMA_VERSION\":\"1.0\"," + "\"SCHEMA_MODE\":\"STRICT\"," + "\"SCHEMA_SKIPSIZE\":0," + "\"SCHEMA_DEFINE\":" + "{" + "\"age\":\"INTEGER, NOT NULL\"" + "}," + "\"SCHEMA_INDEXES\":[\"$.age\"]}"; +using var_t = std::variant>; +class KvUtilVirtualTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + +protected: + static DistributedKvDataManager managerVirtual; + static std::shared_ptr singleKvStoreVirtual; + + static std::string Entry2Str(const Entry &entry); + static void ClearEntry(Entry &entry); + static Blob VariantValue2Blob(const var_t &value); + static Blob VariantKey2Blob(const var_t &value); +}; +std::shared_ptr KvUtilVirtualTest::singleKvStoreVirtual = nullptr; +DistributedKvDataManager KvUtilVirtualTest::managerVirtual; + +void KvUtilVirtualTest::SetUp(void) +{ + ZLOGI("SetUp begin."); +} + +void KvUtilVirtualTest::TearDown(void) +{ + ZLOGI("TearDown begin."); +} + +std::string KvUtilVirtualTest::Entry2Str(const Entry &entry) +{ + ZLOGI("Entry2Str begin."); + return entry.key.ToString() + entry.value.ToString(); +} + +void KvUtilVirtualTest::ClearEntry(Entry &entry) +{ + ZLOGI("ClearEntry begin."); + entry.key.Clear(); + entry.value.Clear(); +} + +Blob KvUtilVirtualTest::VariantKey2Blob(const var_t &value) +{ + ZLOGI("VariantKey2Blob begin."); + std::vector uData; + if (auto *val = std::get_if(&value)) { + std::string data = *val; + uData.insert(uData.end(), data.begin(), data.end()); + } + return Blob(uData); +} + +Blob KvUtilVirtualTest::VariantValue2Blob(const var_t &value) +{ + ZLOGI("VariantValue2Blob begin."); + std::vector data; + auto strValue = std::get_if(&value); + if (strValue != nullptr) { + data.push_back(KvUtils::STRING); + data.insert(data.end(), (*strValue).begin(), (*strValue).end()); + } + auto boolValue = std::get_if(&value); + if (boolValue != nullptr) { + data.push_back(KvUtils::BOOLEAN); + data.push_back(static_cast(*boolValue)); + } + uint8_t *tmp = nullptr; + auto dblValue = std::get_if(&value); + if (dblValue != nullptr) { + double tmp4dbl = *dblValue; + uint64_t tmp64 = htobe64(*reinterpret_cast(&tmp4dbl)); + tmp = reinterpret_cast(&tmp64); + data.push_back(KvUtils::DOUBLE); + data.insert(data.end(), tmp, tmp + sizeof(double) / sizeof(uint8_t)); + } + auto intValue = std::get_if(&value); + if (intValue != nullptr) { + int64_t tmp4int = *intValue; + uint64_t tmp64 = htobe64(*reinterpret_cast(&tmp4int)); + tmp = reinterpret_cast(&tmp64); + data.push_back(KvUtils::INTEGER); + data.insert(data.end(), tmp, tmp + sizeof(int64_t) / sizeof(uint8_t)); + } + auto u8ArrayValue = std::get_if>(&value); + if (u8ArrayValue != nullptr) { + data.push_back(KvUtils::BYTE_ARRAY); + data.insert(data.end(), (*u8ArrayValue).begin(), (*u8ArrayValue).end()); + } + return Blob(data); +} + +void KvUtilVirtualTest::SetUpTestCase(void) +{ + ZLOGI("SetUpTestCase begin."); + Options options = { + .createIfMissing = true, + .encrypt = false, + .autoSync = false, + .kvStoreType = KvStoreType::SINGLE_VERSION, + .schema = VALID_SCHEMA_STRICT_DEFINE }; + options.area = EL1; + options.securityLevel = S1; + options.baseDir = std::string("/data/service/el1/public/database/KvUtilVirtualTest"); + AppId appId = { "KvUtilVirtualTest" }; + StoreId storeId = { "test_single" }; + mkdir(options.baseDir.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); + managerVirtual.DeleteKvStore(appId, storeId, options.baseDir); + managerVirtual.GetSingleKvStore(options, appId, storeId, singleKvStoreVirtual); + EXPECT_NE(singleKvStoreVirtual, nullptr); + singleKvStoreVirtual->Put("test_key_1", "{\"age\":1}"); + singleKvStoreVirtual->Put("test_key_2", "{\"age\":2}"); + singleKvStoreVirtual->Put("test_key_3", "{\"age\":3}"); + singleKvStoreVirtual->Put("kv_utils", "{\"age\":4}"); +} + +void KvUtilVirtualTest::TearDownTestCase(void) +{ + ZLOGI("TearDownTestCase begin."); + managerVirtual.DeleteKvStore({"KvUtilVirtualTest" }, + { "test_single" }, "/data/service/el1/public/database/KvUtilVirtualTest"); + (void)remove("/data/service/el1/public/database/KvUtilVirtualTest/key"); + (void)remove("/data/service/el1/public/database/KvUtilVirtualTest/kvdb"); + (void)remove("/data/service/el1/public/database/KvUtilVirtualTest"); +} + +/** + * @tc.name: KvStoreResultSetToResultSetBridgeAbnormal + * @tc.desc: kvStore resultSetVirtual to resultSetVirtual bridgeVirtual, the former is nullptr + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, KvStoreResultSetToResultSetBridgeAbnormal, TestSize.Level0) +{ + ZLOGI("KvStoreResultSetToResultSetBridgeAbnormal begin."); + std::shared_ptr resultSetVirtual = nullptr; + auto bridgeVirtual = KvUtils::ToResultSetBridge(resultSetVirtual); + EXPECT_EQ(bridgeVirtual, nullptr); +} + +/** + * @tc.name: KvStoreResultSetToResultSetBridge + * @tc.desc: kvStore resultSetVirtual to resultSetVirtual bridgeVirtual + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, KvStoreResultSetToResultSetBridge, TestSize.Level0) +{ + ZLOGI("KvStoreResultSetToResultSetBridge begin."); + DataSharePredicates predicatesVirtual; + predicatesVirtual.KeyPrefix("test"); + DataQuery queryVirtual; + auto statusVirtual = KvUtils::ToQuery(predicatesVirtual, queryVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + std::shared_ptr resultSetVirtual = nullptr; + statusVirtual = singleKvStoreVirtual->GetResultSet(queryVirtual, resultSetVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + EXPECT_NE(resultSetVirtual, nullptr); + EXPECT_EQ(resultSetVirtual->GetCount(), 3); + auto bridgeVirtual = KvUtils::ToResultSetBridge(resultSetVirtual); + EXPECT_NE(bridgeVirtual, nullptr); +} + +/** + * @tc.name: PredicatesToQueryEqualTo + * @tc.desc: to queryVirtual equalTo + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, PredicatesToQueryEqualTo, TestSize.Level0) +{ + ZLOGI("PredicatesToQueryEqualTo begin."); + DataSharePredicates predicatesVirtual; + predicatesVirtual.EqualTo("$.age", 1); + DataQuery queryVirtual; + auto statusVirtual = KvUtils::ToQuery(predicatesVirtual, queryVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + DataQuery trgQueryVirtual; + trgQueryVirtual.EqualTo("$.age", 1); + EXPECT_EQ(queryVirtual.ToString(), trgQueryVirtual.ToString()); +} + +/** + * @tc.name: PredicatesToQueryNotEqualTo + * @tc.desc: to queryVirtual not equalTo + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, PredicatesToQueryNotEqualTo, TestSize.Level0) +{ + ZLOGI("PredicatesToQueryNotEqualTo begin."); + DataSharePredicates predicatesVirtual; + predicatesVirtual.NotEqualTo("$.age", 1); + DataQuery queryVirtual; + auto statusVirtual = KvUtils::ToQuery(predicatesVirtual, queryVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + DataQuery trgQueryVirtual; + trgQueryVirtual.NotEqualTo("$.age", 1); + EXPECT_EQ(queryVirtual.ToString(), trgQueryVirtual.ToString()); +} + +/** + * @tc.name: PredicatesToQueryGreaterThan + * @tc.desc: to queryVirtual greater than + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, PredicatesToQueryGreaterThan, TestSize.Level0) +{ + ZLOGI("PredicatesToQueryGreaterThan begin."); + DataSharePredicates predicatesVirtual; + predicatesVirtual.GreaterThan("$.age", 1); + DataQuery queryVirtual; + auto statusVirtual = KvUtils::ToQuery(predicatesVirtual, queryVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + DataQuery trgQueryVirtual; + trgQueryVirtual.GreaterThan("$.age", 1); + EXPECT_EQ(queryVirtual.ToString(), trgQueryVirtual.ToString()); +} + +/** + * @tc.name: PredicatesToQueryLessThan + * @tc.desc: to queryVirtual less than + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, PredicatesToQueryLessThan, TestSize.Level0) +{ + ZLOGI("PredicatesToQueryLessThan begin."); + DataSharePredicates predicatesVirtual; + predicatesVirtual.LessThan("$.age", 3); + DataQuery queryVirtual; + auto statusVirtual = KvUtils::ToQuery(predicatesVirtual, queryVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + DataQuery trgQueryVirtual; + trgQueryVirtual.LessThan("$.age", 3); + EXPECT_EQ(queryVirtual.ToString(), trgQueryVirtual.ToString()); +} + +/** + * @tc.name: PredicatesToQueryGreaterThanOrEqualTo + * @tc.desc: to queryVirtual greater than or equalTo + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, PredicatesToQueryGreaterThanOrEqualTo, TestSize.Level0) +{ + ZLOGI("PredicatesToQueryGreaterThanOrEqualTo begin."); + DataSharePredicates predicatesVirtual; + predicatesVirtual.GreaterThanOrEqualTo("$.age", 1); + DataQuery queryVirtual; + auto statusVirtual = KvUtils::ToQuery(predicatesVirtual, queryVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + DataQuery trgQueryVirtual; + trgQueryVirtual.GreaterThanOrEqualTo("$.age", 1); + EXPECT_EQ(queryVirtual.ToString(), trgQueryVirtual.ToString()); +} + +/** + * @tc.name: PredicatesToQueryLessThanOrEqualTo + * @tc.desc: to queryVirtual less than or equalTo + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, PredicatesToQueryLessThanOrEqualTo, TestSize.Level0) +{ + ZLOGI("PredicatesToQueryLessThanOrEqualTo begin."); + DataSharePredicates predicatesVirtual; + predicatesVirtual.LessThanOrEqualTo("$.age", 3); + DataQuery queryVirtual; + auto statusVirtual = KvUtils::ToQuery(predicatesVirtual, queryVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + DataQuery trgQueryVirtual; + trgQueryVirtual.LessThanOrEqualTo("$.age", 3); + EXPECT_EQ(queryVirtual.ToString(), trgQueryVirtual.ToString()); +} + +/** + * @tc.name: PredicatesToQueryIn + * @tc.desc: to queryVirtual in + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, PredicatesToQueryIn, TestSize.Level0) +{ + ZLOGI("PredicatesToQueryIn begin."); + std::vector vectInt { 1, 2 }; + DataSharePredicates predicatesVirtual; + predicatesVirtual.In("$.age", vectInt); + DataQuery queryVirtual; + auto statusVirtual = KvUtils::ToQuery(predicatesVirtual, queryVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + DataQuery trgQueryVirtual; + trgQueryVirtual.In("$.age", vectInt); + EXPECT_EQ(queryVirtual.ToString(), trgQueryVirtual.ToString()); +} + +/** + * @tc.name: PredicatesToQueryNotIn + * @tc.desc: to queryVirtual not in + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, PredicatesToQueryNotIn, TestSize.Level0) +{ + ZLOGI("PredicatesToQueryNotIn begin."); + std::vector vectInt { 1, 2 }; + DataSharePredicates predicatesVirtual; + predicatesVirtual.NotIn("$.age", vectInt); + DataQuery queryVirtual; + auto statusVirtual = KvUtils::ToQuery(predicatesVirtual, queryVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + DataQuery trgQueryVirtual; + trgQueryVirtual.NotIn("$.age", vectInt); + EXPECT_EQ(queryVirtual.ToString(), trgQueryVirtual.ToString()); +} + +/** + * @tc.name: PredicatesToQueryLike + * @tc.desc: to queryVirtual or, like + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, PredicatesToQueryLike, TestSize.Level0) +{ + ZLOGI("PredicatesToQueryLike begin."); + DataSharePredicates predicatesVirtual; + predicatesVirtual.Like("$.age", "1"); + predicatesVirtual.Or(); + predicatesVirtual.Like("$.age", "3"); + DataQuery queryVirtual; + auto statusVirtual = KvUtils::ToQuery(predicatesVirtual, queryVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + DataQuery trgQueryVirtual; + trgQueryVirtual.Like("$.age", "1"); + trgQueryVirtual.Or(); + trgQueryVirtual.Like("$.age", "3"); + EXPECT_EQ(queryVirtual.ToString(), trgQueryVirtual.ToString()); +} + +/** + * @tc.name: PredicatesToQueryUnlike + * @tc.desc: to queryVirtual and, unlike + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, PredicatesToQueryUnlike, TestSize.Level0) +{ + ZLOGI("PredicatesToQueryUnlike begin."); + DataSharePredicates predicatesVirtual; + predicatesVirtual.Unlike("$.age", "1"); + predicatesVirtual.And(); + predicatesVirtual.Unlike("$.age", "3"); + DataQuery queryVirtual; + auto statusVirtual = KvUtils::ToQuery(predicatesVirtual, queryVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + DataQuery trgQueryVirtual; + trgQueryVirtual.Unlike("$.age", "1"); + trgQueryVirtual.And(); + trgQueryVirtual.Unlike("$.age", "3"); + EXPECT_EQ(queryVirtual.ToString(), trgQueryVirtual.ToString()); +} + +/** + * @tc.name: PredicatesToQueryIsNull + * @tc.desc: to queryVirtual is null + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, PredicatesToQueryIsNull, TestSize.Level0) +{ + ZLOGI("PredicatesToQueryIsNull begin."); + DataSharePredicates predicatesVirtual; + predicatesVirtual.IsNull("$.age"); + DataQuery queryVirtual; + auto statusVirtual = KvUtils::ToQuery(predicatesVirtual, queryVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + DataQuery trgQueryVirtual; + trgQueryVirtual.IsNull("$.age"); + EXPECT_EQ(queryVirtual.ToString(), trgQueryVirtual.ToString()); +} + +/** + * @tc.name: PredicatesToQueryIsNotNull + * @tc.desc: to queryVirtual is not null + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, PredicatesToQueryIsNotNull, TestSize.Level0) +{ + ZLOGI("PredicatesToQueryIsNotNull begin."); + DataSharePredicates predicatesVirtual; + predicatesVirtual.IsNotNull("$.age"); + DataQuery queryVirtual; + auto statusVirtual = KvUtils::ToQuery(predicatesVirtual, queryVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + DataQuery trgQueryVirtual; + trgQueryVirtual.IsNotNull("$.age"); + EXPECT_EQ(queryVirtual.ToString(), trgQueryVirtual.ToString()); +} + +/** + * @tc.name: PredicatesToQueryOrderByAsc + * @tc.desc: to queryVirtual is order by asc + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, PredicatesToQueryOrderByAsc, TestSize.Level0) +{ + ZLOGI("PredicatesToQueryOrderByAsc begin."); + DataSharePredicates predicatesVirtual; + predicatesVirtual.OrderByAsc("$.age"); + DataQuery queryVirtual; + auto statusVirtual = KvUtils::ToQuery(predicatesVirtual, queryVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + DataQuery trgQueryVirtual; + trgQueryVirtual.OrderByAsc("$.age"); + EXPECT_EQ(queryVirtual.ToString(), trgQueryVirtual.ToString()); +} + +/** + * @tc.name: PredicatesToQueryOrderByDesc + * @tc.desc: to queryVirtual is order by desc + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, PredicatesToQueryOrderByDesc, TestSize.Level0) +{ + ZLOGI("PredicatesToQueryOrderByDesc begin."); + DataSharePredicates predicatesVirtual; + predicatesVirtual.OrderByDesc("$.age"); + DataQuery queryVirtual; + auto statusVirtual = KvUtils::ToQuery(predicatesVirtual, queryVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + DataQuery trgQueryVirtual; + trgQueryVirtual.OrderByDesc("$.age"); + EXPECT_EQ(queryVirtual.ToString(), trgQueryVirtual.ToString()); +} + +/** + * @tc.name: PredicatesToQueryLimit + * @tc.desc: to queryVirtual is limit + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, PredicatesToQueryLimit, TestSize.Level0) +{ + ZLOGI("PredicatesToQueryLimit begin."); + DataSharePredicates predicatesVirtual; + predicatesVirtual.Limit(0, 9); + DataQuery queryVirtual; + auto statusVirtual = KvUtils::ToQuery(predicatesVirtual, queryVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + DataQuery trgQueryVirtual; + trgQueryVirtual.Limit(0, 9); + EXPECT_EQ(queryVirtual.ToString(), trgQueryVirtual.ToString()); +} + +/** + * @tc.name: PredicatesToQueryInKeys + * @tc.desc: to queryVirtual is in keys + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, PredicatesToQueryInKeys, TestSize.Level0) +{ + ZLOGI("PredicatesToQueryInKeys begin."); + std::vector keys { "test_field", "", "^test_field", "^", "test_field_name" }; + DataSharePredicates predicatesVirtual; + predicatesVirtual.InKeys(keys); + DataQuery queryVirtual; + auto statusVirtual = KvUtils::ToQuery(predicatesVirtual, queryVirtual); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + DataQuery trgQueryVirtual; + trgQueryVirtual.InKeys(keys); + EXPECT_EQ(queryVirtual.ToString(), trgQueryVirtual.ToString()); +} + +/** + * @tc.name: DataShareValuesBucketToEntryAbnormal + * @tc.desc: dataShare values bucket to entry, the bucket is invalid + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, DataShareValuesBucketToEntryAbnormal, TestSize.Level0) +{ + ZLOGI("DataShareValuesBucketToEntryAbnormal begin."); + DataShareValuesBucket bucket {}; + Entry trgEntry {}; + auto entry = KvUtils::ToEntry(bucket); + EXPECT_EQ(Entry2Str(entry), Entry2Str(trgEntry)); + bucket.Put("invalid key", "value"); + EXPECT_FALSE(bucket.IsEmpty()); + entry = KvUtils::ToEntry(bucket); + EXPECT_EQ(Entry2Str(entry), Entry2Str(trgEntry)); + bucket.Put(KEY, "value"); + entry = KvUtils::ToEntry(bucket); + EXPECT_EQ(Entry2Str(entry), Entry2Str(trgEntry)); +} + +/** + * @tc.name: DataShareValuesBucketToEntryNull + * @tc.desc: dataShare values bucket to entry, the bucket value is null + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, DataShareValuesBucketToEntryNull, TestSize.Level0) +{ + ZLOGI("DataShareValuesBucketToEntryNull begin."); + DataShareValuesBucket bucket {}; + bucket.Put(KEY, {}); + bucket.Put(VALUE, {}); + auto entry = KvUtils::ToEntry(bucket); + Entry trgEntry; + EXPECT_EQ(Entry2Str(entry), Entry2Str(trgEntry)); +} + +/** + * @tc.name: DataShareValuesBucketToEntryInt64_t + * @tc.desc: dataShare values bucket to entry, the bucket value type is int64_t + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, DataShareValuesBucketToEntryInt64_t, TestSize.Level0) +{ + ZLOGI("DataShareValuesBucketToEntryInt64_t begin."); + DataShareValuesBucket bucket {}; + Entry trgEntry; + var_t varValue; + varValue.emplace<1>(314); + var_t varKey; + varKey.emplace<3>("314"); + bucket.Put(KEY, varKey); + bucket.Put(VALUE, varValue); + auto entry = KvUtils::ToEntry(bucket); + trgEntry.key = VariantKey2Blob(varKey); + trgEntry.value = VariantValue2Blob(varValue); + EXPECT_EQ(Entry2Str(entry), Entry2Str(trgEntry)); +} + +/** + * @tc.name: DataShareValuesBucketToEntryDouble + * @tc.desc: dataShare values bucket to entry, the bucket value type is double + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, DataShareValuesBucketToEntryDouble, TestSize.Level0) +{ + ZLOGI("DataShareValuesBucketToEntryDouble begin."); + DataShareValuesBucket bucket {}; + Entry trgEntry; + var_t varValue; + varValue.emplace<2>(3.14); + var_t varKey; + varKey.emplace<3>("314"); + bucket.Put(KEY, varKey); + bucket.Put(VALUE, varValue); + auto entry = KvUtils::ToEntry(bucket); + trgEntry.key = VariantKey2Blob(varKey); + trgEntry.value = VariantValue2Blob(varValue); + EXPECT_EQ(Entry2Str(entry), Entry2Str(trgEntry)); +} + +/** + * @tc.name: DataShareValuesBucketToEntryString + * @tc.desc: dataShare values bucket to entry, the bucket value type is string + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, DataShareValuesBucketToEntryString, TestSize.Level0) +{ + ZLOGI("DataShareValuesBucketToEntryString begin."); + DataShareValuesBucket bucket {}; + Entry trgEntry; + var_t varValue; + varValue.emplace<3>("3.14"); + var_t varKey; + varKey.emplace<3>("314"); + bucket.Put(KEY, varKey); + bucket.Put(VALUE, varValue); + auto entry = KvUtils::ToEntry(bucket); + trgEntry.key = VariantKey2Blob(varKey); + trgEntry.value = VariantValue2Blob(varValue); + EXPECT_EQ(Entry2Str(entry), Entry2Str(trgEntry)); +} + +/** + * @tc.name: DataShareValuesBucketToEntryBool + * @tc.desc: dataShare values bucket to entry, the bucket value type is bool + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, DataShareValuesBucketToEntryBool, TestSize.Level0) +{ + ZLOGI("DataShareValuesBucketToEntryBool begin."); + DataShareValuesBucket bucket {}; + Entry trgEntry; + var_t varValue; + varValue.emplace<4>(true); + var_t varKey; + varKey.emplace<3>("314"); + bucket.Put(KEY, varKey); + bucket.Put(VALUE, varValue); + auto entry = KvUtils::ToEntry(bucket); + trgEntry.key = VariantKey2Blob(varKey); + trgEntry.value = VariantValue2Blob(varValue); + EXPECT_EQ(Entry2Str(entry), Entry2Str(trgEntry)); +} + +/** + * @tc.name: DataShareValuesBucketToEntryUint8Array + * @tc.desc: dataShare values bucket to entry, the bucket value type is uint8array + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, DataShareValuesBucketToEntryUint8Array, TestSize.Level0) +{ + ZLOGI("DataShareValuesBucketToEntryUint8Array begin."); + DataShareValuesBucket bucket {}; + Entry trgEntry; + var_t varValue; + std::vector vecUint8 { 3, 14 }; + varValue.emplace<5>(vecUint8); + var_t varKey; + varKey.emplace<3>("314"); + bucket.Put(KEY, varKey); + bucket.Put(VALUE, varValue); + auto entry = KvUtils::ToEntry(bucket); + trgEntry.key = VariantKey2Blob(varKey); + trgEntry.value = VariantValue2Blob(varValue); + EXPECT_EQ(Entry2Str(entry), Entry2Str(trgEntry)); +} + +/** + * @tc.name: DataShareValuesBucketToEntryInvalidKey + * @tc.desc: dataShare values bucket to entry, the bucket key type is not string + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, DataShareValuesBucketToEntryInvalidKey, TestSize.Level0) +{ + ZLOGI("DataShareValuesBucketToEntryInvalidKey begin."); + DataShareValuesBucket bucket {}; + Entry trgEntry; + var_t varValue; + std::vector vecUint8 { 3, 14 }; + varValue.emplace<5>(vecUint8); + var_t varKey; + varKey.emplace<1>(314); + bucket.Put(KEY, varKey); + bucket.Put(VALUE, varValue); + auto entry = KvUtils::ToEntry(bucket); + trgEntry.key = VariantKey2Blob(varKey); + EXPECT_EQ(Entry2Str(entry), Entry2Str(trgEntry)); +} + +/** + * @tc.name: DataShareValuesBucketToEntriesAbnormal + * @tc.desc: dataShare values bucket to entries, the buckets is invalid + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, DataShareValuesBucketToEntriesAbnormal, TestSize.Level0) +{ + ZLOGI("DataShareValuesBucketToEntriesAbnormal begin."); + std::vector buckets {}; + auto entries = KvUtils::ToEntries(buckets); + EXPECT_TRUE(entries.empty()); +} + +/** + * @tc.name: DataShareValuesBucketToEntriesNormal + * @tc.desc: dataShare values bucket to entries, the buckets has valid value + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, DataShareValuesBucketToEntriesNormal, TestSize.Level0) +{ + ZLOGI("DataShareValuesBucketToEntriesNormal begin."); + std::vector buckets {}; + DataShareValuesBucket bucket; + Entry trgEntryFirst; + Entry trgEntrySecond; + var_t varValue; + varValue.emplace<1>(314); + var_t varKey; + varKey.emplace<3>("314"); + bucket.Put(KEY, varKey); + bucket.Put(VALUE, varValue); + buckets.emplace_back(bucket); + trgEntryFirst.key = VariantKey2Blob(varKey); + trgEntryFirst.value = VariantValue2Blob(varValue); + bucket.Clear(); + varValue.emplace<2>(3.14); + varKey.emplace<3>("3.14"); + bucket.Put(KEY, varKey); + bucket.Put(VALUE, varValue); + buckets.emplace_back(bucket); + trgEntrySecond.key = VariantKey2Blob(varKey); + trgEntrySecond.value = VariantValue2Blob(varValue); + auto entries = KvUtils::ToEntries(buckets); + EXPECT_EQ(entries.size(), 2); + EXPECT_EQ(Entry2Str(entries[0]), Entry2Str(trgEntryFirst)); + EXPECT_EQ(Entry2Str(entries[1]), Entry2Str(trgEntrySecond)); +} + +/** + * @tc.name: GetKeysFromDataSharePredicatesAbnormal + * @tc.desc: get keys from data share predicatesVirtual, the predicatesVirtual is invalid + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, GetKeysFromDataSharePredicatesAbnormal, TestSize.Level0) +{ + ZLOGI("GetKeysFromDataSharePredicatesAbnormal begin."); + DataSharePredicates predicatesVirtual; + std::vector kvKeys; + auto statusVirtual = KvUtils::GetKeys(predicatesVirtual, kvKeys); + EXPECT_EQ(statusVirtual, Status::ERROR); + predicatesVirtual.EqualTo("$.age", 1); + statusVirtual = KvUtils::GetKeys(predicatesVirtual, kvKeys); + EXPECT_EQ(statusVirtual, Status::NOT_SUPPORT); +} + +/** + * @tc.name: GetKeysFromDataSharePredicatesNormal + * @tc.desc: get keys from data share predicatesVirtual, the predicatesVirtual has valid value + * @tc.type: FUNC + * @tc.require: + * @tc.author: sqlzuojiangjiang + */ +HWTEST_F(KvUtilVirtualTest, GetKeysFromDataSharePredicatesNormal, TestSize.Level0) +{ + ZLOGI("GetKeysFromDataSharePredicatesNormal begin."); + std::vector keys { "test_field", "", "^test_field", "^", "test_field_name" }; + DataSharePredicates predicatesVirtual; + predicatesVirtual.InKeys(keys); + std::vector kvKeys; + auto statusVirtual = KvUtils::GetKeys(predicatesVirtual, kvKeys); + EXPECT_EQ(statusVirtual, Status::SUCCESS); + EXPECT_EQ(keys.size(), kvKeys.size()); + for (size_t i = 0; i < keys.size(); i++) { + EXPECT_EQ(keys[i], kvKeys[i].ToString()); + } +} + +/** + * @tc.name: ToResultSetBridge_NullResultSet_ReturnsNull + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KvUtilsTest, ToResultSetBridge_NullResultSet_ReturnsNull, TestSize.Level0) +{ + ZLOGI("ToResultSetBridge_NullResultSet_ReturnsNull begin."); + std::shared_ptr nullResultSet = nullptr; + auto result = KvUtils::ToResultSetBridge(nullResultSet); + EXPECT_EQ(result, nullptr); +} + +/** + * @tc.name: ToResultSetBridge_ValidResultSet_ReturnsBridge + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KvUtilsTest, ToResultSetBridge_ValidResultSet_ReturnsBridge, TestSize.Level0) +{ + ZLOGI("ToResultSetBridge_ValidResultSet_ReturnsBridge begin."); + auto result = KvUtils::ToResultSetBridge(resultSet); + EXPECT_NE(result, nullptr); +} + +/** + * @tc.name: ToQuery_ValidOperations_Success + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KvUtilsTest, ToQuery_ValidOperations_Success, TestSize.Level0) +{ + ZLOGI("ToQuery_ValidOperations_Success begin."); + predicates->AddOperation({IN_KEY, {"key1", "key2"}}); + Status status = KvUtils::ToQuery(*predicates, *query); + EXPECT_EQ(status, Status::SUCCESS); +} + +/** + * @tc.name: ToQuery_InvalidOperation_NotSupport + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KvUtilsTest, ToQuery_InvalidOperation_NotSupport, TestSize.Level0) +{ + ZLOGI("ToQuery_InvalidOperation_NotSupport begin."); + predicates->AddOperation({-1, {}}); + Status status = KvUtils::ToQuery(*predicates, *query); + EXPECT_EQ(status, Status::NOT_SUPPORT); +} + +/** + * @tc.name: ToEntries_EmptyBuckets_ReturnsEmpty + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KvUtilsTest, ToEntries_EmptyBuckets_ReturnsEmpty, TestSize.Level0) +{ + ZLOGI("ToEntries_EmptyBuckets_ReturnsEmpty begin."); + std::vector emptyBuckets; + auto entries = KvUtils::ToEntries(emptyBuckets); + EXPECT_TRUE(entries.empty()); +} + +/** + * @tc.name: ToEntries_NonEmptyBuckets_ReturnsEntries + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KvUtilsTest, ToEntries_NonEmptyBuckets_ReturnsEntries, TestSize.Level0) +{ + ZLOGI("ToEntries_NonEmptyBuckets_ReturnsEntries begin."); + DataShareValuesBucket bucket; + bucket.valuesMap = {{"key", "value"}}; + std::vector buckets = {bucket}; + auto entries = KvUtils::ToEntries(buckets); + EXPECT_EQ(entries.size(), 1); +} + +/** + * @tc.name: ToEntry_EmptyValuesMap_ReturnsEmptyEntry + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KvUtilsTest, ToEntries_NonEmptyBuckets_ReturnsEntries, TestSize.Level0) +{ + ZLOGI("ToEntries_NonEmptyBuckets_ReturnsEntries begin."); + DataShareValuesBucket bucket; + Entry entry = KvUtils::ToEntry(bucket); + EXPECT_TRUE(entry.key.empty()); + EXPECT_TRUE(entry.value.empty()); +} + +/** + * @tc.name: ToEntry_NonEmptyValuesMap_ReturnsEntry + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KvUtilsTest, ToEntry_NonEmptyValuesMap_ReturnsEntry, TestSize.Level0) +{ + ZLOGI("ToEntry_NonEmptyValuesMap_ReturnsEntry begin."); + DataShareValuesBucket bucket; + bucket.valuesMap = {{"key", "value"}}; + Entry entry = KvUtils::ToEntry(bucket); + EXPECT_FALSE(entry.key.empty()); + EXPECT_FALSE(entry.value.empty()); +} + +/** + * @tc.name: GetKeys_EmptyOperations_ReturnsError + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KvUtilsTest, GetKeys_EmptyOperations_ReturnsError, TestSize.Level0) +{ + ZLOGI("GetKeys_EmptyOperations_ReturnsError begin."); + std::vector keys; + Status status = KvUtils::GetKeys(*predicates, keys); + EXPECT_EQ(status, Status::ERROR); +} + +/** + * @tc.name: GetKeys_ValidInKeyOperation_Success + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KvUtilsTest, GetKeys_ValidInKeyOperation_Success, TestSize.Level0) +{ + ZLOGI("GetKeys_ValidInKeyOperation_Success begin."); + predicates->AddOperation({IN_KEY, {"key1", "key2"}}); + std::vector keys; + Status status = KvUtils::GetKeys(*predicates, keys); + EXPECT_EQ(status, Status::SUCCESS); + EXPECT_EQ(keys.size(), 2); +} + +/** + * @tc.name: GetKeys_InvalidOperation_NotSupport + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KvUtilsTest, GetKeys_InvalidOperation_NotSupport, TestSize.Level0) +{ + ZLOGI("GetKeys_InvalidOperation_NotSupport begin."); + predicates->AddOperation({-1, {}}); + std::vector keys; + Status status = KvUtils::GetKeys(*predicates, keys); + EXPECT_EQ(status, Status::NOT_SUPPORT); +} + +/** + * @tc.name: ToEntryKey_ValidKey_Success + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KvUtilsTest, ToEntryKey_ValidKey_Success, TestSize.Level0) +{ + ZLOGI("ToEntryKey_ValidKey_Success begin."); + std::map values = {{"key", "value"}}; + Blob blob; + Status status = KvUtils::ToEntryKey(values, blob); + EXPECT_EQ(status, Status::SUCCESS); +} + +/** + * @tc.name: ToEntryKey_MissingKey_Error + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KvUtilsTest, ToEntryKey_MissingKey_Error, TestSize.Level0) +{ + ZLOGI("ToEntryKey_MissingKey_Error begin."); + std::map values = {{"otherKey", "value"}}; + Blob blob; + Status status = KvUtils::ToEntryKey(values, blob); + EXPECT_EQ(status, Status::ERROR); +} + +/** + * @tc.name: ToEntryValue_ValidValue_Success + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KvUtilsTest, ToEntryValue_ValidValue_Success, TestSize.Level0) +{ + ZLOGI("ToEntryValue_ValidValue_Success begin."); + std::map values = {{"value", "value"}}; + Blob blob; + Status status = KvUtils::ToEntryValue(values, blob); + EXPECT_EQ(status, Status::SUCCESS); +} + +/** + * @tc.name: ToEntryValue_MissingValue_Error + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KvUtilsTest, ToEntryValue_MissingValue_Error, TestSize.Level0) +{ + ZLOGI("ToEntryValue_MissingValue_Error begin."); + std::map values = {{"otherValue", "value"}}; + Blob blob; + Status status = KvUtils::ToEntryValue(values, blob); + EXPECT_EQ(status, Status::ERROR); +} +} // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/databaseutils/test/kvdb_notifier_virtual_test.cpp b/kv_store/databaseutils/test/kvdb_notifier_virtual_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..06ca65e763eed4224723d4bcd7a8cc61639378de --- /dev/null +++ b/kv_store/databaseutils/test/kvdb_notifier_virtual_test.cpp @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2024 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 "KVDBNotifierVirtualTest" + +#include +#include +#include +#include +#include +#include "kvdb_notifier_client.h" +#include "kvdb_sync_callback.h" +#include "kv_store_observer.h" +#include "kvdb_notifier_stub.h" +#include "message_parcel.h" +#include "types.h" +#include "dev_manager.h" +#include "dds_trace.h" +#include "store_util.h" + +using namespace OHOS::DistributedKv; +using namespace testing; +using namespace testing::ext; +namespace OHOS::Test { +class KVDBNotifierClientVirtualTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void KVDBNotifierClientVirtualTest::SetUpTestCase(void) +{} + +void KVDBNotifierClientVirtualTest::TearDownTestCase(void) +{} + +void KVDBNotifierClientVirtualTest::SetUp(void) +{} + +void KVDBNotifierClientVirtualTest::TearDown(void) +{} + +class MockDevManager : public DevManager { +public: + string ToUUID(const string &device) override + { + if (device == "device1") { + return "uuid1"; + } + return ""; + } +}; + +class MockKvStoreSyncCallback : public KvStoreSyncCallback { +public: + void SyncCompleted(const map &results) override + { + syncCompletedCalled = true; + } + void SyncCompleted(const map &results, uint64_t sequenceId) override + { + syncCompletedWithIdCalled = true; + } + bool syncCompletedCalled = false; + bool syncCompletedWithIdCalled = false; +}; + +class MockKvStoreObserver : public KvStoreObserver { +public: + void OnSwitchChange(const SwitchNotification ¬ification) override + { + onSwitchChangeCalled = true; + } + bool onSwitchChangeCalled = false; +}; + +class MockAsyncDetail : public AsyncDetail { +public: + void operator()(ProgressDetail &&detail) override + { + asyncDetailCalled = true; + } + bool asyncDetailCalled = false; +}; + +class KVDBNotifierClientTest : public testing::Test { +protected: + void SetUp() override + { + devManager = make_shared(); + notifierClient = make_unique(); + } + + shared_ptr devManager; + unique_ptr notifierClient; +}; + +class KVDBNotifierStubVirtualTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void KVDBNotifierStubVirtualTest::SetUpTestCase(void) +{} + +void KVDBNotifierStubVirtualTest::TearDownTestCase(void) +{} + +void KVDBNotifierStubVirtualTest::SetUp(void) +{} + +void KVDBNotifierStubVirtualTest::TearDown(void) +{} + +/** + * @tc.name: SyncCompleted_CallbackFound_CallbackInvoked + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KVDBNotifierClientVirtualTest, SyncCompleted_CallbackFound_CallbackInvoked, TestSize.Level0) +{ + ZLOGI("SyncCompleted_CallbackFound_CallbackInvoked begin."); + uint64_t sequenceId = 1; + auto callback = make_shared(); + notifierClient->AddSyncCallback(callback, sequenceId); + + notifierClient->SyncCompleted({}, sequenceId); + + EXPECT_TRUE(callback->syncCompletedCalled); + EXPECT_TRUE(callback->syncCompletedWithIdCalled); +} + +/** + * @tc.name: SyncCompleted_CallbackNotFound_NoInvocation + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KVDBNotifierClientVirtualTest, SyncCompleted_CallbackNotFound_NoInvocation, TestSize.Level0) +{ + ZLOGI("SyncCompleted_CallbackNotFound_NoInvocation begin."); + uint64_t sequenceId = 1; + notifierClient->SyncCompleted({}, sequenceId); + // No callback added, so no invocation should happen +} + +/** + * @tc.name: OnRemoteChange_DeviceToUUID_RemoteUpdated + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KVDBNotifierClientVirtualTest, OnRemoteChange_DeviceToUUID_RemoteUpdated, TestSize.Level0) +{ + ZLOGI("OnRemoteChange_DeviceToUUID_RemoteUpdated begin."); + map mask = {{"device1", true}}; + notifierClient->OnRemoteChange(mask, static_cast(DataType::TYPE_STATICS)); + + // Check if the remote is updated + auto [exist, value] = notifierClient->remotes_.Find("uuid1"); + EXPECT_TRUE(exist); + EXPECT_TRUE(value.first); +} + +/** + * @tc.name: IsChanged_DeviceExists_ReturnsCorrectStatus + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KVDBNotifierClientVirtualTest, IsChanged_DeviceExists_ReturnsCorrectStatus, TestSize.Level0) +{ + ZLOGI("IsChanged_DeviceExists_ReturnsCorrectStatus begin."); + notifierClient->remotes_.InsertOrAssign("uuid1", make_pair(true, false)); + + EXPECT_TRUE(notifierClient->IsChanged("uuid1", DataType::TYPE_STATICS)); + EXPECT_FALSE(notifierClient->IsChanged("uuid1", DataType::TYPE_DYNAMICAL)); +} + +/** + * @tc.name: AddSyncCallback_NullCallback_NoAddition + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KVDBNotifierClientVirtualTest, AddSyncCallback_NullCallback_NoAddition, TestSize.Level0) +{ + ZLOGI("AddSyncCallback_NullCallback_NoAddition begin."); + uint64_t sequenceId = 1; + notifierClient->AddSyncCallback(nullptr, sequenceId); + + // No callback should be added + EXPECT_FALSE(notifierClient->syncCallbackInfo_.Find(sequenceId).first); +} + +/** + * @tc.name: AddCloudSyncCallback_NullCallback_NoAddition + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KVDBNotifierClientVirtualTest, AddCloudSyncCallback_NullCallback_NoAddition, TestSize.Level0) +{ + ZLOGI("AddCloudSyncCallback_NullCallback_NoAddition begin."); + uint64_t sequenceId = 1; + notifierClient->AddCloudSyncCallback(sequenceId, nullptr); + + // No callback should be added + EXPECT_FALSE(notifierClient->cloudSyncCallbacks_.Find(sequenceId).first); +} + +/** + * @tc.name: AddSwitchCallback_NullObserver_NoAddition + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KVDBNotifierClientVirtualTest, AddSwitchCallback_NullObserver_NoAddition, TestSize.Level0) +{ + ZLOGI("AddSwitchCallback_NullObserver_NoAddition begin."); + notifierClient->AddSwitchCallback("appId", nullptr); + + // No observer should be added + EXPECT_EQ(notifierClient->switchObservers_.Size(), 0); +} + +/** + * @tc.name: AddSwitchCallback_DuplicateObserver_NoAddition + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KVDBNotifierClientVirtualTest, AddSwitchCallback_DuplicateObserver_NoAddition, TestSize.Level0) +{ + ZLOGI("AddSwitchCallback_DuplicateObserver_NoAddition begin."); + auto observer = make_shared(); + notifierClient->AddSwitchCallback("appId", observer); + notifierClient->AddSwitchCallback("appId", observer); + + // Only one observer should be added + EXPECT_EQ(notifierClient->switchObservers_.Size(), 1); +} + +/** + * @tc.name: OnSwitchChange_ObserversNotified + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KVDBNotifierClientVirtualTest, OnSwitchChange_ObserversNotified, TestSize.Level0) +{ + ZLOGI("OnSwitchChange_ObserversNotified begin."); + auto observer = make_shared(); + notifierClient->AddSwitchCallback("appId", observer); + + SwitchNotification notification; + notifierClient->OnSwitchChange(notification); + + EXPECT_TRUE(observer->onSwitchChangeCalled); +} + +/** + * @tc.name: OnRemoteRequest_ValidCodeAndDescriptor_ShouldInvokeHandler + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KVDBNotifierStubVirtualTest, OnRemoteRequest_ValidCodeAndDescriptor_ShouldInvokeHandler, TestSize.Level0) +{ + ZLOGI("OnRemoteRequest_ValidCodeAndDescriptor_ShouldInvokeHandler begin."); + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInterfaceToken(KVDBNotifierStub::GetDescriptor()); + data.WriteInt32(1); // å‡è®¾è¿™æ˜¯æœ‰æ•ˆçš„æ•°æ® + + EXPECT_CALL(*stub, OnSyncCompleted(testing::Ref(data), testing::_)).WillOnce(testing::Return(ERR_NONE)); + + int32_t result = + stub->OnRemoteRequest(static_cast(KVDBNotifierCode::SYNC_COMPLETED), data, reply, option); + EXPECT_EQ(result, ERR_NONE); +} + +/** + * @tc.name: OnRemoteRequest_InvalidDescriptor_ShouldReturnError + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KVDBNotifierStubVirtualTest, OnRemoteRequest_InvalidDescriptor_ShouldReturnError, TestSize.Level0) +{ + ZLOGI("OnRemoteRequest_InvalidDescriptor_ShouldReturnError begin."); + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInterfaceToken(u"InvalidDescriptor"); + + int32_t result = + stub->OnRemoteRequest(static_cast(KVDBNotifierCode::SYNC_COMPLETED), data, reply, option); + EXPECT_EQ(result, -1); +} + +/** + * @tc.name: OnRemoteRequest_CodeOutOfBound_ShouldReturnError + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KVDBNotifierStubVirtualTest, OnRemoteRequest_CodeOutOfBound_ShouldReturnError, TestSize.Level0) +{ + ZLOGI("OnRemoteRequest_CodeOutOfBound_ShouldReturnError begin."); + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInterfaceToken(KVDBNotifierStub::GetDescriptor()); + + int32_t result = + stub->OnRemoteRequest(static_cast(KVDBNotifierCode::TRANS_BUTT), data, reply, option); + EXPECT_EQ(result, + IPCObjectStub::OnRemoteRequest(static_cast(KVDBNotifierCode::TRANS_BUTT), data, reply, option)); +} + +/** + * @tc.name: OnSyncCompleted_ValidData_ShouldInvokeSyncCompleted + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KVDBNotifierStubVirtualTest, OnSyncCompleted_ValidData_ShouldInvokeSyncCompleted, TestSize.Level0) +{ + ZLOGI("OnSyncCompleted_ValidData_ShouldInvokeSyncCompleted begin."); + MessageParcel data; + MessageParcel reply; + std::map results = {{"key", Status::SUCCESS}}; + uint64_t sequenceId = 12345; + + EXPECT_CALL(ITypesUtil, Unmarshal(testing::Ref(data), testing::Ref(results), testing::Ref(sequenceId))) + .WillOnce(testing::Return(true)); + + EXPECT_CALL(*stub, SyncCompleted(testing::_, sequenceId)).Times(1); + + int32_t result = stub->OnSyncCompleted(data, reply); + EXPECT_EQ(result, ERR_NONE); +} + +/** + * @tc.name: OnSyncCompleted_InvalidData_ShouldReturnError + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(KVDBNotifierStubVirtualTest, OnSyncCompleted_InvalidData_ShouldReturnError, TestSize.Level0) +{ + ZLOGI("OnSyncCompleted_InvalidData_ShouldReturnError begin."); + MessageParcel data; + MessageParcel reply; + std::map results; + uint64_t sequenceId = 0; + + EXPECT_CALL(ITypesUtil, Unmarshal(testing::Ref(data), testing::Ref(results), testing::Ref(sequenceId))) + .WillOnce(testing::Return(false)); + + int32_t result = stub->OnSyncCompleted(data, reply); + EXPECT_EQ(result, IPC_STUB_INVALID_DATA_ERR); +} +} // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/databaseutils/test/kvstore_datashare_bridge_virtual_test.cpp b/kv_store/databaseutils/test/kvstore_datashare_bridge_virtual_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..659251ec58a21fdc37a53ec55fd41259436382be --- /dev/null +++ b/kv_store/databaseutils/test/kvstore_datashare_bridge_virtual_test.cpp @@ -0,0 +1,740 @@ +/* + * Copyright (c) 2022 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 "KvstoreDatashareBridgeVirtualTest" + +#include "distributed_kv_data_manager.h" +#include "gtest/gtest.h" +#include "kv_utils.h" +#include +#include +#include "kvstore_datashare_bridge.h" +#include "kvstore_result_set.h" +#include "result_set_bridge.h" +#include "store_errno.h" +#include "types.h" +#include "kvstore_observer_client.h" +#include "kvstore_observer.h" +#include "log_print.h" +#include +#include +#include +#include "kvstore_service_death_notifier.h" +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "kvstore_client_death_observer.h" +#include "datamgr_service_proxy.h" +#include "refbase.h" +#include "system_ability_definition.h" +#include "task_executor.h" + +using namespace testing::ext; +using namespace OHOS::DistributedKv; +using namespace OHOS::DataShare; +namespace OHOS::Test { +class BridgeWriterVirtual final : public ResultSetBridge::Writer { +public: + int AllocRow() override; + int WriteVirtual(uint32_t column) override; + int WriteVirtual(uint32_t column, int64_t value) override; + int WriteVirtual(uint32_t column, double value) override; + int WriteVirtual(uint32_t column, const uint8_t *value, size_t size) override; + int WriteVirtual(uint32_t column, const char *value, size_t size) override; + void SetAllocRowStatue(int status); + Key GetKey() const; + Key GetValue() const; + +private: + int allocStatus_Virtual = E_OK; + std::vector key_Virtual; + std::vector value_Virtual; +}; + +void BridgeWriterVirtual::SetAllocRowStatue(int status) +{ + allocStatus_Virtual = status; +} + +Key BridgeWriterVirtual::GetKey() const +{ + return key_Virtual; +} + +Value BridgeWriterVirtual::GetValue() const +{ + return value_Virtual; +} + +int BridgeWriterVirtual::AllocRow() +{ + return allocStatus_Virtual; +} + +int BridgeWriterVirtual::WriteVirtual(uint32_t column) +{ + return E_OK; +} + +int BridgeWriterVirtual::WriteVirtual(uint32_t column, int64_t value) +{ + return E_OK; +} + +int BridgeWriterVirtual::WriteVirtual(uint32_t column, double value) +{ + return E_OK; +} + +int BridgeWriterVirtual::WriteVirtual(uint32_t column, const uint8_t *value, size_t size) +{ + return E_OK; +} + +int BridgeWriterVirtual::WriteVirtual(uint32_t column, const char *value, size_t size) +{ + if (column < 0 || column > 1 || value == nullptr) { + return E_ERROR; + } + auto vec = std::vector(value, value + size - 1); + if (column == 0) { + key_Virtual.insert(key_Virtual.end(), vec.begin(), vec.end()); + } else { + value_Virtual.insert(value_Virtual.end(), vec.begin(), vec.end()); + } + return E_OK; +} + +class KvstoreDatashareBridgeVirtualTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp() {} + void TearDown() {} + +protected: + static DistributedKvDataManager managerVirtual; + static std::shared_ptr singleKvStoreVirtual; +}; +std::shared_ptr KvstoreDatashareBridgeVirtualTest::singleKvStoreVirtual = nullptr; +DistributedKvDataManager KvstoreDatashareBridgeVirtualTest::managerVirtual; +static constexpr int32_t INVALID_COUNT = -1; +static constexpr const char *VALID_SCHEMA_STRICT_DEFINE = "{\"SCHEMA_VERSION\":\"1.0\"," + "\"SCHEMA_MODE\":\"STRICT\"," + "\"SCHEMA_SKIPSIZE\":0," + "\"SCHEMA_DEFINE\":{" + "\"age\":\"INTEGER, NOT NULL\"" + "}," + "\"SCHEMA_INDEXES\":[\"$.age\"]}"; + +void KvstoreDatashareBridgeVirtualTest::SetUpTestCase(void) +{ + Options options = { .createIfMissing = true, .encrypt = false, .autoSync = false, + .kvStoreType = KvStoreType::SINGLE_VERSION, .schema = VALID_SCHEMA_STRICT_DEFINE }; + options.area = EL1; + options.securityLevel = S1; + options.baseDir = std::string("/data/service/el1/public/database/KvstoreDatashareBridgeVirtualTest"); + AppId appId = { "KvstoreDatashareBridgeVirtualTest" }; + StoreId storeId = { "test_single" }; + mkdir(options.baseDir.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); + managerVirtual.DeleteKvStore(appId, storeId, options.baseDir); + managerVirtual.GetSingleKvStore(options, appId, storeId, singleKvStoreVirtual); + EXPECT_NE(singleKvStoreVirtual, nullptr); + singleKvStoreVirtual->Put("test_key_1", "{\"age\":1}"); + singleKvStoreVirtual->Put("test_key_2", "{\"age\":2}"); + singleKvStoreVirtual->Put("test_key_3", "{\"age\":3}"); + singleKvStoreVirtual->Put("data_share", "{\"age\":4}"); +} + +void KvstoreDatashareBridgeVirtualTest::TearDownTestCase(void) +{ + managerVirtual.DeleteKvStore({"KvstoreDatashareBridgeVirtualTest"}, {"test_single"}, + "/data/service/el1/public/database/KvstoreDatashareBridgeVirtualTest"); + (void) remove("/data/service/el1/public/database/KvstoreDatashareBridgeVirtualTest/key"); + (void) remove("/data/service/el1/public/database/KvstoreDatashareBridgeVirtualTest/kvdb"); + (void) remove("/data/service/el1/public/database/KvstoreDatashareBridgeVirtualTest"); +} + +class MockKvStoreResultSet : public KvStoreResultSet { +public: + explicit MockKvStoreResultSet(int count) : count_(count) + { + } + + int GetCount() override + { + return count_; + } + + bool MoveToPosition(int pos) override + { + return pos >= 0 && pos < count_; + } + + Status GetEntry(Entry &entry) override + { + if (pos_ >= 0 && pos_ < count_) { + entry.key = Key("key" + std::to_string(pos_)); + entry.value = Value("value" + std::to_string(pos_)); + return Status::SUCCESS; + } + return Status::ERROR; + } + +private: + int count_; + int pos_ = -1; +}; + +class MockWriter : public ResultSetBridge::Writer { +public: + int AllocRow() override + { + return E_OK; + } + + int Write(int index, const char *data, int size) override + { + return E_OK; + } +}; + +class KvStoreObserverClientVirtualTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void KvStoreObserverClientVirtualTest::SetUpTestCase(void) +{} + +void KvStoreObserverClientVirtualTest::TearDownTestCase(void) +{} + +void KvStoreObserverClientVirtualTest::SetUp(void) +{} + +void KvStoreObserverClientVirtualTest::TearDown(void) +{} + +class MockKvStoreObserver : public KvStoreObserver { +public: + MOCK_METHOD1(OnChange, void(const ChangeNotification &changeNotification)); + MOCK_METHOD2(OnChange, void(const DataOrigin &origin, IKvStoreObserver::Keys &&keys)); +}; + +class KvStoreServiceDeathNotifierVirtualTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void KvStoreServiceDeathNotifierVirtualTest::SetUpTestCase(void) +{} + +void KvStoreServiceDeathNotifierVirtualTest::TearDownTestCase(void) +{} + +void KvStoreServiceDeathNotifierVirtualTest::SetUp(void) +{} + +void KvStoreServiceDeathNotifierVirtualTest::TearDown(void) +{} + +class MockSystemAbilityManager : public SystemAbilityManager { +public: + MOCK_METHOD(sptr, CheckSystemAbility, (int32_t), (override)); +}; + +class MockTaskExecutor : public TaskExecutor { +public: + MOCK_METHOD(void, Execute, (std::function), (override)); +}; + +class MockKvStoreDeathRecipient : public KvStoreDeathRecipient { +public: + MOCK_METHOD(void, OnRemoteDied, (), (override)); +}; + +class SyncObserverVirtualTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void SyncObserverVirtualTest::SetUpTestCase(void) +{} + +void SyncObserverVirtualTest::TearDownTestCase(void) +{} + +void SyncObserverVirtualTest::SetUp(void) +{} + +void SyncObserverVirtualTest::TearDown(void) +{} + +class MockKvStoreSyncCallback : public KvStoreSyncCallback { +public: + MOCK_METHOD1(SyncCompleted, void(const std::map &results)); +}; + +/** +* @tc.name: SyncCompleted_EmptyCallbacks_NoException +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(MockKvStoreSyncCallback, SyncCompleted_EmptyCallbacks_NoException, TestSize.Level0) +{ + ZLOGI("SyncCompleted_EmptyCallbacks_NoException begin."); + SyncObserver observer; + std::map results; + EXPECT_NO_THROW(observer.SyncCompleted(results)); +} + +/** +* @tc.name: SyncCompleted_NonEmptyCallbacks_CallbacksInvoked +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(MockKvStoreSyncCallback, SyncCompleted_NonEmptyCallbacks_CallbacksInvoked, TestSize.Level0) +{ + ZLOGI("SyncCompleted_NonEmptyCallbacks_CallbacksInvoked begin."); + SyncObserver observer; + auto mockCallback = std::make_shared(); + observer.Add(mockCallback); + + std::map results = {{"key1", Status::SUCCESS}}; + EXPECT_CALL(*mockCallback, SyncCompleted(results)).Times(1); + + observer.SyncCompleted(results); +} + +/** +* @tc.name: GetDistributedKvDataService_ProxyExists_ReturnsProxy +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvStoreServiceDeathNotifierVirtualTest, GetDistributedKvDataService_ProxyExists_ReturnsProxy, TestSize.Level0) +{ + ZLOGI("GetDistributedKvDataService_ProxyExists_ReturnsProxy begin."); + auto &instance = KvStoreServiceDeathNotifier::GetInstance(); + instance.kvDataServiceProxy_ = new DataMgrServiceProxy(nullptr); + + auto proxy = instance.GetDistributedKvDataService(); + + EXPECT_EQ(proxy, instance.kvDataServiceProxy_); +} + +/** +* @tc.name: GetDistributedKvDataService_ProxyDoesNotExist +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvStoreServiceDeathNotifierVirtualTest, GetDistributedKvDataService_ProxyDoesNotExist, TestSize.Level0) +{ + ZLOGI("GetDistributedKvDataService_ProxyDoesNotExist begin."); + auto &instance = KvStoreServiceDeathNotifier::GetInstance(); + instance.kvDataServiceProxy_ = nullptr; + + auto samgr = std::dynamic_pointer_cast( + SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager()); + auto remote = sptr(new RemoteObject("test")); + EXPECT_CALL(*samgr, CheckSystemAbility(DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID)).WillOnce(testing::Return(remote)); + + auto proxy = instance.GetDistributedKvDataService(); + + EXPECT_NE(proxy, nullptr); + EXPECT_NE(instance.kvDataServiceProxy_, nullptr); +} + +/** +* @tc.name: RegisterClientDeathObserver_ProxyExists +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvStoreServiceDeathNotifierVirtualTest, RegisterClientDeathObserver_ProxyExists, TestSize.Level0) +{ + ZLOGI("RegisterClientDeathObserver_ProxyExists begin."); + auto &instance = KvStoreServiceDeathNotifier::GetInstance(); + instance.kvDataServiceProxy_ = new DataMgrServiceProxy(nullptr); + + instance.RegisterClientDeathObserver(); + + EXPECT_NE(instance.clientDeathObserverPtr_, nullptr); +} + +/** +* @tc.name: AddServiceDeathWatcher_Success_AddsWatcher +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvStoreServiceDeathNotifierVirtualTest, AddServiceDeathWatcher_Success_AddsWatcher, TestSize.Level0) +{ + ZLOGI("AddServiceDeathWatcher_Success_AddsWatcher begin."); + auto &instance = KvStoreServiceDeathNotifier::GetInstance(); + auto watcher = std::make_shared(); + + instance.AddServiceDeathWatcher(watcher); + + EXPECT_EQ(instance.serviceDeathWatchers_.size(), 1); +} + +/** +* @tc.name: RemoveServiceDeathWatcher_Found_RemovesWatcher +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvStoreServiceDeathNotifierVirtualTest, RemoveServiceDeathWatcher_Found_RemovesWatcher, TestSize.Level0) +{ + ZLOGI("RemoveServiceDeathWatcher_Found_RemovesWatcher begin."); + auto &instance = KvStoreServiceDeathNotifier::GetInstance(); + auto watcher = std::make_shared(); + instance.serviceDeathWatchers_.insert(watcher); + + instance.RemoveServiceDeathWatcher(watcher); + + EXPECT_EQ(instance.serviceDeathWatchers_.size(), 0); +} + +/** +* @tc.name: ServiceDeathRecipient_OnRemoteDied_NotifiesWatchers +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvStoreServiceDeathNotifierVirtualTest, ServiceDeathRecipient_OnRemoteDied_NotifiesWatchers, TestSize.Level0) +{ + ZLOGI("ServiceDeathRecipient_OnRemoteDied_NotifiesWatchers begin."); + auto &instance = KvStoreServiceDeathNotifier::GetInstance(); + auto watcher = std::make_shared(); + instance.serviceDeathWatchers_.insert(watcher); + + auto executor = std::dynamic_pointer_cast(TaskExecutor::GetInstance().GetExecutor()); + EXPECT_CALL(*executor, Execute(testing::_)).WillOnce(testing::Invoke([](std::function task) { + task(); + })); + + instance.ServiceDeathRecipient().OnRemoteDied(nullptr); + + EXPECT_CALL(*watcher, OnRemoteDied()).Times(1); +} + +/** +* @tc.name: OnChange_ChangeNotification_KvStoreObserverNotNull +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvStoreObserverClientVirtualTest, OnChange_ChangeNotification_KvStoreObserverNotNull, TestSize.Level0) +{ + ZLOGI("OnChange_ChangeNotification_KvStoreObserverNotNull begin."); + ChangeNotification changeNotification; + EXPECT_CALL(*kvStoreObserver, OnChange(Ref(changeNotification))); + kvStoreObserverClient->OnChange(changeNotification); +} + +/** +* @tc.name: OnChange_ChangeNotification_KvStoreObserverNull +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvStoreObserverClientVirtualTest, OnChange_ChangeNotification_KvStoreObserverNull, TestSize.Level0) +{ + ZLOGI("OnChange_ChangeNotification_KvStoreObserverNull begin."); + kvStoreObserverClient = std::make_shared(nullptr); + ChangeNotification changeNotification; + EXPECT_CALL(*kvStoreObserver, OnChange(Ref(changeNotification))).Times(0); + kvStoreObserverClient->OnChange(changeNotification); +} + +/** +* @tc.name: OnChange_DataOriginAndKeys_KvStoreObserverNotNull +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvStoreObserverClientVirtualTest, OnChange_DataOriginAndKeys_KvStoreObserverNotNull, TestSize.Level0) +{ + ZLOGI("OnChange_DataOriginAndKeys_KvStoreObserverNotNull begin."); + DataOrigin origin; + IKvStoreObserver::Keys keys; + EXPECT_CALL(*kvStoreObserver, OnChange(Ref(origin), Ref(keys))); + kvStoreObserverClient->OnChange(origin, std::move(keys)); +} + +/** +* @tc.name: OnChange_DataOriginAndKeys_KvStoreObserverNull +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvStoreObserverClientVirtualTest, OnChange_DataOriginAndKeys_KvStoreObserverNull, TestSize.Level0) +{ + ZLOGI("OnChange_DataOriginAndKeys_KvStoreObserverNull begin."); + kvStoreObserverClient = std::make_shared(nullptr); + DataOrigin origin; + IKvStoreObserver::Keys keys; + EXPECT_CALL(*kvStoreObserver, OnChange(Ref(origin), Ref(keys))).Times(0); + kvStoreObserverClient->OnChange(origin, std::move(keys)); +} + +/** +* @tc.name: GetRowCountByInvalidBridge +* @tc.desc: get row countVirtual, the kvStore resultSetVirtual is nullptr +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvstoreDatashareBridgeVirtualTest, GetRowCountByInvalidBridge, TestSize.Level0) +{ + ZLOGI("GetRowCountByInvalidBridge begin."); + auto bridgeVirtual = std::make_shared(nullptr); + int32_t countVirtual; + auto resultVirtual = bridgeVirtual->GetRowCount(countVirtual); + EXPECT_EQ(resultVirtual, E_ERROR); + EXPECT_EQ(countVirtual, INVALID_COUNT); + std::vector columnNames; + resultVirtual = bridgeVirtual->GetAllColumnNames(columnNames); + EXPECT_FALSE(columnNames.empty()); + EXPECT_EQ(resultVirtual, E_OK); +} + +/** +* @tc.name: KvStoreResultSetToDataShareResultSetAbnormal +* @tc.desc: kvStore resultSetVirtual to dataShare resultSetVirtual, the former has invalid predicate +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvstoreDatashareBridgeVirtualTest, KvStoreResultSetToDataShareResultSetAbnormal, TestSize.Level0) +{ + ZLOGI("KvStoreResultSetToDataShareResultSetAbnormal begin."); + std::shared_ptr resultSetVirtual = nullptr; + DataQuery queryVirtual; + queryVirtual.KeyPrefix("key"); + singleKvStoreVirtual->GetResultSet(queryVirtual, resultSetVirtual); + EXPECT_NE(resultSetVirtual, nullptr); + auto bridgeVirtual = KvUtils::ToResultSetBridge(resultSetVirtual); + int32_t countVirtual; + auto resultVirtual = bridgeVirtual->GetRowCount(countVirtual); + EXPECT_EQ(resultVirtual, E_OK); + EXPECT_EQ(countVirtual, 0); +} + +/** +* @tc.name: KvStoreResultSetToDataShareResultSetNormal +* @tc.desc: kvStore resultSetVirtual to dataShare resultSetVirtual, the former has valid predicate +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvstoreDatashareBridgeVirtualTest, KvStoreResultSetToDataShareResultSetNormal, TestSize.Level0) +{ + ZLOGI("KvStoreResultSetToDataShareResultSetNormal begin."); + DataQuery queryVirtual; + queryVirtual.KeyPrefix("test"); + std::shared_ptr resultSetVirtual = nullptr; + singleKvStoreVirtual->GetResultSet(queryVirtual, resultSetVirtual); + EXPECT_NE(resultSetVirtual, nullptr); + auto bridgeVirtual = KvUtils::ToResultSetBridge(resultSetVirtual); + int32_t countVirtual; + auto resultVirtual = bridgeVirtual->GetRowCount(countVirtual); + EXPECT_EQ(resultVirtual, E_OK); + EXPECT_EQ(countVirtual, 3); + countVirtual = -1; + bridgeVirtual->GetRowCount(countVirtual); + EXPECT_EQ(countVirtual, 3); +} + +/** +* @tc.name: BridgeOnGoAbnormal +* @tc.desc: bridgeVirtual on go, the input parameter is invalid +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvstoreDatashareBridgeVirtualTest, BridgeOnGoAbnormal, TestSize.Level0) +{ + ZLOGI("BridgeOnGoAbnormal begin."); + DataQuery queryVirtual; + queryVirtual.KeyPrefix("test"); + std::shared_ptr resultSetVirtual = nullptr; + singleKvStoreVirtual->GetResultSet(queryVirtual, resultSetVirtual); + EXPECT_NE(resultSetVirtual, nullptr); + auto bridgeVirtual = KvUtils::ToResultSetBridge(resultSetVirtual); + int32_t startVirtual = -1; + int32_t targetVirtual = 0; + BridgeWriterVirtual writerVirtual; + EXPECT_EQ(bridgeVirtual->OnGo(startVirtual, targetVirtual, writerVirtual), -1); + EXPECT_TRUE(writerVirtual.GetKey().Empty()); + EXPECT_TRUE(writerVirtual.GetValue().Empty()); + startVirtual = 0; + targetVirtual = -1; + EXPECT_EQ(bridgeVirtual->OnGo(startVirtual, targetVirtual, writerVirtual), -1); + EXPECT_TRUE(writerVirtual.GetKey().Empty()); + EXPECT_TRUE(writerVirtual.GetValue().Empty()); + startVirtual = 1; + targetVirtual = 0; + EXPECT_EQ(bridgeVirtual->OnGo(startVirtual, targetVirtual, writerVirtual), -1); + EXPECT_TRUE(writerVirtual.GetKey().Empty()); + EXPECT_TRUE(writerVirtual.GetValue().Empty()); + startVirtual = 1; + targetVirtual = 3; + EXPECT_EQ(bridgeVirtual->OnGo(startVirtual, targetVirtual, writerVirtual), -1); + EXPECT_TRUE(writerVirtual.GetKey().Empty()); + EXPECT_TRUE(writerVirtual.GetValue().Empty()); +} + +/** +* @tc.name: BridgeOnGoNormal +* @tc.desc: bridgeVirtual on go, the input parameter is valid +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvstoreDatashareBridgeVirtualTest, BridgeOnGoNormal, TestSize.Level0) +{ + ZLOGI("BridgeOnGoNormal begin."); + DataQuery queryVirtual; + queryVirtual.KeyPrefix("test"); + std::shared_ptr resultSetVirtual = nullptr; + singleKvStoreVirtual->GetResultSet(queryVirtual, resultSetVirtual); + EXPECT_NE(resultSetVirtual, nullptr); + auto bridgeVirtual = KvUtils::ToResultSetBridge(resultSetVirtual); + int startVirtual = 0; + int targetVirtual = 2; + BridgeWriterVirtual writerVirtual; + writerVirtual.SetAllocRowStatue(E_ERROR); + EXPECT_EQ(bridgeVirtual->OnGo(startVirtual, targetVirtual, writerVirtual), -1); + EXPECT_TRUE(writerVirtual.GetKey().Empty()); + EXPECT_TRUE(writerVirtual.GetValue().Empty()); + writerVirtual.SetAllocRowStatue(E_OK); + EXPECT_EQ(bridgeVirtual->OnGo(startVirtual, targetVirtual, writerVirtual), targetVirtual); + size_t keySize = 0; + size_t valueSize = 0; + for (auto i = startVirtual; i <= targetVirtual; i++) { + resultSetVirtual->MoveToPosition(i); + Entry entry; + resultSetVirtual->GetEntry(entry); + keySize += entry.key.Size(); + valueSize += entry.value.Size(); + } + EXPECT_EQ(writerVirtual.GetKey().Size(), keySize); + EXPECT_EQ(writerVirtual.GetValue().Size(), valueSize); +} + +/** +* @tc.name: OnGo_ValidIndices_FillAllRows +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvstoreDatashareBridgeVirtualTest, OnGo_ValidIndices_FillAllRows, TestSize.Level0) +{ + ZLOGI("OnGo_ValidIndices_FillAllRows begin."); + MockWriter writer; + int result = bridge->OnGo(0, 5, writer); + EXPECT_EQ(result, 5); +} + +/** +* @tc.name: OnGo_InvalidStartIndex_ReturnsError +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvstoreDatashareBridgeVirtualTest, OnGo_InvalidStartIndex_ReturnsError, TestSize.Level0) +{ + ZLOGI("OnGo_InvalidStartIndex_ReturnsError begin."); + MockWriter writer; + int result = bridge->OnGo(-1, 5, writer); + EXPECT_EQ(result, -1); +} + +/** +* @tc.name: OnGo_InvalidTargetIndex_ReturnsError +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvstoreDatashareBridgeVirtualTest, OnGo_InvalidTargetIndex_ReturnsError, TestSize.Level0) +{ + ZLOGI("OnGo_InvalidTargetIndex_ReturnsError begin."); + MockWriter writer; + int result = bridge->OnGo(0, 15, writer); + EXPECT_EQ(result, -1); +} + +/** +* @tc.name: OnGo_StartGreaterThanTarget_ReturnsError +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvstoreDatashareBridgeVirtualTest, OnGo_StartGreaterThanTarget_ReturnsError, TestSize.Level0) +{ + ZLOGI("OnGo_StartGreaterThanTarget_ReturnsError begin."); + MockWriter writer; + int result = bridge->OnGo(5, 0, writer); + EXPECT_EQ(result, -1); +} + +/** +* @tc.name: OnGo_FillBlockFails_ReturnsPartialFill +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(KvstoreDatashareBridgeVirtualTest, OnGo_FillBlockFails_ReturnsPartialFill, TestSize.Level0) +{ + ZLOGI("OnGo_FillBlockFails_ReturnsPartialFill begin."); + kvResultSet = std::make_shared(1); + bridge = std::make_shared(kvResultSet); + + MockWriter writer; + int result = bridge->OnGo(0, 5, writer); + EXPECT_EQ(result, 0); +} +} // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/databaseutils/test/local_kv_store_counterfeit_unit_test.cpp b/kv_store/databaseutils/test/local_kv_store_counterfeit_unit_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..930e0e747313b2bb472ed1dc6a7bc053c1dc285e --- /dev/null +++ b/kv_store/databaseutils/test/local_kv_store_counterfeit_unit_test.cpp @@ -0,0 +1,1962 @@ +/* + * Copyright (c) 2024 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 "LocalKvStoreCounterfeitUnitTest" + +#include "block_data.h" +#include "distributed_kv_data_manager.h" +#include "log_print.h" +#include "types.h" +#include +#include +#include +#include + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::DistributedKv; +class LocalKvStoreCounterfeitUnitTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + + static DistributedKvDataManager counterfeitTestManger_; + static std::shared_ptr counterfeitTestStore_; + static Status counterfeitTestStatus_; + static AppId counterfeitTestAppId_; + static StoreId counterfeitTestStoreId_; +}; +std::shared_ptr LocalKvStoreCounterfeitUnitTest::counterfeitTestStore_ = nullptr; +Status LocalKvStoreCounterfeitUnitTest::counterfeitTestStatus_ = Status::ERROR; +DistributedKvDataManager LocalKvStoreCounterfeitUnitTest::counterfeitTestManger_; +AppId LocalKvStoreCounterfeitUnitTest::counterfeitTestAppId_; +StoreId LocalKvStoreCounterfeitUnitTest::counterfeitTestStoreId_; + +void LocalKvStoreCounterfeitUnitTest::SetUpTestCase(void) +{ + mkdir("/data/service/el1/public/database/local", (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); +} + +void LocalKvStoreCounterfeitUnitTest::TearDownTestCase(void) +{ + counterfeitTestManger_.CloseKvStore(counterfeitTestAppId_, counterfeitTestStore_); + counterfeitTestStore_ = nullptr; + counterfeitTestManger_.DeleteKvStore(counterfeitTestAppId_, + counterfeitTestStoreId_, "/data/service/el1/public/database/local"); + (void)remove("/data/service/el1/public/database/local/kvdb"); + (void)remove("/data/service/el1/public/database/local"); +} + +void LocalKvStoreCounterfeitUnitTest::SetUp(void) +{ + Options counterfeitOptions; + counterfeitOptions.securityLevel = S1; + counterfeitOptions.baseDir = std::string("/data/service/el1/public/database/local"); + counterfeitTestAppId_.appId = "local"; // define app name. + counterfeitTestStoreId_.storeId = "MAN"; // define kvstore(database) name + counterfeitTestManger_.DeleteKvStore(counterfeitTestAppId_, counterfeitTestStoreId_, counterfeitOptions.baseDir); + // [create and] open and initialize kvstore instance. + counterfeitTestStatus_ = counterfeitTestManger_.GetSingleKvStore(counterfeitOptions, + counterfeitTestAppId_, counterfeitTestStoreId_, counterfeitTestStore_); + ASSERT_EQ(Status::SUCCESS, counterfeitTestStatus_) << "wrong status"; + ASSERT_NE(nullptr, counterfeitTestStore_) << "kvStore is nullptr"; +} + +void LocalKvStoreCounterfeitUnitTest::TearDown(void) +{ + counterfeitTestManger_.CloseKvStore(counterfeitTestAppId_, counterfeitTestStore_); + counterfeitTestStore_ = nullptr; + counterfeitTestManger_.DeleteKvStore(counterfeitTestAppId_, counterfeitTestStoreId_); +} + +class DeviceObserverCounterfeitUnitTest : public KvStoreObserver { +public: + std::vector insertCounterfeitEntries_; + std::vector updateCounterfeitEntries_; + std::vector deleteCounterfeitEntries_; + std::string counterfeitDeviceId_; + bool isCounterfeitClear_ = false; + DeviceObserverCounterfeitUnitTest(); + ~DeviceObserverCounterfeitUnitTest() = default; + + void OnChange(const ChangeNotification &changeNotification); + + // reset the counterfeitCallCount_ to zero. + void ResetToZero(); + + uint32_t GetCallCount(uint32_t counterfeitTestValue = 1); + +private: + std::mutex counterfeitMutex_; + uint32_t counterfeitCallCount_ = 0; + BlockData counterfeitValue_ { 1, 0 }; +}; + +DeviceObserverCounterfeitUnitTest::DeviceObserverCounterfeitUnitTest() { } + +void DeviceObserverCounterfeitUnitTest::OnChange(const ChangeNotification &changeNotification) +{ + ZLOGD("begin."); + insertCounterfeitEntries_ = changeNotification.GetInsertEntries(); + updateCounterfeitEntries_ = changeNotification.GetUpdateEntries(); + deleteCounterfeitEntries_ = changeNotification.GetDeleteEntries(); + counterfeitDeviceId_ = changeNotification.GetDeviceId(); + isCounterfeitClear_ = changeNotification.IsClear(); + std::lock_guard guard(counterfeitMutex_); + ++counterfeitCallCount_; + counterfeitValue_.SetValue(counterfeitCallCount_); +} + +void DeviceObserverCounterfeitUnitTest::ResetToZero() +{ + std::lock_guard guard(counterfeitMutex_); + counterfeitCallCount_ = 0; + counterfeitValue_.Clear(0); +} + +uint32_t DeviceObserverCounterfeitUnitTest::GetCallCount(uint32_t counterfeitTestValue) +{ + int retryTimes = 0; + uint32_t callCount = 0; + while (retryTimes < counterfeitTestValue) { + callCount = counterfeitValue_.GetValue(); + if (callCount >= counterfeitTestValue) { + break; + } + std::lock_guard guard(counterfeitMutex_); + callCount = counterfeitValue_.GetValue(); + if (callCount >= counterfeitTestValue) { + break; + } + counterfeitValue_.Clear(callCount); + retryTimes++; + } + return callCount; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore001 + * @tc.desc: Subscribe success + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStore001, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore001 begin."); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + auto counterfeitObserver = std::make_shared(); + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 0); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; + counterfeitObserver = nullptr; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore002 + * @tc.desc: Subscribe fail, counterfeitObserver is null + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStore002, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore002 begin."); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + std::shared_ptr counterfeitObserver = nullptr; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::INVALID_ARGUMENT, counterfeitStatus) << "SubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore003 + * @tc.desc: Subscribe success and OnChange callback after put + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStore003, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore003 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + Key counterfeitTestKey = "Id1"; + Value counterfeitTestValue = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey, counterfeitTestValue); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; + counterfeitObserver = nullptr; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore004 + * @tc.desc: The same counterfeitObserver subscribe three times and OnChange callback after put + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStore004, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore004 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::STORE_ALREADY_SUBSCRIBE, counterfeitStatus) << "SubscribeKvStore return wrong"; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::STORE_ALREADY_SUBSCRIBE, counterfeitStatus) << "SubscribeKvStore return wrong"; + + Key counterfeitTestKey = "Id1"; + Value counterfeitTestValue = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey, counterfeitTestValue); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore005 + * @tc.desc: The different counterfeitObserver subscribe three times and OnChange callback after put + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStore005, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore005 begin."); + auto observer1 = std::make_shared(); + auto observer2 = std::make_shared(); + auto observer3 = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, observer1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore failed, wrong"; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, observer2); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore failed, wrong"; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, observer3); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore failed, wrong"; + + Key counterfeitTestKey = "Id1"; + Value counterfeitTestValue = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey, counterfeitTestValue); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "Putting data to KvStore failed, wrong"; + ASSERT_EQ(static_cast(observer1->GetCallCount()), 1); + ASSERT_EQ(static_cast(observer2->GetCallCount()), 1); + ASSERT_EQ(static_cast(observer3->GetCallCount()), 1); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, observer1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, observer2); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, observer3); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore006 + * @tc.desc: Unsubscribe an counterfeitObserver and subscribe again - the map should be cleared after unsubscription. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStore006, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore006 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + Key counterfeitTestKey1 = "Id1"; + Value counterfeitTestValue1 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey1, counterfeitTestValue1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; + + Key counterfeitTestKey2 = "Id2"; + Value counterfeitTestValue2 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey2, counterfeitTestValue2); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + + counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + Key counterfeitTestKey3 = "Id3"; + Value counterfeitTestValue3 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey3, counterfeitTestValue3); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount(2)), 2); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore007 + * @tc.desc: Subscribe to an counterfeitObserver - OnChange callback is called multiple times after the put operation. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStore007, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore007 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + Key counterfeitTestKey1 = "Id1"; + Value counterfeitTestValue1 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey1, counterfeitTestValue1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + + Key counterfeitTestKey2 = "Id2"; + Value counterfeitTestValue2 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey2, counterfeitTestValue2); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + + Key counterfeitTestKey3 = "Id3"; + Value counterfeitTestValue3 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey3, counterfeitTestValue3); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount(3)), 3); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore008 +* @tc.desc: Subscribe to an counterfeitObserver - OnChange callback is + called multiple times after the put&update operations. +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStore008, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore008 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + Key counterfeitTestKey1 = "Id1"; + Value counterfeitTestValue1 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey1, counterfeitTestValue1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + + Key counterfeitTestKey2 = "Id2"; + Value counterfeitTestValue2 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey2, counterfeitTestValue2); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + + Key counterfeitTestKey3 = "Id1"; + Value counterfeitTestValue3 = "subscribe03"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey3, counterfeitTestValue3); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount(3)), 3); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore009 + * @tc.desc: Subscribe to an counterfeitObserver - OnChange + * callback is called multiple times after the putBatch operation. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStore009, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore009 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + // before update. + std::vector counterfeitTestEntries1; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries1.push_back(counterfeitTestEnty1); + counterfeitTestEntries1.push_back(counterfeitTestEnty2); + counterfeitTestEntries1.push_back(counterfeitTestEnty3); + + std::vector counterfeitTestEntries2; + Entry counterfeitTestEnty4, counterfeitTestEnty5; + counterfeitTestEnty4.counterfeitTestKey = "Id4"; + counterfeitTestEnty4.counterfeitTestValue = "subscribe"; + counterfeitTestEnty5.counterfeitTestKey = "Id5"; + counterfeitTestEnty5.counterfeitTestValue = "subscribe"; + counterfeitTestEntries2.push_back(counterfeitTestEnty4); + counterfeitTestEntries2.push_back(counterfeitTestEnty5); + + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries2); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount(2)), 2); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore010 +* @tc.desc: Subscribe to an counterfeitObserver - OnChange callback is + called multiple times after the putBatch update operation. +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStore010, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore010 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + // before update. + std::vector counterfeitTestEntries1; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries1.push_back(counterfeitTestEnty1); + counterfeitTestEntries1.push_back(counterfeitTestEnty2); + counterfeitTestEntries1.push_back(counterfeitTestEnty3); + + std::vector counterfeitTestEntries2; + Entry counterfeitTestEnty4, counterfeitTestEnty5; + counterfeitTestEnty4.counterfeitTestKey = "Id1"; + counterfeitTestEnty4.counterfeitTestValue = "modify"; + counterfeitTestEnty5.counterfeitTestKey = "Id2"; + counterfeitTestEnty5.counterfeitTestValue = "modify"; + counterfeitTestEntries2.push_back(counterfeitTestEnty4); + counterfeitTestEntries2.push_back(counterfeitTestEnty5); + + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries2); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount(2)), 2); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore011 + * @tc.desc: Subscribe to an counterfeitObserver - OnChange callback is called after successful deletion. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStore011, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore011 begin."); + auto counterfeitObserver = std::make_shared(); + std::vector counterfeitTestEntries; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitTestEntries.push_back(counterfeitTestEnty3); + + Status counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + counterfeitStatus = counterfeitTestStore_->Delete("Id1"); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore Delete data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore012 + * @tc.desc: Subscribe to an counterfeitObserver - OnChange callback is not called after deletion of non-existing keys. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStore012, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore012 begin."); + auto counterfeitObserver = std::make_shared(); + std::vector counterfeitTestEntries; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitTestEntries.push_back(counterfeitTestEnty3); + + Status counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + counterfeitStatus = counterfeitTestStore_->Delete("Id4"); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore Delete data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 0); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore013 + * @tc.desc: Subscribe to an counterfeitObserver - OnChange callback is called after KvStore is cleared. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStore013, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore013 begin."); + auto counterfeitObserver = std::make_shared(); + std::vector counterfeitTestEntries; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitTestEntries.push_back(counterfeitTestEnty3); + + Status counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 0); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore014 +* @tc.desc: Subscribe to an counterfeitObserver - OnChange callback is + not called after non-existing data in KvStore is cleared. +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStore014, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore014 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 0); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore015 + * @tc.desc: Subscribe to an counterfeitObserver - OnChange callback is called after the deleteBatch operation. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStore015, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore015 begin."); + auto counterfeitObserver = std::make_shared(); + std::vector counterfeitTestEntries; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitTestEntries.push_back(counterfeitTestEnty3); + + std::vector keys; + keys.push_back("Id1"); + keys.push_back("Id2"); + + Status counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + counterfeitStatus = counterfeitTestStore_->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore DeleteBatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore016 + * @tc.desc: Subscribe to an counterfeitObserver - OnChange callback is called after deleteBatch of non-existing keys. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStore016, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore016 begin."); + auto counterfeitObserver = std::make_shared(); + std::vector counterfeitTestEntries; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitTestEntries.push_back(counterfeitTestEnty3); + + std::vector keys; + keys.push_back("Id4"); + keys.push_back("Id5"); + + Status counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + counterfeitStatus = counterfeitTestStore_->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore DeleteBatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 0); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore020 + * @tc.desc: Unsubscribe an counterfeitObserver two times. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStore020, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore020 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::STORE_NOT_SUBSCRIBE, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification001 +* @tc.desc: Subscribe to an counterfeitObserver successfully - callback is + called with a notification after the put operation. +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification001, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification001 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + Key counterfeitTestKey = "Id1"; + Value counterfeitTestValue = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey, counterfeitTestValue); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ZLOGD("kvstore_ddm_subscribekvstore_003"); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id1", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + ZLOGD("kvstore_ddm_subscribekvstore_003 size:%zu.", counterfeitObserver->insertCounterfeitEntries_.size()); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification002 +* @tc.desc: Subscribe to the same counterfeitObserver three times - callback is + called with a notification after the put operation. +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification002, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification002 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::STORE_ALREADY_SUBSCRIBE, counterfeitStatus) << "SubscribeKvStore return wrong"; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::STORE_ALREADY_SUBSCRIBE, counterfeitStatus) << "SubscribeKvStore return wrong"; + + Key counterfeitTestKey = "Id1"; + Value counterfeitTestValue = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey, counterfeitTestValue); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id1", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification003 + * @tc.desc: The different counterfeitObserver subscribe three times and callback with notification after put + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification003, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification003 begin."); + auto observer1 = std::make_shared(); + auto observer2 = std::make_shared(); + auto observer3 = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, observer1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, observer2); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, observer3); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + Key counterfeitTestKey = "Id1"; + Value counterfeitTestValue = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey, counterfeitTestValue); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(observer1->GetCallCount()), 1); + ASSERT_EQ(static_cast(observer1->insertCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id1", observer1->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", observer1->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + ASSERT_EQ(static_cast(observer2->GetCallCount()), 1); + ASSERT_EQ(static_cast(observer2->insertCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id1", observer2->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", observer2->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + ASSERT_EQ(static_cast(observer3->GetCallCount()), 1); + ASSERT_EQ(static_cast(observer3->insertCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id1", observer3->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", observer3->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, observer1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, observer2); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, observer3); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification004 + * @tc.desc: Verify notification after an counterfeitObserver is unsubscribed and then subscribed again. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification004, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification004 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + Key counterfeitTestKey1 = "Id1"; + Value counterfeitTestValue1 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey1, counterfeitTestValue1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id1", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; + + Key counterfeitTestKey2 = "Id2"; + Value counterfeitTestValue2 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey2, counterfeitTestValue2); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id1", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + Key counterfeitTestKey3 = "Id3"; + Value counterfeitTestValue3 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey3, counterfeitTestValue3); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id3", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification005 + * @tc.desc: Subscribe to an counterfeitObserver, callback with notification many times after put the different data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification005, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification005 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + Key counterfeitTestKey1 = "Id1"; + Value counterfeitTestValue1 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey1, counterfeitTestValue1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id1", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + Key counterfeitTestKey2 = "Id2"; + Value counterfeitTestValue2 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey2, counterfeitTestValue2); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id2", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + Key counterfeitTestKey3 = "Id3"; + Value counterfeitTestValue3 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey3, counterfeitTestValue3); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount(3)), 3); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id3", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification006 + * @tc.desc: Subscribe to an counterfeitObserver, callback with notification many times after put the same data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification006, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification006 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + Key counterfeitTestKey1 = "Id1"; + Value counterfeitTestValue1 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey1, counterfeitTestValue1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id1", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + Key counterfeitTestKey2 = "Id1"; + Value counterfeitTestValue2 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey2, counterfeitTestValue2); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(counterfeitObserver->updateCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id1", counterfeitObserver->updateCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->updateCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + Key counterfeitTestKey3 = "Id1"; + Value counterfeitTestValue3 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey3, counterfeitTestValue3); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount(3)), 3); + ASSERT_EQ(static_cast(counterfeitObserver->updateCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id1", counterfeitObserver->updateCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->updateCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification007 + * @tc.desc: Subscribe to an counterfeitObserver, callback with notification many times after put&update + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification007, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification007 begin."); + auto counterfeitObserver = std::make_shared(); + Key counterfeitTestKey1 = "Id1"; + Value counterfeitTestValue1 = "subscribe"; + Status counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey1, counterfeitTestValue1); + + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + + Key counterfeitTestKey2 = "Id2"; + Value counterfeitTestValue2 = "subscribe"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey2, counterfeitTestValue2); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + Key counterfeitTestKey3 = "Id1"; + Value counterfeitTestValue3 = "subscribe03"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey3, counterfeitTestValue3); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->updateCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id1", counterfeitObserver->updateCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe03", counterfeitObserver->updateCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification008 + * @tc.desc: Subscribe to an counterfeitObserver, callback with notification one times after putbatch&update + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification008, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification008 begin."); + std::vector counterfeitTestEntries; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitTestEntries.push_back(counterfeitTestEnty3); + + Status counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + counterfeitTestEntries.clear(); + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe_modify"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe_modify"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->updateCounterfeitEntries_.size()), 2); + ASSERT_EQ("Id1", counterfeitObserver->updateCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe_modify", counterfeitObserver->updateCounterfeitEntries_[0].counterfeitTestValue.ToString()); + ASSERT_EQ("Id2", counterfeitObserver->updateCounterfeitEntries_[1].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe_modify", counterfeitObserver->updateCounterfeitEntries_[1].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification009 + * @tc.desc: Subscribe to an counterfeitObserver, callback with notification one times after putbatch all different data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification009, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification009 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + std::vector counterfeitTestEntries; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitTestEntries.push_back(counterfeitTestEnty3); + + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 3); + ASSERT_EQ("Id1", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + ASSERT_EQ("Id2", counterfeitObserver->insertCounterfeitEntries_[1].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[1].counterfeitTestValue.ToString()); + ASSERT_EQ("Id3", counterfeitObserver->insertCounterfeitEntries_[2].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[2].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification010 +* @tc.desc: Subscribe to an counterfeitObserver, + callback with notification one times after putbatch both different and same data +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification010, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification010 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + std::vector counterfeitTestEntries; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id1"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id2"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitTestEntries.push_back(counterfeitTestEnty3); + + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 2); + ASSERT_EQ("Id1", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + ASSERT_EQ("Id2", counterfeitObserver->insertCounterfeitEntries_[1].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[1].counterfeitTestValue.ToString()); + ASSERT_EQ(static_cast(counterfeitObserver->updateCounterfeitEntries_.size()), 0); + ASSERT_EQ(static_cast(counterfeitObserver->deleteCounterfeitEntries_.size()), 0); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification011 + * @tc.desc: Subscribe to an counterfeitObserver, callback with notification one times after putbatch all same data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification011, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification011 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + std::vector counterfeitTestEntries; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id1"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id1"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitTestEntries.push_back(counterfeitTestEnty3); + + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id1", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + ASSERT_EQ(static_cast(counterfeitObserver->updateCounterfeitEntries_.size()), 0); + ASSERT_EQ(static_cast(counterfeitObserver->deleteCounterfeitEntries_.size()), 0); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification012 + * @tc.desc: Subscribe to an observer, callback with notification many times after putbatch all different data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification012, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification012 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + std::vector counterfeitTestEntries1; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries1.push_back(counterfeitTestEnty1); + counterfeitTestEntries1.push_back(counterfeitTestEnty2); + counterfeitTestEntries1.push_back(counterfeitTestEnty3); + + std::vector counterfeitTestEntries2; + Entry counterfeitTestEnty4, counterfeitTestEnty5; + counterfeitTestEnty4.counterfeitTestKey = "Id4"; + counterfeitTestEnty4.counterfeitTestValue = "subscribe"; + counterfeitTestEnty5.counterfeitTestKey = "Id5"; + counterfeitTestEnty5.counterfeitTestValue = "subscribe"; + counterfeitTestEntries2.push_back(counterfeitTestEnty4); + counterfeitTestEntries2.push_back(counterfeitTestEnty5); + + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 3); + ASSERT_EQ("Id1", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + ASSERT_EQ("Id2", counterfeitObserver->insertCounterfeitEntries_[1].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[1].counterfeitTestValue.ToString()); + ASSERT_EQ("Id3", counterfeitObserver->insertCounterfeitEntries_[2].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[2].counterfeitTestValue.ToString()); +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification012b + * @tc.desc: Subscribe to an observer, callback with notification many times after putbatch all different data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification012b, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification012b begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + std::vector counterfeitTestEntries1; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries1.push_back(counterfeitTestEnty1); + counterfeitTestEntries1.push_back(counterfeitTestEnty2); + counterfeitTestEntries1.push_back(counterfeitTestEnty3); + + std::vector counterfeitTestEntries2; + Entry counterfeitTestEnty4, counterfeitTestEnty5; + counterfeitTestEnty4.counterfeitTestKey = "Id4"; + counterfeitTestEnty4.counterfeitTestValue = "subscribe"; + counterfeitTestEnty5.counterfeitTestKey = "Id5"; + counterfeitTestEnty5.counterfeitTestValue = "subscribe"; + counterfeitTestEntries2.push_back(counterfeitTestEnty4); + counterfeitTestEntries2.push_back(counterfeitTestEnty5); + + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries2); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 2); + ASSERT_EQ("Id4", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + ASSERT_EQ("Id5", counterfeitObserver->insertCounterfeitEntries_[1].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[1].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification013 +* @tc.desc: Subscribe to an counterfeitObserver, + callback with notification many times after putbatch both different and same data +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification013, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification013 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + std::vector counterfeitTestEntries1; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries1.push_back(counterfeitTestEnty1); + counterfeitTestEntries1.push_back(counterfeitTestEnty2); + counterfeitTestEntries1.push_back(counterfeitTestEnty3); + + std::vector counterfeitTestEntries2; + Entry counterfeitTestEnty4, counterfeitTestEnty5; + counterfeitTestEnty4.counterfeitTestKey = "Id1"; + counterfeitTestEnty4.counterfeitTestValue = "subscribe"; + counterfeitTestEnty5.counterfeitTestKey = "Id4"; + counterfeitTestEnty5.counterfeitTestValue = "subscribe"; + counterfeitTestEntries2.push_back(counterfeitTestEnty4); + counterfeitTestEntries2.push_back(counterfeitTestEnty5); + + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 3); + ASSERT_EQ("Id1", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + ASSERT_EQ("Id2", counterfeitObserver->insertCounterfeitEntries_[1].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[1].counterfeitTestValue.ToString()); + ASSERT_EQ("Id3", counterfeitObserver->insertCounterfeitEntries_[2].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[2].counterfeitTestValue.ToString()); +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification013b +* @tc.desc: Subscribe to an counterfeitObserver, + callback with notification many times after putbatch both different and same data +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification013b, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification013b begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + std::vector counterfeitTestEntries1; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries1.push_back(counterfeitTestEnty1); + counterfeitTestEntries1.push_back(counterfeitTestEnty2); + counterfeitTestEntries1.push_back(counterfeitTestEnty3); + + std::vector counterfeitTestEntries2; + Entry counterfeitTestEnty4, counterfeitTestEnty5; + counterfeitTestEnty4.counterfeitTestKey = "Id1"; + counterfeitTestEnty4.counterfeitTestValue = "subscribe"; + counterfeitTestEnty5.counterfeitTestKey = "Id4"; + counterfeitTestEnty5.counterfeitTestValue = "subscribe"; + counterfeitTestEntries2.push_back(counterfeitTestEnty4); + counterfeitTestEntries2.push_back(counterfeitTestEnty5); + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries2); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(counterfeitObserver->updateCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id1", counterfeitObserver->updateCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->updateCounterfeitEntries_[0].counterfeitTestValue.ToString()); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id4", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification014 + * @tc.desc: Subscribe to an counterfeitObserver, callback with notification many times after putbatch all same data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification014, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification014 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + std::vector counterfeitTestEntries1; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries1.push_back(counterfeitTestEnty1); + counterfeitTestEntries1.push_back(counterfeitTestEnty2); + counterfeitTestEntries1.push_back(counterfeitTestEnty3); + + std::vector counterfeitTestEntries2; + Entry counterfeitTestEnty4, counterfeitTestEnty5; + counterfeitTestEnty4.counterfeitTestKey = "Id1"; + counterfeitTestEnty4.counterfeitTestValue = "subscribe"; + counterfeitTestEnty5.counterfeitTestKey = "Id2"; + counterfeitTestEnty5.counterfeitTestValue = "subscribe"; + counterfeitTestEntries2.push_back(counterfeitTestEnty4); + counterfeitTestEntries2.push_back(counterfeitTestEnty5); + + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 3); + ASSERT_EQ("Id1", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + ASSERT_EQ("Id2", counterfeitObserver->insertCounterfeitEntries_[1].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[1].counterfeitTestValue.ToString()); + ASSERT_EQ("Id3", counterfeitObserver->insertCounterfeitEntries_[2].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[2].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries2); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(counterfeitObserver->updateCounterfeitEntries_.size()), 2); + ASSERT_EQ("Id1", counterfeitObserver->updateCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->updateCounterfeitEntries_[0].counterfeitTestValue.ToString()); + ASSERT_EQ("Id2", counterfeitObserver->updateCounterfeitEntries_[1].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->updateCounterfeitEntries_[1].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification015 + * @tc.desc: Subscribe to an counterfeitObserver, callback with notification many times after putbatch complex data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification015, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification015 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + std::vector counterfeitTestEntries1; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id1"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries1.push_back(counterfeitTestEnty1); + counterfeitTestEntries1.push_back(counterfeitTestEnty2); + counterfeitTestEntries1.push_back(counterfeitTestEnty3); + + std::vector counterfeitTestEntries2; + Entry counterfeitTestEnty4, counterfeitTestEnty5; + counterfeitTestEnty4.counterfeitTestKey = "Id1"; + counterfeitTestEnty4.counterfeitTestValue = "subscribe"; + counterfeitTestEnty5.counterfeitTestKey = "Id2"; + counterfeitTestEnty5.counterfeitTestValue = "subscribe"; + counterfeitTestEntries2.push_back(counterfeitTestEnty4); + counterfeitTestEntries2.push_back(counterfeitTestEnty5); + + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->updateCounterfeitEntries_.size()), 0); + ASSERT_EQ(static_cast(counterfeitObserver->deleteCounterfeitEntries_.size()), 0); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 2); + ASSERT_EQ("Id1", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + ASSERT_EQ("Id3", counterfeitObserver->insertCounterfeitEntries_[1].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[1].counterfeitTestValue.ToString()); +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification015b + * @tc.desc: Subscribe to an counterfeitObserver, callback with notification many times after putbatch complex data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification015b, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification015b begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + std::vector counterfeitTestEntries1; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id1"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries1.push_back(counterfeitTestEnty1); + counterfeitTestEntries1.push_back(counterfeitTestEnty2); + counterfeitTestEntries1.push_back(counterfeitTestEnty3); + + std::vector counterfeitTestEntries2; + Entry counterfeitTestEnty4, counterfeitTestEnty5; + counterfeitTestEnty4.counterfeitTestKey = "Id1"; + counterfeitTestEnty4.counterfeitTestValue = "subscribe"; + counterfeitTestEnty5.counterfeitTestKey = "Id2"; + counterfeitTestEnty5.counterfeitTestValue = "subscribe"; + counterfeitTestEntries2.push_back(counterfeitTestEnty4); + counterfeitTestEntries2.push_back(counterfeitTestEnty5); + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries2); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(counterfeitObserver->updateCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id1", counterfeitObserver->updateCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->updateCounterfeitEntries_[0].counterfeitTestValue.ToString()); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id2", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->insertCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification016 + * @tc.desc: Pressure test subscribe, callback with notification many times after putbatch + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification016, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification016 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + int times = 100; // 100 times + std::vector counterfeitTestEntries; + for (int i = 0; i < times; i++) { + Entry counterfeitTestEnty; + counterfeitTestEnty.counterfeitTestKey = std::to_string(i); + counterfeitTestEnty.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty); + } + + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 100); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification017 + * @tc.desc: Subscribe to an counterfeitObserver, callback with notification after delete success + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification017, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification017 begin."); + auto counterfeitObserver = std::make_shared(); + std::vector counterfeitTestEntries; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitTestEntries.push_back(counterfeitTestEnty3); + + Status counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + counterfeitStatus = counterfeitTestStore_->Delete("Id1"); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore Delete data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->deleteCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id1", counterfeitObserver->deleteCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->deleteCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification018 + * @tc.desc: Subscribe to an counterfeitObserver, not callback after delete which counterfeitTestKey not exist + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification018, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification018 begin."); + auto counterfeitObserver = std::make_shared(); + std::vector counterfeitTestEntries; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitTestEntries.push_back(counterfeitTestEnty3); + + Status counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + counterfeitStatus = counterfeitTestStore_->Delete("Id4"); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore Delete data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 0); + ASSERT_EQ(static_cast(counterfeitObserver->deleteCounterfeitEntries_.size()), 0); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification019 +* @tc.desc: Subscribe to an counterfeitObserver, + delete the same data many times and only first delete callback with notification +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification019, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification019 begin."); + auto counterfeitObserver = std::make_shared(); + std::vector counterfeitTestEntries; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitTestEntries.push_back(counterfeitTestEnty3); + + Status counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + counterfeitStatus = counterfeitTestStore_->Delete("Id1"); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore Delete data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->deleteCounterfeitEntries_.size()), 1); + ASSERT_EQ("Id1", counterfeitObserver->deleteCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->deleteCounterfeitEntries_[0].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->Delete("Id1"); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore Delete data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount(2)), 1); + ASSERT_EQ(static_cast(counterfeitObserver->deleteCounterfeitEntries_.size()), 1); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification020 + * @tc.desc: Subscribe to an counterfeitObserver, callback with notification after deleteBatch + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification020, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification020 begin."); + auto counterfeitObserver = std::make_shared(); + std::vector counterfeitTestEntries; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitTestEntries.push_back(counterfeitTestEnty3); + + std::vector keys; + keys.push_back("Id1"); + keys.push_back("Id2"); + + Status counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + counterfeitStatus = counterfeitTestStore_->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore DeleteBatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->deleteCounterfeitEntries_.size()), 2); + ASSERT_EQ("Id1", counterfeitObserver->deleteCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->deleteCounterfeitEntries_[0].counterfeitTestValue.ToString()); + ASSERT_EQ("Id2", counterfeitObserver->deleteCounterfeitEntries_[1].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->deleteCounterfeitEntries_[1].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification021 + * @tc.desc: Subscribe to an counterfeitObserver, not callback after deleteBatch which all keys not exist + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification021, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification021 begin."); + auto counterfeitObserver = std::make_shared(); + std::vector counterfeitTestEntries; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitTestEntries.push_back(counterfeitTestEnty3); + + std::vector keys; + keys.push_back("Id4"); + keys.push_back("Id5"); + + Status counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + counterfeitStatus = counterfeitTestStore_->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore DeleteBatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 0); + ASSERT_EQ(static_cast(counterfeitObserver->deleteCounterfeitEntries_.size()), 0); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification022 +* @tc.desc: Subscribe to an counterfeitObserver, + deletebatch the same data many times and only first deletebatch callback with +* notification +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification022, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification022 begin."); + auto counterfeitObserver = std::make_shared(); + std::vector counterfeitTestEntries; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + counterfeitTestEnty1.counterfeitTestKey = "Id1"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id2"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id3"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitTestEntries.push_back(counterfeitTestEnty3); + + std::vector keys; + keys.push_back("Id1"); + keys.push_back("Id2"); + + Status counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + counterfeitStatus = counterfeitTestStore_->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore DeleteBatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(counterfeitObserver->deleteCounterfeitEntries_.size()), 2); + ASSERT_EQ("Id1", counterfeitObserver->deleteCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->deleteCounterfeitEntries_[0].counterfeitTestValue.ToString()); + ASSERT_EQ("Id2", counterfeitObserver->deleteCounterfeitEntries_[1].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->deleteCounterfeitEntries_[1].counterfeitTestValue.ToString()); + + counterfeitStatus = counterfeitTestStore_->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore DeleteBatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount(2)), 1); + ASSERT_EQ(static_cast(counterfeitObserver->deleteCounterfeitEntries_.size()), 2); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification023 + * @tc.desc: Subscribe to an counterfeitObserver, include Clear Put PutBatch Delete DeleteBatch + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification023, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification023 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + Key counterfeitTestKey1 = "Id1"; + Value counterfeitTestValue1 = "subscribe"; + + std::vector counterfeitTestEntries; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + counterfeitTestEnty1.counterfeitTestKey = "Id2"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id3"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id4"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitTestEntries.push_back(counterfeitTestEnty3); + + std::vector keys; + keys.push_back("Id2"); + keys.push_back("Id3"); + + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey1, counterfeitTestValue1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + counterfeitStatus = counterfeitTestStore_->Delete(counterfeitTestKey1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore delete data return wrong"; + counterfeitStatus = counterfeitTestStore_->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore DeleteBatch data return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount(4)), 4); + // every callback will clear vector + ASSERT_EQ(static_cast(counterfeitObserver->deleteCounterfeitEntries_.size()), 2); + ASSERT_EQ("Id2", counterfeitObserver->deleteCounterfeitEntries_[0].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->deleteCounterfeitEntries_[0].counterfeitTestValue.ToString()); + ASSERT_EQ("Id3", counterfeitObserver->deleteCounterfeitEntries_[1].counterfeitTestKey.ToString()); + ASSERT_EQ("subscribe", counterfeitObserver->deleteCounterfeitEntries_[1].counterfeitTestValue.ToString()); + ASSERT_EQ(static_cast(counterfeitObserver->updateCounterfeitEntries_.size()), 0); + ASSERT_EQ(static_cast(counterfeitObserver->insertCounterfeitEntries_.size()), 0); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification024 + * @tc.desc: Subscribe to an counterfeitObserver[use transaction], include Clear Put PutBatch Delete DeleteBatch + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreCounterfeitUnitTest, KvStoreDdmSubscribeKvStoreNotification024, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification024 begin."); + auto counterfeitObserver = std::make_shared(); + SubscribeType counterfeitSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status counterfeitStatus = counterfeitTestStore_->SubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "SubscribeKvStore return wrong"; + + Key counterfeitTestKey1 = "Id1"; + Value counterfeitTestValue1 = "subscribe"; + + std::vector counterfeitTestEntries; + Entry counterfeitTestEnty1, counterfeitTestEnty2, counterfeitTestEnty3; + counterfeitTestEnty1.counterfeitTestKey = "Id2"; + counterfeitTestEnty1.counterfeitTestValue = "subscribe"; + counterfeitTestEnty2.counterfeitTestKey = "Id3"; + counterfeitTestEnty2.counterfeitTestValue = "subscribe"; + counterfeitTestEnty3.counterfeitTestKey = "Id4"; + counterfeitTestEnty3.counterfeitTestValue = "subscribe"; + counterfeitTestEntries.push_back(counterfeitTestEnty1); + counterfeitTestEntries.push_back(counterfeitTestEnty2); + counterfeitTestEntries.push_back(counterfeitTestEnty3); + + std::vector keys; + keys.push_back("Id2"); + keys.push_back("Id3"); + + counterfeitStatus = counterfeitTestStore_->StartTransaction(); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore startTransaction return wrong"; + counterfeitStatus = counterfeitTestStore_->Put(counterfeitTestKey1, counterfeitTestValue1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore put data return wrong"; + counterfeitStatus = counterfeitTestStore_->PutBatch(counterfeitTestEntries); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore putbatch data return wrong"; + counterfeitStatus = counterfeitTestStore_->Delete(counterfeitTestKey1); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore delete data return wrong"; + counterfeitStatus = counterfeitTestStore_->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore DeleteBatch data return wrong"; + counterfeitStatus = counterfeitTestStore_->Commit(); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "KvStore Commit return wrong"; + ASSERT_EQ(static_cast(counterfeitObserver->GetCallCount()), 1); + + counterfeitStatus = counterfeitTestStore_->UnSubscribeKvStore(counterfeitSubscribeType, counterfeitObserver); + ASSERT_EQ(Status::SUCCESS, counterfeitStatus) << "UnSubscribeKvStore return wrong"; +} \ No newline at end of file diff --git a/kv_store/databaseutils/test/local_kv_store_sham_test.cpp b/kv_store/databaseutils/test/local_kv_store_sham_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4bfb39618ff68120ced29b98f9f4558ccde8e060 --- /dev/null +++ b/kv_store/databaseutils/test/local_kv_store_sham_test.cpp @@ -0,0 +1,2138 @@ +/* + * Copyright (c) 2024 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 "LocalKvStoreShamTest" + +#include "block_data.h" +#include "distributed_kv_data_manager.h" +#include "log_print.h" +#include "types.h" +#include +#include +#include +#include + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::DistributedKv; +class LocalKvStoreShamTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + + static DistributedKvDataManager manager_Sham; + static std::shared_ptr kvStore_Sham; + static Status status_Sham; + static AppId appId_Sham; + static StoreId storeId_Sham; +}; +std::shared_ptr LocalKvStoreShamTest::kvStore_Sham = nullptr; +Status LocalKvStoreShamTest::status_Sham = Status::ERROR; +DistributedKvDataManager LocalKvStoreShamTest::manager_Sham; +AppId LocalKvStoreShamTest::appId_Sham; +StoreId LocalKvStoreShamTest::storeId_Sham; + +void LocalKvStoreShamTest::SetUpTestCase(void) +{ + mkdir("/data/service/el1/public/database/dev_local_sub", (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); +} + +void LocalKvStoreShamTest::TearDownTestCase(void) +{ + manager_Sham.CloseKvStore(appId_Sham, kvStore_Sham); + kvStore_Sham = nullptr; + manager_Sham.DeleteKvStore(appId_Sham, storeId_Sham, "/data/service/el1/public/database/dev_local_sub"); + (void)remove("/data/service/el1/public/database/dev_local_sub/kvdb"); + (void)remove("/data/service/el1/public/database/dev_local_sub"); +} + +void LocalKvStoreShamTest::SetUp(void) +{ + Options options; + options.securityLevel = S1; + options.baseDir = std::string("/data/service/el1/public/database/dev_local_sub"); + appId_Sham.appId = "dev_local_sub"; // define app name. + storeId_Sham.storeId = "student"; // define kvstore(database) name + manager_Sham.DeleteKvStore(appId_Sham, storeId_Sham, options.baseDir); + // [create and] open and initialize kvstore instance. + status_Sham = manager_Sham.GetSingleKvStore(options, appId_Sham, storeId_Sham, kvStore_Sham); + ASSERT_EQ(Status::SUCCESS, status_Sham) << "wrong statusSham"; + ASSERT_NE(nullptr, kvStore_Sham) << "kvStore is nullptr"; +} + +void LocalKvStoreShamTest::TearDown(void) +{ + manager_Sham.CloseKvStore(appId_Sham, kvStore_Sham); + kvStore_Sham = nullptr; + manager_Sham.DeleteKvStore(appId_Sham, storeId_Sham); +} + +class DeviceObserverShamTest : public KvStoreObserver { +public: + std::vector insertEntries_; + std::vector updateEntries_; + std::vector deleteEntries_; + std::string deviceId_; + bool isClear_ = false; + DeviceObserverShamTest(); + ~DeviceObserverShamTest() = default; + + void OnChange(const ChangeNotification &changeNotification); + + // reset the callCount_ to zero. + void ResetToZero(); + + uint32_t GetCallCount(uint32_t valueSham = 1); + +private: + std::mutex mutex_; + uint32_t callCount_ = 0; + BlockData value_ { 1, 0 }; +}; + +DeviceObserverShamTest::DeviceObserverShamTest() { } + +void DeviceObserverShamTest::OnChange(const ChangeNotification &changeNotification) +{ + ZLOGD("begin."); + insertEntries_ = changeNotification.GetInsertEntries(); + updateEntries_ = changeNotification.GetUpdateEntries(); + deleteEntries_ = changeNotification.GetDeleteEntries(); + deviceId_ = changeNotification.GetDeviceId(); + isClear_ = changeNotification.IsClear(); + std::lock_guard guard(mutex_); + ++callCount_; + value_.SetValue(callCount_); +} + +void DeviceObserverShamTest::ResetToZero() +{ + std::lock_guard guard(mutex_); + callCount_ = 0; + value_.Clear(0); +} + +uint32_t DeviceObserverShamTest::GetCallCount(uint32_t valueSham) +{ + int retry = 0; + uint32_t callTimes = 0; + while (retry < valueSham) { + callTimes = value_.GetValue(); + if (callTimes >= valueSham) { + break; + } + std::lock_guard guard(mutex_); + callTimes = value_.GetValue(); + if (callTimes >= valueSham) { + break; + } + value_.Clear(callTimes); + retry++; + } + return callTimes; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore001 + * @tc.desc: Subscribe success + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStore001, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore001 begin."); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + auto observerSham = std::make_shared(); + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 0); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + observerSham = nullptr; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore002 + * @tc.desc: Subscribe fail, observerSham is null + * @tc.type: FUNC + * @tc.require: AR000CQDU9 AR000CQS37 + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStore002, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore002 begin."); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + std::shared_ptr observerSham = nullptr; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::INVALID_ARGUMENT, statusSham) << "SubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore003 + * @tc.desc: Subscribe success and OnChange callback after put + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStore003, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore003 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key keySham = "Id1"; + Value valueSham = "subscribe"; + statusSham = kvStore_Sham->Put(keySham, valueSham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + observerSham = nullptr; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore004 + * @tc.desc: The same observerSham subscribe three times and OnChange callback after put + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStore004, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore004 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::STORE_ALREADY_SUBSCRIBE, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::STORE_ALREADY_SUBSCRIBE, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key keySham = "Id1"; + Value valueSham = "subscribe"; + statusSham = kvStore_Sham->Put(keySham, valueSham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore005 + * @tc.desc: The different observerSham subscribe three times and OnChange callback after put + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStore005, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore005 begin."); + auto observer1 = std::make_shared(); + auto observer2 = std::make_shared(); + auto observer3 = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observer1); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore failed, wrong statusSham"; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observer2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore failed, wrong statusSham"; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observer3); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore failed, wrong statusSham"; + + Key keySham = "Id1"; + Value valueSham = "subscribe"; + statusSham = kvStore_Sham->Put(keySham, valueSham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "Putting data to KvStore failed, wrong statusSham"; + ASSERT_EQ(static_cast(observer1->GetCallCount()), 1); + ASSERT_EQ(static_cast(observer2->GetCallCount()), 1); + ASSERT_EQ(static_cast(observer3->GetCallCount()), 1); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observer1); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observer2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observer3); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore006 + * @tc.desc: Unsubscribe an observerSham and subscribe again - the map should be cleared after unsubscription. + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStore006, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore006 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key key1Sham = "Id1"; + Value value1Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key1Sham, value1Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + + Key key2Sham = "Id2"; + Value value2Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key2Sham, value2Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + + kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + Key key3Sham = "Id3"; + Value value3Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key3Sham, value3Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(2)), 2); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore007 + * @tc.desc: Subscribe to an observerSham - OnChange callback is called multiple times after the put operation. + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStore007, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore007 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key key1Sham = "Id1"; + Value value1Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key1Sham, value1Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + + Key key2Sham = "Id2"; + Value value2Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key2Sham, value2Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + + Key key3Sham = "Id3"; + Value value3Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key3Sham, value3Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(3)), 3); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore008 +* @tc.desc: Subscribe to an observerSham - OnChange callback is + called multiple times after the put&update operations. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: SQL +*/ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStore008, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore008 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key key1Sham = "Id1"; + Value value1Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key1Sham, value1Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + + Key key2Sham = "Id2"; + Value value2Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key2Sham, value2Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + + Key key3Sham = "Id1"; + Value value3Sham = "subscribe03"; + statusSham = kvStore_Sham->Put(key3Sham, value3Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(3)), 3); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore009 + * @tc.desc: Subscribe to an observerSham - OnChange callback is called multiple times after the putBatch operation. + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStore009, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore009 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + // before update. + std::vector entries1Sham; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries1Sham.push_back(entrySham1); + entries1Sham.push_back(entrySham2); + entries1Sham.push_back(entrySham3); + + std::vector entries2; + Entry entrySham4, entrySham5; + entrySham4.keySham = "Id4"; + entrySham4.valueSham = "subscribe"; + entrySham5.keySham = "Id5"; + entrySham5.valueSham = "subscribe"; + entries2.push_back(entrySham4); + entries2.push_back(entrySham5); + + statusSham = kvStore_Sham->PutBatch(entries1Sham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + statusSham = kvStore_Sham->PutBatch(entries2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(2)), 2); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore010 +* @tc.desc: Subscribe to an observerSham - OnChange callback is + called multiple times after the putBatch update operation. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: SQL +*/ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStore010, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore010 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + // before update. + std::vector entries1Sham; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries1Sham.push_back(entrySham1); + entries1Sham.push_back(entrySham2); + entries1Sham.push_back(entrySham3); + + std::vector entries2; + Entry entrySham4, entrySham5; + entrySham4.keySham = "Id1"; + entrySham4.valueSham = "modify"; + entrySham5.keySham = "Id2"; + entrySham5.valueSham = "modify"; + entries2.push_back(entrySham4); + entries2.push_back(entrySham5); + + statusSham = kvStore_Sham->PutBatch(entries1Sham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + statusSham = kvStore_Sham->PutBatch(entries2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(2)), 2); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore011 + * @tc.desc: Subscribe to an observerSham - OnChange callback is called after successful deletion. + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStore011, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore011 begin."); + auto observerSham = std::make_shared(); + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + Status statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStore_Sham->Delete("Id1"); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore Delete data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore012 + * @tc.desc: Subscribe to an observerSham - OnChange callback is not called after deletion of non-existing keys. + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStore012, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore012 begin."); + auto observerSham = std::make_shared(); + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + Status statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStore_Sham->Delete("Id4"); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore Delete data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 0); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore013 + * @tc.desc: Subscribe to an observerSham - OnChange callback is called after KvStore is cleared. + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStore013, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore013 begin."); + auto observerSham = std::make_shared(); + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + Status statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 0); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore014 +* @tc.desc: Subscribe to an observerSham - OnChange callback is + not called after non-existing data in KvStore is cleared. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: SQL +*/ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStore014, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore014 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 0); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore015 + * @tc.desc: Subscribe to an observerSham - OnChange callback is called after the deleteBatch operation. + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStore015, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore015 begin."); + auto observerSham = std::make_shared(); + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + std::vector keys; + keys.push_back("Id1"); + keys.push_back("Id2"); + + Status statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + statusSham = kvStore_Sham->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore016 + * @tc.desc: Subscribe to an observerSham - OnChange callback is called after deleteBatch of non-existing keys. + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStore016, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore016 begin."); + auto observerSham = std::make_shared(); + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + std::vector keys; + keys.push_back("Id4"); + keys.push_back("Id5"); + + Status statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + statusSham = kvStore_Sham->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 0); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore020 + * @tc.desc: Unsubscribe an observerSham two times. + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStore020, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore020 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::STORE_NOT_SUBSCRIBE, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification001 +* @tc.desc: Subscribe to an observerSham successfully - callback is + called with a notification after the put operation. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: SQL +*/ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification001, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification001 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key keySham = "Id1"; + Value valueSham = "subscribe"; + statusSham = kvStore_Sham->Put(keySham, valueSham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ZLOGD("kvstore_ddm_subscribekvstore_003"); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 1); + ASSERT_EQ("Id1", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + ZLOGD("kvstore_ddm_subscribekvstore_003 size:%zu.", observerSham->insertEntries_.size()); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification002 +* @tc.desc: Subscribe to the same observerSham three times - callback is + called with a notification after the put operation. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: SQL +*/ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification002, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification002 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::STORE_ALREADY_SUBSCRIBE, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::STORE_ALREADY_SUBSCRIBE, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key keySham = "Id1"; + Value valueSham = "subscribe"; + statusSham = kvStore_Sham->Put(keySham, valueSham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 1); + ASSERT_EQ("Id1", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification003 + * @tc.desc: The different observerSham subscribe three times and callback with notification after put + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification003, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification003 begin."); + auto observer1 = std::make_shared(); + auto observer2 = std::make_shared(); + auto observer3 = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observer1); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observer2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observer3); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key keySham = "Id1"; + Value valueSham = "subscribe"; + statusSham = kvStore_Sham->Put(keySham, valueSham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observer1->GetCallCount()), 1); + ASSERT_EQ(static_cast(observer1->insertEntries_.size()), 1); + ASSERT_EQ("Id1", observer1->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observer1->insertEntries_[0].valueSham.ToString()); + + ASSERT_EQ(static_cast(observer2->GetCallCount()), 1); + ASSERT_EQ(static_cast(observer2->insertEntries_.size()), 1); + ASSERT_EQ("Id1", observer2->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observer2->insertEntries_[0].valueSham.ToString()); + + ASSERT_EQ(static_cast(observer3->GetCallCount()), 1); + ASSERT_EQ(static_cast(observer3->insertEntries_.size()), 1); + ASSERT_EQ("Id1", observer3->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observer3->insertEntries_[0].valueSham.ToString()); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observer1); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observer2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observer3); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification004 + * @tc.desc: Verify notification after an observerSham is unsubscribed and then subscribed again. + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification004, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification004 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key key1Sham = "Id1"; + Value value1Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key1Sham, value1Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 1); + ASSERT_EQ("Id1", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + + Key key2Sham = "Id2"; + Value value2Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key2Sham, value2Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 1); + ASSERT_EQ("Id1", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + + kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + Key key3Sham = "Id3"; + Value value3Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key3Sham, value3Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 1); + ASSERT_EQ("Id3", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification005 + * @tc.desc: Subscribe to an observerSham, callback with notification many times after put the different data + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification005, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification005 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key key1Sham = "Id1"; + Value value1Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key1Sham, value1Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 1); + ASSERT_EQ("Id1", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + + Key key2Sham = "Id2"; + Value value2Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key2Sham, value2Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 1); + ASSERT_EQ("Id2", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + + Key key3Sham = "Id3"; + Value value3Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key3Sham, value3Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(3)), 3); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 1); + ASSERT_EQ("Id3", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification006 + * @tc.desc: Subscribe to an observerSham, callback with notification many times after put the same data + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification006, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification006 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key key1Sham = "Id1"; + Value value1Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key1Sham, value1Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 1); + ASSERT_EQ("Id1", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + + Key key2Sham = "Id1"; + Value value2Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key2Sham, value2Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(observerSham->updateEntries_.size()), 1); + ASSERT_EQ("Id1", observerSham->updateEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->updateEntries_[0].valueSham.ToString()); + + Key key3Sham = "Id1"; + Value value3Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key3Sham, value3Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(3)), 3); + ASSERT_EQ(static_cast(observerSham->updateEntries_.size()), 1); + ASSERT_EQ("Id1", observerSham->updateEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->updateEntries_[0].valueSham.ToString()); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification007 + * @tc.desc: Subscribe to an observerSham, callback with notification many times after put&update + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification007, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification007 begin."); + auto observerSham = std::make_shared(); + Key key1Sham = "Id1"; + Value value1Sham = "subscribe"; + Status statusSham = kvStore_Sham->Put(key1Sham, value1Sham); + // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + + Key key2Sham = "Id2"; + Value value2Sham = "subscribe"; + statusSham = kvStore_Sham->Put(key2Sham, value2Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key key3Sham = "Id1"; + Value value3Sham = "subscribe03"; + statusSham = kvStore_Sham->Put(key3Sham, value3Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->updateEntries_.size()), 1); + ASSERT_EQ("Id1", observerSham->updateEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe03", observerSham->updateEntries_[0].valueSham.ToString()); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification008 + * @tc.desc: Subscribe to an observerSham, callback with notification one times after putbatch&update + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification008, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification008 begin."); + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + Status statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + entries.clear(); + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe_modify"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe_modify"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->updateEntries_.size()), 2); + ASSERT_EQ("Id1", observerSham->updateEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe_modify", observerSham->updateEntries_[0].valueSham.ToString()); + ASSERT_EQ("Id2", observerSham->updateEntries_[1].keySham.ToString()); + ASSERT_EQ("subscribe_modify", observerSham->updateEntries_[1].valueSham.ToString()); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification009 + * @tc.desc: Subscribe to an observerSham, callback with notification one times after putbatch all different data + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification009, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification009 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 3); + ASSERT_EQ("Id1", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + ASSERT_EQ("Id2", observerSham->insertEntries_[1].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[1].valueSham.ToString()); + ASSERT_EQ("Id3", observerSham->insertEntries_[2].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[2].valueSham.ToString()); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification010 +* @tc.desc: Subscribe to an observerSham, + callback with notification one times after putbatch both different and same data +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: SQL +*/ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification010, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification010 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id1"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id2"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 2); + ASSERT_EQ("Id1", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + ASSERT_EQ("Id2", observerSham->insertEntries_[1].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[1].valueSham.ToString()); + ASSERT_EQ(static_cast(observerSham->updateEntries_.size()), 0); + ASSERT_EQ(static_cast(observerSham->deleteEntries_.size()), 0); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification011 + * @tc.desc: Subscribe to an observerSham, callback with notification one times after putbatch all same data + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification011, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification011 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id1"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id1"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 1); + ASSERT_EQ("Id1", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + ASSERT_EQ(static_cast(observerSham->updateEntries_.size()), 0); + ASSERT_EQ(static_cast(observerSham->deleteEntries_.size()), 0); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification012 + * @tc.desc: Subscribe to an observerSham, callback with notification many times after putbatch all different data + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification012, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification012 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entries1Sham; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries1Sham.push_back(entrySham1); + entries1Sham.push_back(entrySham2); + entries1Sham.push_back(entrySham3); + + std::vector entries2; + Entry entrySham4, entrySham5; + entrySham4.keySham = "Id4"; + entrySham4.valueSham = "subscribe"; + entrySham5.keySham = "Id5"; + entrySham5.valueSham = "subscribe"; + entries2.push_back(entrySham4); + entries2.push_back(entrySham5); + + statusSham = kvStore_Sham->PutBatch(entries1Sham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 3); + ASSERT_EQ("Id1", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + ASSERT_EQ("Id2", observerSham->insertEntries_[1].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[1].valueSham.ToString()); + ASSERT_EQ("Id3", observerSham->insertEntries_[2].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[2].valueSham.ToString()); +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification012b + * @tc.desc: Subscribe to an observerSham, callback with notification many times after putbatch all different data + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification012b, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification012b begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entries1Sham; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries1Sham.push_back(entrySham1); + entries1Sham.push_back(entrySham2); + entries1Sham.push_back(entrySham3); + + std::vector entries2; + Entry entrySham4, entrySham5; + entrySham4.keySham = "Id4"; + entrySham4.valueSham = "subscribe"; + entrySham5.keySham = "Id5"; + entrySham5.valueSham = "subscribe"; + entries2.push_back(entrySham4); + entries2.push_back(entrySham5); + + statusSham = kvStore_Sham->PutBatch(entries2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 2); + ASSERT_EQ("Id4", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + ASSERT_EQ("Id5", observerSham->insertEntries_[1].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[1].valueSham.ToString()); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification013 +* @tc.desc: Subscribe to an observerSham, + callback with notification many times after putbatch both different and same data +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: SQL +*/ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification013, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification013 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entries1Sham; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries1Sham.push_back(entrySham1); + entries1Sham.push_back(entrySham2); + entries1Sham.push_back(entrySham3); + + std::vector entries2; + Entry entrySham4, entrySham5; + entrySham4.keySham = "Id1"; + entrySham4.valueSham = "subscribe"; + entrySham5.keySham = "Id4"; + entrySham5.valueSham = "subscribe"; + entries2.push_back(entrySham4); + entries2.push_back(entrySham5); + + statusSham = kvStore_Sham->PutBatch(entries1Sham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 3); + ASSERT_EQ("Id1", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + ASSERT_EQ("Id2", observerSham->insertEntries_[1].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[1].valueSham.ToString()); + ASSERT_EQ("Id3", observerSham->insertEntries_[2].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[2].valueSham.ToString()); +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification013b +* @tc.desc: Subscribe to an observerSham, + callback with notification many times after putbatch both different and same data +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: SQL +*/ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification013b, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification013b begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entries1Sham; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries1Sham.push_back(entrySham1); + entries1Sham.push_back(entrySham2); + entries1Sham.push_back(entrySham3); + + std::vector entries2; + Entry entrySham4, entrySham5; + entrySham4.keySham = "Id1"; + entrySham4.valueSham = "subscribe"; + entrySham5.keySham = "Id4"; + entrySham5.valueSham = "subscribe"; + entries2.push_back(entrySham4); + entries2.push_back(entrySham5); + statusSham = kvStore_Sham->PutBatch(entries2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(observerSham->updateEntries_.size()), 1); + ASSERT_EQ("Id1", observerSham->updateEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->updateEntries_[0].valueSham.ToString()); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 1); + ASSERT_EQ("Id4", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification014 + * @tc.desc: Subscribe to an observerSham, callback with notification many times after putbatch all same data + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification014, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification014 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entries1Sham; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries1Sham.push_back(entrySham1); + entries1Sham.push_back(entrySham2); + entries1Sham.push_back(entrySham3); + + std::vector entries2; + Entry entrySham4, entrySham5; + entrySham4.keySham = "Id1"; + entrySham4.valueSham = "subscribe"; + entrySham5.keySham = "Id2"; + entrySham5.valueSham = "subscribe"; + entries2.push_back(entrySham4); + entries2.push_back(entrySham5); + + statusSham = kvStore_Sham->PutBatch(entries1Sham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 3); + ASSERT_EQ("Id1", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + ASSERT_EQ("Id2", observerSham->insertEntries_[1].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[1].valueSham.ToString()); + ASSERT_EQ("Id3", observerSham->insertEntries_[2].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[2].valueSham.ToString()); + + statusSham = kvStore_Sham->PutBatch(entries2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(observerSham->updateEntries_.size()), 2); + ASSERT_EQ("Id1", observerSham->updateEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->updateEntries_[0].valueSham.ToString()); + ASSERT_EQ("Id2", observerSham->updateEntries_[1].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->updateEntries_[1].valueSham.ToString()); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification015 + * @tc.desc: Subscribe to an observerSham, callback with notification many times after putbatch complex data + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification015, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification015 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entries1Sham; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id1"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries1Sham.push_back(entrySham1); + entries1Sham.push_back(entrySham2); + entries1Sham.push_back(entrySham3); + + std::vector entries2; + Entry entrySham4, entrySham5; + entrySham4.keySham = "Id1"; + entrySham4.valueSham = "subscribe"; + entrySham5.keySham = "Id2"; + entrySham5.valueSham = "subscribe"; + entries2.push_back(entrySham4); + entries2.push_back(entrySham5); + + statusSham = kvStore_Sham->PutBatch(entries1Sham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->updateEntries_.size()), 0); + ASSERT_EQ(static_cast(observerSham->deleteEntries_.size()), 0); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 2); + ASSERT_EQ("Id1", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + ASSERT_EQ("Id3", observerSham->insertEntries_[1].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[1].valueSham.ToString()); +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification015b + * @tc.desc: Subscribe to an observerSham, callback with notification many times after putbatch complex data + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification015b, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification015b begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entries1Sham; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id1"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries1Sham.push_back(entrySham1); + entries1Sham.push_back(entrySham2); + entries1Sham.push_back(entrySham3); + + std::vector entries2; + Entry entrySham4, entrySham5; + entrySham4.keySham = "Id1"; + entrySham4.valueSham = "subscribe"; + entrySham5.keySham = "Id2"; + entrySham5.valueSham = "subscribe"; + entries2.push_back(entrySham4); + entries2.push_back(entrySham5); + statusSham = kvStore_Sham->PutBatch(entries2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(observerSham->updateEntries_.size()), 1); + ASSERT_EQ("Id1", observerSham->updateEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->updateEntries_[0].valueSham.ToString()); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 1); + ASSERT_EQ("Id2", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->insertEntries_[0].valueSham.ToString()); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification016 + * @tc.desc: Pressure test subscribe, callback with notification many times after putbatch + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification016, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification016 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + int times = 100; // 100 times + std::vector entries; + for (int i = 0; i < times; i++) { + Entry entrySham; + entrySham.keySham = std::to_string(i); + entrySham.valueSham = "subscribe"; + entries.push_back(entrySham); + } + + statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 100); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification017 + * @tc.desc: Subscribe to an observerSham, callback with notification after delete success + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification017, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification017 begin."); + auto observerSham = std::make_shared(); + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + Status statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStore_Sham->Delete("Id1"); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore Delete data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->deleteEntries_.size()), 1); + ASSERT_EQ("Id1", observerSham->deleteEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->deleteEntries_[0].valueSham.ToString()); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification018 + * @tc.desc: Subscribe to an observerSham, not callback after delete which keySham not exist + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification018, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification018 begin."); + auto observerSham = std::make_shared(); + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + Status statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStore_Sham->Delete("Id4"); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore Delete data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 0); + ASSERT_EQ(static_cast(observerSham->deleteEntries_.size()), 0); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification019 +* @tc.desc: Subscribe to an observerSham, + delete the same data many times and only first delete callback with notification +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: SQL +*/ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification019, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification019 begin."); + auto observerSham = std::make_shared(); + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + Status statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStore_Sham->Delete("Id1"); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore Delete data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->deleteEntries_.size()), 1); + ASSERT_EQ("Id1", observerSham->deleteEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->deleteEntries_[0].valueSham.ToString()); + + statusSham = kvStore_Sham->Delete("Id1"); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore Delete data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(2)), 1); + ASSERT_EQ(static_cast(observerSham->deleteEntries_.size()), 1); // not callback so not clear + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification020 + * @tc.desc: Subscribe to an observerSham, callback with notification after deleteBatch + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification020, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification020 begin."); + auto observerSham = std::make_shared(); + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + std::vector keys; + keys.push_back("Id1"); + keys.push_back("Id2"); + + Status statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + statusSham = kvStore_Sham->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->deleteEntries_.size()), 2); + ASSERT_EQ("Id1", observerSham->deleteEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->deleteEntries_[0].valueSham.ToString()); + ASSERT_EQ("Id2", observerSham->deleteEntries_[1].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->deleteEntries_[1].valueSham.ToString()); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification021 + * @tc.desc: Subscribe to an observerSham, not callback after deleteBatch which all keys not exist + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification021, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification021 begin."); + auto observerSham = std::make_shared(); + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + std::vector keys; + keys.push_back("Id4"); + keys.push_back("Id5"); + + Status statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + statusSham = kvStore_Sham->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 0); + ASSERT_EQ(static_cast(observerSham->deleteEntries_.size()), 0); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification022 +* @tc.desc: Subscribe to an observerSham, + deletebatch the same data many times and only first deletebatch callback with +* notification +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: SQL +*/ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification022, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification022 begin."); + auto observerSham = std::make_shared(); + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.keySham = "Id1"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id2"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id3"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + std::vector keys; + keys.push_back("Id1"); + keys.push_back("Id2"); + + Status statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + statusSham = kvStore_Sham->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->deleteEntries_.size()), 2); + ASSERT_EQ("Id1", observerSham->deleteEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->deleteEntries_[0].valueSham.ToString()); + ASSERT_EQ("Id2", observerSham->deleteEntries_[1].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->deleteEntries_[1].valueSham.ToString()); + + statusSham = kvStore_Sham->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(2)), 1); + ASSERT_EQ(static_cast(observerSham->deleteEntries_.size()), 2); // not callback so not clear + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification023 + * @tc.desc: Subscribe to an observerSham, include Clear Put PutBatch Delete DeleteBatch + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification023, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification023 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key key1Sham = "Id1"; + Value value1Sham = "subscribe"; + + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.keySham = "Id2"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id3"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id4"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + std::vector keys; + keys.push_back("Id2"); + keys.push_back("Id3"); + + statusSham = kvStore_Sham->Put(key1Sham, value1Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + statusSham = kvStore_Sham->Delete(key1Sham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore delete data return wrong statusSham"; + statusSham = kvStore_Sham->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(4)), 4); + // every callback will clear vector + ASSERT_EQ(static_cast(observerSham->deleteEntries_.size()), 2); + ASSERT_EQ("Id2", observerSham->deleteEntries_[0].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->deleteEntries_[0].valueSham.ToString()); + ASSERT_EQ("Id3", observerSham->deleteEntries_[1].keySham.ToString()); + ASSERT_EQ("subscribe", observerSham->deleteEntries_[1].valueSham.ToString()); + ASSERT_EQ(static_cast(observerSham->updateEntries_.size()), 0); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 0); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification024 + * @tc.desc: Subscribe to an observerSham[use transaction], include Clear Put PutBatch Delete DeleteBatch + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification024, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification024 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key key1Sham = "Id1"; + Value value1Sham = "subscribe"; + + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.keySham = "Id2"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id3"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id4"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + std::vector keys; + keys.push_back("Id2"); + keys.push_back("Id3"); + + statusSham = kvStore_Sham->StartTransaction(); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore startTransaction return wrong statusSham"; + statusSham = kvStore_Sham->Put(key1Sham, value1Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + statusSham = kvStore_Sham->Delete(key1Sham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore delete data return wrong statusSham"; + statusSham = kvStore_Sham->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + statusSham = kvStore_Sham->Commit(); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore Commit return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification025 + * @tc.desc: Subscribe to an observerSham[use transaction], include Clear Put PutBatch Delete DeleteBatch + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification025, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification025 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key key1Sham = "Id1"; + Value value1Sham = "subscribe"; + + std::vector entries; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.keySham = "Id2"; + entrySham1.valueSham = "subscribe"; + entrySham2.keySham = "Id3"; + entrySham2.valueSham = "subscribe"; + entrySham3.keySham = "Id4"; + entrySham3.valueSham = "subscribe"; + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + + std::vector keys; + keys.push_back("Id2"); + keys.push_back("Id3"); + + statusSham = kvStore_Sham->StartTransaction(); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore startTransaction return wrong statusSham"; + statusSham = kvStore_Sham->Put(key1Sham, value1Sham); // insert or update keySham-valueSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + statusSham = kvStore_Sham->Delete(key1Sham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore delete data return wrong statusSham"; + statusSham = kvStore_Sham->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + statusSham = kvStore_Sham->Rollback(); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore Commit return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 0); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 0); + ASSERT_EQ(static_cast(observerSham->updateEntries_.size()), 0); + ASSERT_EQ(static_cast(observerSham->deleteEntries_.size()), 0); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + observerSham = nullptr; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification026 + * @tc.desc: Subscribe to an observerSham[use transaction], include bigData PutBatch update insert delete + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification026, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification026 begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entries; + Entry entrySham0, entrySham1, entrySham2, entrySham3, entrySham4; + + int maxValueSize = 2 * 1024 * 1024; // max valueSham size is 2M. + std::vector val(maxValueSize); + for (int i = 0; i < maxValueSize; i++) { + val[i] = static_cast(i); + } + Value valueSham = val; + + int maxValueSize2 = 1000 * 1024; // max valueSham size is 1000k. + std::vector val2(maxValueSize2); + for (int i = 0; i < maxValueSize2; i++) { + val2[i] = static_cast(i); + } + Value value2Sham = val2; + + entrySham0.keySham = "SingleKvStoreDdmPutBatch006_0"; + entrySham0.valueSham = "beijing"; + entrySham1.keySham = "SingleKvStoreDdmPutBatch006_1"; + entrySham1.valueSham = valueSham; + entrySham2.keySham = "SingleKvStoreDdmPutBatch006_2"; + entrySham2.valueSham = valueSham; + entrySham3.keySham = "SingleKvStoreDdmPutBatch006_3"; + entrySham3.valueSham = "ZuiHouBuZhiTianZaiShui"; + entrySham4.keySham = "SingleKvStoreDdmPutBatch006_4"; + entrySham4.valueSham = valueSham; + + entries.push_back(entrySham0); + entries.push_back(entrySham1); + entries.push_back(entrySham2); + entries.push_back(entrySham3); + entries.push_back(entrySham4); + + statusSham = kvStore_Sham->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount()), 1); + ASSERT_EQ(static_cast(observerSham->insertEntries_.size()), 5); + ASSERT_EQ("SingleKvStoreDdmPutBatch006_0", observerSham->insertEntries_[0].keySham.ToString()); + ASSERT_EQ("beijing", observerSham->insertEntries_[0].valueSham.ToString()); + ASSERT_EQ("SingleKvStoreDdmPutBatch006_1", observerSham->insertEntries_[1].keySham.ToString()); + ASSERT_EQ("SingleKvStoreDdmPutBatch006_2", observerSham->insertEntries_[2].keySham.ToString()); + ASSERT_EQ("SingleKvStoreDdmPutBatch006_3", observerSham->insertEntries_[3].keySham.ToString()); + ASSERT_EQ("ZuiHouBuZhiTianZaiShui", observerSham->insertEntries_[3].valueSham.ToString()); +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification026b + * @tc.desc: Subscribe to an observerSham[use transaction], include bigData PutBatch update insert delete + * @tc.type: FUNC + * @tc.require: I5GG0N + * @tc.author: SQL + */ +HWTEST_F(LocalKvStoreShamTest, KvStoreDdmSubscribeKvStoreNotification026b, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification026b begin."); + auto observerSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStore_Sham->SubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entries; + Entry entrySham5, entrySham6, entrySham7; + + int maxValueSize = 2 * 1024 * 1024; // max valueSham size is 2M. + std::vector val(maxValueSize); + for (int i = 0; i < maxValueSize; i++) { + val[i] = static_cast(i); + } + Value valueSham = val; + + int maxValueSize2 = 1000 * 1024; // max valueSham size is 1000k. + std::vector val2(maxValueSize2); + for (int i = 0; i < maxValueSize2; i++) { + val2[i] = static_cast(i); + } + + entrySham5.keySham = "SingleKvStoreDdmPutBatch006_2"; + entrySham5.valueSham = val2; + entrySham6.keySham = "SingleKvStoreDdmPutBatch006_3"; + entrySham6.valueSham = "ManChuanXingMengYaXingHe"; + entrySham7.keySham = "SingleKvStoreDdmPutBatch006_4"; + entrySham7.valueSham = val2; + std::vector updateEntries; + updateEntries.push_back(entrySham5); + updateEntries.push_back(entrySham6); + updateEntries.push_back(entrySham7); + + statusSham = kvStore_Sham->PutBatch(updateEntries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putBatch update data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(observerSham->updateEntries_.size()), 3); + ASSERT_EQ("SingleKvStoreDdmPutBatch006_2", observerSham->updateEntries_[0].keySham.ToString()); + ASSERT_EQ("SingleKvStoreDdmPutBatch006_3", observerSham->updateEntries_[1].keySham.ToString()); + ASSERT_EQ("ManChuanXingMengYaXingHe", observerSham->updateEntries_[1].valueSham.ToString()); + ASSERT_EQ("SingleKvStoreDdmPutBatch006_4", observerSham->updateEntries_[2].keySham.ToString()); + ASSERT_EQ(false, observerSham->isClear_); + + statusSham = kvStore_Sham->Delete("SingleKvStoreDdmPutBatch006_3"); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore delete data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham->GetCallCount(3)), 3); + ASSERT_EQ(static_cast(observerSham->deleteEntries_.size()), 1); + ASSERT_EQ("SingleKvStoreDdmPutBatch006_3", observerSham->deleteEntries_[0].keySham.ToString()); + + statusSham = kvStore_Sham->UnSubscribeKvStore(subscribeTypeSham, observerSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} \ No newline at end of file diff --git a/kv_store/databaseutils/test/local_kv_store_sham_unit_test.cpp b/kv_store/databaseutils/test/local_kv_store_sham_unit_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..59dd7c0341e047086a82da749fadce10faa1c37d --- /dev/null +++ b/kv_store/databaseutils/test/local_kv_store_sham_unit_test.cpp @@ -0,0 +1,1959 @@ +/* + * Copyright (c) 2024 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 "LocalKvStoreShamUnitTest" + +#include "block_data.h" +#include "distributed_kv_data_manager.h" +#include "log_print.h" +#include "types.h" +#include +#include +#include +#include + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::DistributedKv; +class LocalKvStoreShamUnitTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + + static DistributedKvDataManager shamTestManger_; + static std::shared_ptr shamTestStore_; + static Status shamTestStatus_; + static AppId shamTestAppId_; + static StoreId shamTestStoreId_; +}; +std::shared_ptr LocalKvStoreShamUnitTest::shamTestStore_ = nullptr; +Status LocalKvStoreShamUnitTest::shamTestStatus_ = Status::ERROR; +DistributedKvDataManager LocalKvStoreShamUnitTest::shamTestManger_; +AppId LocalKvStoreShamUnitTest::shamTestAppId_; +StoreId LocalKvStoreShamUnitTest::shamTestStoreId_; + +void LocalKvStoreShamUnitTest::SetUpTestCase(void) +{ + mkdir("/data/service/el1/public/database/local", (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); +} + +void LocalKvStoreShamUnitTest::TearDownTestCase(void) +{ + shamTestManger_.CloseKvStore(shamTestAppId_, shamTestStore_); + shamTestStore_ = nullptr; + shamTestManger_.DeleteKvStore(shamTestAppId_, shamTestStoreId_, "/data/service/el1/public/database/local"); + (void)remove("/data/service/el1/public/database/local/kvdb"); + (void)remove("/data/service/el1/public/database/local"); +} + +void LocalKvStoreShamUnitTest::SetUp(void) +{ + Options shamOptions; + shamOptions.securityLevel = S1; + shamOptions.baseDir = std::string("/data/service/el1/public/database/local"); + shamTestAppId_.appId = "local"; // define app name. + shamTestStoreId_.storeId = "MAN"; // define kvstore(database) name + shamTestManger_.DeleteKvStore(shamTestAppId_, shamTestStoreId_, shamOptions.baseDir); + // [create and] open and initialize kvstore instance. + shamTestStatus_ = shamTestManger_.GetSingleKvStore(shamOptions, shamTestAppId_, shamTestStoreId_, shamTestStore_); + ASSERT_EQ(Status::SUCCESS, shamTestStatus_) << "wrong status"; + ASSERT_NE(nullptr, shamTestStore_) << "kvStore is nullptr"; +} + +void LocalKvStoreShamUnitTest::TearDown(void) +{ + shamTestManger_.CloseKvStore(shamTestAppId_, shamTestStore_); + shamTestStore_ = nullptr; + shamTestManger_.DeleteKvStore(shamTestAppId_, shamTestStoreId_); +} + +class DeviceObserverShamUnitTest : public KvStoreObserver { +public: + std::vector insertShamEntries_; + std::vector updateShamEntries_; + std::vector deleteShamEntries_; + std::string shamDeviceId_; + bool isShamClear_ = false; + DeviceObserverShamUnitTest(); + ~DeviceObserverShamUnitTest() = default; + + void OnChange(const ChangeNotification &changeNotification); + + // reset the shamCallCount_ to zero. + void ResetToZero(); + + uint32_t GetCallCount(uint32_t shamTestValue = 1); + +private: + std::mutex shamMutex_; + uint32_t shamCallCount_ = 0; + BlockData shamValue_ { 1, 0 }; +}; + +DeviceObserverShamUnitTest::DeviceObserverShamUnitTest() { } + +void DeviceObserverShamUnitTest::OnChange(const ChangeNotification &changeNotification) +{ + ZLOGD("begin."); + insertShamEntries_ = changeNotification.GetInsertEntries(); + updateShamEntries_ = changeNotification.GetUpdateEntries(); + deleteShamEntries_ = changeNotification.GetDeleteEntries(); + shamDeviceId_ = changeNotification.GetDeviceId(); + isShamClear_ = changeNotification.IsClear(); + std::lock_guard guard(shamMutex_); + ++shamCallCount_; + shamValue_.SetValue(shamCallCount_); +} + +void DeviceObserverShamUnitTest::ResetToZero() +{ + std::lock_guard guard(shamMutex_); + shamCallCount_ = 0; + shamValue_.Clear(0); +} + +uint32_t DeviceObserverShamUnitTest::GetCallCount(uint32_t shamTestValue) +{ + int retryTimes = 0; + uint32_t callCount = 0; + while (retryTimes < shamTestValue) { + callCount = shamValue_.GetValue(); + if (callCount >= shamTestValue) { + break; + } + std::lock_guard guard(shamMutex_); + callCount = shamValue_.GetValue(); + if (callCount >= shamTestValue) { + break; + } + shamValue_.Clear(callCount); + retryTimes++; + } + return callCount; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore001 + * @tc.desc: Subscribe success + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStore001, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore001 begin."); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + auto shamObserver = std::make_shared(); + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 0); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; + shamObserver = nullptr; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore002 + * @tc.desc: Subscribe fail, shamObserver is null + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStore002, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore002 begin."); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + std::shared_ptr shamObserver = nullptr; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::INVALID_ARGUMENT, shamStatus) << "SubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore003 + * @tc.desc: Subscribe success and OnChange callback after put + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStore003, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore003 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + Key shamTestKey = "Id1"; + Value shamTestValue = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey, shamTestValue); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; + shamObserver = nullptr; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore004 + * @tc.desc: The same shamObserver subscribe three times and OnChange callback after put + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStore004, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore004 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::STORE_ALREADY_SUBSCRIBE, shamStatus) << "SubscribeKvStore return wrong"; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::STORE_ALREADY_SUBSCRIBE, shamStatus) << "SubscribeKvStore return wrong"; + + Key shamTestKey = "Id1"; + Value shamTestValue = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey, shamTestValue); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore005 + * @tc.desc: The different shamObserver subscribe three times and OnChange callback after put + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStore005, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore005 begin."); + auto observer1 = std::make_shared(); + auto observer2 = std::make_shared(); + auto observer3 = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, observer1); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore failed, wrong"; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, observer2); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore failed, wrong"; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, observer3); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore failed, wrong"; + + Key shamTestKey = "Id1"; + Value shamTestValue = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey, shamTestValue); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "Putting data to KvStore failed, wrong"; + ASSERT_EQ(static_cast(observer1->GetCallCount()), 1); + ASSERT_EQ(static_cast(observer2->GetCallCount()), 1); + ASSERT_EQ(static_cast(observer3->GetCallCount()), 1); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, observer1); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, observer2); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, observer3); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore006 + * @tc.desc: Unsubscribe an shamObserver and subscribe again - the map should be cleared after unsubscription. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStore006, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore006 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + Key shamTestKey1 = "Id1"; + Value shamTestValue1 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey1, shamTestValue1); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; + + Key shamTestKey2 = "Id2"; + Value shamTestValue2 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey2, shamTestValue2); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + + shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + Key shamTestKey3 = "Id3"; + Value shamTestValue3 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey3, shamTestValue3); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount(2)), 2); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore007 + * @tc.desc: Subscribe to an shamObserver - OnChange callback is called multiple times after the put operation. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStore007, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore007 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + Key shamTestKey1 = "Id1"; + Value shamTestValue1 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey1, shamTestValue1); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + + Key shamTestKey2 = "Id2"; + Value shamTestValue2 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey2, shamTestValue2); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + + Key shamTestKey3 = "Id3"; + Value shamTestValue3 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey3, shamTestValue3); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount(3)), 3); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore008 +* @tc.desc: Subscribe to an shamObserver - OnChange callback is + called multiple times after the put&update operations. +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStore008, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore008 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + Key shamTestKey1 = "Id1"; + Value shamTestValue1 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey1, shamTestValue1); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + + Key shamTestKey2 = "Id2"; + Value shamTestValue2 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey2, shamTestValue2); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + + Key shamTestKey3 = "Id1"; + Value shamTestValue3 = "subscribe03"; + shamStatus = shamTestStore_->Put(shamTestKey3, shamTestValue3); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount(3)), 3); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore009 + * @tc.desc: Subscribe to an shamObserver - OnChange callback is called multiple times after the putBatch operation. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStore009, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore009 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + // before update. + std::vector shamTestEntries1; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries1.push_back(shamTestEnty1); + shamTestEntries1.push_back(shamTestEnty2); + shamTestEntries1.push_back(shamTestEnty3); + + std::vector shamTestEntries2; + Entry shamTestEnty4, shamTestEnty5; + shamTestEnty4.shamTestKey = "Id4"; + shamTestEnty4.shamTestValue = "subscribe"; + shamTestEnty5.shamTestKey = "Id5"; + shamTestEnty5.shamTestValue = "subscribe"; + shamTestEntries2.push_back(shamTestEnty4); + shamTestEntries2.push_back(shamTestEnty5); + + shamStatus = shamTestStore_->PutBatch(shamTestEntries1); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + shamStatus = shamTestStore_->PutBatch(shamTestEntries2); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount(2)), 2); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore010 +* @tc.desc: Subscribe to an shamObserver - OnChange callback is + called multiple times after the putBatch update operation. +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStore010, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore010 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + // before update. + std::vector shamTestEntries1; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries1.push_back(shamTestEnty1); + shamTestEntries1.push_back(shamTestEnty2); + shamTestEntries1.push_back(shamTestEnty3); + + std::vector shamTestEntries2; + Entry shamTestEnty4, shamTestEnty5; + shamTestEnty4.shamTestKey = "Id1"; + shamTestEnty4.shamTestValue = "modify"; + shamTestEnty5.shamTestKey = "Id2"; + shamTestEnty5.shamTestValue = "modify"; + shamTestEntries2.push_back(shamTestEnty4); + shamTestEntries2.push_back(shamTestEnty5); + + shamStatus = shamTestStore_->PutBatch(shamTestEntries1); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + shamStatus = shamTestStore_->PutBatch(shamTestEntries2); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount(2)), 2); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore011 + * @tc.desc: Subscribe to an shamObserver - OnChange callback is called after successful deletion. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStore011, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore011 begin."); + auto shamObserver = std::make_shared(); + std::vector shamTestEntries; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamTestEntries.push_back(shamTestEnty3); + + Status shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + shamStatus = shamTestStore_->Delete("Id1"); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore Delete data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore012 + * @tc.desc: Subscribe to an shamObserver - OnChange callback is not called after deletion of non-existing keys. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStore012, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore012 begin."); + auto shamObserver = std::make_shared(); + std::vector shamTestEntries; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamTestEntries.push_back(shamTestEnty3); + + Status shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + shamStatus = shamTestStore_->Delete("Id4"); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore Delete data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 0); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore013 + * @tc.desc: Subscribe to an shamObserver - OnChange callback is called after KvStore is cleared. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStore013, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore013 begin."); + auto shamObserver = std::make_shared(); + std::vector shamTestEntries; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamTestEntries.push_back(shamTestEnty3); + + Status shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 0); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore014 +* @tc.desc: Subscribe to an shamObserver - OnChange callback is + not called after non-existing data in KvStore is cleared. +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStore014, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore014 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 0); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore015 + * @tc.desc: Subscribe to an shamObserver - OnChange callback is called after the deleteBatch operation. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStore015, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore015 begin."); + auto shamObserver = std::make_shared(); + std::vector shamTestEntries; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamTestEntries.push_back(shamTestEnty3); + + std::vector keys; + keys.push_back("Id1"); + keys.push_back("Id2"); + + Status shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + shamStatus = shamTestStore_->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore DeleteBatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore016 + * @tc.desc: Subscribe to an shamObserver - OnChange callback is called after deleteBatch of non-existing keys. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStore016, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore016 begin."); + auto shamObserver = std::make_shared(); + std::vector shamTestEntries; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamTestEntries.push_back(shamTestEnty3); + + std::vector keys; + keys.push_back("Id4"); + keys.push_back("Id5"); + + Status shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + shamStatus = shamTestStore_->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore DeleteBatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 0); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore020 + * @tc.desc: Unsubscribe an shamObserver two times. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStore020, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore020 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::STORE_NOT_SUBSCRIBE, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification001 +* @tc.desc: Subscribe to an shamObserver successfully - callback is + called with a notification after the put operation. +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification001, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification001 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + Key shamTestKey = "Id1"; + Value shamTestValue = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey, shamTestValue); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ZLOGD("kvstore_ddm_subscribekvstore_003"); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 1); + ASSERT_EQ("Id1", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + ZLOGD("kvstore_ddm_subscribekvstore_003 size:%zu.", shamObserver->insertShamEntries_.size()); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification002 +* @tc.desc: Subscribe to the same shamObserver three times - callback is + called with a notification after the put operation. +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification002, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification002 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::STORE_ALREADY_SUBSCRIBE, shamStatus) << "SubscribeKvStore return wrong"; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::STORE_ALREADY_SUBSCRIBE, shamStatus) << "SubscribeKvStore return wrong"; + + Key shamTestKey = "Id1"; + Value shamTestValue = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey, shamTestValue); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 1); + ASSERT_EQ("Id1", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification003 + * @tc.desc: The different shamObserver subscribe three times and callback with notification after put + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification003, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification003 begin."); + auto observer1 = std::make_shared(); + auto observer2 = std::make_shared(); + auto observer3 = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, observer1); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, observer2); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, observer3); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + Key shamTestKey = "Id1"; + Value shamTestValue = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey, shamTestValue); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(observer1->GetCallCount()), 1); + ASSERT_EQ(static_cast(observer1->insertShamEntries_.size()), 1); + ASSERT_EQ("Id1", observer1->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", observer1->insertShamEntries_[0].shamTestValue.ToString()); + + ASSERT_EQ(static_cast(observer2->GetCallCount()), 1); + ASSERT_EQ(static_cast(observer2->insertShamEntries_.size()), 1); + ASSERT_EQ("Id1", observer2->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", observer2->insertShamEntries_[0].shamTestValue.ToString()); + + ASSERT_EQ(static_cast(observer3->GetCallCount()), 1); + ASSERT_EQ(static_cast(observer3->insertShamEntries_.size()), 1); + ASSERT_EQ("Id1", observer3->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", observer3->insertShamEntries_[0].shamTestValue.ToString()); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, observer1); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, observer2); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, observer3); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification004 + * @tc.desc: Verify notification after an shamObserver is unsubscribed and then subscribed again. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification004, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification004 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + Key shamTestKey1 = "Id1"; + Value shamTestValue1 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey1, shamTestValue1); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 1); + ASSERT_EQ("Id1", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; + + Key shamTestKey2 = "Id2"; + Value shamTestValue2 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey2, shamTestValue2); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 1); + ASSERT_EQ("Id1", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + + shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + Key shamTestKey3 = "Id3"; + Value shamTestValue3 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey3, shamTestValue3); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 1); + ASSERT_EQ("Id3", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification005 + * @tc.desc: Subscribe to an shamObserver, callback with notification many times after put the different data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification005, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification005 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + Key shamTestKey1 = "Id1"; + Value shamTestValue1 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey1, shamTestValue1); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 1); + ASSERT_EQ("Id1", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + + Key shamTestKey2 = "Id2"; + Value shamTestValue2 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey2, shamTestValue2); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 1); + ASSERT_EQ("Id2", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + + Key shamTestKey3 = "Id3"; + Value shamTestValue3 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey3, shamTestValue3); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount(3)), 3); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 1); + ASSERT_EQ("Id3", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification006 + * @tc.desc: Subscribe to an shamObserver, callback with notification many times after put the same data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification006, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification006 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + Key shamTestKey1 = "Id1"; + Value shamTestValue1 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey1, shamTestValue1); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 1); + ASSERT_EQ("Id1", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + + Key shamTestKey2 = "Id1"; + Value shamTestValue2 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey2, shamTestValue2); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(shamObserver->updateShamEntries_.size()), 1); + ASSERT_EQ("Id1", shamObserver->updateShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->updateShamEntries_[0].shamTestValue.ToString()); + + Key shamTestKey3 = "Id1"; + Value shamTestValue3 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey3, shamTestValue3); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount(3)), 3); + ASSERT_EQ(static_cast(shamObserver->updateShamEntries_.size()), 1); + ASSERT_EQ("Id1", shamObserver->updateShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->updateShamEntries_[0].shamTestValue.ToString()); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification007 + * @tc.desc: Subscribe to an shamObserver, callback with notification many times after put&update + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification007, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification007 begin."); + auto shamObserver = std::make_shared(); + Key shamTestKey1 = "Id1"; + Value shamTestValue1 = "subscribe"; + Status shamStatus = shamTestStore_->Put(shamTestKey1, shamTestValue1); + // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + + Key shamTestKey2 = "Id2"; + Value shamTestValue2 = "subscribe"; + shamStatus = shamTestStore_->Put(shamTestKey2, shamTestValue2); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + Key shamTestKey3 = "Id1"; + Value shamTestValue3 = "subscribe03"; + shamStatus = shamTestStore_->Put(shamTestKey3, shamTestValue3); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->updateShamEntries_.size()), 1); + ASSERT_EQ("Id1", shamObserver->updateShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe03", shamObserver->updateShamEntries_[0].shamTestValue.ToString()); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification008 + * @tc.desc: Subscribe to an shamObserver, callback with notification one times after putbatch&update + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification008, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification008 begin."); + std::vector shamTestEntries; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamTestEntries.push_back(shamTestEnty3); + + Status shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + shamTestEntries.clear(); + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe_modify"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe_modify"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->updateShamEntries_.size()), 2); + ASSERT_EQ("Id1", shamObserver->updateShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe_modify", shamObserver->updateShamEntries_[0].shamTestValue.ToString()); + ASSERT_EQ("Id2", shamObserver->updateShamEntries_[1].shamTestKey.ToString()); + ASSERT_EQ("subscribe_modify", shamObserver->updateShamEntries_[1].shamTestValue.ToString()); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification009 + * @tc.desc: Subscribe to an shamObserver, callback with notification one times after putbatch all different data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification009, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification009 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + std::vector shamTestEntries; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamTestEntries.push_back(shamTestEnty3); + + shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 3); + ASSERT_EQ("Id1", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + ASSERT_EQ("Id2", shamObserver->insertShamEntries_[1].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[1].shamTestValue.ToString()); + ASSERT_EQ("Id3", shamObserver->insertShamEntries_[2].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[2].shamTestValue.ToString()); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification010 +* @tc.desc: Subscribe to an shamObserver, + callback with notification one times after putbatch both different and same data +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification010, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification010 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + std::vector shamTestEntries; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id1"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id2"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamTestEntries.push_back(shamTestEnty3); + + shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 2); + ASSERT_EQ("Id1", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + ASSERT_EQ("Id2", shamObserver->insertShamEntries_[1].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[1].shamTestValue.ToString()); + ASSERT_EQ(static_cast(shamObserver->updateShamEntries_.size()), 0); + ASSERT_EQ(static_cast(shamObserver->deleteShamEntries_.size()), 0); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification011 + * @tc.desc: Subscribe to an shamObserver, callback with notification one times after putbatch all same data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification011, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification011 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + std::vector shamTestEntries; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id1"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id1"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamTestEntries.push_back(shamTestEnty3); + + shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 1); + ASSERT_EQ("Id1", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + ASSERT_EQ(static_cast(shamObserver->updateShamEntries_.size()), 0); + ASSERT_EQ(static_cast(shamObserver->deleteShamEntries_.size()), 0); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification012 + * @tc.desc: Subscribe to an shamObserver, callback with notification many times after putbatch all different data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification012, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification012 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + std::vector shamTestEntries1; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries1.push_back(shamTestEnty1); + shamTestEntries1.push_back(shamTestEnty2); + shamTestEntries1.push_back(shamTestEnty3); + + std::vector shamTestEntries2; + Entry shamTestEnty4, shamTestEnty5; + shamTestEnty4.shamTestKey = "Id4"; + shamTestEnty4.shamTestValue = "subscribe"; + shamTestEnty5.shamTestKey = "Id5"; + shamTestEnty5.shamTestValue = "subscribe"; + shamTestEntries2.push_back(shamTestEnty4); + shamTestEntries2.push_back(shamTestEnty5); + + shamStatus = shamTestStore_->PutBatch(shamTestEntries1); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 3); + ASSERT_EQ("Id1", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + ASSERT_EQ("Id2", shamObserver->insertShamEntries_[1].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[1].shamTestValue.ToString()); + ASSERT_EQ("Id3", shamObserver->insertShamEntries_[2].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[2].shamTestValue.ToString()); +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification012b + * @tc.desc: Subscribe to an shamObserver, callback with notification many times after putbatch all different data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification012b, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification012b begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + std::vector shamTestEntries1; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries1.push_back(shamTestEnty1); + shamTestEntries1.push_back(shamTestEnty2); + shamTestEntries1.push_back(shamTestEnty3); + + std::vector shamTestEntries2; + Entry shamTestEnty4, shamTestEnty5; + shamTestEnty4.shamTestKey = "Id4"; + shamTestEnty4.shamTestValue = "subscribe"; + shamTestEnty5.shamTestKey = "Id5"; + shamTestEnty5.shamTestValue = "subscribe"; + shamTestEntries2.push_back(shamTestEnty4); + shamTestEntries2.push_back(shamTestEnty5); + + shamStatus = shamTestStore_->PutBatch(shamTestEntries2); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 2); + ASSERT_EQ("Id4", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + ASSERT_EQ("Id5", shamObserver->insertShamEntries_[1].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[1].shamTestValue.ToString()); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification013 +* @tc.desc: Subscribe to an shamObserver, + callback with notification many times after putbatch both different and same data +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification013, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification013 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + std::vector shamTestEntries1; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries1.push_back(shamTestEnty1); + shamTestEntries1.push_back(shamTestEnty2); + shamTestEntries1.push_back(shamTestEnty3); + + std::vector shamTestEntries2; + Entry shamTestEnty4, shamTestEnty5; + shamTestEnty4.shamTestKey = "Id1"; + shamTestEnty4.shamTestValue = "subscribe"; + shamTestEnty5.shamTestKey = "Id4"; + shamTestEnty5.shamTestValue = "subscribe"; + shamTestEntries2.push_back(shamTestEnty4); + shamTestEntries2.push_back(shamTestEnty5); + + shamStatus = shamTestStore_->PutBatch(shamTestEntries1); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 3); + ASSERT_EQ("Id1", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + ASSERT_EQ("Id2", shamObserver->insertShamEntries_[1].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[1].shamTestValue.ToString()); + ASSERT_EQ("Id3", shamObserver->insertShamEntries_[2].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[2].shamTestValue.ToString()); +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification013b +* @tc.desc: Subscribe to an shamObserver, + callback with notification many times after putbatch both different and same data +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification013b, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification013b begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + std::vector shamTestEntries1; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries1.push_back(shamTestEnty1); + shamTestEntries1.push_back(shamTestEnty2); + shamTestEntries1.push_back(shamTestEnty3); + + std::vector shamTestEntries2; + Entry shamTestEnty4, shamTestEnty5; + shamTestEnty4.shamTestKey = "Id1"; + shamTestEnty4.shamTestValue = "subscribe"; + shamTestEnty5.shamTestKey = "Id4"; + shamTestEnty5.shamTestValue = "subscribe"; + shamTestEntries2.push_back(shamTestEnty4); + shamTestEntries2.push_back(shamTestEnty5); + shamStatus = shamTestStore_->PutBatch(shamTestEntries2); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(shamObserver->updateShamEntries_.size()), 1); + ASSERT_EQ("Id1", shamObserver->updateShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->updateShamEntries_[0].shamTestValue.ToString()); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 1); + ASSERT_EQ("Id4", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification014 + * @tc.desc: Subscribe to an shamObserver, callback with notification many times after putbatch all same data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification014, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification014 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + std::vector shamTestEntries1; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries1.push_back(shamTestEnty1); + shamTestEntries1.push_back(shamTestEnty2); + shamTestEntries1.push_back(shamTestEnty3); + + std::vector shamTestEntries2; + Entry shamTestEnty4, shamTestEnty5; + shamTestEnty4.shamTestKey = "Id1"; + shamTestEnty4.shamTestValue = "subscribe"; + shamTestEnty5.shamTestKey = "Id2"; + shamTestEnty5.shamTestValue = "subscribe"; + shamTestEntries2.push_back(shamTestEnty4); + shamTestEntries2.push_back(shamTestEnty5); + + shamStatus = shamTestStore_->PutBatch(shamTestEntries1); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 3); + ASSERT_EQ("Id1", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + ASSERT_EQ("Id2", shamObserver->insertShamEntries_[1].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[1].shamTestValue.ToString()); + ASSERT_EQ("Id3", shamObserver->insertShamEntries_[2].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[2].shamTestValue.ToString()); + + shamStatus = shamTestStore_->PutBatch(shamTestEntries2); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(shamObserver->updateShamEntries_.size()), 2); + ASSERT_EQ("Id1", shamObserver->updateShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->updateShamEntries_[0].shamTestValue.ToString()); + ASSERT_EQ("Id2", shamObserver->updateShamEntries_[1].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->updateShamEntries_[1].shamTestValue.ToString()); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification015 + * @tc.desc: Subscribe to an shamObserver, callback with notification many times after putbatch complex data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification015, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification015 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + std::vector shamTestEntries1; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id1"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries1.push_back(shamTestEnty1); + shamTestEntries1.push_back(shamTestEnty2); + shamTestEntries1.push_back(shamTestEnty3); + + std::vector shamTestEntries2; + Entry shamTestEnty4, shamTestEnty5; + shamTestEnty4.shamTestKey = "Id1"; + shamTestEnty4.shamTestValue = "subscribe"; + shamTestEnty5.shamTestKey = "Id2"; + shamTestEnty5.shamTestValue = "subscribe"; + shamTestEntries2.push_back(shamTestEnty4); + shamTestEntries2.push_back(shamTestEnty5); + + shamStatus = shamTestStore_->PutBatch(shamTestEntries1); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->updateShamEntries_.size()), 0); + ASSERT_EQ(static_cast(shamObserver->deleteShamEntries_.size()), 0); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 2); + ASSERT_EQ("Id1", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + ASSERT_EQ("Id3", shamObserver->insertShamEntries_[1].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[1].shamTestValue.ToString()); +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification015b + * @tc.desc: Subscribe to an shamObserver, callback with notification many times after putbatch complex data + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification015b, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification015b begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + std::vector shamTestEntries1; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id1"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries1.push_back(shamTestEnty1); + shamTestEntries1.push_back(shamTestEnty2); + shamTestEntries1.push_back(shamTestEnty3); + + std::vector shamTestEntries2; + Entry shamTestEnty4, shamTestEnty5; + shamTestEnty4.shamTestKey = "Id1"; + shamTestEnty4.shamTestValue = "subscribe"; + shamTestEnty5.shamTestKey = "Id2"; + shamTestEnty5.shamTestValue = "subscribe"; + shamTestEntries2.push_back(shamTestEnty4); + shamTestEntries2.push_back(shamTestEnty5); + shamStatus = shamTestStore_->PutBatch(shamTestEntries2); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount(2)), 2); + ASSERT_EQ(static_cast(shamObserver->updateShamEntries_.size()), 1); + ASSERT_EQ("Id1", shamObserver->updateShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->updateShamEntries_[0].shamTestValue.ToString()); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 1); + ASSERT_EQ("Id2", shamObserver->insertShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->insertShamEntries_[0].shamTestValue.ToString()); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification016 + * @tc.desc: Pressure test subscribe, callback with notification many times after putbatch + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification016, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification016 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + int times = 100; // 100 times + std::vector shamTestEntries; + for (int i = 0; i < times; i++) { + Entry shamTestEnty; + shamTestEnty.shamTestKey = std::to_string(i); + shamTestEnty.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty); + } + + shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 100); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification017 + * @tc.desc: Subscribe to an shamObserver, callback with notification after delete success + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification017, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification017 begin."); + auto shamObserver = std::make_shared(); + std::vector shamTestEntries; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamTestEntries.push_back(shamTestEnty3); + + Status shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + shamStatus = shamTestStore_->Delete("Id1"); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore Delete data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->deleteShamEntries_.size()), 1); + ASSERT_EQ("Id1", shamObserver->deleteShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->deleteShamEntries_[0].shamTestValue.ToString()); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification018 + * @tc.desc: Subscribe to an shamObserver, not callback after delete which shamTestKey not exist + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification018, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification018 begin."); + auto shamObserver = std::make_shared(); + std::vector shamTestEntries; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamTestEntries.push_back(shamTestEnty3); + + Status shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + shamStatus = shamTestStore_->Delete("Id4"); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore Delete data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 0); + ASSERT_EQ(static_cast(shamObserver->deleteShamEntries_.size()), 0); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification019 +* @tc.desc: Subscribe to an shamObserver, + delete the same data many times and only first delete callback with notification +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification019, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification019 begin."); + auto shamObserver = std::make_shared(); + std::vector shamTestEntries; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamTestEntries.push_back(shamTestEnty3); + + Status shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + shamStatus = shamTestStore_->Delete("Id1"); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore Delete data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->deleteShamEntries_.size()), 1); + ASSERT_EQ("Id1", shamObserver->deleteShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->deleteShamEntries_[0].shamTestValue.ToString()); + + shamStatus = shamTestStore_->Delete("Id1"); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore Delete data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount(2)), 1); + ASSERT_EQ(static_cast(shamObserver->deleteShamEntries_.size()), 1); // not callback so not clear + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification020 + * @tc.desc: Subscribe to an shamObserver, callback with notification after deleteBatch + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification020, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification020 begin."); + auto shamObserver = std::make_shared(); + std::vector shamTestEntries; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamTestEntries.push_back(shamTestEnty3); + + std::vector keys; + keys.push_back("Id1"); + keys.push_back("Id2"); + + Status shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + shamStatus = shamTestStore_->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore DeleteBatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->deleteShamEntries_.size()), 2); + ASSERT_EQ("Id1", shamObserver->deleteShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->deleteShamEntries_[0].shamTestValue.ToString()); + ASSERT_EQ("Id2", shamObserver->deleteShamEntries_[1].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->deleteShamEntries_[1].shamTestValue.ToString()); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification021 + * @tc.desc: Subscribe to an shamObserver, not callback after deleteBatch which all keys not exist + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification021, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification021 begin."); + auto shamObserver = std::make_shared(); + std::vector shamTestEntries; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamTestEntries.push_back(shamTestEnty3); + + std::vector keys; + keys.push_back("Id4"); + keys.push_back("Id5"); + + Status shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + shamStatus = shamTestStore_->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore DeleteBatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 0); + ASSERT_EQ(static_cast(shamObserver->deleteShamEntries_.size()), 0); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification022 +* @tc.desc: Subscribe to an shamObserver, + deletebatch the same data many times and only first deletebatch callback with +* notification +* @tc.type: FUNC +* @tc.require: +* @tc.author: +*/ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification022, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification022 begin."); + auto shamObserver = std::make_shared(); + std::vector shamTestEntries; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + shamTestEnty1.shamTestKey = "Id1"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id2"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id3"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamTestEntries.push_back(shamTestEnty3); + + std::vector keys; + keys.push_back("Id1"); + keys.push_back("Id2"); + + Status shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + shamStatus = shamTestStore_->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore DeleteBatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + ASSERT_EQ(static_cast(shamObserver->deleteShamEntries_.size()), 2); + ASSERT_EQ("Id1", shamObserver->deleteShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->deleteShamEntries_[0].shamTestValue.ToString()); + ASSERT_EQ("Id2", shamObserver->deleteShamEntries_[1].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->deleteShamEntries_[1].shamTestValue.ToString()); + + shamStatus = shamTestStore_->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore DeleteBatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount(2)), 1); + ASSERT_EQ(static_cast(shamObserver->deleteShamEntries_.size()), 2); // not callback so not clear + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification023 + * @tc.desc: Subscribe to an shamObserver, include Clear Put PutBatch Delete DeleteBatch + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification023, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification023 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + Key shamTestKey1 = "Id1"; + Value shamTestValue1 = "subscribe"; + + std::vector shamTestEntries; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + shamTestEnty1.shamTestKey = "Id2"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id3"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id4"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamTestEntries.push_back(shamTestEnty3); + + std::vector keys; + keys.push_back("Id2"); + keys.push_back("Id3"); + + shamStatus = shamTestStore_->Put(shamTestKey1, shamTestValue1); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + shamStatus = shamTestStore_->Delete(shamTestKey1); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore delete data return wrong"; + shamStatus = shamTestStore_->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore DeleteBatch data return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount(4)), 4); + // every callback will clear vector + ASSERT_EQ(static_cast(shamObserver->deleteShamEntries_.size()), 2); + ASSERT_EQ("Id2", shamObserver->deleteShamEntries_[0].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->deleteShamEntries_[0].shamTestValue.ToString()); + ASSERT_EQ("Id3", shamObserver->deleteShamEntries_[1].shamTestKey.ToString()); + ASSERT_EQ("subscribe", shamObserver->deleteShamEntries_[1].shamTestValue.ToString()); + ASSERT_EQ(static_cast(shamObserver->updateShamEntries_.size()), 0); + ASSERT_EQ(static_cast(shamObserver->insertShamEntries_.size()), 0); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification024 + * @tc.desc: Subscribe to an shamObserver[use transaction], include Clear Put PutBatch Delete DeleteBatch + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(LocalKvStoreShamUnitTest, KvStoreDdmSubscribeKvStoreNotification024, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification024 begin."); + auto shamObserver = std::make_shared(); + SubscribeType shamSubscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status shamStatus = shamTestStore_->SubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "SubscribeKvStore return wrong"; + + Key shamTestKey1 = "Id1"; + Value shamTestValue1 = "subscribe"; + + std::vector shamTestEntries; + Entry shamTestEnty1, shamTestEnty2, shamTestEnty3; + shamTestEnty1.shamTestKey = "Id2"; + shamTestEnty1.shamTestValue = "subscribe"; + shamTestEnty2.shamTestKey = "Id3"; + shamTestEnty2.shamTestValue = "subscribe"; + shamTestEnty3.shamTestKey = "Id4"; + shamTestEnty3.shamTestValue = "subscribe"; + shamTestEntries.push_back(shamTestEnty1); + shamTestEntries.push_back(shamTestEnty2); + shamTestEntries.push_back(shamTestEnty3); + + std::vector keys; + keys.push_back("Id2"); + keys.push_back("Id3"); + + shamStatus = shamTestStore_->StartTransaction(); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore startTransaction return wrong"; + shamStatus = shamTestStore_->Put(shamTestKey1, shamTestValue1); // insert or update shamTestKey-shamTestValue + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore put data return wrong"; + shamStatus = shamTestStore_->PutBatch(shamTestEntries); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore putbatch data return wrong"; + shamStatus = shamTestStore_->Delete(shamTestKey1); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore delete data return wrong"; + shamStatus = shamTestStore_->DeleteBatch(keys); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore DeleteBatch data return wrong"; + shamStatus = shamTestStore_->Commit(); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "KvStore Commit return wrong"; + ASSERT_EQ(static_cast(shamObserver->GetCallCount()), 1); + + shamStatus = shamTestStore_->UnSubscribeKvStore(shamSubscribeType, shamObserver); + ASSERT_EQ(Status::SUCCESS, shamStatus) << "UnSubscribeKvStore return wrong"; +} \ No newline at end of file diff --git a/kv_store/databaseutils/test/local_kv_store_virtual_test.cpp b/kv_store/databaseutils/test/local_kv_store_virtual_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..41a2c7f8eacf709dbe08ef47fb0f62077a180810 --- /dev/null +++ b/kv_store/databaseutils/test/local_kv_store_virtual_test.cpp @@ -0,0 +1,2140 @@ +/* + * Copyright (c) 2024 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 "LocalKvStoreVirtualTest" +#include +#include +#include +#include +#include "block_data.h" +#include "distributed_kv_data_manager.h" +#include "log_print.h" +#include "types.h" + +using namespace testing::ext; +using namespace OHOS::DistributedKv; +using namespace OHOS; +class LocalKvStoreVirtualTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + + static DistributedKvDataManager manager_Virtual; + static std::shared_ptr kvStore_Virtual; + static Status status_Virtual; + static AppId appId_Virtual; + static StoreId storeId_Virtual; +}; +std::shared_ptr LocalKvStoreVirtualTest::kvStore_Virtual = nullptr; +Status LocalKvStoreVirtualTest::status_Virtual = Status::ERROR; +DistributedKvDataManager LocalKvStoreVirtualTest::manager_Virtual; +AppId LocalKvStoreVirtualTest::appId_Virtual; +StoreId LocalKvStoreVirtualTest::storeId_Virtual; + +void LocalKvStoreVirtualTest::SetUpTestCase(void) +{ + mkdir("/data/service/el1/public/database/dev_local_sub", (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); +} + +void LocalKvStoreVirtualTest::TearDownTestCase(void) +{ + manager_Virtual.CloseKvStore(appId_Virtual, kvStore_Virtual); + kvStore_Virtual = nullptr; + manager_Virtual.DeleteKvStore(appId_Virtual, storeId_Virtual, "/data/service/el1/public/database/dev_local_sub"); + (void)remove("/data/service/el1/public/database/dev_local_sub/kvdb"); + (void)remove("/data/service/el1/public/database/dev_local_sub"); +} + +void LocalKvStoreVirtualTest::SetUp(void) +{ + Options options; + options.securityLevel = S1; + options.baseDir = std::string("/data/service/el1/public/database/dev_local_sub"); + appId_Virtual.appId = "dev_local_sub"; // define app name. + storeId_Virtual.storeId = "student"; // define kvstore(database) name + manager_Virtual.DeleteKvStore(appId_Virtual, storeId_Virtual, options.baseDir); + // [create and] open and initialize kvstore instance. + status_Virtual = manager_Virtual.GetSingleKvStore(options, appId_Virtual, storeId_Virtual, kvStore_Virtual); + EXPECT_EQ(Status::SUCCESS, status_Virtual) << "wrong statusVirtual"; + EXPECT_NE(nullptr, kvStore_Virtual) << "kvStore is nullptr"; +} + +void LocalKvStoreVirtualTest::TearDown(void) +{ + manager_Virtual.CloseKvStore(appId_Virtual, kvStore_Virtual); + kvStore_Virtual = nullptr; + manager_Virtual.DeleteKvStore(appId_Virtual, storeId_Virtual); +} + +class DeviceObserverTest : public KvStoreObserver { +public: + std::vector insertEntries_; + std::vector updateEntries_; + std::vector deleteEntries_; + std::string deviceId_; + bool isClear_ = false; + DeviceObserverTest(); + ~DeviceObserverTest() = default; + + void OnChange(const ChangeNotification &changeNotification); + + // reset the callCount_ to zero. + void ResetToZero(); + + uint32_t GetCallCount(uint32_t valueVirtual = 1); + +private: + std::mutex mutex_; + uint32_t callCount_ = 0; + BlockData value_{ 1, 0 }; +}; + +DeviceObserverTest::DeviceObserverTest() +{ +} + +void DeviceObserverTest::OnChange(const ChangeNotification &changeNotification) +{ + ZLOGD("begin."); + insertEntries_ = changeNotification.GetInsertEntries(); + updateEntries_ = changeNotification.GetUpdateEntries(); + deleteEntries_ = changeNotification.GetDeleteEntries(); + deviceId_ = changeNotification.GetDeviceId(); + isClear_ = changeNotification.IsClear(); + std::lock_guard guard(mutex_); + ++callCount_; + value_.SetValue(callCount_); +} + +void DeviceObserverTest::ResetToZero() +{ + std::lock_guard guard(mutex_); + callCount_ = 0; + value_.Clear(0); +} + +uint32_t DeviceObserverTest::GetCallCount(uint32_t valueVirtual) +{ + int retry = 0; + uint32_t callTimes = 0; + while (retry < valueVirtual) { + callTimes = value_.GetValue(); + if (callTimes >= valueVirtual) { + break; + } + std::lock_guard guard(mutex_); + callTimes = value_.GetValue(); + if (callTimes >= valueVirtual) { + break; + } + value_.Clear(callTimes); + retry++; + } + return callTimes; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore001 +* @tc.desc: Subscribe success +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStore001, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore001 begin."); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + auto observerVirtual = std::make_shared(); + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 0); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + observerVirtual = nullptr; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore002 +* @tc.desc: Subscribe fail, observerVirtual is null +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStore002, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore002 begin."); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + std::shared_ptr observerVirtual = nullptr; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::INVALID_ARGUMENT, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore003 +* @tc.desc: Subscribe success and OnChange callback after put +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStore003, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore003 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key keyVirtual = "Id1"; + Value valueVirtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(keyVirtual, valueVirtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + observerVirtual = nullptr; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore004 +* @tc.desc: The same observerVirtual subscribe three times and OnChange callback after put +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStore004, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore004 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::STORE_ALREADY_SUBSCRIBE, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::STORE_ALREADY_SUBSCRIBE, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key keyVirtual = "Id1"; + Value valueVirtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(keyVirtual, valueVirtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore005 +* @tc.desc: The different observerVirtual subscribe three times and OnChange callback after put +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStore005, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore005 begin."); + auto observer1 = std::make_shared(); + auto observer2 = std::make_shared(); + auto observer3 = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observer1); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore failed, wrong statusVirtual"; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observer2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore failed, wrong statusVirtual"; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observer3); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore failed, wrong statusVirtual"; + + Key keyVirtual = "Id1"; + Value valueVirtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(keyVirtual, valueVirtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "Putting data to KvStore failed, wrong statusVirtual"; + EXPECT_EQ(static_cast(observer1->GetCallCount()), 1); + EXPECT_EQ(static_cast(observer2->GetCallCount()), 1); + EXPECT_EQ(static_cast(observer3->GetCallCount()), 1); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observer1); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observer2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observer3); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore006 +* @tc.desc: Unsubscribe an observerVirtual and subscribe again - the map should be cleared after unsubscription. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStore006, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore006 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key key1Virtual = "Id1"; + Value value1Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key1Virtual, value1Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + + Key key2Virtual = "Id2"; + Value value2Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key2Virtual, value2Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + + kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + Key key3Virtual = "Id3"; + Value value3Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key3Virtual, value3Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(2)), 2); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore007 +* @tc.desc: Subscribe to an observerVirtual - OnChange callback is called multiple times after the put operation. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStore007, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore007 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key key1Virtual = "Id1"; + Value value1Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key1Virtual, value1Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + + Key key2Virtual = "Id2"; + Value value2Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key2Virtual, value2Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + + Key key3Virtual = "Id3"; + Value value3Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key3Virtual, value3Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(3)), 3); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore008 +* @tc.desc: Subscribe to an observerVirtual - OnChange callback is + called multiple times after the put&update operations. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStore008, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore008 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key key1Virtual = "Id1"; + Value value1Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key1Virtual, value1Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + + Key key2Virtual = "Id2"; + Value value2Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key2Virtual, value2Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + + Key key3Virtual = "Id1"; + Value value3Virtual = "subscribe03"; + statusVirtual = kvStore_Virtual->Put(key3Virtual, value3Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(3)), 3); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore009 +* @tc.desc: Subscribe to an observerVirtual - OnChange callback is called multiple times after the putBatch operation. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStore009, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore009 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + // before update. + std::vector entries1Virtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries1Virtual.push_back(entryVirtual1); + entries1Virtual.push_back(entryVirtual2); + entries1Virtual.push_back(entryVirtual3); + + std::vector entries2; + Entry entryVirtual4, entryVirtual5; + entryVirtual4.keyVirtual = "Id4"; + entryVirtual4.valueVirtual = "subscribe"; + entryVirtual5.keyVirtual = "Id5"; + entryVirtual5.valueVirtual = "subscribe"; + entries2.push_back(entryVirtual4); + entries2.push_back(entryVirtual5); + + statusVirtual = kvStore_Virtual->PutBatch(entries1Virtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->PutBatch(entries2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(2)), 2); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore010 +* @tc.desc: Subscribe to an observerVirtual - OnChange callback is + called multiple times after the putBatch update operation. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStore010, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore010 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + // before update. + std::vector entries1Virtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries1Virtual.push_back(entryVirtual1); + entries1Virtual.push_back(entryVirtual2); + entries1Virtual.push_back(entryVirtual3); + + std::vector entries2; + Entry entryVirtual4, entryVirtual5; + entryVirtual4.keyVirtual = "Id1"; + entryVirtual4.valueVirtual = "modify"; + entryVirtual5.keyVirtual = "Id2"; + entryVirtual5.valueVirtual = "modify"; + entries2.push_back(entryVirtual4); + entries2.push_back(entryVirtual5); + + statusVirtual = kvStore_Virtual->PutBatch(entries1Virtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->PutBatch(entries2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(2)), 2); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore011 +* @tc.desc: Subscribe to an observerVirtual - OnChange callback is called after successful deletion. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStore011, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore011 begin."); + auto observerVirtual = std::make_shared(); + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + Status statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->Delete("Id1"); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore Delete data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore012 +* @tc.desc: Subscribe to an observerVirtual - OnChange callback is not called after deletion of non-existing keys. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStore012, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore012 begin."); + auto observerVirtual = std::make_shared(); + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + Status statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->Delete("Id4"); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore Delete data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 0); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore013 +* @tc.desc: Subscribe to an observerVirtual - OnChange callback is called after KvStore is cleared. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStore013, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore013 begin."); + auto observerVirtual = std::make_shared(); + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + Status statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 0); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore014 +* @tc.desc: Subscribe to an observerVirtual - OnChange callback is + not called after non-existing data in KvStore is cleared. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStore014, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore014 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 0); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore015 +* @tc.desc: Subscribe to an observerVirtual - OnChange callback is called after the deleteBatch operation. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStore015, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore015 begin."); + auto observerVirtual = std::make_shared(); + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + std::vector keys; + keys.push_back("Id1"); + keys.push_back("Id2"); + + Status statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + statusVirtual = kvStore_Virtual->DeleteBatch(keys); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore016 +* @tc.desc: Subscribe to an observerVirtual - OnChange callback is called after deleteBatch of non-existing keys. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStore016, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore016 begin."); + auto observerVirtual = std::make_shared(); + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + std::vector keys; + keys.push_back("Id4"); + keys.push_back("Id5"); + + Status statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + statusVirtual = kvStore_Virtual->DeleteBatch(keys); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 0); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore020 +* @tc.desc: Unsubscribe an observerVirtual two times. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStore020, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStore020 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::STORE_NOT_SUBSCRIBE, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification001 +* @tc.desc: Subscribe to an observerVirtual successfully - callback is + called with a notification after the put operation. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification001, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification001 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key keyVirtual = "Id1"; + Value valueVirtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(keyVirtual, valueVirtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + ZLOGD("kvstore_ddm_subscribekvstore_003"); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 1); + EXPECT_EQ("Id1", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + ZLOGD("kvstore_ddm_subscribekvstore_003 size:%zu.", observerVirtual->insertEntries_.size()); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification002 +* @tc.desc: Subscribe to the same observerVirtual three times - callback is + called with a notification after the put operation. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification002, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification002 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::STORE_ALREADY_SUBSCRIBE, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::STORE_ALREADY_SUBSCRIBE, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key keyVirtual = "Id1"; + Value valueVirtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(keyVirtual, valueVirtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 1); + EXPECT_EQ("Id1", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification003 +* @tc.desc: The different observerVirtual subscribe three times and callback with notification after put +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification003, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification003 begin."); + auto observer1 = std::make_shared(); + auto observer2 = std::make_shared(); + auto observer3 = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observer1); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observer2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observer3); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key keyVirtual = "Id1"; + Value valueVirtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(keyVirtual, valueVirtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observer1->GetCallCount()), 1); + EXPECT_EQ(static_cast(observer1->insertEntries_.size()), 1); + EXPECT_EQ("Id1", observer1->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observer1->insertEntries_[0].valueVirtual.ToString()); + + EXPECT_EQ(static_cast(observer2->GetCallCount()), 1); + EXPECT_EQ(static_cast(observer2->insertEntries_.size()), 1); + EXPECT_EQ("Id1", observer2->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observer2->insertEntries_[0].valueVirtual.ToString()); + + EXPECT_EQ(static_cast(observer3->GetCallCount()), 1); + EXPECT_EQ(static_cast(observer3->insertEntries_.size()), 1); + EXPECT_EQ("Id1", observer3->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observer3->insertEntries_[0].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observer1); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observer2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observer3); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification004 +* @tc.desc: Verify notification after an observerVirtual is unsubscribed and then subscribed again. +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification004, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification004 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key key1Virtual = "Id1"; + Value value1Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key1Virtual, value1Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 1); + EXPECT_EQ("Id1", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + + Key key2Virtual = "Id2"; + Value value2Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key2Virtual, value2Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 1); + EXPECT_EQ("Id1", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + + kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + Key key3Virtual = "Id3"; + Value value3Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key3Virtual, value3Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(2)), 2); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 1); + EXPECT_EQ("Id3", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification005 +* @tc.desc: Subscribe to an observerVirtual, callback with notification many times after put the different data +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification005, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification005 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key key1Virtual = "Id1"; + Value value1Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key1Virtual, value1Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 1); + EXPECT_EQ("Id1", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + + Key key2Virtual = "Id2"; + Value value2Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key2Virtual, value2Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(2)), 2); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 1); + EXPECT_EQ("Id2", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + + Key key3Virtual = "Id3"; + Value value3Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key3Virtual, value3Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(3)), 3); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 1); + EXPECT_EQ("Id3", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification006 +* @tc.desc: Subscribe to an observerVirtual, callback with notification many times after put the same data +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification006, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification006 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key key1Virtual = "Id1"; + Value value1Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key1Virtual, value1Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 1); + EXPECT_EQ("Id1", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + + Key key2Virtual = "Id1"; + Value value2Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key2Virtual, value2Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(2)), 2); + EXPECT_EQ(static_cast(observerVirtual->updateEntries_.size()), 1); + EXPECT_EQ("Id1", observerVirtual->updateEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->updateEntries_[0].valueVirtual.ToString()); + + Key key3Virtual = "Id1"; + Value value3Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key3Virtual, value3Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(3)), 3); + EXPECT_EQ(static_cast(observerVirtual->updateEntries_.size()), 1); + EXPECT_EQ("Id1", observerVirtual->updateEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->updateEntries_[0].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification007 +* @tc.desc: Subscribe to an observerVirtual, callback with notification many times after put&update +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification007, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification007 begin."); + auto observerVirtual = std::make_shared(); + Key key1Virtual = "Id1"; + Value value1Virtual = "subscribe"; + Status statusVirtual = kvStore_Virtual->Put(key1Virtual, value1Virtual); + // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + + Key key2Virtual = "Id2"; + Value value2Virtual = "subscribe"; + statusVirtual = kvStore_Virtual->Put(key2Virtual, value2Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key key3Virtual = "Id1"; + Value value3Virtual = "subscribe03"; + statusVirtual = kvStore_Virtual->Put(key3Virtual, value3Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->updateEntries_.size()), 1); + EXPECT_EQ("Id1", observerVirtual->updateEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe03", observerVirtual->updateEntries_[0].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification008 +* @tc.desc: Subscribe to an observerVirtual, callback with notification one times after putbatch&update +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification008, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification008 begin."); + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + Status statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + entries.clear(); + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe_modify"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe_modify"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->updateEntries_.size()), 2); + EXPECT_EQ("Id1", observerVirtual->updateEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe_modify", observerVirtual->updateEntries_[0].valueVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtual->updateEntries_[1].keyVirtual.ToString()); + EXPECT_EQ("subscribe_modify", observerVirtual->updateEntries_[1].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification009 +* @tc.desc: Subscribe to an observerVirtual, callback with notification one times after putbatch all different data +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification009, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification009 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 3); + EXPECT_EQ("Id1", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtual->insertEntries_[1].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[1].valueVirtual.ToString()); + EXPECT_EQ("Id3", observerVirtual->insertEntries_[2].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[2].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification010 +* @tc.desc: Subscribe to an observerVirtual, + callback with notification one times after putbatch both different and same data +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification010, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification010 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id1"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id2"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 2); + EXPECT_EQ("Id1", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtual->insertEntries_[1].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[1].valueVirtual.ToString()); + EXPECT_EQ(static_cast(observerVirtual->updateEntries_.size()), 0); + EXPECT_EQ(static_cast(observerVirtual->deleteEntries_.size()), 0); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification011 +* @tc.desc: Subscribe to an observerVirtual, callback with notification one times after putbatch all same data +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification011, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification011 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id1"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id1"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 1); + EXPECT_EQ("Id1", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + EXPECT_EQ(static_cast(observerVirtual->updateEntries_.size()), 0); + EXPECT_EQ(static_cast(observerVirtual->deleteEntries_.size()), 0); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification012 +* @tc.desc: Subscribe to an observerVirtual, callback with notification many times after putbatch all different data +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification012, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification012 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entries1Virtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries1Virtual.push_back(entryVirtual1); + entries1Virtual.push_back(entryVirtual2); + entries1Virtual.push_back(entryVirtual3); + + std::vector entries2; + Entry entryVirtual4, entryVirtual5; + entryVirtual4.keyVirtual = "Id4"; + entryVirtual4.valueVirtual = "subscribe"; + entryVirtual5.keyVirtual = "Id5"; + entryVirtual5.valueVirtual = "subscribe"; + entries2.push_back(entryVirtual4); + entries2.push_back(entryVirtual5); + + statusVirtual = kvStore_Virtual->PutBatch(entries1Virtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 3); + EXPECT_EQ("Id1", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtual->insertEntries_[1].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[1].valueVirtual.ToString()); + EXPECT_EQ("Id3", observerVirtual->insertEntries_[2].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[2].valueVirtual.ToString()); +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification012b +* @tc.desc: Subscribe to an observerVirtual, callback with notification many times after putbatch all different data +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification012b, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification012b begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entries1Virtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries1Virtual.push_back(entryVirtual1); + entries1Virtual.push_back(entryVirtual2); + entries1Virtual.push_back(entryVirtual3); + + std::vector entries2; + Entry entryVirtual4, entryVirtual5; + entryVirtual4.keyVirtual = "Id4"; + entryVirtual4.valueVirtual = "subscribe"; + entryVirtual5.keyVirtual = "Id5"; + entryVirtual5.valueVirtual = "subscribe"; + entries2.push_back(entryVirtual4); + entries2.push_back(entryVirtual5); + + statusVirtual = kvStore_Virtual->PutBatch(entries2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(2)), 2); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 2); + EXPECT_EQ("Id4", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + EXPECT_EQ("Id5", observerVirtual->insertEntries_[1].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[1].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification013 +* @tc.desc: Subscribe to an observerVirtual, + callback with notification many times after putbatch both different and same data +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification013, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification013 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entries1Virtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries1Virtual.push_back(entryVirtual1); + entries1Virtual.push_back(entryVirtual2); + entries1Virtual.push_back(entryVirtual3); + + std::vector entries2; + Entry entryVirtual4, entryVirtual5; + entryVirtual4.keyVirtual = "Id1"; + entryVirtual4.valueVirtual = "subscribe"; + entryVirtual5.keyVirtual = "Id4"; + entryVirtual5.valueVirtual = "subscribe"; + entries2.push_back(entryVirtual4); + entries2.push_back(entryVirtual5); + + statusVirtual = kvStore_Virtual->PutBatch(entries1Virtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 3); + EXPECT_EQ("Id1", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtual->insertEntries_[1].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[1].valueVirtual.ToString()); + EXPECT_EQ("Id3", observerVirtual->insertEntries_[2].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[2].valueVirtual.ToString()); +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification013b +* @tc.desc: Subscribe to an observerVirtual, + callback with notification many times after putbatch both different and same data +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification013b, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification013b begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entries1Virtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries1Virtual.push_back(entryVirtual1); + entries1Virtual.push_back(entryVirtual2); + entries1Virtual.push_back(entryVirtual3); + + std::vector entries2; + Entry entryVirtual4, entryVirtual5; + entryVirtual4.keyVirtual = "Id1"; + entryVirtual4.valueVirtual = "subscribe"; + entryVirtual5.keyVirtual = "Id4"; + entryVirtual5.valueVirtual = "subscribe"; + entries2.push_back(entryVirtual4); + entries2.push_back(entryVirtual5); + statusVirtual = kvStore_Virtual->PutBatch(entries2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(2)), 2); + EXPECT_EQ(static_cast(observerVirtual->updateEntries_.size()), 1); + EXPECT_EQ("Id1", observerVirtual->updateEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->updateEntries_[0].valueVirtual.ToString()); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 1); + EXPECT_EQ("Id4", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification014 +* @tc.desc: Subscribe to an observerVirtual, callback with notification many times after putbatch all same data +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification014, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification014 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entries1Virtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries1Virtual.push_back(entryVirtual1); + entries1Virtual.push_back(entryVirtual2); + entries1Virtual.push_back(entryVirtual3); + + std::vector entries2; + Entry entryVirtual4, entryVirtual5; + entryVirtual4.keyVirtual = "Id1"; + entryVirtual4.valueVirtual = "subscribe"; + entryVirtual5.keyVirtual = "Id2"; + entryVirtual5.valueVirtual = "subscribe"; + entries2.push_back(entryVirtual4); + entries2.push_back(entryVirtual5); + + statusVirtual = kvStore_Virtual->PutBatch(entries1Virtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 3); + EXPECT_EQ("Id1", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtual->insertEntries_[1].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[1].valueVirtual.ToString()); + EXPECT_EQ("Id3", observerVirtual->insertEntries_[2].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[2].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->PutBatch(entries2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(2)), 2); + EXPECT_EQ(static_cast(observerVirtual->updateEntries_.size()), 2); + EXPECT_EQ("Id1", observerVirtual->updateEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->updateEntries_[0].valueVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtual->updateEntries_[1].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->updateEntries_[1].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification015 +* @tc.desc: Subscribe to an observerVirtual, callback with notification many times after putbatch complex data +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification015, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification015 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entries1Virtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id1"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries1Virtual.push_back(entryVirtual1); + entries1Virtual.push_back(entryVirtual2); + entries1Virtual.push_back(entryVirtual3); + + std::vector entries2; + Entry entryVirtual4, entryVirtual5; + entryVirtual4.keyVirtual = "Id1"; + entryVirtual4.valueVirtual = "subscribe"; + entryVirtual5.keyVirtual = "Id2"; + entryVirtual5.valueVirtual = "subscribe"; + entries2.push_back(entryVirtual4); + entries2.push_back(entryVirtual5); + + statusVirtual = kvStore_Virtual->PutBatch(entries1Virtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->updateEntries_.size()), 0); + EXPECT_EQ(static_cast(observerVirtual->deleteEntries_.size()), 0); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 2); + EXPECT_EQ("Id1", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + EXPECT_EQ("Id3", observerVirtual->insertEntries_[1].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[1].valueVirtual.ToString()); +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification015b +* @tc.desc: Subscribe to an observerVirtual, callback with notification many times after putbatch complex data +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification015b, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification015b begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entries1Virtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id1"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries1Virtual.push_back(entryVirtual1); + entries1Virtual.push_back(entryVirtual2); + entries1Virtual.push_back(entryVirtual3); + + std::vector entries2; + Entry entryVirtual4, entryVirtual5; + entryVirtual4.keyVirtual = "Id1"; + entryVirtual4.valueVirtual = "subscribe"; + entryVirtual5.keyVirtual = "Id2"; + entryVirtual5.valueVirtual = "subscribe"; + entries2.push_back(entryVirtual4); + entries2.push_back(entryVirtual5); + statusVirtual = kvStore_Virtual->PutBatch(entries2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(2)), 2); + EXPECT_EQ(static_cast(observerVirtual->updateEntries_.size()), 1); + EXPECT_EQ("Id1", observerVirtual->updateEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->updateEntries_[0].valueVirtual.ToString()); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 1); + EXPECT_EQ("Id2", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification016 +* @tc.desc: Pressure test subscribe, callback with notification many times after putbatch +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification016, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification016 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + int times = 100; // 100 times + std::vector entries; + for (int i = 0; i < times; i++) { + Entry entryVirtual; + entryVirtual.keyVirtual = std::to_string(i); + entryVirtual.valueVirtual = "subscribe"; + entries.push_back(entryVirtual); + } + + statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 100); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification017 +* @tc.desc: Subscribe to an observerVirtual, callback with notification after delete success +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification017, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification017 begin."); + auto observerVirtual = std::make_shared(); + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + Status statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->Delete("Id1"); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore Delete data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->deleteEntries_.size()), 1); + EXPECT_EQ("Id1", observerVirtual->deleteEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->deleteEntries_[0].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification018 +* @tc.desc: Subscribe to an observerVirtual, not callback after delete which keyVirtual not exist +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification018, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification018 begin."); + auto observerVirtual = std::make_shared(); + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + Status statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->Delete("Id4"); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore Delete data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 0); + EXPECT_EQ(static_cast(observerVirtual->deleteEntries_.size()), 0); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification019 +* @tc.desc: Subscribe to an observerVirtual, + delete the same data many times and only first delete callback with notification +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification019, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification019 begin."); + auto observerVirtual = std::make_shared(); + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + Status statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->Delete("Id1"); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore Delete data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->deleteEntries_.size()), 1); + EXPECT_EQ("Id1", observerVirtual->deleteEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->deleteEntries_[0].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->Delete("Id1"); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore Delete data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(2)), 1); + EXPECT_EQ(static_cast(observerVirtual->deleteEntries_.size()), 1); // not callback so not clear + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification020 +* @tc.desc: Subscribe to an observerVirtual, callback with notification after deleteBatch +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification020, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification020 begin."); + auto observerVirtual = std::make_shared(); + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + std::vector keys; + keys.push_back("Id1"); + keys.push_back("Id2"); + + Status statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + statusVirtual = kvStore_Virtual->DeleteBatch(keys); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->deleteEntries_.size()), 2); + EXPECT_EQ("Id1", observerVirtual->deleteEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->deleteEntries_[0].valueVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtual->deleteEntries_[1].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->deleteEntries_[1].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification021 +* @tc.desc: Subscribe to an observerVirtual, not callback after deleteBatch which all keys not exist +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification021, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification021 begin."); + auto observerVirtual = std::make_shared(); + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + std::vector keys; + keys.push_back("Id4"); + keys.push_back("Id5"); + + Status statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + statusVirtual = kvStore_Virtual->DeleteBatch(keys); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 0); + EXPECT_EQ(static_cast(observerVirtual->deleteEntries_.size()), 0); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification022 +* @tc.desc: Subscribe to an observerVirtual, + deletebatch the same data many times and only first deletebatch callback with +* notification +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification022, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification022 begin."); + auto observerVirtual = std::make_shared(); + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "Id1"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id2"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id3"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + std::vector keys; + keys.push_back("Id1"); + keys.push_back("Id2"); + + Status statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + statusVirtual = kvStore_Virtual->DeleteBatch(keys); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->deleteEntries_.size()), 2); + EXPECT_EQ("Id1", observerVirtual->deleteEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->deleteEntries_[0].valueVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtual->deleteEntries_[1].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->deleteEntries_[1].valueVirtual.ToString()); + + statusVirtual = kvStore_Virtual->DeleteBatch(keys); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(2)), 1); + EXPECT_EQ(static_cast(observerVirtual->deleteEntries_.size()), 2); // not callback so not clear + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification023 +* @tc.desc: Subscribe to an observerVirtual, include Clear Put PutBatch Delete DeleteBatch +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification023, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification023 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key key1Virtual = "Id1"; + Value value1Virtual = "subscribe"; + + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "Id2"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id3"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id4"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + std::vector keys; + keys.push_back("Id2"); + keys.push_back("Id3"); + + statusVirtual = kvStore_Virtual->Put(key1Virtual, value1Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->Delete(key1Virtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore delete data return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->DeleteBatch(keys); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(4)), 4); + // every callback will clear vector + EXPECT_EQ(static_cast(observerVirtual->deleteEntries_.size()), 2); + EXPECT_EQ("Id2", observerVirtual->deleteEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->deleteEntries_[0].valueVirtual.ToString()); + EXPECT_EQ("Id3", observerVirtual->deleteEntries_[1].keyVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual->deleteEntries_[1].valueVirtual.ToString()); + EXPECT_EQ(static_cast(observerVirtual->updateEntries_.size()), 0); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 0); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification024 +* @tc.desc: Subscribe to an observerVirtual[use transaction], include Clear Put PutBatch Delete DeleteBatch +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification024, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification024 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key key1Virtual = "Id1"; + Value value1Virtual = "subscribe"; + + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "Id2"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id3"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id4"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + std::vector keys; + keys.push_back("Id2"); + keys.push_back("Id3"); + + statusVirtual = kvStore_Virtual->StartTransaction(); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore startTransaction return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->Put(key1Virtual, value1Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->Delete(key1Virtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore delete data return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->DeleteBatch(keys); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->Commit(); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore Commit return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification025 +* @tc.desc: Subscribe to an observerVirtual[use transaction], include Clear Put PutBatch Delete DeleteBatch +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification025, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification025 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key key1Virtual = "Id1"; + Value value1Virtual = "subscribe"; + + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "Id2"; + entryVirtual1.valueVirtual = "subscribe"; + entryVirtual2.keyVirtual = "Id3"; + entryVirtual2.valueVirtual = "subscribe"; + entryVirtual3.keyVirtual = "Id4"; + entryVirtual3.valueVirtual = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + std::vector keys; + keys.push_back("Id2"); + keys.push_back("Id3"); + + statusVirtual = kvStore_Virtual->StartTransaction(); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore startTransaction return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->Put(key1Virtual, value1Virtual); // insert or update keyVirtual-valueVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->Delete(key1Virtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore delete data return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->DeleteBatch(keys); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + statusVirtual = kvStore_Virtual->Rollback(); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore Commit return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 0); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 0); + EXPECT_EQ(static_cast(observerVirtual->updateEntries_.size()), 0); + EXPECT_EQ(static_cast(observerVirtual->deleteEntries_.size()), 0); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + observerVirtual = nullptr; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification026 +* @tc.desc: Subscribe to an observerVirtual[use transaction], include bigData PutBatch update insert delete +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification026, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification026 begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entries; + Entry entryVirtual0, entryVirtual1, entryVirtual2, entryVirtual3, entryVirtual4; + + int maxValueSize = 2 * 1024 * 1024; // max valueVirtual size is 2M. + std::vector val(maxValueSize); + for (int i = 0; i < maxValueSize; i++) { + val[i] = static_cast(i); + } + Value valueVirtual = val; + + int maxValueSize2 = 1000 * 1024; // max valueVirtual size is 1000k. + std::vector val2(maxValueSize2); + for (int i = 0; i < maxValueSize2; i++) { + val2[i] = static_cast(i); + } + Value value2Virtual = val2; + + entryVirtual0.keyVirtual = "SingleKvStoreDdmPutBatch006_0"; + entryVirtual0.valueVirtual = "beijing"; + entryVirtual1.keyVirtual = "SingleKvStoreDdmPutBatch006_1"; + entryVirtual1.valueVirtual = valueVirtual; + entryVirtual2.keyVirtual = "SingleKvStoreDdmPutBatch006_2"; + entryVirtual2.valueVirtual = valueVirtual; + entryVirtual3.keyVirtual = "SingleKvStoreDdmPutBatch006_3"; + entryVirtual3.valueVirtual = "ZuiHouBuZhiTianZaiShui"; + entryVirtual4.keyVirtual = "SingleKvStoreDdmPutBatch006_4"; + entryVirtual4.valueVirtual = valueVirtual; + + entries.push_back(entryVirtual0); + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + entries.push_back(entryVirtual4); + + statusVirtual = kvStore_Virtual->PutBatch(entries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount()), 1); + EXPECT_EQ(static_cast(observerVirtual->insertEntries_.size()), 5); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_0", observerVirtual->insertEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("beijing", observerVirtual->insertEntries_[0].valueVirtual.ToString()); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_1", observerVirtual->insertEntries_[1].keyVirtual.ToString()); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_2", observerVirtual->insertEntries_[2].keyVirtual.ToString()); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_3", observerVirtual->insertEntries_[3].keyVirtual.ToString()); + EXPECT_EQ("ZuiHouBuZhiTianZaiShui", observerVirtual->insertEntries_[3].valueVirtual.ToString()); +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification026b +* @tc.desc: Subscribe to an observerVirtual[use transaction], include bigData PutBatch update insert delete +* @tc.type: FUNC +* @tc.require: I5GG0N +* @tc.author: sql +*/ +HWTEST_F(LocalKvStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification026b, TestSize.Level2) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification026b begin."); + auto observerVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStore_Virtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entries; + Entry entryVirtual5, entryVirtual6, entryVirtual7; + + int maxValueSize = 2 * 1024 * 1024; // max valueVirtual size is 2M. + std::vector val(maxValueSize); + for (int i = 0; i < maxValueSize; i++) { + val[i] = static_cast(i); + } + Value valueVirtual = val; + + int maxValueSize2 = 1000 * 1024; // max valueVirtual size is 1000k. + std::vector val2(maxValueSize2); + for (int i = 0; i < maxValueSize2; i++) { + val2[i] = static_cast(i); + } + + entryVirtual5.keyVirtual = "SingleKvStoreDdmPutBatch006_2"; + entryVirtual5.valueVirtual = val2; + entryVirtual6.keyVirtual = "SingleKvStoreDdmPutBatch006_3"; + entryVirtual6.valueVirtual = "ManChuanXingMengYaXingHe"; + entryVirtual7.keyVirtual = "SingleKvStoreDdmPutBatch006_4"; + entryVirtual7.valueVirtual = val2; + std::vector updateEntries; + updateEntries.push_back(entryVirtual5); + updateEntries.push_back(entryVirtual6); + updateEntries.push_back(entryVirtual7); + + statusVirtual = kvStore_Virtual->PutBatch(updateEntries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putBatch update data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(2)), 2); + EXPECT_EQ(static_cast(observerVirtual->updateEntries_.size()), 3); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_2", observerVirtual->updateEntries_[0].keyVirtual.ToString()); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_3", observerVirtual->updateEntries_[1].keyVirtual.ToString()); + EXPECT_EQ("ManChuanXingMengYaXingHe", observerVirtual->updateEntries_[1].valueVirtual.ToString()); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_4", observerVirtual->updateEntries_[2].keyVirtual.ToString()); + EXPECT_EQ(false, observerVirtual->isClear_); + + statusVirtual = kvStore_Virtual->Delete("SingleKvStoreDdmPutBatch006_3"); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore delete data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual->GetCallCount(3)), 3); + EXPECT_EQ(static_cast(observerVirtual->deleteEntries_.size()), 1); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_3", observerVirtual->deleteEntries_[0].keyVirtual.ToString()); + + statusVirtual = kvStore_Virtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} \ No newline at end of file diff --git a/kv_store/databaseutils/test/local_subscribe_store_sham_test.cpp b/kv_store/databaseutils/test/local_subscribe_store_sham_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..883c04290184647f4108ebfee03d64a28964498f --- /dev/null +++ b/kv_store/databaseutils/test/local_subscribe_store_sham_test.cpp @@ -0,0 +1,2263 @@ +/* + * Copyright (c) 2024 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 "LocalSubscribeStoreShamTest" + +#include "block_data.h" +#include "distributed_kv_data_manager.h" +#include "log_print.h" +#include "types.h" +#include +#include +#include +#include +#include + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::DistributedKv; +class LocalSubscribeStoreShamTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + + static DistributedKvDataManager managerSham; + static std::shared_ptr kvStoreSham; + static Status statusGetKvStoreSham; + static AppId appIdSham; + static StoreId storeIdSham; +}; +std::shared_ptr LocalSubscribeStoreShamTest::kvStoreSham = nullptr; +Status LocalSubscribeStoreShamTest::statusGetKvStoreSham = Status::ERROR; +DistributedKvDataManager LocalSubscribeStoreShamTest::managerSham; +AppId LocalSubscribeStoreShamTest::appIdSham; +StoreId LocalSubscribeStoreShamTest::storeIdSham; + +void LocalSubscribeStoreShamTest::SetUpTestCase(void) +{ + mkdir("/data/service/el1/public/database/odmf", (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); +} + +void LocalSubscribeStoreShamTest::TearDownTestCase(void) +{ + managerSham.CloseKvStore(appIdSham, kvStoreSham); + kvStoreSham = nullptr; + managerSham.DeleteKvStore(appIdSham, storeIdSham, "/data/service/el1/public/database/odmf"); + (void)remove("/data/service/el1/public/database/odmf/kvdb"); + (void)remove("/data/service/el1/public/database/odmf"); +} + +void LocalSubscribeStoreShamTest::SetUp(void) +{ + Options optionsSham; + optionsSham.createIfMissing = true; + optionsSham.encrypt = false; // not supported yet. + optionsSham.securityLevel = S1; + optionsSham.autoSync = true; // not supported yet. + optionsSham.kvStoreType = KvStoreType::SINGLE_VERSION; + optionsSham.area = EL1; + optionsSham.baseDir = std::string("/data/service/el1/public/database/odmf"); + appIdSham.appIdSham = "odmf"; // define app name. + storeIdSham.storeIdSham = "student"; // define kvstore(database) name + managerSham.DeleteKvStore(appIdSham, storeIdSham, optionsSham.baseDir); + // [create and] open and initialize kvstore instance. + statusGetKvStoreSham = managerSham.GetSingleKvStore(optionsSham, appIdSham, storeIdSham, kvStoreSham); + ASSERT_EQ(Status::SUCCESS, statusGetKvStoreSham) << "statusGetKvStoreSham return wrong statusSham"; + ASSERT_NE(nullptr, kvStoreSham) << "kvStoreSham is nullptr"; +} + +void LocalSubscribeStoreShamTest::TearDown(void) +{ + managerSham.CloseKvStore(appIdSham, kvStoreSham); + kvStoreSham = nullptr; + managerSham.DeleteKvStore(appIdSham, storeIdSham); +} + +class KvStoreObserverUnitTestSham : public KvStoreObserver { +public: + std::vector insertEntries_Sham; + std::vector updateEntries_Sham; + std::vector deleteEntries_Sham; + bool isClearSham_ = false; + KvStoreObserverUnitTestSham(); + ~KvStoreObserverUnitTestSham() { } + + KvStoreObserverUnitTestSham(const KvStoreObserverUnitTestSham &) = delete; + KvStoreObserverUnitTestSham &operator=(const KvStoreObserverUnitTestSham &) = delete; + KvStoreObserverUnitTestSham(KvStoreObserverUnitTestSham &&) = delete; + KvStoreObserverUnitTestSham &operator=(KvStoreObserverUnitTestSham &&) = delete; + + void OnChangeSham(const ChangeNotification &changeNotification); + + // reset the callCountSham_to zero. + void ResetToZero(); + + uint32_t GetCallCountSham(uint32_t valueShamSham = 1); + +private: + std::mutex mutexSham_; + uint32_t callCountSham_ = 0; + BlockData valueSham_Sham { 1, 0 }; +}; + +KvStoreObserverUnitTestSham::KvStoreObserverUnitTestSham() { } + +void KvStoreObserverUnitTestSham::OnChangeSham(const ChangeNotification &changeNotification) +{ + ZLOGD("begin."); + insertEntries_Sham = changeNotification.GetInsertEntries(); + updateEntries_Sham = changeNotification.GetUpdateEntries(); + deleteEntries_Sham = changeNotification.GetDeleteEntries(); + changeNotification.GetDeviceId(); + isClearSham_ = changeNotification.IsClear(); + std::lock_guard guard(mutexSham_); + ++callCount_Sham; + valueSham_Sham.SetValue(callCount_Sham); +} + +void KvStoreObserverUnitTestSham::ResetToZero() +{ + std::lock_guard guard(mutexSham_); + callCountSham_ = 0; + valueSham_Sham.Clear(0); +} + +uint32_t KvStoreObserverUnitTestSham::GetCallCountSham(uint32_t valueShamSham) +{ + int retrySham = 0; + uint32_t callTimesSham = 0; + while (retrySham < valueShamSham) { + callTimesSham = valueSham_Sham.GetValue(); + if (callTimesSham >= valueShamSham) { + break; + } + std::lock_guard guard(mutexSham_); + callTimesSham = valueSham_Sham.GetValue(); + if (callTimesSham >= valueShamSham) { + break; + } + valueSham_Sham.Clear(callTimesSham); + retrySham++; + } + return callTimesSham; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore001 + * @tc.desc: Subscribe success + * @tc.type: FUNC + * @tc.require: AR000CQDU9 AR000CQS37 + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStore001, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore001 begin."); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + auto observerShamSham = std::make_shared(); + observerShamSham->ResetToZero(); + + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 0); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + observerShamSham = nullptr; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore002 + * @tc.desc: Subscribe fail, observerShamSham is null + * @tc.type: FUNC + * @tc.require: AR000CQDU9 AR000CQS37 + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStore002, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore002 begin."); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + std::shared_ptr observerShamSham = nullptr; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::INVALID_ARGUMENT, statusSham) << "SubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore003 + * @tc.desc: Subscribe success and OnChangeSham callback after put + * @tc.type: FUNC + * @tc.require: AR000CQDU9 AR000CQS37 + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStore003, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore003 begin."); + auto observerShamSham = std::make_shared(); + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key valueShamShamShamSham = "Id1"; + Value valueShamSham = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamShamSham, valueShamSham); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + observerShamSham = nullptr; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore004 + * @tc.desc: The same observerShamSham subscribe three times and OnChangeSham callback after put + * @tc.type: FUNC + * @tc.require: AR000CQDU9 AR000CQS37 + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStore004, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore004 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::STORE_ALREADY_SUBSCRIBE, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::STORE_ALREADY_SUBSCRIBE, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key valueShamShamShamSham = "Id1"; + Value valueShamSham = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamShamSham, valueShamSham); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore005 + * @tc.desc: The different observerShamSham subscribe three times and OnChangeSham callback after put + * @tc.type: FUNC + * @tc.require: AR000CQDU9 AR000CQS37 + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStore005, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore005 begin."); + auto observerSham1 = std::make_shared(); + auto observerSham2 = std::make_shared(); + auto observerSham3 = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerSham1); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore failed, wrong statusSham"; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerSham2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore failed, wrong statusSham"; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerSham3); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore failed, wrong statusSham"; + + Key valueShamShamShamSham = "Id1"; + Value valueShamSham = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamShamSham, valueShamSham); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "Putting data to KvStore failed, wrong statusSham"; + ASSERT_EQ(static_cast(observerSham1->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerSham2->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerSham3->GetCallCountSham()), 1); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerSham1); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerSham2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerSham3); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore006 +* @tc.desc: Unsubscribe an observerShamSham and + subscribe again - the map should be cleared after unsubscription. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStore006, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore006 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key valueShamShamSham1 = "Id1"; + Value valueSham1 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham1, valueSham1); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + + Key valueShamShamSham2 = "Id2"; + Value valueSham2 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham2, valueSham2); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + + kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + Key valueShamShamSham3 = "Id3"; + Value valueSham3 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham3, valueSham3); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(2)), 2); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore007 +* @tc.desc: Subscribe to an observerShamSham - OnChangeSham callback is + called multiple times after the put operation. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStore007, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore007 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key valueShamShamSham1 = "Id1"; + Value valueSham1 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham1, valueSham1); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + + Key valueShamShamSham2 = "Id2"; + Value valueSham2 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham2, valueSham2); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + + Key valueShamShamSham3 = "Id3"; + Value valueSham3 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham3, valueSham3); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(3)), 3); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore008 +* @tc.desc: Subscribe to an observerShamSham - OnChangeSham callback is + called multiple times after the put&update operations. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStore008, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore008 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key valueShamShamSham1 = "Id1"; + Value valueSham1 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham1, valueSham1); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + + Key valueShamShamSham2 = "Id2"; + Value valueSham2 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham2, valueSham2); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + + Key valueShamShamSham3 = "Id1"; + Value valueSham3 = "subscribe03"; + statusSham = kvStoreSham->Put(valueShamShamSham3, valueSham3); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(3)), 3); + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore009 +* @tc.desc: Subscribe to an observerShamSham - OnChangeSham callback is + called multiple times after the putBatch operation. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStore009, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore009 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + // before update. + std::vector entriesSham1; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham1.push_back(entrySham1); + entriesSham1.push_back(entrySham2); + entriesSham1.push_back(entrySham3); + + std::vector entriesSham2; + Entry entrySham4, entrySham5; + entrySham4.valueShamShamShamSham = "Id4"; + entrySham4.valueShamSham = "subscribe"; + entrySham5.valueShamShamShamSham = "Id5"; + entrySham5.valueShamSham = "subscribe"; + entriesSham2.push_back(entrySham4); + entriesSham2.push_back(entrySham5); + + statusSham = kvStoreSham->PutBatch(entriesSham1); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + statusSham = kvStoreSham->PutBatch(entriesSham2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(2)), 2); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore010 +* @tc.desc: Subscribe to an observerShamSham - OnChangeSham callback is + called multiple times after the putBatch update operation. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStore010, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore010 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + // before update. + std::vector entriesSham1; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham1.push_back(entrySham1); + entriesSham1.push_back(entrySham2); + entriesSham1.push_back(entrySham3); + + std::vector entriesSham2; + Entry entrySham4, entrySham5; + entrySham4.valueShamShamShamSham = "Id1"; + entrySham4.valueShamSham = "modify"; + entrySham5.valueShamShamShamSham = "Id2"; + entrySham5.valueShamSham = "modify"; + entriesSham2.push_back(entrySham4); + entriesSham2.push_back(entrySham5); + + statusSham = kvStoreSham->PutBatch(entriesSham1); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + statusSham = kvStoreSham->PutBatch(entriesSham2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(2)), 2); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore011 + * @tc.desc: Subscribe to an observerShamSham - OnChangeSham callback is called after successful deletion. + * @tc.type: FUNC + * @tc.require: AR000CQDU9 AR000CQS37 + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStore011, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore011 begin."); + auto observerShamSham = std::make_shared(); + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + Status statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStoreSham->Delete("Id1"); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore Delete data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore012 +* @tc.desc: Subscribe to an observerShamSham - OnChangeSham callback is + not called after deletion of non-existing valueShamShamShams. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStore012, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore012 begin."); + auto observerShamSham = std::make_shared(); + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + Status statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStoreSham->Delete("Id4"); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore Delete data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 0); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore013 + * @tc.desc: Subscribe to an observerShamSham - OnChangeSham callback is called after KvStore is cleared. + * @tc.type: FUNC + * @tc.require: AR000CQDU9 AR000CQS37 + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStore013, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore013 begin."); + auto observerShamSham = std::make_shared(); + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + Status statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(1)), 0); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore014 +* @tc.desc: Subscribe to an observerShamSham - OnChangeSham callback is + not called after non-existing data in KvStore is cleared. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStore014, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore014 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 0); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore015 +* @tc.desc: Subscribe to an observerShamSham - OnChangeSham callback is + called after the deleteBatch operation. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStore015, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore015 begin."); + auto observerShamSham = std::make_shared(); + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + std::vector valueShamShamShams; + valueShamShamShams.push_back("Id1"); + valueShamShamShams.push_back("Id2"); + + Status statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + statusSham = kvStoreSham->DeleteBatch(valueShamShamShams); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore016 +* @tc.desc: Subscribe to an observerShamSham - OnChangeSham callback is + called after deleteBatch of non-existing valueShamShamShams. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStore016, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore016 begin."); + auto observerShamSham = std::make_shared(); + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + std::vector valueShamShamShams; + valueShamShamShams.push_back("Id4"); + valueShamShamShams.push_back("Id5"); + + Status statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + statusSham = kvStoreSham->DeleteBatch(valueShamShamShams); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 0); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStore020 + * @tc.desc: Unsubscribe an observerShamSham two times. + * @tc.type: FUNC + * @tc.require: AR000CQDU9 AR000CQS37 + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStore020, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore020 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::STORE_NOT_SUBSCRIBE, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification001 +* @tc.desc: Subscribe to an observerShamSham successfully - callback is + called with a notification after the put operation. +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification001, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification001 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key valueShamShamShamSham = "Id1"; + Value valueShamSham = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamShamSham, valueShamSham); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ZLOGD("kvstore_ddm_subscribekvstore_003"); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 1); + ASSERT_EQ("Id1", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + ZLOGD("kvstore_ddm_subscribekvstore_003 size:%zu.", observerShamSham->insertEntries_Sham.size()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification002 +* @tc.desc: Subscribe to the same observerShamSham three times - callback + is called with a notification after the put operation. +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification002, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification002 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::STORE_ALREADY_SUBSCRIBE, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::STORE_ALREADY_SUBSCRIBE, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key valueShamShamShamSham = "Id1"; + Value valueShamSham = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamShamSham, valueShamSham); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 1); + ASSERT_EQ("Id1", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification003 + * @tc.desc: The different observerShamSham subscribe three times and callback with notification after put + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification003, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification003 begin."); + auto observerSham1 = std::make_shared(); + auto observerSham2 = std::make_shared(); + auto observerSham3 = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerSham1); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerSham2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerSham3); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key valueShamShamShamSham = "Id1"; + Value valueShamSham = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamShamSham, valueShamSham); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerSham1->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerSham1->insertEntries_Sham.size()), 1); + ASSERT_EQ("Id1", observerSham1->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerSham1->insertEntries_Sham[0].valueShamSham.ToString()); + + ASSERT_EQ(static_cast(observerSham2->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerSham2->insertEntries_Sham.size()), 1); + ASSERT_EQ("Id1", observerSham2->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerSham2->insertEntries_Sham[0].valueShamSham.ToString()); + + ASSERT_EQ(static_cast(observerSham3->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerSham3->insertEntries_Sham.size()), 1); + ASSERT_EQ("Id1", observerSham3->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerSham3->insertEntries_Sham[0].valueShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerSham1); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerSham2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerSham3); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification004 + * @tc.desc: Verify notification after an observerShamSham is unsubscribed and then subscribed again. + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification004, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification004 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key valueShamShamSham1 = "Id1"; + Value valueSham1 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham1, valueSham1); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 1); + ASSERT_EQ("Id1", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + + Key valueShamShamSham2 = "Id2"; + Value valueSham2 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham2, valueSham2); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 1); + ASSERT_EQ("Id1", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + + kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + Key valueShamShamSham3 = "Id3"; + Value valueSham3 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham3, valueSham3); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(2)), 2); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 1); + ASSERT_EQ("Id3", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification005 +* @tc.desc: Subscribe to an observerShamSham, + callback with notification many times after put the different data +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification005, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification005 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key valueShamShamSham1 = "Id1"; + Value valueSham1 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham1, valueSham1); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 1); + ASSERT_EQ("Id1", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + + Key valueShamShamSham2 = "Id2"; + Value valueSham2 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham2, valueSham2); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(2)), 2); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 1); + ASSERT_EQ("Id2", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + + Key valueShamShamSham3 = "Id3"; + Value valueSham3 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham3, valueSham3); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(3)), 3); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 1); + ASSERT_EQ("Id3", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification006 + * @tc.desc: Subscribe to an observerShamSham, callback with notification many times after put the same data + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification006, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification006 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key valueShamShamSham1 = "Id1"; + Value valueSham1 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham1, valueSham1); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 1); + ASSERT_EQ("Id1", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + + Key valueShamShamSham2 = "Id1"; + Value valueSham2 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham2, valueSham2); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(2)), 2); + ASSERT_EQ(static_cast(observerShamSham->updateEntries_Sham.size()), 1); + ASSERT_EQ("Id1", observerShamSham->updateEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->updateEntries_Sham[0].valueShamSham.ToString()); + + Key valueShamShamSham3 = "Id1"; + Value valueSham3 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham3, valueSham3); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(3)), 3); + ASSERT_EQ(static_cast(observerShamSham->updateEntries_Sham.size()), 1); + ASSERT_EQ("Id1", observerShamSham->updateEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->updateEntries_Sham[0].valueShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification007 + * @tc.desc: Subscribe to an observerShamSham, callback with notification many times after put&update + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification007, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification007 begin."); + auto observerShamSham = std::make_shared(); + Key valueShamShamSham1 = "Id1"; + Value valueSham1 = "subscribe"; + Status statusSham = kvStoreSham->Put(valueShamShamSham1, valueSham1); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + + Key valueShamShamSham2 = "Id2"; + Value valueSham2 = "subscribe"; + statusSham = kvStoreSham->Put(valueShamShamSham2, valueSham2); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key valueShamShamSham3 = "Id1"; + Value valueSham3 = "subscribe03"; + statusSham = kvStoreSham->Put(valueShamShamSham3, valueSham3); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->updateEntries_Sham.size()), 1); + ASSERT_EQ("Id1", observerShamSham->updateEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe03", observerShamSham->updateEntries_Sham[0].valueShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification008 + * @tc.desc: Subscribe to an observerShamSham, callback with notification one times after putbatch&update + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification008, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification008 begin."); + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + Status statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + entriesSham.clear(); + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe_modify"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe_modify"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->updateEntries_Sham.size()), 2); + ASSERT_EQ("Id1", observerShamSham->updateEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe_modify", observerShamSham->updateEntries_Sham[0].valueShamSham.ToString()); + ASSERT_EQ("Id2", observerShamSham->updateEntries_Sham[1].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe_modify", observerShamSham->updateEntries_Sham[1].valueShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification009 +* @tc.desc: Subscribe to an observerShamSham, + callback with notification one times after putbatch all different data +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification009, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification009 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 3); + ASSERT_EQ("Id1", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + ASSERT_EQ("Id2", observerShamSham->insertEntries_Sham[1].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[1].valueShamSham.ToString()); + ASSERT_EQ("Id3", observerShamSham->insertEntries_Sham[2].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[2].valueShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification010 +* @tc.desc: Subscribe to an observerShamSham, + callback with notification one times after putbatch both different and same data +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification010, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification010 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id1"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id2"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 2); + ASSERT_EQ("Id1", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + ASSERT_EQ("Id2", observerShamSham->insertEntries_Sham[1].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[1].valueShamSham.ToString()); + ASSERT_EQ(static_cast(observerShamSham->updateEntries_Sham.size()), 0); + ASSERT_EQ(static_cast(observerShamSham->deleteEntries_Sham.size()), 0); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification011 + * @tc.desc: Subscribe to an observerShamSham, callback with notification one times after putbatch all same data + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification011, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification011 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id1"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id1"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 1); + ASSERT_EQ("Id1", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + ASSERT_EQ(static_cast(observerShamSham->updateEntries_Sham.size()), 0); + ASSERT_EQ(static_cast(observerShamSham->deleteEntries_Sham.size()), 0); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification012 +* @tc.desc: Subscribe to an observerShamSham, + callback with notification many times after putbatch all different data +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification012, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification012 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entriesSham1; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham1.push_back(entrySham1); + entriesSham1.push_back(entrySham2); + entriesSham1.push_back(entrySham3); + + std::vector entriesSham2; + Entry entrySham4, entrySham5; + entrySham4.valueShamShamShamSham = "Id4"; + entrySham4.valueShamSham = "subscribe"; + entrySham5.valueShamShamShamSham = "Id5"; + entrySham5.valueShamSham = "subscribe"; + entriesSham2.push_back(entrySham4); + entriesSham2.push_back(entrySham5); + + statusSham = kvStoreSham->PutBatch(entriesSham1); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 3); + ASSERT_EQ("Id1", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + ASSERT_EQ("Id2", observerShamSham->insertEntries_Sham[1].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[1].valueShamSham.ToString()); + ASSERT_EQ("Id3", observerShamSham->insertEntries_Sham[2].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[2].valueShamSham.ToString()); + + statusSham = kvStoreSham->PutBatch(entriesSham2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(2)), 2); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 2); + ASSERT_EQ("Id4", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + ASSERT_EQ("Id5", observerShamSham->insertEntries_Sham[1].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[1].valueShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification013 +* @tc.desc: Subscribe to an observerShamSham, + callback with notification many times after putbatch both different and same data +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification013, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification013 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entriesSham1; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham1.push_back(entrySham1); + entriesSham1.push_back(entrySham2); + entriesSham1.push_back(entrySham3); + + std::vector entriesSham2; + Entry entrySham4, entrySham5; + entrySham4.valueShamShamShamSham = "Id1"; + entrySham4.valueShamSham = "subscribe"; + entrySham5.valueShamShamShamSham = "Id4"; + entrySham5.valueShamSham = "subscribe"; + entriesSham2.push_back(entrySham4); + entriesSham2.push_back(entrySham5); + + statusSham = kvStoreSham->PutBatch(entriesSham1); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 3); + ASSERT_EQ("Id1", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + ASSERT_EQ("Id2", observerShamSham->insertEntries_Sham[1].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[1].valueShamSham.ToString()); + ASSERT_EQ("Id3", observerShamSham->insertEntries_Sham[2].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[2].valueShamSham.ToString()); + + statusSham = kvStoreSham->PutBatch(entriesSham2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(2)), 2); + ASSERT_EQ(static_cast(observerShamSham->updateEntries_Sham.size()), 1); + ASSERT_EQ("Id1", observerShamSham->updateEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->updateEntries_Sham[0].valueShamSham.ToString()); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 1); + ASSERT_EQ("Id4", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification014 +* @tc.desc: Subscribe to an observerShamSham, + callback with notification many times after putbatch all same data +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification014, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification014 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entriesSham1; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham1.push_back(entrySham1); + entriesSham1.push_back(entrySham2); + entriesSham1.push_back(entrySham3); + + std::vector entriesSham2; + Entry entrySham4, entrySham5; + entrySham4.valueShamShamShamSham = "Id1"; + entrySham4.valueShamSham = "subscribe"; + entrySham5.valueShamShamShamSham = "Id2"; + entrySham5.valueShamSham = "subscribe"; + entriesSham2.push_back(entrySham4); + entriesSham2.push_back(entrySham5); + + statusSham = kvStoreSham->PutBatch(entriesSham1); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 3); + ASSERT_EQ("Id1", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + ASSERT_EQ("Id2", observerShamSham->insertEntries_Sham[1].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[1].valueShamSham.ToString()); + ASSERT_EQ("Id3", observerShamSham->insertEntries_Sham[2].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[2].valueShamSham.ToString()); + + statusSham = kvStoreSham->PutBatch(entriesSham2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(2)), 2); + ASSERT_EQ(static_cast(observerShamSham->updateEntries_Sham.size()), 2); + ASSERT_EQ("Id1", observerShamSham->updateEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->updateEntries_Sham[0].valueShamSham.ToString()); + ASSERT_EQ("Id2", observerShamSham->updateEntries_Sham[1].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->updateEntries_Sham[1].valueShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification015 + * @tc.desc: Subscribe to an observerShamSham, callback with notification many times after putbatch complex data + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification015, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification015 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entriesSham1; + Entry entrySham1, entrySham2, entrySham3; + + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id1"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham1.push_back(entrySham1); + entriesSham1.push_back(entrySham2); + entriesSham1.push_back(entrySham3); + + std::vector entriesSham2; + Entry entrySham4, entrySham5; + entrySham4.valueShamShamShamSham = "Id1"; + entrySham4.valueShamSham = "subscribe"; + entrySham5.valueShamShamShamSham = "Id2"; + entrySham5.valueShamSham = "subscribe"; + entriesSham2.push_back(entrySham4); + entriesSham2.push_back(entrySham5); + + statusSham = kvStoreSham->PutBatch(entriesSham1); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->updateEntries_Sham.size()), 0); + ASSERT_EQ(static_cast(observerShamSham->deleteEntries_Sham.size()), 0); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 2); + ASSERT_EQ("Id1", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + ASSERT_EQ("Id3", observerShamSham->insertEntries_Sham[1].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[1].valueShamSham.ToString()); + + statusSham = kvStoreSham->PutBatch(entriesSham2); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(2)), 2); + ASSERT_EQ(static_cast(observerShamSham->updateEntries_Sham.size()), 1); + ASSERT_EQ("Id1", observerShamSham->updateEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->updateEntries_Sham[0].valueShamSham.ToString()); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 1); + ASSERT_EQ("Id2", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification016 + * @tc.desc: Pressure test subscribe, callback with notification many times after putbatch + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification016, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification016 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + int times = 100; // 100 times + std::vector entriesSham; + for (int i = 0; i < times; i++) { + Entry entrySham; + entrySham.valueShamShamShamSham = std::to_string(i); + entrySham.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham); + } + + statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 100); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification017 + * @tc.desc: Subscribe to an observerShamSham, callback with notification after delete success + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification017, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification017 begin."); + auto observerShamSham = std::make_shared(); + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + Status statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStoreSham->Delete("Id1"); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore Delete data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->deleteEntries_Sham.size()), 1); + ASSERT_EQ("Id1", observerShamSham->deleteEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->deleteEntries_Sham[0].valueShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification018 +* @tc.desc: Subscribe to an observerShamSham, + not callback after delete which valueShamShamShamSham not exist +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification018, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification018 begin."); + auto observerShamSham = std::make_shared(); + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + Status statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStoreSham->Delete("Id4"); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore Delete data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 0); + ASSERT_EQ(static_cast(observerShamSham->deleteEntries_Sham.size()), 0); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification019 +* @tc.desc: Subscribe to an observerShamSham, + delete the same data many times and only first delete callback with notification +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification019, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification019 begin."); + auto observerShamSham = std::make_shared(); + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + Status statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + statusSham = kvStoreSham->Delete("Id1"); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore Delete data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->deleteEntries_Sham.size()), 1); + ASSERT_EQ("Id1", observerShamSham->deleteEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->deleteEntries_Sham[0].valueShamSham.ToString()); + + statusSham = kvStoreSham->Delete("Id1"); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore Delete data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(2)), 1); + ASSERT_EQ(static_cast(observerShamSham->deleteEntries_Sham.size()), 1); + // not callback so not clear + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification020 + * @tc.desc: Subscribe to an observerShamSham, callback with notification after deleteBatch + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification020, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification020 begin."); + auto observerShamSham = std::make_shared(); + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + std::vector valueShamShamShams; + valueShamShamShams.push_back("Id1"); + valueShamShamShams.push_back("Id2"); + + Status statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + statusSham = kvStoreSham->DeleteBatch(valueShamShamShams); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->deleteEntries_Sham.size()), 2); + ASSERT_EQ("Id1", observerShamSham->deleteEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->deleteEntries_Sham[0].valueShamSham.ToString()); + ASSERT_EQ("Id2", observerShamSham->deleteEntries_Sham[1].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->deleteEntries_Sham[1].valueShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification021 +* @tc.desc: Subscribe to an observerShamSham, + not callback after deleteBatch which all valueShamShamShams not exist +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification021, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification021 begin."); + auto observerShamSham = std::make_shared(); + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + std::vector valueShamShamShams; + valueShamShamShams.push_back("Id4"); + valueShamShamShams.push_back("Id5"); + + Status statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + statusSham = kvStoreSham->DeleteBatch(valueShamShamShams); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 0); + ASSERT_EQ(static_cast(observerShamSham->deleteEntries_Sham.size()), 0); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification022 +* @tc.desc: Subscribe to an observerShamSham, + deletebatch the same data many times and only first deletebatch callback with +* notification +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Sham +*/ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification022, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification022 begin."); + auto observerShamSham = std::make_shared(); + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.valueShamShamShamSham = "Id1"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id2"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id3"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + std::vector valueShamShamShams; + valueShamShamShams.push_back("Id1"); + valueShamShamShams.push_back("Id2"); + + Status statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + statusSham = kvStoreSham->DeleteBatch(valueShamShamShams); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->deleteEntries_Sham.size()), 2); + ASSERT_EQ("Id1", observerShamSham->deleteEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->deleteEntries_Sham[0].valueShamSham.ToString()); + ASSERT_EQ("Id2", observerShamSham->deleteEntries_Sham[1].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->deleteEntries_Sham[1].valueShamSham.ToString()); + + statusSham = kvStoreSham->DeleteBatch(valueShamShamShams); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(2)), 1); + ASSERT_EQ(static_cast(observerShamSham->deleteEntries_Sham.size()), 2); + // not callback so not clear + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification023 + * @tc.desc: Subscribe to an observerShamSham, include Clear Put PutBatch Delete DeleteBatch + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification023, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification023 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key valueShamShamSham1 = "Id1"; + Value valueSham1 = "subscribe"; + + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.valueShamShamShamSham = "Id2"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id3"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id4"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + std::vector valueShamShamShams; + valueShamShamShams.push_back("Id2"); + valueShamShamShams.push_back("Id3"); + + statusSham = kvStoreSham->Put(valueShamShamSham1, valueSham1); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + statusSham = kvStoreSham->Delete(valueShamShamSham1); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore delete data return wrong statusSham"; + statusSham = kvStoreSham->DeleteBatch(valueShamShamShams); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(4)), 4); + // every callback will clear vector + ASSERT_EQ(static_cast(observerShamSham->deleteEntries_Sham.size()), 2); + ASSERT_EQ("Id2", observerShamSham->deleteEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->deleteEntries_Sham[0].valueShamSham.ToString()); + ASSERT_EQ("Id3", observerShamSham->deleteEntries_Sham[1].valueShamShamShamSham.ToString()); + ASSERT_EQ("subscribe", observerShamSham->deleteEntries_Sham[1].valueShamSham.ToString()); + ASSERT_EQ(static_cast(observerShamSham->updateEntries_Sham.size()), 0); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 0); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification024 + * @tc.desc: Subscribe to an observerShamSham[use transaction], include Clear Put PutBatch Delete DeleteBatch + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification024, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification024 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key valueShamShamSham1 = "Id1"; + Value valueSham1 = "subscribe"; + + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.valueShamShamShamSham = "Id2"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id3"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id4"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + std::vector valueShamShamShams; + valueShamShamShams.push_back("Id2"); + valueShamShamShams.push_back("Id3"); + + statusSham = kvStoreSham->StartTransaction(); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore startTransaction return wrong statusSham"; + statusSham = kvStoreSham->Put(valueShamShamSham1, valueSham1); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + statusSham = kvStoreSham->Delete(valueShamShamSham1); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore delete data return wrong statusSham"; + statusSham = kvStoreSham->DeleteBatch(valueShamShamShams); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + statusSham = kvStoreSham->Commit(); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore Commit return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification025 + * @tc.desc: Subscribe to an observerShamSham[use transaction], include Clear Put PutBatch Delete DeleteBatch + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification025, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification025 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + Key valueShamShamSham1 = "Id1"; + Value valueSham1 = "subscribe"; + + std::vector entriesSham; + Entry entrySham1, entrySham2, entrySham3; + entrySham1.valueShamShamShamSham = "Id2"; + entrySham1.valueShamSham = "subscribe"; + entrySham2.valueShamShamShamSham = "Id3"; + entrySham2.valueShamSham = "subscribe"; + entrySham3.valueShamShamShamSham = "Id4"; + entrySham3.valueShamSham = "subscribe"; + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + entriesSham.push_back(entrySham3); + + std::vector valueShamShamShams; + valueShamShamShams.push_back("Id2"); + valueShamShamShams.push_back("Id3"); + + statusSham = kvStoreSham->StartTransaction(); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore startTransaction return wrong statusSham"; + statusSham = kvStoreSham->Put(valueShamShamSham1, valueSham1); + // insert or update valueShamShamShamSham-valueShamSham + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore put data return wrong statusSham"; + statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + statusSham = kvStoreSham->Delete(valueShamShamSham1); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore delete data return wrong statusSham"; + statusSham = kvStoreSham->DeleteBatch(valueShamShamShams); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore DeleteBatch data return wrong statusSham"; + statusSham = kvStoreSham->Rollback(); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore Commit return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 0); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 0); + ASSERT_EQ(static_cast(observerShamSham->updateEntries_Sham.size()), 0); + ASSERT_EQ(static_cast(observerShamSham->deleteEntries_Sham.size()), 0); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; + observerShamSham = nullptr; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification0261 + * @tc.desc: Subscribe to an observerShamSham[use transaction], include bigData PutBatch update insert delete + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification0261, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification0261 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entriesSham; + Entry entrySham0, entrySham1, entrySham2; + + int maxValueSize = 2 * 1024 * 1024; // max valueShamSham size is 2M. + std::vector val(maxValueSize); + for (int i = 0; i < maxValueSize; i++) { + val[i] = static_cast(i); + } + Value valueShamSham = val; + + int maxValueSize2 = 1000 * 1024; // max valueShamSham size is 1000k. + std::vector val2(maxValueSize2); + for (int i = 0; i < maxValueSize2; i++) { + val2[i] = static_cast(i); + } + Value valueSham2 = val2; + + entrySham0.valueShamShamShamSham = "SingleKvStoreDdmPutBatch006_0"; + entrySham0.valueShamSham = "beijing"; + entrySham1.valueShamShamShamSham = "SingleKvStoreDdmPutBatch006_1"; + entrySham1.valueShamSham = valueShamSham; + entrySham2.valueShamShamShamSham = "SingleKvStoreDdmPutBatch006_2"; + entrySham2.valueShamSham = valueShamSham; + + entriesSham.push_back(entrySham0); + entriesSham.push_back(entrySham1); + entriesSham.push_back(entrySham2); + + statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 5); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_0", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("beijing", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_1", observerShamSham->insertEntries_Sham[1].valueShamShamShamSham.ToString()); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_2", observerShamSham->insertEntries_Sham[2].valueShamShamShamSham.ToString()); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_3", observerShamSham->insertEntries_Sham[3].valueShamShamShamSham.ToString()); + ASSERT_EQ("ZuiHouBuZhiTianZaiShui", observerShamSham->insertEntries_Sham[3].valueShamSham.ToString()); +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification0262 + * @tc.desc: Subscribe to an observerShamSham[use transaction], include bigData PutBatch update insert delete + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification0262, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification0262 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entriesSham; + Entry entrySham3, entrySham4; + + int maxValueSize = 2 * 1024 * 1024; // max valueShamSham size is 2M. + std::vector val(maxValueSize); + for (int i = 0; i < maxValueSize; i++) { + val[i] = static_cast(i); + } + Value valueShamSham = val; + + int maxValueSize2 = 1000 * 1024; // max valueShamSham size is 1000k. + std::vector val2(maxValueSize2); + for (int i = 0; i < maxValueSize2; i++) { + val2[i] = static_cast(i); + } + Value valueSham2 = val2; + + entrySham3.valueShamShamShamSham = "SingleKvStoreDdmPutBatch006_3"; + entrySham3.valueShamSham = "ZuiHouBuZhiTianZaiShui"; + entrySham4.valueShamShamShamSham = "SingleKvStoreDdmPutBatch006_4"; + entrySham4.valueShamSham = valueShamSham; + + entriesSham.push_back(entrySham3); + entriesSham.push_back(entrySham4); + + statusSham = kvStoreSham->PutBatch(entriesSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putbatch data return wrong statusSham"; + + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham()), 1); + ASSERT_EQ(static_cast(observerShamSham->insertEntries_Sham.size()), 5); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_0", observerShamSham->insertEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ("beijing", observerShamSham->insertEntries_Sham[0].valueShamSham.ToString()); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_1", observerShamSham->insertEntries_Sham[1].valueShamShamShamSham.ToString()); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_2", observerShamSham->insertEntries_Sham[2].valueShamShamShamSham.ToString()); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_3", observerShamSham->insertEntries_Sham[3].valueShamShamShamSham.ToString()); + ASSERT_EQ("ZuiHouBuZhiTianZaiShui", observerShamSham->insertEntries_Sham[3].valueShamSham.ToString()); +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification0263 + * @tc.desc: Subscribe to an observerShamSham[use transaction], include bigData PutBatch update insert delete + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification0263, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification0263 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entriesSham; + Entry entrySham5; + + int maxValueSize = 2 * 1024 * 1024; // max valueShamSham size is 2M. + std::vector val(maxValueSize); + for (int i = 0; i < maxValueSize; i++) { + val[i] = static_cast(i); + } + Value valueShamSham = val; + + int maxValueSize2 = 1000 * 1024; // max valueShamSham size is 1000k. + std::vector val2(maxValueSize2); + for (int i = 0; i < maxValueSize2; i++) { + val2[i] = static_cast(i); + } + + entrySham5.valueShamShamShamSham = "SingleKvStoreDdmPutBatch006_2"; + entrySham5.valueShamSham = val2; + + std::vector updateEntries; + updateEntries.push_back(entrySham5); + + statusSham = kvStoreSham->PutBatch(updateEntries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putBatch update data return wrong statusSham"; + + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(2)), 2); + ASSERT_EQ(static_cast(observerShamSham->updateEntries_Sham.size()), 3); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_2", observerShamSham->updateEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_3", observerShamSham->updateEntries_Sham[1].valueShamShamShamSham.ToString()); + ASSERT_EQ("ManChuanXingMengYaXingHe", observerShamSham->updateEntries_Sham[1].valueShamSham.ToString()); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_4", observerShamSham->updateEntries_Sham[2].valueShamShamShamSham.ToString()); + ASSERT_EQ(false, observerShamSham->isClearSham_); + + statusSham = kvStoreSham->Delete("SingleKvStoreDdmPutBatch006_3"); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore delete data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(3)), 3); + ASSERT_EQ(static_cast(observerShamSham->deleteEntries_Sham.size()), 1); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_3", observerShamSham->deleteEntries_Sham[0].valueShamShamShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification0264 + * @tc.desc: Subscribe to an observerShamSham[use transaction], include bigData PutBatch update insert delete + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification0264, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification0264 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entriesSham; + Entry entrySham6; + + int maxValueSize = 2 * 1024 * 1024; // max valueShamSham size is 2M. + std::vector val(maxValueSize); + for (int i = 0; i < maxValueSize; i++) { + val[i] = static_cast(i); + } + Value valueShamSham = val; + + int maxValueSize2 = 1000 * 1024; // max valueShamSham size is 1000k. + std::vector val2(maxValueSize2); + for (int i = 0; i < maxValueSize2; i++) { + val2[i] = static_cast(i); + } + + entrySham6.valueShamShamShamSham = "SingleKvStoreDdmPutBatch006_3"; + entrySham6.valueShamSham = "ManChuanXingMengYaXingHe"; + + std::vector updateEntries; + updateEntries.push_back(entrySham6); + statusSham = kvStoreSham->PutBatch(updateEntries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putBatch update data return wrong statusSham"; + + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(2)), 2); + ASSERT_EQ(static_cast(observerShamSham->updateEntries_Sham.size()), 3); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_2", observerShamSham->updateEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_3", observerShamSham->updateEntries_Sham[1].valueShamShamShamSham.ToString()); + ASSERT_EQ("ManChuanXingMengYaXingHe", observerShamSham->updateEntries_Sham[1].valueShamSham.ToString()); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_4", observerShamSham->updateEntries_Sham[2].valueShamShamShamSham.ToString()); + ASSERT_EQ(false, observerShamSham->isClearSham_); + + statusSham = kvStoreSham->Delete("SingleKvStoreDdmPutBatch006_3"); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore delete data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(3)), 3); + ASSERT_EQ(static_cast(observerShamSham->deleteEntries_Sham.size()), 1); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_3", observerShamSham->deleteEntries_Sham[0].valueShamShamShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} + +/** + * @tc.name: KvStoreDdmSubscribeKvStoreNotification0265 + * @tc.desc: Subscribe to an observerShamSham[use transaction], include bigData PutBatch update insert delete + * @tc.type: FUNC + * @tc.require: AR000CIFGM + * @tc.author: Sham + */ +HWTEST_F(LocalSubscribeStoreShamTest, KvStoreDdmSubscribeKvStoreNotification0265, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification0265 begin."); + auto observerShamSham = std::make_shared(); + SubscribeType subscribeTypeSham = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusSham = kvStoreSham->SubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "SubscribeKvStore return wrong statusSham"; + + std::vector entriesSham; + Entry entrySham7; + + int maxValueSize = 2 * 1024 * 1024; // max valueShamSham size is 2M. + std::vector val(maxValueSize); + for (int i = 0; i < maxValueSize; i++) { + val[i] = static_cast(i); + } + Value valueShamSham = val; + + int maxValueSize2 = 1000 * 1024; // max valueShamSham size is 1000k. + std::vector val2(maxValueSize2); + for (int i = 0; i < maxValueSize2; i++) { + val2[i] = static_cast(i); + } + + entrySham7.valueShamShamShamSham = "SingleKvStoreDdmPutBatch006_4"; + entrySham7.valueShamSham = val2; + std::vector updateEntries; + + updateEntries.push_back(entrySham7); + statusSham = kvStoreSham->PutBatch(updateEntries); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore putBatch update data return wrong statusSham"; + + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(2)), 2); + ASSERT_EQ(static_cast(observerShamSham->updateEntries_Sham.size()), 3); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_2", observerShamSham->updateEntries_Sham[0].valueShamShamShamSham.ToString()); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_3", observerShamSham->updateEntries_Sham[1].valueShamShamShamSham.ToString()); + ASSERT_EQ("ManChuanXingMengYaXingHe", observerShamSham->updateEntries_Sham[1].valueShamSham.ToString()); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_4", observerShamSham->updateEntries_Sham[2].valueShamShamShamSham.ToString()); + ASSERT_EQ(false, observerShamSham->isClearSham_); + + statusSham = kvStoreSham->Delete("SingleKvStoreDdmPutBatch006_3"); + ASSERT_EQ(Status::SUCCESS, statusSham) << "KvStore delete data return wrong statusSham"; + ASSERT_EQ(static_cast(observerShamSham->GetCallCountSham(3)), 3); + ASSERT_EQ(static_cast(observerShamSham->deleteEntries_Sham.size()), 1); + ASSERT_EQ( + "SingleKvStoreDdmPutBatch006_3", observerShamSham->deleteEntries_Sham[0].valueShamShamShamSham.ToString()); + + statusSham = kvStoreSham->UnSubscribeKvStore(subscribeTypeSham, observerShamSham); + ASSERT_EQ(Status::SUCCESS, statusSham) << "UnSubscribeKvStore return wrong statusSham"; +} \ No newline at end of file diff --git a/kv_store/databaseutils/test/local_subscribe_store_virtual_test.cpp b/kv_store/databaseutils/test/local_subscribe_store_virtual_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0cd9b7e2a7f597892313905fb9e4df44d7110cc2 --- /dev/null +++ b/kv_store/databaseutils/test/local_subscribe_store_virtual_test.cpp @@ -0,0 +1,2272 @@ +/* + * Copyright (c) 2021 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 "LocalSubscribeStoreVirtualTest" +#include +#include +#include +#include +#include "block_data.h" +#include "distributed_kv_data_manager.h" +#include "log_print.h" +#include "types.h" + +using namespace testing::ext; +using namespace OHOS::DistributedKv; +using namespace OHOS; +class LocalSubscribeStoreVirtualTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + + static DistributedKvDataManager managerVirtual; + static std::shared_ptr kvStoreVirtual; + static Status statusGetKvStoreVirtual; + static AppId appIdVirtual; + static StoreId storeIdVirtual; +}; +std::shared_ptr LocalSubscribeStoreVirtualTest::kvStoreVirtual = nullptr; +Status LocalSubscribeStoreVirtualTest::statusGetKvStoreVirtual = Status::ERROR; +DistributedKvDataManager LocalSubscribeStoreVirtualTest::managerVirtual; +AppId LocalSubscribeStoreVirtualTest::appIdVirtual; +StoreId LocalSubscribeStoreVirtualTest::storeIdVirtual; + +void LocalSubscribeStoreVirtualTest::SetUpTestCase(void) +{ + mkdir("/data/service/el1/public/database/odmf", (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); +} + +void LocalSubscribeStoreVirtualTest::TearDownTestCase(void) +{ + managerVirtual.CloseKvStore(appIdVirtual, kvStoreVirtual); + kvStoreVirtual = nullptr; + managerVirtual.DeleteKvStore(appIdVirtual, storeIdVirtual, "/data/service/el1/public/database/odmf"); + (void)remove("/data/service/el1/public/database/odmf/kvdb"); + (void)remove("/data/service/el1/public/database/odmf"); +} + +void LocalSubscribeStoreVirtualTest::SetUp(void) +{ + Options optionsVirtual; + optionsVirtual.createIfMissing = true; + optionsVirtual.encrypt = false; // not supported yet. + optionsVirtual.securityLevel = S1; + optionsVirtual.autoSync = true; // not supported yet. + optionsVirtual.kvStoreType = KvStoreType::SINGLE_VERSION; + optionsVirtual.area = EL1; + optionsVirtual.baseDir = std::string("/data/service/el1/public/database/odmf"); + appIdVirtual.appIdVirtual = "odmf"; // define app name. + storeIdVirtual.storeIdVirtual = "student"; // define kvstore(database) name + managerVirtual.DeleteKvStore(appIdVirtual, storeIdVirtual, optionsVirtual.baseDir); + // [create and] open and initialize kvstore instance. + statusGetKvStoreVirtual = + managerVirtual.GetSingleKvStore(optionsVirtual, appIdVirtual, storeIdVirtual, kvStoreVirtual); + EXPECT_EQ(Status::SUCCESS, statusGetKvStoreVirtual) << "statusGetKvStoreVirtual return wrong statusVirtual"; + EXPECT_NE(nullptr, kvStoreVirtual) << "kvStoreVirtual is nullptr"; +} + +void LocalSubscribeStoreVirtualTest::TearDown(void) +{ + managerVirtual.CloseKvStore(appIdVirtual, kvStoreVirtual); + kvStoreVirtual = nullptr; + managerVirtual.DeleteKvStore(appIdVirtual, storeIdVirtual); +} + +class KvStoreObserverUnitTestVirtual : public KvStoreObserver { +public: + std::vector insertEntries_Virtual; + std::vector updateEntries_Virtual; + std::vector deleteEntries_Virtual; + bool isClearVirtual_ = false; + KvStoreObserverUnitTestVirtual(); + ~KvStoreObserverUnitTestVirtual() + {} + + KvStoreObserverUnitTestVirtual(const KvStoreObserverUnitTestVirtual &) = delete; + KvStoreObserverUnitTestVirtual &operator=(const KvStoreObserverUnitTestVirtual &) = delete; + KvStoreObserverUnitTestVirtual(KvStoreObserverUnitTestVirtual &&) = delete; + KvStoreObserverUnitTestVirtual &operator=(KvStoreObserverUnitTestVirtual &&) = delete; + + void OnChangeVirtual(const ChangeNotification &changeNotification); + + // reset the callCountVirtual_to zero. + void ResetToZero(); + + uint32_t GetCallCountVirtual(uint32_t valueVirtualVirtual = 1); + +private: + std::mutex mutexVirtual_; + uint32_t callCountVirtual_ = 0; + BlockData valueVirtual_Virtual{ 1, 0 }; +}; + +KvStoreObserverUnitTestVirtual::KvStoreObserverUnitTestVirtual() +{ +} + +void KvStoreObserverUnitTestVirtual::OnChangeVirtual(const ChangeNotification &changeNotification) +{ + ZLOGD("begin."); + insertEntries_Virtual = changeNotification.GetInsertEntries(); + updateEntries_Virtual = changeNotification.GetUpdateEntries(); + deleteEntries_Virtual = changeNotification.GetDeleteEntries(); + changeNotification.GetDeviceId(); + isClearVirtual_ = changeNotification.IsClear(); + std::lock_guard guard(mutexVirtual_); + ++callCount_Virtual; + valueVirtual_Virtual.SetValue(callCount_Virtual); +} + +void KvStoreObserverUnitTestVirtual::ResetToZero() +{ + std::lock_guard guard(mutexVirtual_); + callCountVirtual_ = 0; + valueVirtual_Virtual.Clear(0); +} + +uint32_t KvStoreObserverUnitTestVirtual::GetCallCountVirtual(uint32_t valueVirtualVirtual) +{ + int retryVirtual = 0; + uint32_t callTimesVirtual = 0; + while (retryVirtual < valueVirtualVirtual) { + callTimesVirtual = valueVirtual_Virtual.GetValue(); + if (callTimesVirtual >= valueVirtualVirtual) { + break; + } + std::lock_guard guard(mutexVirtual_); + callTimesVirtual = valueVirtual_Virtual.GetValue(); + if (callTimesVirtual >= valueVirtualVirtual) { + break; + } + valueVirtual_Virtual.Clear(callTimesVirtual); + retryVirtual++; + } + return callTimesVirtual; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore001 +* @tc.desc: Subscribe success +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStore001, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore001 begin."); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + auto observerVirtualVirtual = std::make_shared(); + observerVirtualVirtual->ResetToZero(); + + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 0); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + observerVirtualVirtual = nullptr; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore002 +* @tc.desc: Subscribe fail, observerVirtualVirtual is null +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStore002, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore002 begin."); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + std::shared_ptr observerVirtualVirtual = nullptr; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::INVALID_ARGUMENT, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore003 +* @tc.desc: Subscribe success and OnChangeVirtual callback after put +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStore003, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStore003 begin."); + auto observerVirtualVirtual = std::make_shared(); + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key valueVirtualVirtualVirtualVirtual = "Id1"; + Value valueVirtualVirtual = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtualVirtual, valueVirtualVirtual); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + observerVirtualVirtual = nullptr; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore004 +* @tc.desc: The same observerVirtualVirtual subscribe three times and OnChangeVirtual callback after put +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStore004, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore004 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::STORE_ALREADY_SUBSCRIBE, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::STORE_ALREADY_SUBSCRIBE, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key valueVirtualVirtualVirtualVirtual = "Id1"; + Value valueVirtualVirtual = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtualVirtual, valueVirtualVirtual); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore005 +* @tc.desc: The different observerVirtualVirtual subscribe three times and OnChangeVirtual callback after put +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStore005, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore005 begin."); + auto observerVirtual1 = std::make_shared(); + auto observerVirtual2 = std::make_shared(); + auto observerVirtual3 = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual1); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore failed, wrong statusVirtual"; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore failed, wrong statusVirtual"; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual3); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore failed, wrong statusVirtual"; + + Key valueVirtualVirtualVirtualVirtual = "Id1"; + Value valueVirtualVirtual = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtualVirtual, valueVirtualVirtual); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "Putting data to KvStore failed, wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual1->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtual2->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtual3->GetCallCountVirtual()), 1); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual1); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual3); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore006 +* @tc.desc: Unsubscribe an observerVirtualVirtual and + subscribe again - the map should be cleared after unsubscription. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStore006, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore006 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key valueVirtualVirtualVirtual1 = "Id1"; + Value valueVirtual1 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual1, valueVirtual1); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + + Key valueVirtualVirtualVirtual2 = "Id2"; + Value valueVirtual2 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual2, valueVirtual2); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + + kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + Key valueVirtualVirtualVirtual3 = "Id3"; + Value valueVirtual3 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual3, valueVirtual3); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(2)), 2); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore007 +* @tc.desc: Subscribe to an observerVirtualVirtual - OnChangeVirtual callback is + called multiple times after the put operation. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStore007, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore007 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key valueVirtualVirtualVirtual1 = "Id1"; + Value valueVirtual1 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual1, valueVirtual1); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + + Key valueVirtualVirtualVirtual2 = "Id2"; + Value valueVirtual2 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual2, valueVirtual2); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + + Key valueVirtualVirtualVirtual3 = "Id3"; + Value valueVirtual3 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual3, valueVirtual3); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(3)), 3); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore008 +* @tc.desc: Subscribe to an observerVirtualVirtual - OnChangeVirtual callback is + called multiple times after the put&update operations. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStore008, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore008 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key valueVirtualVirtualVirtual1 = "Id1"; + Value valueVirtual1 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual1, valueVirtual1); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + + Key valueVirtualVirtualVirtual2 = "Id2"; + Value valueVirtual2 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual2, valueVirtual2); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + + Key valueVirtualVirtualVirtual3 = "Id1"; + Value valueVirtual3 = "subscribe03"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual3, valueVirtual3); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(3)), 3); + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore009 +* @tc.desc: Subscribe to an observerVirtualVirtual - OnChangeVirtual callback is + called multiple times after the putBatch operation. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStore009, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore009 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + // before update. + std::vector entriesVirtual1; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual1.push_back(entryVirtual1); + entriesVirtual1.push_back(entryVirtual2); + entriesVirtual1.push_back(entryVirtual3); + + std::vector entriesVirtual2; + Entry entryVirtual4, entryVirtual5; + entryVirtual4.valueVirtualVirtualVirtualVirtual = "Id4"; + entryVirtual4.valueVirtualVirtual = "subscribe"; + entryVirtual5.valueVirtualVirtualVirtualVirtual = "Id5"; + entryVirtual5.valueVirtualVirtual = "subscribe"; + entriesVirtual2.push_back(entryVirtual4); + entriesVirtual2.push_back(entryVirtual5); + + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual1); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(2)), 2); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore010 +* @tc.desc: Subscribe to an observerVirtualVirtual - OnChangeVirtual callback is + called multiple times after the putBatch update operation. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStore010, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore010 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + // before update. + std::vector entriesVirtual1; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual1.push_back(entryVirtual1); + entriesVirtual1.push_back(entryVirtual2); + entriesVirtual1.push_back(entryVirtual3); + + std::vector entriesVirtual2; + Entry entryVirtual4, entryVirtual5; + entryVirtual4.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual4.valueVirtualVirtual = "modify"; + entryVirtual5.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual5.valueVirtualVirtual = "modify"; + entriesVirtual2.push_back(entryVirtual4); + entriesVirtual2.push_back(entryVirtual5); + + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual1); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(2)), 2); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore011 +* @tc.desc: Subscribe to an observerVirtualVirtual - OnChangeVirtual callback is called after successful deletion. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStore011, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore011 begin."); + auto observerVirtualVirtual = std::make_shared(); + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + Status statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->Delete("Id1"); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore Delete data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore012 +* @tc.desc: Subscribe to an observerVirtualVirtual - OnChangeVirtual callback is + not called after deletion of non-existing valueVirtualVirtualVirtuals. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStore012, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore012 begin."); + auto observerVirtualVirtual = std::make_shared(); + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + Status statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->Delete("Id4"); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore Delete data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 0); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore013 +* @tc.desc: Subscribe to an observerVirtualVirtual - OnChangeVirtual callback is called after KvStore is cleared. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStore013, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore013 begin."); + auto observerVirtualVirtual = std::make_shared(); + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + Status statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(1)), 0); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore014 +* @tc.desc: Subscribe to an observerVirtualVirtual - OnChangeVirtual callback is + not called after non-existing data in KvStore is cleared. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStore014, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore014 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 0); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore015 +* @tc.desc: Subscribe to an observerVirtualVirtual - OnChangeVirtual callback is + called after the deleteBatch operation. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStore015, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore015 begin."); + auto observerVirtualVirtual = std::make_shared(); + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + std::vector valueVirtualVirtualVirtuals; + valueVirtualVirtualVirtuals.push_back("Id1"); + valueVirtualVirtualVirtuals.push_back("Id2"); + + Status statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + statusVirtual = kvStoreVirtual->DeleteBatch(valueVirtualVirtualVirtuals); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore016 +* @tc.desc: Subscribe to an observerVirtualVirtual - OnChangeVirtual callback is + called after deleteBatch of non-existing valueVirtualVirtualVirtuals. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStore016, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore016 begin."); + auto observerVirtualVirtual = std::make_shared(); + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + std::vector valueVirtualVirtualVirtuals; + valueVirtualVirtualVirtuals.push_back("Id4"); + valueVirtualVirtualVirtuals.push_back("Id5"); + + Status statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + statusVirtual = kvStoreVirtual->DeleteBatch(valueVirtualVirtualVirtuals); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 0); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStore020 +* @tc.desc: Unsubscribe an observerVirtualVirtual two times. +* @tc.type: FUNC +* @tc.require: AR000CQDU9 AR000CQS37 +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStore020, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStore020 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::STORE_NOT_SUBSCRIBE, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification001 +* @tc.desc: Subscribe to an observerVirtualVirtual successfully - callback is + called with a notification after the put operation. +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification001, TestSize.Level1) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification001 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key valueVirtualVirtualVirtualVirtual = "Id1"; + Value valueVirtualVirtual = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtualVirtual, valueVirtualVirtual); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + ZLOGD("kvstore_ddm_subscribekvstore_003"); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 1); + EXPECT_EQ("Id1", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + ZLOGD("kvstore_ddm_subscribekvstore_003 size:%zu.", observerVirtualVirtual->insertEntries_Virtual.size()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification002 +* @tc.desc: Subscribe to the same observerVirtualVirtual three times - callback + is called with a notification after the put operation. +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification002, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification002 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::STORE_ALREADY_SUBSCRIBE, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::STORE_ALREADY_SUBSCRIBE, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key valueVirtualVirtualVirtualVirtual = "Id1"; + Value valueVirtualVirtual = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtualVirtual, valueVirtualVirtual); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 1); + EXPECT_EQ("Id1", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification003 +* @tc.desc: The different observerVirtualVirtual subscribe three times and callback with notification after put +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification003, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification003 begin."); + auto observerVirtual1 = std::make_shared(); + auto observerVirtual2 = std::make_shared(); + auto observerVirtual3 = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual1); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtual3); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key valueVirtualVirtualVirtualVirtual = "Id1"; + Value valueVirtualVirtual = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtualVirtual, valueVirtualVirtual); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtual1->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtual1->insertEntries_Virtual.size()), 1); + EXPECT_EQ("Id1", observerVirtual1->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual1->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + + EXPECT_EQ(static_cast(observerVirtual2->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtual2->insertEntries_Virtual.size()), 1); + EXPECT_EQ("Id1", observerVirtual2->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual2->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + + EXPECT_EQ(static_cast(observerVirtual3->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtual3->insertEntries_Virtual.size()), 1); + EXPECT_EQ("Id1", observerVirtual3->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtual3->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual1); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtual3); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification004 +* @tc.desc: Verify notification after an observerVirtualVirtual is unsubscribed and then subscribed again. +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification004, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification004 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key valueVirtualVirtualVirtual1 = "Id1"; + Value valueVirtual1 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual1, valueVirtual1); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 1); + EXPECT_EQ("Id1", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + + Key valueVirtualVirtualVirtual2 = "Id2"; + Value valueVirtual2 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual2, valueVirtual2); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 1); + EXPECT_EQ("Id1", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + + kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + Key valueVirtualVirtualVirtual3 = "Id3"; + Value valueVirtual3 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual3, valueVirtual3); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(2)), 2); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 1); + EXPECT_EQ("Id3", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification005 +* @tc.desc: Subscribe to an observerVirtualVirtual, + callback with notification many times after put the different data +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification005, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification005 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key valueVirtualVirtualVirtual1 = "Id1"; + Value valueVirtual1 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual1, valueVirtual1); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 1); + EXPECT_EQ("Id1", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + + Key valueVirtualVirtualVirtual2 = "Id2"; + Value valueVirtual2 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual2, valueVirtual2); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(2)), 2); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 1); + EXPECT_EQ("Id2", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + + Key valueVirtualVirtualVirtual3 = "Id3"; + Value valueVirtual3 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual3, valueVirtual3); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(3)), 3); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 1); + EXPECT_EQ("Id3", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification006 +* @tc.desc: Subscribe to an observerVirtualVirtual, callback with notification many times after put the same data +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification006, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification006 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key valueVirtualVirtualVirtual1 = "Id1"; + Value valueVirtual1 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual1, valueVirtual1); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 1); + EXPECT_EQ("Id1", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + + Key valueVirtualVirtualVirtual2 = "Id1"; + Value valueVirtual2 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual2, valueVirtual2); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(2)), 2); + EXPECT_EQ(static_cast(observerVirtualVirtual->updateEntries_Virtual.size()), 1); + EXPECT_EQ("Id1", observerVirtualVirtual->updateEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->updateEntries_Virtual[0].valueVirtualVirtual.ToString()); + + Key valueVirtualVirtualVirtual3 = "Id1"; + Value valueVirtual3 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual3, valueVirtual3); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(3)), 3); + EXPECT_EQ(static_cast(observerVirtualVirtual->updateEntries_Virtual.size()), 1); + EXPECT_EQ("Id1", observerVirtualVirtual->updateEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->updateEntries_Virtual[0].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification007 +* @tc.desc: Subscribe to an observerVirtualVirtual, callback with notification many times after put&update +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification007, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification007 begin."); + auto observerVirtualVirtual = std::make_shared(); + Key valueVirtualVirtualVirtual1 = "Id1"; + Value valueVirtual1 = "subscribe"; + Status statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual1, valueVirtual1); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + + Key valueVirtualVirtualVirtual2 = "Id2"; + Value valueVirtual2 = "subscribe"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual2, valueVirtual2); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key valueVirtualVirtualVirtual3 = "Id1"; + Value valueVirtual3 = "subscribe03"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual3, valueVirtual3); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->updateEntries_Virtual.size()), 1); + EXPECT_EQ("Id1", observerVirtualVirtual->updateEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe03", observerVirtualVirtual->updateEntries_Virtual[0].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification008 +* @tc.desc: Subscribe to an observerVirtualVirtual, callback with notification one times after putbatch&update +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification008, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification008 begin."); + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + Status statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + entriesVirtual.clear(); + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe_modify"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe_modify"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->updateEntries_Virtual.size()), 2); + EXPECT_EQ("Id1", observerVirtualVirtual->updateEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe_modify", observerVirtualVirtual->updateEntries_Virtual[0].valueVirtualVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtualVirtual->updateEntries_Virtual[1].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe_modify", observerVirtualVirtual->updateEntries_Virtual[1].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification009 +* @tc.desc: Subscribe to an observerVirtualVirtual, + callback with notification one times after putbatch all different data +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification009, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification009 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 3); + EXPECT_EQ("Id1", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtualVirtual->insertEntries_Virtual[1].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[1].valueVirtualVirtual.ToString()); + EXPECT_EQ("Id3", observerVirtualVirtual->insertEntries_Virtual[2].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[2].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification010 +* @tc.desc: Subscribe to an observerVirtualVirtual, + callback with notification one times after putbatch both different and same data +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification010, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification010 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 2); + EXPECT_EQ("Id1", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtualVirtual->insertEntries_Virtual[1].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[1].valueVirtualVirtual.ToString()); + EXPECT_EQ(static_cast(observerVirtualVirtual->updateEntries_Virtual.size()), 0); + EXPECT_EQ(static_cast(observerVirtualVirtual->deleteEntries_Virtual.size()), 0); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification011 +* @tc.desc: Subscribe to an observerVirtualVirtual, callback with notification one times after putbatch all same data +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification011, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification011 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 1); + EXPECT_EQ("Id1", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + EXPECT_EQ(static_cast(observerVirtualVirtual->updateEntries_Virtual.size()), 0); + EXPECT_EQ(static_cast(observerVirtualVirtual->deleteEntries_Virtual.size()), 0); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification012 +* @tc.desc: Subscribe to an observerVirtualVirtual, + callback with notification many times after putbatch all different data +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification012, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification012 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entriesVirtual1; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual1.push_back(entryVirtual1); + entriesVirtual1.push_back(entryVirtual2); + entriesVirtual1.push_back(entryVirtual3); + + std::vector entriesVirtual2; + Entry entryVirtual4, entryVirtual5; + entryVirtual4.valueVirtualVirtualVirtualVirtual = "Id4"; + entryVirtual4.valueVirtualVirtual = "subscribe"; + entryVirtual5.valueVirtualVirtualVirtualVirtual = "Id5"; + entryVirtual5.valueVirtualVirtual = "subscribe"; + entriesVirtual2.push_back(entryVirtual4); + entriesVirtual2.push_back(entryVirtual5); + + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual1); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 3); + EXPECT_EQ("Id1", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtualVirtual->insertEntries_Virtual[1].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[1].valueVirtualVirtual.ToString()); + EXPECT_EQ("Id3", observerVirtualVirtual->insertEntries_Virtual[2].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[2].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(2)), 2); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 2); + EXPECT_EQ("Id4", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + EXPECT_EQ("Id5", observerVirtualVirtual->insertEntries_Virtual[1].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[1].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification013 +* @tc.desc: Subscribe to an observerVirtualVirtual, + callback with notification many times after putbatch both different and same data +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification013, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification013 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entriesVirtual1; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual1.push_back(entryVirtual1); + entriesVirtual1.push_back(entryVirtual2); + entriesVirtual1.push_back(entryVirtual3); + + std::vector entriesVirtual2; + Entry entryVirtual4, entryVirtual5; + entryVirtual4.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual4.valueVirtualVirtual = "subscribe"; + entryVirtual5.valueVirtualVirtualVirtualVirtual = "Id4"; + entryVirtual5.valueVirtualVirtual = "subscribe"; + entriesVirtual2.push_back(entryVirtual4); + entriesVirtual2.push_back(entryVirtual5); + + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual1); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 3); + EXPECT_EQ("Id1", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtualVirtual->insertEntries_Virtual[1].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[1].valueVirtualVirtual.ToString()); + EXPECT_EQ("Id3", observerVirtualVirtual->insertEntries_Virtual[2].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[2].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(2)), 2); + EXPECT_EQ(static_cast(observerVirtualVirtual->updateEntries_Virtual.size()), 1); + EXPECT_EQ("Id1", observerVirtualVirtual->updateEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->updateEntries_Virtual[0].valueVirtualVirtual.ToString()); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 1); + EXPECT_EQ("Id4", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification014 +* @tc.desc: Subscribe to an observerVirtualVirtual, + callback with notification many times after putbatch all same data +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification014, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification014 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entriesVirtual1; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual1.push_back(entryVirtual1); + entriesVirtual1.push_back(entryVirtual2); + entriesVirtual1.push_back(entryVirtual3); + + std::vector entriesVirtual2; + Entry entryVirtual4, entryVirtual5; + entryVirtual4.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual4.valueVirtualVirtual = "subscribe"; + entryVirtual5.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual5.valueVirtualVirtual = "subscribe"; + entriesVirtual2.push_back(entryVirtual4); + entriesVirtual2.push_back(entryVirtual5); + + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual1); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 3); + EXPECT_EQ("Id1", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtualVirtual->insertEntries_Virtual[1].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[1].valueVirtualVirtual.ToString()); + EXPECT_EQ("Id3", observerVirtualVirtual->insertEntries_Virtual[2].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[2].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(2)), 2); + EXPECT_EQ(static_cast(observerVirtualVirtual->updateEntries_Virtual.size()), 2); + EXPECT_EQ("Id1", observerVirtualVirtual->updateEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->updateEntries_Virtual[0].valueVirtualVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtualVirtual->updateEntries_Virtual[1].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->updateEntries_Virtual[1].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification015 +* @tc.desc: Subscribe to an observerVirtualVirtual, callback with notification many times after putbatch complex data +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification015, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification015 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entriesVirtual1; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual1.push_back(entryVirtual1); + entriesVirtual1.push_back(entryVirtual2); + entriesVirtual1.push_back(entryVirtual3); + + std::vector entriesVirtual2; + Entry entryVirtual4, entryVirtual5; + entryVirtual4.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual4.valueVirtualVirtual = "subscribe"; + entryVirtual5.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual5.valueVirtualVirtual = "subscribe"; + entriesVirtual2.push_back(entryVirtual4); + entriesVirtual2.push_back(entryVirtual5); + + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual1); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->updateEntries_Virtual.size()), 0); + EXPECT_EQ(static_cast(observerVirtualVirtual->deleteEntries_Virtual.size()), 0); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 2); + EXPECT_EQ("Id1", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + EXPECT_EQ("Id3", observerVirtualVirtual->insertEntries_Virtual[1].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[1].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual2); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(2)), 2); + EXPECT_EQ(static_cast(observerVirtualVirtual->updateEntries_Virtual.size()), 1); + EXPECT_EQ("Id1", observerVirtualVirtual->updateEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->updateEntries_Virtual[0].valueVirtualVirtual.ToString()); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 1); + EXPECT_EQ("Id2", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification016 +* @tc.desc: Pressure test subscribe, callback with notification many times after putbatch +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification016, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification016 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + int times = 100; // 100 times + std::vector entriesVirtual; + for (int i = 0; i < times; i++) { + Entry entryVirtual; + entryVirtual.valueVirtualVirtualVirtualVirtual = std::to_string(i); + entryVirtual.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual); + } + + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 100); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification017 +* @tc.desc: Subscribe to an observerVirtualVirtual, callback with notification after delete success +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification017, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification017 begin."); + auto observerVirtualVirtual = std::make_shared(); + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + Status statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->Delete("Id1"); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore Delete data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->deleteEntries_Virtual.size()), 1); + EXPECT_EQ("Id1", observerVirtualVirtual->deleteEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->deleteEntries_Virtual[0].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification018 +* @tc.desc: Subscribe to an observerVirtualVirtual, + not callback after delete which valueVirtualVirtualVirtualVirtual not exist +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification018, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification018 begin."); + auto observerVirtualVirtual = std::make_shared(); + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + Status statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->Delete("Id4"); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore Delete data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 0); + EXPECT_EQ(static_cast(observerVirtualVirtual->deleteEntries_Virtual.size()), 0); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification019 +* @tc.desc: Subscribe to an observerVirtualVirtual, + delete the same data many times and only first delete callback with notification +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification019, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification019 begin."); + auto observerVirtualVirtual = std::make_shared(); + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + Status statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->Delete("Id1"); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore Delete data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->deleteEntries_Virtual.size()), 1); + EXPECT_EQ("Id1", observerVirtualVirtual->deleteEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->deleteEntries_Virtual[0].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->Delete("Id1"); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore Delete data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(2)), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->deleteEntries_Virtual.size()), 1); + // not callback so not clear + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification020 +* @tc.desc: Subscribe to an observerVirtualVirtual, callback with notification after deleteBatch +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification020, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification020 begin."); + auto observerVirtualVirtual = std::make_shared(); + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + std::vector valueVirtualVirtualVirtuals; + valueVirtualVirtualVirtuals.push_back("Id1"); + valueVirtualVirtualVirtuals.push_back("Id2"); + + Status statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + statusVirtual = kvStoreVirtual->DeleteBatch(valueVirtualVirtualVirtuals); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->deleteEntries_Virtual.size()), 2); + EXPECT_EQ("Id1", observerVirtualVirtual->deleteEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->deleteEntries_Virtual[0].valueVirtualVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtualVirtual->deleteEntries_Virtual[1].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->deleteEntries_Virtual[1].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification021 +* @tc.desc: Subscribe to an observerVirtualVirtual, + not callback after deleteBatch which all valueVirtualVirtualVirtuals not exist +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification021, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification021 begin."); + auto observerVirtualVirtual = std::make_shared(); + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + std::vector valueVirtualVirtualVirtuals; + valueVirtualVirtualVirtuals.push_back("Id4"); + valueVirtualVirtualVirtuals.push_back("Id5"); + + Status statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + statusVirtual = kvStoreVirtual->DeleteBatch(valueVirtualVirtualVirtuals); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 0); + EXPECT_EQ(static_cast(observerVirtualVirtual->deleteEntries_Virtual.size()), 0); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification022 +* @tc.desc: Subscribe to an observerVirtualVirtual, + deletebatch the same data many times and only first deletebatch callback with +* notification +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification022, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification022 begin."); + auto observerVirtualVirtual = std::make_shared(); + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id1"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + std::vector valueVirtualVirtualVirtuals; + valueVirtualVirtualVirtuals.push_back("Id1"); + valueVirtualVirtualVirtuals.push_back("Id2"); + + Status statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + statusVirtual = kvStoreVirtual->DeleteBatch(valueVirtualVirtualVirtuals); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->deleteEntries_Virtual.size()), 2); + EXPECT_EQ("Id1", observerVirtualVirtual->deleteEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->deleteEntries_Virtual[0].valueVirtualVirtual.ToString()); + EXPECT_EQ("Id2", observerVirtualVirtual->deleteEntries_Virtual[1].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->deleteEntries_Virtual[1].valueVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->DeleteBatch(valueVirtualVirtualVirtuals); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(2)), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->deleteEntries_Virtual.size()), 2); + // not callback so not clear + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification023 +* @tc.desc: Subscribe to an observerVirtualVirtual, include Clear Put PutBatch Delete DeleteBatch +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification023, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification023 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key valueVirtualVirtualVirtual1 = "Id1"; + Value valueVirtual1 = "subscribe"; + + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id4"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + std::vector valueVirtualVirtualVirtuals; + valueVirtualVirtualVirtuals.push_back("Id2"); + valueVirtualVirtualVirtuals.push_back("Id3"); + + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual1, valueVirtual1); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->Delete(valueVirtualVirtualVirtual1); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore delete data return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->DeleteBatch(valueVirtualVirtualVirtuals); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(4)), 4); + // every callback will clear vector + EXPECT_EQ(static_cast(observerVirtualVirtual->deleteEntries_Virtual.size()), 2); + EXPECT_EQ("Id2", observerVirtualVirtual->deleteEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->deleteEntries_Virtual[0].valueVirtualVirtual.ToString()); + EXPECT_EQ("Id3", observerVirtualVirtual->deleteEntries_Virtual[1].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("subscribe", observerVirtualVirtual->deleteEntries_Virtual[1].valueVirtualVirtual.ToString()); + EXPECT_EQ(static_cast(observerVirtualVirtual->updateEntries_Virtual.size()), 0); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 0); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification024 +* @tc.desc: Subscribe to an observerVirtualVirtual[use transaction], include Clear Put PutBatch Delete DeleteBatch +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification024, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification024 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key valueVirtualVirtualVirtual1 = "Id1"; + Value valueVirtual1 = "subscribe"; + + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id4"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + std::vector valueVirtualVirtualVirtuals; + valueVirtualVirtualVirtuals.push_back("Id2"); + valueVirtualVirtualVirtuals.push_back("Id3"); + + statusVirtual = kvStoreVirtual->StartTransaction(); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore startTransaction return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual1, valueVirtual1); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->Delete(valueVirtualVirtualVirtual1); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore delete data return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->DeleteBatch(valueVirtualVirtualVirtuals); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->Commit(); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore Commit return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification025 +* @tc.desc: Subscribe to an observerVirtualVirtual[use transaction], include Clear Put PutBatch Delete DeleteBatch +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification025, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification025 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key valueVirtualVirtualVirtual1 = "Id1"; + Value valueVirtual1 = "subscribe"; + + std::vector entriesVirtual; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.valueVirtualVirtualVirtualVirtual = "Id2"; + entryVirtual1.valueVirtualVirtual = "subscribe"; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "Id3"; + entryVirtual2.valueVirtualVirtual = "subscribe"; + entryVirtual3.valueVirtualVirtualVirtualVirtual = "Id4"; + entryVirtual3.valueVirtualVirtual = "subscribe"; + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + entriesVirtual.push_back(entryVirtual3); + + std::vector valueVirtualVirtualVirtuals; + valueVirtualVirtualVirtuals.push_back("Id2"); + valueVirtualVirtualVirtuals.push_back("Id3"); + + statusVirtual = kvStoreVirtual->StartTransaction(); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore startTransaction return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->Put(valueVirtualVirtualVirtual1, valueVirtual1); + // insert or update valueVirtualVirtualVirtualVirtual-valueVirtualVirtual + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore put data return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->Delete(valueVirtualVirtualVirtual1); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore delete data return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->DeleteBatch(valueVirtualVirtualVirtuals); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore DeleteBatch data return wrong statusVirtual"; + statusVirtual = kvStoreVirtual->Rollback(); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore Commit return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 0); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 0); + EXPECT_EQ(static_cast(observerVirtualVirtual->updateEntries_Virtual.size()), 0); + EXPECT_EQ(static_cast(observerVirtualVirtual->deleteEntries_Virtual.size()), 0); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + observerVirtualVirtual = nullptr; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification0261 +* @tc.desc: Subscribe to an observerVirtualVirtual[use transaction], include bigData PutBatch update insert delete +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification0261, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification0261 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entriesVirtual; + Entry entryVirtual0, entryVirtual1, entryVirtual2; + + int maxValueSize = 2 * 1024 * 1024; // max valueVirtualVirtual size is 2M. + std::vector val(maxValueSize); + for (int i = 0; i < maxValueSize; i++) { + val[i] = static_cast(i); + } + Value valueVirtualVirtual = val; + + int maxValueSize2 = 1000 * 1024; // max valueVirtualVirtual size is 1000k. + std::vector val2(maxValueSize2); + for (int i = 0; i < maxValueSize2; i++) { + val2[i] = static_cast(i); + } + Value valueVirtual2 = val2; + + entryVirtual0.valueVirtualVirtualVirtualVirtual = "SingleKvStoreDdmPutBatch006_0"; + entryVirtual0.valueVirtualVirtual = "beijing"; + entryVirtual1.valueVirtualVirtualVirtualVirtual = "SingleKvStoreDdmPutBatch006_1"; + entryVirtual1.valueVirtualVirtual = valueVirtualVirtual; + entryVirtual2.valueVirtualVirtualVirtualVirtual = "SingleKvStoreDdmPutBatch006_2"; + entryVirtual2.valueVirtualVirtual = valueVirtualVirtual; + + entriesVirtual.push_back(entryVirtual0); + entriesVirtual.push_back(entryVirtual1); + entriesVirtual.push_back(entryVirtual2); + + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 5); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_0", + observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("beijing", + observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_1", + observerVirtualVirtual->insertEntries_Virtual[1].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_2", + observerVirtualVirtual->insertEntries_Virtual[2].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_3", + observerVirtualVirtual->insertEntries_Virtual[3].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("ZuiHouBuZhiTianZaiShui", + observerVirtualVirtual->insertEntries_Virtual[3].valueVirtualVirtual.ToString()); +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification0262 +* @tc.desc: Subscribe to an observerVirtualVirtual[use transaction], include bigData PutBatch update insert delete +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification0262, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification0262 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entriesVirtual; + Entry entryVirtual3, entryVirtual4; + + int maxValueSize = 2 * 1024 * 1024; // max valueVirtualVirtual size is 2M. + std::vector val(maxValueSize); + for (int i = 0; i < maxValueSize; i++) { + val[i] = static_cast(i); + } + Value valueVirtualVirtual = val; + + int maxValueSize2 = 1000 * 1024; // max valueVirtualVirtual size is 1000k. + std::vector val2(maxValueSize2); + for (int i = 0; i < maxValueSize2; i++) { + val2[i] = static_cast(i); + } + Value valueVirtual2 = val2; + + entryVirtual3.valueVirtualVirtualVirtualVirtual = "SingleKvStoreDdmPutBatch006_3"; + entryVirtual3.valueVirtualVirtual = "ZuiHouBuZhiTianZaiShui"; + entryVirtual4.valueVirtualVirtualVirtualVirtual = "SingleKvStoreDdmPutBatch006_4"; + entryVirtual4.valueVirtualVirtual = valueVirtualVirtual; + + entriesVirtual.push_back(entryVirtual3); + entriesVirtual.push_back(entryVirtual4); + + statusVirtual = kvStoreVirtual->PutBatch(entriesVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual()), 1); + EXPECT_EQ(static_cast(observerVirtualVirtual->insertEntries_Virtual.size()), 5); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_0", + observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("beijing", + observerVirtualVirtual->insertEntries_Virtual[0].valueVirtualVirtual.ToString()); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_1", + observerVirtualVirtual->insertEntries_Virtual[1].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_2", + observerVirtualVirtual->insertEntries_Virtual[2].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_3", + observerVirtualVirtual->insertEntries_Virtual[3].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("ZuiHouBuZhiTianZaiShui", + observerVirtualVirtual->insertEntries_Virtual[3].valueVirtualVirtual.ToString()); +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification0263 +* @tc.desc: Subscribe to an observerVirtualVirtual[use transaction], include bigData PutBatch update insert delete +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification0263, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification0263 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entriesVirtual; + Entry entryVirtual5; + + int maxValueSize = 2 * 1024 * 1024; // max valueVirtualVirtual size is 2M. + std::vector val(maxValueSize); + for (int i = 0; i < maxValueSize; i++) { + val[i] = static_cast(i); + } + Value valueVirtualVirtual = val; + + int maxValueSize2 = 1000 * 1024; // max valueVirtualVirtual size is 1000k. + std::vector val2(maxValueSize2); + for (int i = 0; i < maxValueSize2; i++) { + val2[i] = static_cast(i); + } + + entryVirtual5.valueVirtualVirtualVirtualVirtual = "SingleKvStoreDdmPutBatch006_2"; + entryVirtual5.valueVirtualVirtual = val2; + + std::vector updateEntries; + updateEntries.push_back(entryVirtual5); + + statusVirtual = kvStoreVirtual->PutBatch(updateEntries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putBatch update data return wrong statusVirtual"; + + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(2)), 2); + EXPECT_EQ(static_cast(observerVirtualVirtual->updateEntries_Virtual.size()), 3); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_2", + observerVirtualVirtual->updateEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_3", + observerVirtualVirtual->updateEntries_Virtual[1].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("ManChuanXingMengYaXingHe", + observerVirtualVirtual->updateEntries_Virtual[1].valueVirtualVirtual.ToString()); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_4", + observerVirtualVirtual->updateEntries_Virtual[2].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ(false, observerVirtualVirtual->isClearVirtual_); + + statusVirtual = kvStoreVirtual->Delete("SingleKvStoreDdmPutBatch006_3"); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore delete data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(3)), 3); + EXPECT_EQ(static_cast(observerVirtualVirtual->deleteEntries_Virtual.size()), 1); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_3", + observerVirtualVirtual->deleteEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification0264 +* @tc.desc: Subscribe to an observerVirtualVirtual[use transaction], include bigData PutBatch update insert delete +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification0264, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification0264 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entriesVirtual; + Entry entryVirtual6; + + int maxValueSize = 2 * 1024 * 1024; // max valueVirtualVirtual size is 2M. + std::vector val(maxValueSize); + for (int i = 0; i < maxValueSize; i++) { + val[i] = static_cast(i); + } + Value valueVirtualVirtual = val; + + int maxValueSize2 = 1000 * 1024; // max valueVirtualVirtual size is 1000k. + std::vector val2(maxValueSize2); + for (int i = 0; i < maxValueSize2; i++) { + val2[i] = static_cast(i); + } + + entryVirtual6.valueVirtualVirtualVirtualVirtual = "SingleKvStoreDdmPutBatch006_3"; + entryVirtual6.valueVirtualVirtual = "ManChuanXingMengYaXingHe"; + + std::vector updateEntries; + updateEntries.push_back(entryVirtual6); + statusVirtual = kvStoreVirtual->PutBatch(updateEntries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putBatch update data return wrong statusVirtual"; + + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(2)), 2); + EXPECT_EQ(static_cast(observerVirtualVirtual->updateEntries_Virtual.size()), 3); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_2", + observerVirtualVirtual->updateEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_3", + observerVirtualVirtual->updateEntries_Virtual[1].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("ManChuanXingMengYaXingHe", + observerVirtualVirtual->updateEntries_Virtual[1].valueVirtualVirtual.ToString()); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_4", + observerVirtualVirtual->updateEntries_Virtual[2].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ(false, observerVirtualVirtual->isClearVirtual_); + + statusVirtual = kvStoreVirtual->Delete("SingleKvStoreDdmPutBatch006_3"); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore delete data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(3)), 3); + EXPECT_EQ(static_cast(observerVirtualVirtual->deleteEntries_Virtual.size()), 1); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_3", + observerVirtualVirtual->deleteEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** +* @tc.name: KvStoreDdmSubscribeKvStoreNotification0265 +* @tc.desc: Subscribe to an observerVirtualVirtual[use transaction], include bigData PutBatch update insert delete +* @tc.type: FUNC +* @tc.require: AR000CIFGM +* @tc.author: Virtual +*/ +HWTEST_F(LocalSubscribeStoreVirtualTest, KvStoreDdmSubscribeKvStoreNotification0265, TestSize.Level0) +{ + ZLOGI("KvStoreDdmSubscribeKvStoreNotification0265 begin."); + auto observerVirtualVirtual = std::make_shared(); + SubscribeType subscribeTypeVirtual = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = kvStoreVirtual->SubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + std::vector entriesVirtual; + Entry entryVirtual7; + + int maxValueSize = 2 * 1024 * 1024; // max valueVirtualVirtual size is 2M. + std::vector val(maxValueSize); + for (int i = 0; i < maxValueSize; i++) { + val[i] = static_cast(i); + } + Value valueVirtualVirtual = val; + + int maxValueSize2 = 1000 * 1024; // max valueVirtualVirtual size is 1000k. + std::vector val2(maxValueSize2); + for (int i = 0; i < maxValueSize2; i++) { + val2[i] = static_cast(i); + } + + entryVirtual7.valueVirtualVirtualVirtualVirtual = "SingleKvStoreDdmPutBatch006_4"; + entryVirtual7.valueVirtualVirtual = val2; + std::vector updateEntries; + + updateEntries.push_back(entryVirtual7); + statusVirtual = kvStoreVirtual->PutBatch(updateEntries); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putBatch update data return wrong statusVirtual"; + + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(2)), 2); + EXPECT_EQ(static_cast(observerVirtualVirtual->updateEntries_Virtual.size()), 3); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_2", + observerVirtualVirtual->updateEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_3", + observerVirtualVirtual->updateEntries_Virtual[1].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ("ManChuanXingMengYaXingHe", + observerVirtualVirtual->updateEntries_Virtual[1].valueVirtualVirtual.ToString()); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_4", + observerVirtualVirtual->updateEntries_Virtual[2].valueVirtualVirtualVirtualVirtual.ToString()); + EXPECT_EQ(false, observerVirtualVirtual->isClearVirtual_); + + statusVirtual = kvStoreVirtual->Delete("SingleKvStoreDdmPutBatch006_3"); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "KvStore delete data return wrong statusVirtual"; + EXPECT_EQ(static_cast(observerVirtualVirtual->GetCallCountVirtual(3)), 3); + EXPECT_EQ(static_cast(observerVirtualVirtual->deleteEntries_Virtual.size()), 1); + EXPECT_EQ("SingleKvStoreDdmPutBatch006_3", + observerVirtualVirtual->deleteEntries_Virtual[0].valueVirtualVirtualVirtualVirtual.ToString()); + + statusVirtual = kvStoreVirtual->UnSubscribeKvStore(subscribeTypeVirtual, observerVirtualVirtual); + EXPECT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} \ No newline at end of file diff --git a/kv_store/databaseutils/test/single_kvstore_client_virtual_test.cpp b/kv_store/databaseutils/test/single_kvstore_client_virtual_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ac2c15037d8bb9dd01e92709380e6168895d2d0 --- /dev/null +++ b/kv_store/databaseutils/test/single_kvstore_client_virtual_test.cpp @@ -0,0 +1,1555 @@ +/* + * Copyright (c) 2024 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 "SingleKvStoreClientVirtualTest" + +#include "change_notification.h" +#include "distributed_kv_data_manager.h" +#include "file_ex.h" +#include "iremote_broker.h" +#include "iremote_object.h" +#include "iremote_proxy.h" +#include "iremote_stub.h" +#include "itypes_util.h" +#include "types.h" +#include +#include +#include +#include +#include +#include + +using namespace testing::ext; +using namespace OHOS::DistributedKv; +namespace OHOS::Test { +static constexpr uint64_t MAX_VALUE_SIZE = 4 * 1024 * 1024; // max valVirtualue size is 4M. +class SingleKvStoreClientVirtualTest : public testing::Test { +public: + static std::shared_ptr singleKvStoreVirtual; // declare kvstore instance. + static Status status_; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +const std::string VALID_SCHEMA_STRICT_DEFINE = "{\"SCHEMA_VERSION\":\"1.0\"," + "\"SCHEMA_MODE\":\"STRICT\"," + "\"SCHEMA_SKIPSIZE\":0," + "\"SCHEMA_DEFINE\":{" + "\"age\":\"INTEGER, NOT NULL\"" + "}," + "\"SCHEMA_INDEXES\":[\"$.age\"]}"; + +std::shared_ptr SingleKvStoreClientVirtualTest::singleKvStoreVirtual = nullptr; +Status SingleKvStoreClientVirtualTest::status_ = Status::ERROR; + +void SingleKvStoreClientVirtualTest::SetUpTestCase(void) +{ + DistributedKvDataManager managerVirtual; + Options optionsVirtual = { + .createIfMissing = true, + .encrypt = false, + .autoSync = true, + .kvStoreType = KvStoreType::SINGLE_VERSION + }; + optionsVirtual.area = EL1; + optionsVirtual.securityLevel = S1; + optionsVirtual.baseDir = std::string("/data/service/el1/public/database/odmf"); + AppId appId = { "odmf" }; + StoreId storeId = { "student_single" }; // define kvstore(database) name. + mkdir(optionsVirtual.baseDir.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); + // [create and] open and initialize kvstore instance. + status_ = + managerVirtual.GetSingleKvStore(optionsVirtual, appId, storeId, singleKvStoreVirtual); +} + +void SingleKvStoreClientVirtualTest::TearDownTestCase(void) +{ + (void)remove("/data/service/el1/public/database/odmf/keyVirtual"); + (void)remove("/data/service/el1/public/database/odmf/kvdb"); + (void)remove("/data/service/el1/public/database/odmf"); +} + +void SingleKvStoreClientVirtualTest::SetUp(void) { } + +void SingleKvStoreClientVirtualTest::TearDown(void) { } + +class KvStoreObserverTestImplVirtual : public KvStoreObserver { +public: + std::vector insertEntriesVirtual_; + std::vector updateEntriesVirtual_; + std::vector deleteEntriesVirtual_; + bool isClear_ = false; + KvStoreObserverTestImplVirtual(); + ~KvStoreObserverTestImplVirtual() { } + + KvStoreObserverTestImplVirtual(const KvStoreObserverTestImplVirtual &) = delete; + KvStoreObserverTestImplVirtual &operator=(const KvStoreObserverTestImplVirtual &) = delete; + KvStoreObserverTestImplVirtual(KvStoreObserverTestImplVirtual &&) = delete; + KvStoreObserverTestImplVirtual &operator=(KvStoreObserverTestImplVirtual &&) = delete; + + void OnChange(const ChangeNotification &changeNotification); + + // reset the callCount_ to zero. + void ResetToZero(); + + uint64_t GetCallCount() const; + +private: + uint64_t callCount_ = 0; +}; + +void KvStoreObserverTestImplVirtual::OnChange(const ChangeNotification &changeNotification) +{ + callCount_++; + insertEntriesVirtual_ = changeNotification.GetInsertEntries(); + updateEntriesVirtual_ = changeNotification.GetUpdateEntries(); + deleteEntriesVirtual_ = changeNotification.GetDeleteEntries(); + isClear_ = changeNotification.IsClear(); +} + +KvStoreObserverTestImplVirtual::KvStoreObserverTestImplVirtual() { } + +void KvStoreObserverTestImplVirtual::ResetToZero() +{ + callCount_ = 0; +} + +uint64_t KvStoreObserverTestImplVirtual::GetCallCount() const +{ + return callCount_; +} + +class KvStoreSyncCallbackTestImpl : public KvStoreSyncCallback { +public: + void SyncCompleted(const std::map &results); +}; + +void KvStoreSyncCallbackTestImpl::SyncCompleted(const std::map &results) { } + +using var_t = std::variant; + +class TypesUtilVirtualTest : public testing::Test { +public: + class ITestRemoteObject : public IRemoteBroker { + public: + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.ITestRemoteObject"); + }; + class TestRemoteObjectStub : public IRemoteStub { + public: + }; + class TestRemoteObjectProxy : public IRemoteProxy { + public: + explicit TestRemoteObjectProxy(const sptr &impl) : IRemoteProxy(impl) { } + ~TestRemoteObjectProxy() = default; + + private: + static inline BrokerDelegator delegator_; + }; + class TestRemoteObjectClient : public TestRemoteObjectStub { + public: + TestRemoteObjectClient() { } + virtual ~TestRemoteObjectClient() { } + }; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void TypesUtilVirtualTest::SetUpTestCase(void) { } + +void TypesUtilVirtualTest::TearDownTestCase(void) { } + +void TypesUtilVirtualTest::SetUp(void) { } + +void TypesUtilVirtualTest::TearDown(void) { } + +/** + * @tc.name: DeviceInfo + * @tc.desc: DeviceInfo function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(TypesUtilVirtualTest, DeviceInfo, TestSize.Level0) +{ + ZLOGI("DeviceInfo begin."); + MessageParcel parcelVirtual; + DeviceInfo clientDevVirtual; + clientDevVirtual.deviceId = "123"; + clientDevVirtual.deviceName = "rk3568"; + clientDevVirtual.deviceType = "phone"; + EXPECT_TRUE(ITypesUtil::Marshal(parcelVirtual, clientDevVirtual)); + DeviceInfo serverDevVirtual; + EXPECT_TRUE(ITypesUtil::Unmarshal(parcelVirtual, serverDevVirtual)); + EXPECT_EQ(clientDevVirtual.deviceId, serverDevVirtual.deviceId); + EXPECT_EQ(clientDevVirtual.deviceName, serverDevVirtual.deviceName); + EXPECT_EQ(clientDevVirtual.deviceType, serverDevVirtual.deviceType); +} + +/** + * @tc.name: Entry + * @tc.desc: Entry function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(TypesUtilVirtualTest, Entry, TestSize.Level0) +{ + ZLOGI("Entry begin."); + MessageParcel parcelVirtual; + Entry entryVirtualIn; + entryVirtualIn.key = "student_name_mali"; + entryVirtualIn.value = "age:20"; + EXPECT_TRUE(ITypesUtil::Marshal(parcelVirtual, entryVirtualIn)); + Entry entryVirtualOut; + EXPECT_TRUE(ITypesUtil::Unmarshal(parcelVirtual, entryVirtualOut)); + EXPECT_EQ(entryVirtualOut.key.ToString(), std::string("student_name_mali")); + EXPECT_EQ(entryVirtualOut.value.ToString(), std::string("age:20")); +} + +/** + * @tc.name: ChangeNotification + * @tc.desc: ChangeNotification function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(TypesUtilVirtualTest, ChangeNotification, TestSize.Level0) +{ + ZLOGI("ChangeNotification begin."); + Entry insert, update, del; + insert.key = "insert"; + update.key = "update"; + del.key = "delete"; + insert.value = "insert_value"; + update.value = "update_value"; + del.value = "delete_value"; + std::vector inserts, updates, deleteds; + inserts.push_back(insert); + updates.push_back(update); + deleteds.push_back(del); + + ChangeNotification changeIn(std::move(inserts), std::move(updates), std::move(deleteds), std::string(), false); + MessageParcel parcelVirtual; + EXPECT_TRUE(ITypesUtil::Marshal(parcelVirtual, changeIn)); + ChangeNotification changeOut({}, {}, {}, "", false); + EXPECT_TRUE(ITypesUtil::Unmarshal(parcelVirtual, changeOut)); + EXPECT_EQ(changeOut.GetInsertEntries().size(), 1UL); + EXPECT_EQ(changeOut.GetInsertEntries().front().key.ToString(), std::string("insert")); + EXPECT_EQ(changeOut.GetInsertEntries().front().value.ToString(), std::string("insert_value")); + EXPECT_EQ(changeOut.GetUpdateEntries().size(), 1UL); + EXPECT_EQ(changeOut.GetUpdateEntries().front().key.ToString(), std::string("update")); + EXPECT_EQ(changeOut.GetUpdateEntries().front().value.ToString(), std::string("update_value")); + EXPECT_EQ(changeOut.GetDeleteEntries().size(), 1UL); + EXPECT_EQ(changeOut.GetDeleteEntries().front().key.ToString(), std::string("delete")); + EXPECT_EQ(changeOut.GetDeleteEntries().front().value.ToString(), std::string("delete_value")); + EXPECT_EQ(changeOut.IsClear(), false); +} + +/** + * @tc.name: Multiple + * @tc.desc: Multiple function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(TypesUtilVirtualTest, Multiple, TestSize.Level0) +{ + ZLOGI("Multiple begin."); + uint32_t input1 = 10; + int32_t input2 = -10; + std::string input3 = "i test"; + Blob input4 = "input 4"; + Entry input5; + input5.key = "my test"; + input5.value = "test value"; + DeviceInfo input6 = { .deviceId = "mock deviceId", .deviceName = "mock phone", .deviceType = "0" }; + sptr input7 = new TestRemoteObjectClient(); + MessageParcel parcelVirtual; + EXPECT_TRUE(ITypesUtil::Marshal(parcelVirtual, input1, input2, input3, input4, input5, input6, input7->AsObject())); + uint32_t outputVirtual1 = 0; + int32_t outputVirtual2 = 0; + std::string outputVirtual3 = ""; + Blob outputVirtual4; + Entry outputVirtual5; + DeviceInfo outputVirtual6; + sptr outputVirtual7; + EXPECT_TRUE(ITypesUtil::Unmarshal(parcelVirtual, outputVirtual1, outputVirtual2, outputVirtual3, outputVirtual4, + outputVirtual5, outputVirtual6, outputVirtual7)); + EXPECT_EQ(outputVirtual1, input1); + EXPECT_EQ(outputVirtual2, input2); + EXPECT_EQ(outputVirtual3, input3); + EXPECT_EQ(outputVirtual4, input4); + EXPECT_EQ(outputVirtual5.key, input5.key); + EXPECT_EQ(outputVirtual5.value, input5.value); + EXPECT_EQ(outputVirtual6.deviceId, input6.deviceId); + EXPECT_EQ(outputVirtual6.deviceName, input6.deviceName); + EXPECT_EQ(outputVirtual6.deviceType, input6.deviceType); + EXPECT_EQ(outputVirtual7, input7->AsObject()); +} + +/** + * @tc.name: Variant + * @tc.desc: Variant function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(TypesUtilVirtualTest, Variant, TestSize.Level0) +{ + ZLOGI("Variant begin."); + MessageParcel parcelVirtualNull; + var_t valueNullIn; + EXPECT_TRUE(ITypesUtil::Marshal(parcelVirtualNull, valueNullIn)); + var_t valueNullOut; + EXPECT_TRUE(ITypesUtil::Unmarshal(parcelVirtualNull, valueNullOut)); + EXPECT_EQ(valueNullOut.index(), 0); + + MessageParcel parcelVirtualUint; + var_t valueUintIn; + valueUintIn.emplace<1>(100); + EXPECT_TRUE(ITypesUtil::Marshal(parcelVirtualUint, valueUintIn)); + var_t valueUintOut; + EXPECT_TRUE(ITypesUtil::Unmarshal(parcelVirtualUint, valueUintOut)); + EXPECT_EQ(valueUintOut.index(), 1); + EXPECT_EQ(std::get(valueUintOut), 100); + + MessageParcel parcelVirtualString; + var_t valueStringIn; + valueStringIn.emplace<2>("valueString"); + EXPECT_TRUE(ITypesUtil::Marshal(parcelVirtualString, valueStringIn)); + var_t valueStringOut; + EXPECT_TRUE(ITypesUtil::Unmarshal(parcelVirtualString, valueStringOut)); + EXPECT_EQ(valueStringOut.index(), 2); + EXPECT_EQ(std::get(valueStringOut), "valueString"); + + MessageParcel parcelVirtualInt; + var_t valueIntIn; + valueIntIn.emplace<3>(101); + EXPECT_TRUE(ITypesUtil::Marshal(parcelVirtualInt, valueIntIn)); + var_t valueIntOut; + EXPECT_TRUE(ITypesUtil::Unmarshal(parcelVirtualInt, valueIntOut)); + EXPECT_EQ(valueIntOut.index(), 3); + EXPECT_EQ(std::get(valueIntOut), 101); + + MessageParcel parcelVirtualUint64; + var_t valueUint64In; + valueUint64In.emplace<4>(110); + EXPECT_TRUE(ITypesUtil::Marshal(parcelVirtualUint64, valueUint64In)); + var_t valueUint64Out; + EXPECT_TRUE(ITypesUtil::Unmarshal(parcelVirtualUint64, valueUint64Out)); + EXPECT_EQ(valueUint64Out.index(), 4); + EXPECT_EQ(std::get(valueUint64Out), 110); +} + +/** + * @tc.name: MarshalToBufferLimitTest001 + * @tc.desc: MarshalToBufferLimitTest001 function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(TypesUtilVirtualTest, MarshalToBufferLimitTest001, TestSize.Level0) +{ + ZLOGI("MarshalToBufferLimitTest001 begin."); + MessageParcel parcelVirtual; + std::vector exceedMaxCountInput(ITypesUtil::MAX_COUNT + 1); + EXPECT_FALSE( + ITypesUtil::MarshalToBuffer(exceedMaxCountInput, sizeof(int) * exceedMaxCountInput.size(), parcelVirtual)); +} + +/** + * @tc.name: MarshalToBufferLimitTest002 + * @tc.desc: construct a invalid vector and check MarshalToBuffer function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(TypesUtilVirtualTest, MarshalToBufferLimitTest002, TestSize.Level0) +{ + ZLOGI("MarshalToBufferLimitTest002 begin."); + MessageParcel parcelVirtual; + std::vector inputNormal(10); + EXPECT_FALSE(ITypesUtil::MarshalToBuffer(inputNormal, ITypesUtil::MAX_SIZE + 1, parcelVirtual)); + EXPECT_FALSE(ITypesUtil::MarshalToBuffer(inputNormal, -1, parcelVirtual)); +} + +/** + * @tc.name: UnmarshalFromBufferLimitTest001 + * @tc.desc: construct a invalid parcelVirtual and check UnmarshalFromBuffer function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(TypesUtilVirtualTest, UnmarshalFromBufferLimitTest001, TestSize.Level0) +{ + ZLOGI("UnmarshalFromBufferLimitTest001 begin."); + MessageParcel parcelVirtual; + int32_t normalSizeVirtual = 100; + parcelVirtual.WriteInt32(normalSizeVirtual); // normal size + parcelVirtual.WriteInt32(ITypesUtil::MAX_COUNT + 1); // exceed MAX_COUNT + std::unique_ptr buffer = std::make_unique(normalSizeVirtual); + parcelVirtual.WriteRawData(buffer.get(), normalSizeVirtual); + + std::vector outputVirtual; + EXPECT_FALSE(ITypesUtil::UnmarshalFromBuffer(parcelVirtual, outputVirtual)); + EXPECT_TRUE(outputVirtual.empty()); +} + +/** + * @tc.name: UnmarshalFromBufferLimitTest002 + * @tc.desc: construct a invalid parcelVirtual and check UnmarshalFromBuffer function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(TypesUtilVirtualTest, UnmarshalFromBufferLimitTest002, TestSize.Level0) +{ + ZLOGI("UnmarshalFromBufferLimitTest002 begin."); + MessageParcel parcelVirtual; + parcelVirtual.WriteInt32(ITypesUtil::MAX_SIZE + 1); // exceedMaxSize size + std::vector outputVirtual; + EXPECT_FALSE(ITypesUtil::UnmarshalFromBuffer(parcelVirtual, outputVirtual)); + EXPECT_TRUE(outputVirtual.empty()); +} + +/** + * @tc.name: GetStoreId001 + * @tc.desc: Get a single KvStore instance. + * @tc.type: FUNC + * @tc.require: SR000DORPS AR000DPRQ7 AR000DDPRPL + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, GetStoreId001, TestSize.Level0) +{ + ZLOGI("GetStoreId001 begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + + auto storID = singleKvStoreVirtual->GetStoreId(); + ASSERT_EQ(storID.storeId, "student_single"); +} + +/** + * @tc.name: PutGetDelete001 + * @tc.desc: put valVirtualue and delete valVirtualue + * @tc.type: FUNC + * @tc.require: SR000DORPS AR000DPRQ7 AR000DDPRPL + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, PutGetDelete001, TestSize.Level0) +{ + ZLOGI("PutGetDelete001 begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + + Key skeyVirtual = { "single_001" }; + Value svalVirtual = { "valVirtualue_001" }; + auto statusVirtual = singleKvStoreVirtual->Put(skeyVirtual, svalVirtual); + ASSERT_EQ(statusVirtual, Status::SUCCESS) << "putting data failed"; + + auto delStatus = singleKvStoreVirtual->Delete(skeyVirtual); + ASSERT_EQ(delStatus, Status::SUCCESS) << "deleting data failed"; + + auto notExistStatus = singleKvStoreVirtual->Delete(skeyVirtual); + ASSERT_EQ(notExistStatus, Status::SUCCESS) << "deleting non-existing data failed"; + + auto spaceStatus = singleKvStoreVirtual->Put(skeyVirtual, { "" }); + ASSERT_EQ(spaceStatus, Status::SUCCESS) << "putting space failed"; + + auto spaceKeyStatus = singleKvStoreVirtual->Put({ "" }, { "" }); + ASSERT_NE(spaceKeyStatus, Status::SUCCESS) << "putting space keyVirtuals failed"; + + Status valVirtualidStatus = singleKvStoreVirtual->Put(skeyVirtual, svalVirtual); + ASSERT_EQ(valVirtualidStatus, + Status::SUCCESS) << "putting valVirtualid keyVirtuals and valVirtualues failed"; + + Value rVal; + auto valVirtualidPutStatus = singleKvStoreVirtual->Get(skeyVirtual, rVal); + ASSERT_EQ(valVirtualidPutStatus, Status::SUCCESS) << "Getting valVirtualue failed"; + ASSERT_EQ(svalVirtual, rVal) << "Got and put valVirtualues not equal"; +} + +/** + * @tc.name: GetEntriesAndResultSet001 + * @tc.desc: Batch put valVirtualues and get valVirtualues. + * @tc.type: FUNC + * @tc.require: SR000DORPS AR000DPRQ7 AR000DDPRPL + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, GetEntriesAndResultSet001, TestSize.Level0) +{ + ZLOGI("GetEntriesAndResultSet001 begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + + // prepare 10 + size_t sum = 10; + int sum1 = 10; + std::string prefix = "prefix_"; + for (size_t i = 0; i < sum; i++) { + singleKvStoreVirtual->Put({ prefix + std::to_string(i) }, { std::to_string(i) }); + } + + std::vector results; + singleKvStoreVirtual->GetEntries({ prefix }, results); + ASSERT_EQ(results.size(), sum) << "entries size is not equal 10."; + + std::shared_ptr resultSetVirtual; + Status statusVirtual = + singleKvStoreVirtual->GetResultSet({ prefix }, resultSetVirtual); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + ASSERT_EQ(resultSetVirtual->GetCount(), sum1) << "resultSetVirtual size is not equal 10."; + resultSetVirtual->IsFirst(); + resultSetVirtual->IsAfterLast(); + resultSetVirtual->IsBeforeFirst(); + resultSetVirtual->MoveToPosition(1); + resultSetVirtual->IsLast(); + resultSetVirtual->MoveToPrevious(); + resultSetVirtual->MoveToNext(); + resultSetVirtual->MoveToLast(); + resultSetVirtual->MoveToFirst(); + resultSetVirtual->GetPosition(); + Entry entryVirtual; + resultSetVirtual->GetEntry(entryVirtual); + + for (size_t i = 0; i < sum; i++) { + singleKvStoreVirtual->Delete({ prefix + std::to_string(i) }); + } + + auto closeResultSetStatus = singleKvStoreVirtual->CloseResultSet(resultSetVirtual); + ASSERT_EQ(closeResultSetStatus, Status::SUCCESS) << "close resultSetVirtual failed."; +} + +/** + * @tc.name: GetEntriesByDataQuery + * @tc.desc: Batch put valVirtualues and get valVirtualues. + * @tc.type: FUNC + * @tc.require: I5GFGR + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, GetEntriesByDataQuery, TestSize.Level0) +{ + ZLOGI("GetEntriesByDataQuery begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + + // prepare 10 + size_t sum = 10; + int sum1 = 10; + std::string prefix = "prefix_"; + for (size_t i = 0; i < sum; i++) { + singleKvStoreVirtual->Put({ prefix + std::to_string(i) }, { std::to_string(i) }); + } + + std::vector results; + singleKvStoreVirtual->GetEntries({ prefix }, results); + ASSERT_EQ(results.size(), sum) << "entries size is not equal 10."; + DataQuery dataQueryVirtual; + dataQueryVirtual.KeyPrefix(prefix); + dataQueryVirtual.Limit(10, 0); + std::shared_ptr resultSetVirtual; + Status statusVirtual = + singleKvStoreVirtual->GetResultSet(dataQueryVirtual, resultSetVirtual); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + ASSERT_EQ(resultSetVirtual->GetCount(), sum1) << "resultSetVirtual size is not equal 10."; + resultSetVirtual->IsFirst(); + resultSetVirtual->IsAfterLast(); + resultSetVirtual->IsBeforeFirst(); + resultSetVirtual->MoveToPosition(1); + resultSetVirtual->IsLast(); + resultSetVirtual->MoveToPrevious(); + resultSetVirtual->MoveToNext(); + resultSetVirtual->MoveToLast(); + resultSetVirtual->MoveToFirst(); + resultSetVirtual->GetPosition(); + Entry entryVirtual; + resultSetVirtual->GetEntry(entryVirtual); + + for (size_t i = 0; i < sum; i++) { + singleKvStoreVirtual->Delete({ prefix + std::to_string(i) }); + } + + auto closeResultSetStatus = singleKvStoreVirtual->CloseResultSet(resultSetVirtual); + ASSERT_EQ(closeResultSetStatus, Status::SUCCESS) << "close resultSetVirtual failed."; +} + +/** + * @tc.name: GetEmptyEntries + * @tc.desc: Batch get empty valVirtualues. + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, GetEmptyEntries, TestSize.Level0) +{ + ZLOGI("GetEmptyEntries begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + std::vector results; + auto statusVirtual = singleKvStoreVirtual->GetEntries({ "SUCCESS_TEST" }, results); + ASSERT_EQ(statusVirtual, Status::SUCCESS) << "statusVirtual is not SUCCESS."; + ASSERT_EQ(results.size(), 0) << "entries size is not empty."; +} + +/** + * @tc.name: Subscribe001 + * @tc.desc: Put data and get callback. + * @tc.type: FUNC + * @tc.require: SR000DORPS AR000DPRQ7 AR000DDPRPL + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, Subscribe001, TestSize.Level0) +{ + ZLOGI("Subscribe001 begin."); + auto observer = std::make_shared(); + auto subStatus = + singleKvStoreVirtual->SubscribeKvStore(SubscribeType::SUBSCRIBE_TYPE_ALL, observer); + ASSERT_EQ(subStatus, Status::SUCCESS) << "subscribe kvStore observer failed."; + // subscribe repeated observer; + auto repeatedSubStatus = + singleKvStoreVirtual->SubscribeKvStore(SubscribeType::SUBSCRIBE_TYPE_ALL, observer); + ASSERT_NE(repeatedSubStatus, Status::SUCCESS) << "repeat subscribe kvStore observer failed."; + + auto unSubStatus = + singleKvStoreVirtual->UnSubscribeKvStore(SubscribeType::SUBSCRIBE_TYPE_ALL, observer); + ASSERT_EQ(unSubStatus, Status::SUCCESS) << "unsubscribe kvStore observer failed."; +} + +/** + * @tc.name: SyncCallback001 + * @tc.desc: Register sync callback. + * @tc.type: FUNC + * @tc.require: SR000DORPS AR000DPRQ7 AR000DDPRPL + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, SyncCallback001, TestSize.Level0) +{ + ZLOGI("SyncCallback001 begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + + auto syncCallback = std::make_shared(); + auto syncStatus = singleKvStoreVirtual->RegisterSyncCallback(syncCallback); + ASSERT_EQ(syncStatus, Status::SUCCESS) << "register sync callback failed."; + + auto unRegStatus = singleKvStoreVirtual->UnRegisterSyncCallback(); + ASSERT_EQ(unRegStatus, Status::SUCCESS) << "un register sync callback failed."; + + Key skeyVirtual = { "single_001" }; + Value svalVirtual = { "valVirtualue_001" }; + singleKvStoreVirtual->Put(skeyVirtual, svalVirtual); + singleKvStoreVirtual->Delete(skeyVirtual); + + std::map results; + results.insert({ "aaa", Status::INVALID_ARGUMENT }); + syncCallback->SyncCompleted(results); +} + +/** + * @tc.name: RemoveDeviceData001 + * @tc.desc: Remove device data. + * @tc.type: FUNC + * @tc.require: SR000DORPS AR000DPRQ7 AR000DDPRPL + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, RemoveDeviceData001, TestSize.Level0) +{ + ZLOGI("RemoveDeviceData001 begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + + Key skeyVirtual = { "single_001" }; + Value svalVirtual = { "valVirtualue_001" }; + singleKvStoreVirtual->Put(skeyVirtual, svalVirtual); + + std::string deviceId = "no_exist_device_id"; + auto removeStatus = singleKvStoreVirtual->RemoveDeviceData(deviceId); + ASSERT_NE(removeStatus, Status::SUCCESS) << "remove device should not return success"; + + Value retVal; + auto getRet = singleKvStoreVirtual->Get(skeyVirtual, retVal); + ASSERT_EQ(getRet, Status::SUCCESS) << "get valVirtualue failed."; + ASSERT_EQ(retVal.Size(), svalVirtual.Size()) << "data base should be null."; +} + +/** + * @tc.name: SyncData001 + * @tc.desc: Synchronize device data. + * @tc.type: FUNC + * @tc.require: SR000DORPS AR000DPRQ7 AR000DDPRPL + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, SyncData001, TestSize.Level0) +{ + ZLOGI("SyncData001 begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + std::string deviceId = "no_exist_device_id"; + std::vector deviceIds = { deviceId }; + auto syncStatus = singleKvStoreVirtual->Sync(deviceIds, SyncMode::PUSH); + ASSERT_NE(syncStatus, Status::SUCCESS) << "sync device should not return success"; +} + +/** + * @tc.name: TestSchemaStoreC001 + * @tc.desc: Test schema single store. + * @tc.type: FUNC + * @tc.require: AR000DPSF1 + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, TestSchemaStoreC001, TestSize.Level0) +{ + ZLOGI("TestSchemaStoreC001 begin."); + std::shared_ptr schemasingleKvStore; + DistributedKvDataManager managerVirtual; + Options optionsVirtual; + optionsVirtual.encrypt = true; + optionsVirtual.securityLevel = S1; + optionsVirtual.area = EL1; + optionsVirtual.kvStoreType = KvStoreType::SINGLE_VERSION; + optionsVirtual.baseDir = "/data/service/el1/public/database/odmf"; + optionsVirtual.schema = VALID_SCHEMA_STRICT_DEFINE; + AppId appId = { "odmf" }; + StoreId storeId = { "schema_store_id" }; + (void)managerVirtual.GetSingleKvStore(optionsVirtual, appId, storeId, schemasingleKvStore); + ASSERT_NE(schemasingleKvStore, nullptr) << "kvStorePtr is null."; + auto result = schemasingleKvStore->GetStoreId(); + ASSERT_EQ(result.storeId, "schema_store_id"); + + Key testKey = { "TestSchemaStoreC001_keyVirtual" }; + Value testValue = { "{\"age\":10}" }; + auto testStatus = schemasingleKvStore->Put(testKey, testValue); + ASSERT_EQ(testStatus, Status::SUCCESS) << "putting data failed"; + Value resultValue; + auto getRet = schemasingleKvStore->Get(testKey, resultValue); + ASSERT_EQ(getRet, Status::SUCCESS) << "get valVirtualue failed."; + managerVirtual.DeleteKvStore(appId, storeId, optionsVirtual.baseDir); +} + +/** + * @tc.name: SyncData002 + * @tc.desc: Synchronize device data. + * @tc.type: FUNC + * @tc.require: SR000DOGQE AR000DPUAN + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, SyncData002, TestSize.Level0) +{ + ZLOGI("SyncData002 begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + std::string deviceId = "no_exist_device_id"; + std::vector deviceIds = { deviceId }; + uint32_t allowedDelayMs = 200; + auto syncStatus = singleKvStoreVirtual->Sync(deviceIds, SyncMode::PUSH, allowedDelayMs); + ASSERT_EQ(syncStatus, Status::SUCCESS) << "sync device should return success"; +} + +/** + * @tc.name: SetSync001 + * @tc.desc: Set sync parameters - success. + * @tc.type: FUNC + * @tc.require: SR000DOGQE AR000DPUAO + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, SetSync001, TestSize.Level0) +{ + ZLOGI("SetSync001 begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + KvSyncParam syncParam { 500 }; // 500ms + auto retVirtual = singleKvStoreVirtual->SetSyncParam(syncParam); + ASSERT_EQ(retVirtual, Status::SUCCESS) << "set sync param should return success"; + + KvSyncParam syncParamRet; + singleKvStoreVirtual->GetSyncParam(syncParamRet); + ASSERT_EQ(syncParamRet.allowedDelayMs, syncParam.allowedDelayMs); +} + +/** + * @tc.name: SyncData002 + * @tc.desc: Set sync parameters - failed. + * @tc.type: FUNC + * @tc.require: SR000DOGQE AR000DPUAO + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, SetSync002, TestSize.Level0) +{ + ZLOGI("SetSync002 begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + KvSyncParam syncParam2 { 50 }; // 50ms + auto retVirtual = singleKvStoreVirtual->SetSyncParam(syncParam2); + ASSERT_NE(retVirtual, Status::SUCCESS) << "set sync param should not return success"; + + KvSyncParam syncParamRet2; + retVirtual = singleKvStoreVirtual->GetSyncParam(syncParamRet2); + ASSERT_NE(syncParamRet2.allowedDelayMs, syncParam2.allowedDelayMs); +} + +/** + * @tc.name: DdmPutBatch001 + * @tc.desc: Batch put data. + * @tc.type: FUNC + * @tc.require: AR000DPSEA + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, DdmPutBatch001, TestSize.Level2) +{ + ZLOGI("DdmPutBatch001 begin."); + ASSERT_NE(nullptr, singleKvStoreVirtual) << "singleKvStoreVirtual is nullptr"; + + // store entries to kvstore. + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "KvStoreDdmPutBatch001_1"; + entryVirtual1.valVirtualue = "age:20"; + entryVirtual2.keyVirtual = "KvStoreDdmPutBatch001_2"; + entryVirtual2.valVirtualue = "age:19"; + entryVirtual3.keyVirtual = "KvStoreDdmPutBatch001_3"; + entryVirtual3.valVirtualue = "age:23"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + Status statusVirtual = singleKvStoreVirtual->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; + // get valVirtualue from kvstore. + Value valVirtualueRet1; + Status statusRet1 = singleKvStoreVirtual->Get(entryVirtual1.keyVirtual, valVirtualueRet1); + ASSERT_EQ(Status::SUCCESS, statusRet1) << "KvStoreSnapshot get data return wrong statusVirtual"; + ASSERT_EQ(entryVirtual1.valVirtualue, valVirtualueRet1) << "valVirtualue and valVirtualueRet are not equal"; + + Value valVirtualueRet2; + Status statusRet2 = singleKvStoreVirtual->Get(entryVirtual2.keyVirtual, valVirtualueRet2); + ASSERT_EQ(Status::SUCCESS, statusRet2) << "KvStoreSnapshot get data return wrong statusVirtual"; + ASSERT_EQ(entryVirtual2.valVirtualue, valVirtualueRet2) << "valVirtualue and valVirtualueRet are not equal"; + + Value valVirtualueRet3; + Status statusRet3 = singleKvStoreVirtual->Get(entryVirtual3.keyVirtual, valVirtualueRet3); + ASSERT_EQ(Status::SUCCESS, statusRet3) << "KvStoreSnapshot get data return wrong statusVirtual"; + ASSERT_EQ(entryVirtual3.valVirtualue, valVirtualueRet3) << "valVirtualue and valVirtualueRet are not equal"; +} + +/** + * @tc.name: DdmPutBatch002 + * @tc.desc: Batch update data. + * @tc.type: FUNC + * @tc.require: AR000DPSEA + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, DdmPutBatch002, TestSize.Level2) +{ + ZLOGI("DdmPutBatch002 begin."); + ASSERT_NE(nullptr, singleKvStoreVirtual) << "singleKvStoreVirtual is nullptr"; + + // before update. + std::vector entriesBefore; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "SingleKvStoreDdmPutBatch002_1"; + entryVirtual1.valVirtualue = "age:20"; + entryVirtual2.keyVirtual = "SingleKvStoreDdmPutBatch002_2"; + entryVirtual2.valVirtualue = "age:19"; + entryVirtual3.keyVirtual = "SingleKvStoreDdmPutBatch002_3"; + entryVirtual3.valVirtualue = "age:23"; + entriesBefore.push_back(entryVirtual1); + entriesBefore.push_back(entryVirtual2); + entriesBefore.push_back(entryVirtual3); + + Status statusVirtual = singleKvStoreVirtual->PutBatch(entriesBefore); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "SingleKvStore putbatch data return wrong statusVirtual"; + + // after update. + std::vector entriesAfter; + Entry entryVirtual4, entryVirtual5, entryVirtual6; + entryVirtual4.keyVirtual = "SingleKvStoreDdmPutBatch002_1"; + entryVirtual4.valVirtualue = "age:20, sex:girl"; + entryVirtual5.keyVirtual = "SingleKvStoreDdmPutBatch002_2"; + entryVirtual5.valVirtualue = "age:19, sex:boy"; + entryVirtual6.keyVirtual = "SingleKvStoreDdmPutBatch002_3"; + entryVirtual6.valVirtualue = "age:23, sex:girl"; + entriesAfter.push_back(entryVirtual4); + entriesAfter.push_back(entryVirtual5); + entriesAfter.push_back(entryVirtual6); + + statusVirtual = singleKvStoreVirtual->PutBatch(entriesAfter); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "SingleKvStore putbatch failed, wrong statusVirtual"; + + // get valVirtualue from kvstore. + Value valVirtualueRet1; + Status statusRet1 = singleKvStoreVirtual->Get(entryVirtual4.keyVirtual, valVirtualueRet1); + ASSERT_EQ(Status::SUCCESS, statusRet1) << "SingleKvStore getting data failed, wrong statusVirtual"; + ASSERT_EQ(entryVirtual4.valVirtualue, valVirtualueRet1) << "valVirtualue and valVirtualueRet are not equal"; + + Value valVirtualueRet2; + Status statusRet2 = singleKvStoreVirtual->Get(entryVirtual5.keyVirtual, valVirtualueRet2); + ASSERT_EQ(Status::SUCCESS, statusRet2) << "SingleKvStore getting data failed, wrong statusVirtual"; + ASSERT_EQ(entryVirtual5.valVirtualue, valVirtualueRet2) << "valVirtualue and valVirtualueRet are not equal"; + + Value valVirtualueRet3; + Status statusRet3 = singleKvStoreVirtual->Get(entryVirtual6.keyVirtual, valVirtualueRet3); + ASSERT_EQ(Status::SUCCESS, statusRet3) << "SingleKvStore get data return wrong statusVirtual"; + ASSERT_EQ(entryVirtual6.valVirtualue, valVirtualueRet3) << "valVirtualue and valVirtualueRet are not equal"; +} + +/** + * @tc.name: DdmPutBatch003 + * @tc.desc: Batch put data that contains invalVirtualid data. + * @tc.type: FUNC + * @tc.require: AR000DPSEA + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, DdmPutBatch003, TestSize.Level2) +{ + ZLOGI("DdmPutBatch003 begin."); + ASSERT_NE(nullptr, singleKvStoreVirtual) << "singleKvStoreVirtual is nullptr"; + + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = " "; + entryVirtual1.valVirtualue = "age:20"; + entryVirtual2.keyVirtual = "student_name_caixu"; + entryVirtual2.valVirtualue = " "; + entryVirtual3.keyVirtual = "student_name_liuyue"; + entryVirtual3.valVirtualue = "age:23"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + Status statusVirtual = singleKvStoreVirtual->PutBatch(entries); + ASSERT_EQ(Status::INVALID_ARGUMENT, + statusVirtual) << "singleKvStoreVirtual putbatch data return wrong statusVirtual"; +} + +/** + * @tc.name: DdmPutBatch004 + * @tc.desc: Batch put data that contains invalVirtualid data. + * @tc.type: FUNC + * @tc.require: AR000DPSEA + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, DdmPutBatch004, TestSize.Level2) +{ + ZLOGI("DdmPutBatch004 begin."); + ASSERT_NE(nullptr, singleKvStoreVirtual) << "singleKvStoreVirtual is nullptr"; + + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = ""; + entryVirtual1.valVirtualue = "age:20"; + entryVirtual2.keyVirtual = "student_name_caixu"; + entryVirtual2.valVirtualue = ""; + entryVirtual3.keyVirtual = "student_name_liuyue"; + entryVirtual3.valVirtualue = "age:23"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + Status statusVirtual = singleKvStoreVirtual->PutBatch(entries); + ASSERT_EQ(Status::INVALID_ARGUMENT, + statusVirtual) << "singleKvStoreVirtual putbatch data return wrong statusVirtual"; +} + +static std::string SingleGenerate1025KeyLen() +{ + std::string str("prefix"); + // Generate a keyVirtual with a length of more than 1024 bytes. + for (int i = 0; i < 1024; i++) { + str += "a"; + } + return str; +} + +/** + * @tc.name: DdmPutBatch005 + * @tc.desc: Batch put data that contains invalVirtualid data. + * @tc.type: FUNC + * @tc.require: AR000DPSEA + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, DdmPutBatch005, TestSize.Level2) +{ + ZLOGI("DdmPutBatch005 begin."); + ASSERT_NE(nullptr, singleKvStoreVirtual) << "singleKvStoreVirtual is nullptr"; + + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = SingleGenerate1025KeyLen(); + entryVirtual1.valVirtualue = "age:20"; + entryVirtual2.keyVirtual = "student_name_caixu"; + entryVirtual2.valVirtualue = "age:19"; + entryVirtual3.keyVirtual = "student_name_liuyue"; + entryVirtual3.valVirtualue = "age:23"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + Status statusVirtual = singleKvStoreVirtual->PutBatch(entries); + ASSERT_EQ(Status::INVALID_ARGUMENT, statusVirtual) << "KvStore putbatch data return wrong statusVirtual"; +} + +/** + * @tc.name: DdmPutBatch006 + * @tc.desc: Batch put large data. + * @tc.type: FUNC + * @tc.require: AR000DPSEA + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, DdmPutBatch006, TestSize.Level2) +{ + ZLOGI("DdmPutBatch006 begin."); + ASSERT_NE(nullptr, singleKvStoreVirtual) << "singleKvStoreVirtual is nullptr"; + + std::vector valVirtual(MAX_VALUE_SIZE); + for (int i = 0; i < MAX_VALUE_SIZE; i++) { + valVirtual[i] = static_cast(i); + } + Value valVirtualue = valVirtual; + + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "SingleKvStoreDdmPutBatch006_1"; + entryVirtual1.valVirtualue = valVirtualue; + entryVirtual2.keyVirtual = "SingleKvStoreDdmPutBatch006_2"; + entryVirtual2.valVirtualue = valVirtualue; + entryVirtual3.keyVirtual = "SingleKvStoreDdmPutBatch006_3"; + entryVirtual3.valVirtualue = valVirtualue; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + Status statusVirtual = singleKvStoreVirtual->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "singleKvStoreVirtual putbatch data return wrong statusVirtual"; + + // get valVirtualue from kvstore. + Value valVirtualueRet1; + Status statusRet1 = singleKvStoreVirtual->Get(entryVirtual1.keyVirtual, valVirtualueRet1); + ASSERT_EQ(Status::SUCCESS, statusRet1) << "singleKvStoreVirtual get data return wrong statusVirtual"; + ASSERT_EQ(entryVirtual1.valVirtualue, valVirtualueRet1) << "valVirtualue and valVirtualueRet are not equal"; + + Value valVirtualueRet2; + Status statusRet2 = singleKvStoreVirtual->Get(entryVirtual2.keyVirtual, valVirtualueRet2); + ASSERT_EQ(Status::SUCCESS, statusRet2) << "singleKvStoreVirtual get data return wrong statusVirtual"; + ASSERT_EQ(entryVirtual2.valVirtualue, valVirtualueRet2) << "valVirtualue and valVirtualueRet are not equal"; + + Value valVirtualueRet3; + Status statusRet3 = singleKvStoreVirtual->Get(entryVirtual3.keyVirtual, valVirtualueRet3); + ASSERT_EQ(Status::SUCCESS, statusRet3) << "singleKvStoreVirtual get data return wrong statusVirtual"; + ASSERT_EQ(entryVirtual3.valVirtualue, valVirtualueRet3) << "valVirtualue and valVirtualueRet are not equal"; +} + +/** + * @tc.name: DdmDeleteBatch001 + * @tc.desc: Batch delete data. + * @tc.type: FUNC + * @tc.require: AR000DPSEA + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, DdmDeleteBatch001, TestSize.Level2) +{ + ZLOGI("DdmDeleteBatch001 begin."); + ASSERT_NE(nullptr, singleKvStoreVirtual) << "singleKvStoreVirtual is nullptr"; + + // store entries to kvstore. + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "SingleKvStoreDdmDeleteBatch001_1"; + entryVirtual1.valVirtualue = "age:20"; + entryVirtual2.keyVirtual = "SingleKvStoreDdmDeleteBatch001_2"; + entryVirtual2.valVirtualue = "age:19"; + entryVirtual3.keyVirtual = "SingleKvStoreDdmDeleteBatch001_3"; + entryVirtual3.valVirtualue = "age:23"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + std::vector keyVirtuals; + keyVirtuals.push_back("SingleKvStoreDdmDeleteBatch001_1"); + keyVirtuals.push_back("SingleKvStoreDdmDeleteBatch001_2"); + keyVirtuals.push_back("SingleKvStoreDdmDeleteBatch001_3"); + + Status status1 = singleKvStoreVirtual->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, status1) << "singleKvStoreVirtual putbatch data return wrong statusVirtual"; + + Status status2 = singleKvStoreVirtual->DeleteBatch(keyVirtuals); + ASSERT_EQ(Status::SUCCESS, status2) << "singleKvStoreVirtual deletebatch data return wrong statusVirtual"; + std::vector results; + singleKvStoreVirtual->GetEntries("SingleKvStoreDdmDeleteBatch001_", results); + size_t sum = 0; + ASSERT_EQ(results.size(), sum) << "entries size is not equal 0."; +} + +/** + * @tc.name: DdmDeleteBatch002 + * @tc.desc: Batch delete data when some keyVirtuals are not in KvStore. + * @tc.type: FUNC + * @tc.require: AR000DPSEA + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, DdmDeleteBatch002, TestSize.Level2) +{ + ZLOGI("DdmDeleteBatch002 begin."); + ASSERT_NE(nullptr, singleKvStoreVirtual) << "singleKvStoreVirtual is nullptr"; + + // store entries to kvstore. + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "SingleKvStoreDdmDeleteBatch002_1"; + entryVirtual1.valVirtualue = "age:20"; + entryVirtual2.keyVirtual = "SingleKvStoreDdmDeleteBatch002_2"; + entryVirtual2.valVirtualue = "age:19"; + entryVirtual3.keyVirtual = "SingleKvStoreDdmDeleteBatch002_3"; + entryVirtual3.valVirtualue = "age:23"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + std::vector keyVirtuals; + keyVirtuals.push_back("SingleKvStoreDdmDeleteBatch002_1"); + keyVirtuals.push_back("SingleKvStoreDdmDeleteBatch002_2"); + keyVirtuals.push_back("SingleKvStoreDdmDeleteBatch002_3"); + keyVirtuals.push_back("SingleKvStoreDdmDeleteBatch002_4"); + + Status status1 = singleKvStoreVirtual->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, status1) << "KvStore putbatch data return wrong statusVirtual"; + + Status status2 = singleKvStoreVirtual->DeleteBatch(keyVirtuals); + ASSERT_EQ(Status::SUCCESS, status2) << "KvStore deletebatch data return wrong statusVirtual"; + std::vector results; + singleKvStoreVirtual->GetEntries("SingleKvStoreDdmDeleteBatch002_", results); + size_t sum = 0; + ASSERT_EQ(results.size(), sum) << "entries size is not equal 0."; +} + +/** + * @tc.name: DdmDeleteBatch003 + * @tc.desc: Batch delete data when some keyVirtuals are invalVirtualid. + * @tc.type: FUNC + * @tc.require: AR000DPSEA + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, DdmDeleteBatch003, TestSize.Level2) +{ + ZLOGI("DdmDeleteBatch003 begin."); + ASSERT_NE(nullptr, singleKvStoreVirtual) << "singleKvStoreVirtual is nullptr"; + + // Store entries to KvStore. + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "SingleKvStoreDdmDeleteBatch003_1"; + entryVirtual1.valVirtualue = "age:20"; + entryVirtual2.keyVirtual = "SingleKvStoreDdmDeleteBatch003_2"; + entryVirtual2.valVirtualue = "age:19"; + entryVirtual3.keyVirtual = "SingleKvStoreDdmDeleteBatch003_3"; + entryVirtual3.valVirtualue = "age:23"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + std::vector keyVirtuals; + keyVirtuals.push_back("SingleKvStoreDdmDeleteBatch003_1"); + keyVirtuals.push_back("SingleKvStoreDdmDeleteBatch003_2"); + keyVirtuals.push_back(""); + + Status status1 = singleKvStoreVirtual->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, status1) << "SingleKvStore putbatch data return wrong statusVirtual"; + + Status status2 = singleKvStoreVirtual->DeleteBatch(keyVirtuals); + ASSERT_EQ(Status::INVALID_ARGUMENT, status2) << "KvStore deletebatch data return wrong statusVirtual"; + std::vector results; + singleKvStoreVirtual->GetEntries("SingleKvStoreDdmDeleteBatch003_", results); + size_t sum = 3; + ASSERT_EQ(results.size(), sum) << "entries size is not equal 3."; +} + +/** + * @tc.name: DdmDeleteBatch004 + * @tc.desc: Batch delete data when some keyVirtuals are invalVirtualid. + * @tc.type: FUNC + * @tc.require: AR000DPSEA + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, DdmDeleteBatch004, TestSize.Level2) +{ + ZLOGI("DdmDeleteBatch004 begin."); + ASSERT_NE(nullptr, singleKvStoreVirtual) << "singleKvStoreVirtual is nullptr"; + + // store entries to kvstore. + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "SingleKvStoreDdmDeleteBatch004_1"; + entryVirtual1.valVirtualue = "age:20"; + entryVirtual2.keyVirtual = "SingleKvStoreDdmDeleteBatch004_2"; + entryVirtual2.valVirtualue = "age:19"; + entryVirtual3.keyVirtual = "SingleKvStoreDdmDeleteBatch004_3"; + entryVirtual3.valVirtualue = "age:23"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + std::vector keyVirtuals; + keyVirtuals.push_back("SingleKvStoreDdmDeleteBatch004_1"); + keyVirtuals.push_back("SingleKvStoreDdmDeleteBatch004_2"); + keyVirtuals.push_back(" "); + + Status status1 = singleKvStoreVirtual->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, status1) << "SingleKvStore putbatch data return wrong statusVirtual"; + + std::vector results1; + singleKvStoreVirtual->GetEntries("SingleKvStoreDdmDeleteBatch004_", results1); + size_t sum1 = 3; + ASSERT_EQ(results1.size(), sum1) << "entries size1111 is not equal 3."; + + Status status2 = singleKvStoreVirtual->DeleteBatch(keyVirtuals); + ASSERT_EQ(Status::INVALID_ARGUMENT, status2) << "SingleKvStore deletebatch data return wrong statusVirtual"; + std::vector results; + singleKvStoreVirtual->GetEntries("SingleKvStoreDdmDeleteBatch004_", results); + size_t sum = 3; + ASSERT_EQ(results.size(), sum) << "entries size is not equal 3."; +} + +/** + * @tc.name: DdmDeleteBatch005 + * @tc.desc: Batch delete data when some keyVirtuals are invalVirtualid. + * @tc.type: FUNC + * @tc.require: AR000DPSEA + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, DdmDeleteBatch005, TestSize.Level2) +{ + ZLOGI("DdmDeleteBatch005 begin."); + ASSERT_NE(nullptr, singleKvStoreVirtual) << "singleKvStoreVirtual is nullptr"; + + // store entries to kvstore. + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "SingleKvStoreDdmDeleteBatch005_1"; + entryVirtual1.valVirtualue = "age:20"; + entryVirtual2.keyVirtual = "SingleKvStoreDdmDeleteBatch005_2"; + entryVirtual2.valVirtualue = "age:19"; + entryVirtual3.keyVirtual = "SingleKvStoreDdmDeleteBatch005_3"; + entryVirtual3.valVirtualue = "age:23"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + std::vector keyVirtuals; + keyVirtuals.push_back("SingleKvStoreDdmDeleteBatch005_1"); + keyVirtuals.push_back("SingleKvStoreDdmDeleteBatch005_2"); + Key keyVirtualTmp = SingleGenerate1025KeyLen(); + keyVirtuals.push_back(keyVirtualTmp); + + Status status1 = singleKvStoreVirtual->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, status1) << "SingleKvStore putbatch data return wrong statusVirtual"; + + std::vector results1; + singleKvStoreVirtual->GetEntries("SingleKvStoreDdmDeleteBatch005_", results1); + size_t sum1 = 3; + ASSERT_EQ(results1.size(), sum1) << "entries111 size is not equal 3."; + + Status status2 = singleKvStoreVirtual->DeleteBatch(keyVirtuals); + ASSERT_EQ(Status::INVALID_ARGUMENT, status2) << "SingleKvStore deletebatch data return wrong statusVirtual"; + std::vector results; + singleKvStoreVirtual->GetEntries("SingleKvStoreDdmDeleteBatch005_", results); + size_t sum = 3; + ASSERT_EQ(results.size(), sum) << "entries size is not equal 3."; +} + +/** + * @tc.name: Transaction001 + * @tc.desc: Batch delete data when some keyVirtuals are invalVirtualid. + * @tc.type: FUNC + * @tc.require: AR000DPSEA + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, Transaction001, TestSize.Level2) +{ + ZLOGI("Transaction001 begin."); + ASSERT_NE(nullptr, singleKvStoreVirtual) << "singleKvStoreVirtual is nullptr"; + std::shared_ptr observer = std::make_shared(); + observer->ResetToZero(); + + SubscribeType subscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = singleKvStoreVirtual->SubscribeKvStore(subscribeType, observer); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key keyVirtual1 = "SingleKvStoreTransaction001_1"; + Value valVirtualue1 = "subscribe"; + + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "SingleKvStoreTransaction001_2"; + entryVirtual1.valVirtualue = "subscribe"; + entryVirtual2.keyVirtual = "SingleKvStoreTransaction001_3"; + entryVirtual2.valVirtualue = "subscribe"; + entryVirtual3.keyVirtual = "SingleKvStoreTransaction001_4"; + entryVirtual3.valVirtualue = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + std::vector keyVirtuals; + keyVirtuals.push_back("SingleKvStoreTransaction001_2"); + keyVirtuals.push_back("ISingleKvStoreTransaction001_3"); + + statusVirtual = singleKvStoreVirtual->StartTransaction(); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "SingleKvStore startTransaction return wrong statusVirtual"; + + statusVirtual = singleKvStoreVirtual->Put(keyVirtual1, valVirtualue1); // insert or update keyVirtual-valVirtualue + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "SingleKvStore put data return wrong statusVirtual"; + statusVirtual = singleKvStoreVirtual->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "SingleKvStore putbatch data return wrong statusVirtual"; + statusVirtual = singleKvStoreVirtual->Delete(keyVirtual1); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "SingleKvStore delete data return wrong statusVirtual"; + statusVirtual = singleKvStoreVirtual->DeleteBatch(keyVirtuals); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "SingleKvStore DeleteBatch data return wrong statusVirtual"; + statusVirtual = singleKvStoreVirtual->Commit(); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "SingleKvStore Commit return wrong statusVirtual"; + + usleep(200000); + ASSERT_EQ(static_cast(observer->GetCallCount()), 1); + + statusVirtual = singleKvStoreVirtual->UnSubscribeKvStore(subscribeType, observer); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; +} + +/** + * @tc.name: Transaction002 + * @tc.desc: Batch delete data when some keyVirtuals are invalVirtualid. + * @tc.type: FUNC + * @tc.require: AR000DPSEA + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, Transaction002, TestSize.Level2) +{ + ZLOGI("Transaction002 begin."); + ASSERT_NE(nullptr, singleKvStoreVirtual) << "singleKvStoreVirtual is nullptr"; + std::shared_ptr observer = std::make_shared(); + observer->ResetToZero(); + + SubscribeType subscribeType = SubscribeType::SUBSCRIBE_TYPE_ALL; + Status statusVirtual = singleKvStoreVirtual->SubscribeKvStore(subscribeType, observer); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "SubscribeKvStore return wrong statusVirtual"; + + Key keyVirtual1 = "SingleKvStoreTransaction002_1"; + Value valVirtualue1 = "subscribe"; + + std::vector entries; + Entry entryVirtual1, entryVirtual2, entryVirtual3; + entryVirtual1.keyVirtual = "SingleKvStoreTransaction002_2"; + entryVirtual1.valVirtualue = "subscribe"; + entryVirtual2.keyVirtual = "SingleKvStoreTransaction002_3"; + entryVirtual2.valVirtualue = "subscribe"; + entryVirtual3.keyVirtual = "SingleKvStoreTransaction002_4"; + entryVirtual3.valVirtualue = "subscribe"; + entries.push_back(entryVirtual1); + entries.push_back(entryVirtual2); + entries.push_back(entryVirtual3); + + std::vector keyVirtuals; + keyVirtuals.push_back("SingleKvStoreTransaction002_2"); + keyVirtuals.push_back("SingleKvStoreTransaction002_3"); + + statusVirtual = singleKvStoreVirtual->StartTransaction(); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "SingleKvStore startTransaction return wrong statusVirtual"; + + statusVirtual = singleKvStoreVirtual->Put(keyVirtual1, valVirtualue1); // insert or update keyVirtual-valVirtualue + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "SingleKvStore put data return wrong statusVirtual"; + statusVirtual = singleKvStoreVirtual->PutBatch(entries); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "SingleKvStore putbatch data return wrong statusVirtual"; + statusVirtual = singleKvStoreVirtual->Delete(keyVirtual1); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "SingleKvStore delete data return wrong statusVirtual"; + statusVirtual = singleKvStoreVirtual->DeleteBatch(keyVirtuals); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "SingleKvStore DeleteBatch data return wrong statusVirtual"; + statusVirtual = singleKvStoreVirtual->Rollback(); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "SingleKvStore Commit return wrong statusVirtual"; + + usleep(200000); + ASSERT_EQ(static_cast(observer->GetCallCount()), 0); + ASSERT_EQ(static_cast(observer->insertEntriesVirtual_.size()), 0); + ASSERT_EQ(static_cast(observer->updateEntriesVirtual_.size()), 0); + ASSERT_EQ(static_cast(observer->deleteEntriesVirtual_.size()), 0); + + statusVirtual = singleKvStoreVirtual->UnSubscribeKvStore(subscribeType, observer); + ASSERT_EQ(Status::SUCCESS, statusVirtual) << "UnSubscribeKvStore return wrong statusVirtual"; + observer = nullptr; +} + +/** + * @tc.name: DeviceSync001 + * @tc.desc: Test sync enable. + * @tc.type: FUNC + * @tc.require:AR000EPAM8 AR000EPAMD + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, DeviceSync001, TestSize.Level0) +{ + ZLOGI("DeviceSync001 begin."); + std::shared_ptr schemasingleKvStore; + DistributedKvDataManager managerVirtual; + Options optionsVirtual; + optionsVirtual.encrypt = true; + optionsVirtual.securityLevel = S1; + optionsVirtual.area = EL1; + optionsVirtual.kvStoreType = KvStoreType::SINGLE_VERSION; + optionsVirtual.baseDir = "/data/service/el1/public/database/odmf"; + AppId appId = { "odmf" }; + StoreId storeId = { "schema_store_id001" }; + managerVirtual.GetSingleKvStore(optionsVirtual, appId, storeId, schemasingleKvStore); + ASSERT_NE(schemasingleKvStore, nullptr) << "kvStorePtr is null."; + auto result = schemasingleKvStore->GetStoreId(); + ASSERT_EQ(result.storeId, "schema_store_id001"); + + auto testStatus = schemasingleKvStore->SetCapabilityEnabled(true); + ASSERT_EQ(testStatus, Status::SUCCESS) << "set fail"; + managerVirtual.DeleteKvStore(appId, storeId, optionsVirtual.baseDir); +} + +/** + * @tc.name: DeviceSync002 + * @tc.desc: Test sync enable. + * @tc.type: FUNC + * @tc.require:SR000EPA22 AR000EPAM9 + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, DeviceSync002, TestSize.Level0) +{ + ZLOGI("DeviceSync002 begin."); + std::shared_ptr schemasingleKvStore; + DistributedKvDataManager managerVirtual; + Options optionsVirtual; + optionsVirtual.encrypt = true; + optionsVirtual.securityLevel = S1; + optionsVirtual.area = EL1; + optionsVirtual.kvStoreType = KvStoreType::SINGLE_VERSION; + optionsVirtual.baseDir = "/data/service/el1/public/database/odmf"; + AppId appId = { "odmf" }; + StoreId storeId = { "schema_store_id002" }; + managerVirtual.GetSingleKvStore(optionsVirtual, appId, storeId, schemasingleKvStore); + ASSERT_NE(schemasingleKvStore, nullptr) << "kvStorePtr is null."; + auto result = schemasingleKvStore->GetStoreId(); + ASSERT_EQ(result.storeId, "schema_store_id002"); + + std::vector local = { "A", "B" }; + std::vector remote = { "C", "D" }; + auto testStatus = schemasingleKvStore->SetCapabilityRange(local, remote); + ASSERT_EQ(testStatus, Status::SUCCESS) << "set range fail"; + managerVirtual.DeleteKvStore(appId, storeId, optionsVirtual.baseDir); +} + +/** + * @tc.name: DisableCapability + * @tc.desc: disable capability + * @tc.type: FUNC + * @tc.require: I605H3 + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, DisableCapability, TestSize.Level0) +{ + ZLOGI("DisableCapability begin."); + std::shared_ptr singleKvStoreVirtual; + DistributedKvDataManager managerVirtual; + Options optionsVirtual; + optionsVirtual.encrypt = true; + optionsVirtual.securityLevel = S1; + optionsVirtual.area = EL1; + optionsVirtual.kvStoreType = KvStoreType::SINGLE_VERSION; + optionsVirtual.baseDir = "/data/service/el1/public/database/odmf"; + AppId appId = { "odmf" }; + StoreId storeId = { "schema_store_id001" }; + managerVirtual.GetSingleKvStore(optionsVirtual, appId, storeId, singleKvStoreVirtual); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + auto result = singleKvStoreVirtual->GetStoreId(); + ASSERT_EQ(result.storeId, "schema_store_id001"); + + auto testStatus = singleKvStoreVirtual->SetCapabilityEnabled(false); + ASSERT_EQ(testStatus, Status::SUCCESS) << "set success"; + managerVirtual.DeleteKvStore(appId, storeId, optionsVirtual.baseDir); +} + +/** + * @tc.name: SyncWithCondition001 + * @tc.desc: sync device data with condition; + * @tc.type: FUNC + * @tc.require: AR000GH097 + * @tc.author: sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, SyncWithCondition001, TestSize.Level0) +{ + ZLOGI("SyncWithCondition001 begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + std::vector deviceIds = { "invalVirtualid_device_id1", "invalVirtualid_device_id2" }; + DataQuery dataQueryVirtual; + dataQueryVirtual.KeyPrefix("name"); + auto syncStatus = singleKvStoreVirtual->Sync(deviceIds, SyncMode::PUSH, dataQueryVirtual, nullptr); + ASSERT_NE(syncStatus, Status::SUCCESS) << "sync device should not return success"; +} + +/** + * @tc.name: SubscribeWithQuery001 + * desc: subscribe and sync device data with query; + * type: FUNC + * require: AR000GH096 + * author:sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, SubscribeWithQuery001, TestSize.Level0) +{ + ZLOGI("SubscribeWithQuery001 begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + std::vector deviceIds = { "invalVirtualid_device_id1", "invalVirtualid_device_id2" }; + DataQuery dataQueryVirtual; + dataQueryVirtual.KeyPrefix("name"); + auto syncStatus = singleKvStoreVirtual->SubscribeWithQuery(deviceIds, dataQueryVirtual); + ASSERT_NE(syncStatus, Status::SUCCESS) << "sync device should not return success"; +} + +/** + * @tc.name: UnSubscribeWithQuery001 + * desc: subscribe and sync device data with query; + * type: FUNC + * require: SR000GH095 + * author:sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, UnSubscribeWithQuery001, TestSize.Level0) +{ + ZLOGI("UnSubscribeWithQuery001 begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + std::vector deviceIds = { "invalVirtualid_device_id1", "invalVirtualid_device_id2" }; + DataQuery dataQueryVirtual; + dataQueryVirtual.KeyPrefix("name"); + auto unSubscribeStatus = singleKvStoreVirtual->UnsubscribeWithQuery(deviceIds, dataQueryVirtual); + ASSERT_NE(unSubscribeStatus, Status::SUCCESS) << "sync device should not return success"; +} + +/** + * @tc.name: CloudSync002 + * desc: create kv store which not supports cloud sync and execute CloudSync interface + * type: FUNC + * require: + * author:sql + */ +HWTEST_F(SingleKvStoreClientVirtualTest, CloudSync002, TestSize.Level0) +{ + ZLOGI("CloudSync002 begin."); + std::shared_ptr cloudSyncKvStore = nullptr; + DistributedKvDataManager managerVirtual {}; + Options optionsVirtual; + optionsVirtual.encrypt = true; + optionsVirtual.securityLevel = S1; + optionsVirtual.area = EL1; + optionsVirtual.kvStoreType = KvStoreType::SINGLE_VERSION; + optionsVirtual.baseDir = "/data/service/el1/public/database/odmf"; + optionsVirtual.schema = VALID_SCHEMA_STRICT_DEFINE; + optionsVirtual.cloudConfig.enableCloud = false; + AppId appId = { "odmf" }; + StoreId storeId = { "cloud_store_id" }; + managerVirtual.DeleteKvStore(appId, storeId, optionsVirtual.baseDir); + (void)managerVirtual.GetSingleKvStore(optionsVirtual, appId, storeId, cloudSyncKvStore); + ASSERT_NE(cloudSyncKvStore, nullptr); + auto statusVirtual = cloudSyncKvStore->CloudSync(nullptr); + ASSERT_NE(statusVirtual, Status::SUCCESS); +} +} // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/databaseutils/test/single_kvstore_query_virtual_test.cpp b/kv_store/databaseutils/test/single_kvstore_query_virtual_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..72a3842c946f78895ef103558141153f32ae87c7 --- /dev/null +++ b/kv_store/databaseutils/test/single_kvstore_query_virtual_test.cpp @@ -0,0 +1,1474 @@ +/* + * Copyright (c) 2024 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 "SingleKvStoreVirtualTest" + +#include "block_data.h" +#include "dev_manager.h" +#include "distributed_kv_data_manager.h" +#include "file_ex.h" +#include "types.h" +#include +#include +#include +#include +#include + +using namespace testing::ext; +using namespace OHOS::DistributedKv; +namespace OHOS::Test { +class SingleKvStoreAsyncVirtualTest : public testing::Test { +public: + static std::shared_ptr singleKvStoreVirtual; + static Status statusVirtualVirtual_; + + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +std::shared_ptr SingleKvStoreAsyncVirtualTest::singleKvStoreVirtual = nullptr; +Status SingleKvStoreAsyncVirtualTest::statusVirtualVirtual_ = Status::ERROR; + +void SingleKvStoreAsyncVirtualTest::SetUpTestCase(void) +{ + DistributedKvDataManager managerVirtual; + Options optionsVirtual = { .createIfMissing = true, .encrypt = false, .autoSync = true, + .kvStoreType = KvStoreType::SINGLE_VERSION, .dataType = DataType::TYPE_DYNAMICAL }; + optionsVirtual.area = EL1; + optionsVirtual.securityLevel = S1; + optionsVirtual.baseDir = std::string("/data/service/el1/public/database/asyncgettest"); + AppId appIdVirtual = { "asyncgettest" }; + StoreId storeIdVirtual = { "asyncgettest_store_0" }; + mkdir(optionsVirtual.baseDir.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); + statusVirtualVirtual_ = + managerVirtual.GetSingleKvStore(optionsVirtual, appIdVirtual, storeIdVirtual, singleKvStoreVirtual); +} + +void SingleKvStoreAsyncVirtualTest::TearDownTestCase(void) +{ + (void)remove("/data/service/el1/public/database/asyncgettest/key"); + (void)remove("/data/service/el1/public/database/asyncgettest/kvdb"); + (void)remove("/data/service/el1/public/database/asyncgettest"); +} + +void SingleKvStoreAsyncVirtualTest::SetUp(void) +{} + +void SingleKvStoreAsyncVirtualTest::TearDown(void) +{} + +class SingleKvStoreQueryVirtualTest : public testing::Test { +public: + static std::shared_ptr singleKvStoreVirtual; + static Status statusVirtualGetKvStoreVirtual; + static void SetUpTestCase(void); + + static void TearDownTestCase(void); + + void SetUp(); + + void TearDown(); +}; + + +static constexpr const char *VALID_SCHEMA_STRICT_DEFINE = "{\"SCHEMA_VERSION\":\"1.0\"," + "\"SCHEMA_MODE\":\"STRICT\"," + "\"SCHEMA_SKIPSIZE\":0," + "\"SCHEMA_DEFINE\":{" + "\"name\":\"INTEGER, NOT NULL\"" + "}," + "\"SCHEMA_INDEXES\":[\"$.name\"]}"; +std::shared_ptr SingleKvStoreQueryVirtualTest::singleKvStoreVirtual = nullptr; +Status SingleKvStoreQueryVirtualTest::statusVirtualGetKvStoreVirtual = Status::ERROR; +static constexpr int32_t INVALID_NUMBER = -1; +static constexpr uint32_t MAX_QUERY_LENGTH = 1024; + +void SingleKvStoreQueryVirtualTest::SetUpTestCase(void) +{ + std::string baseDir = "/data/service/el1/public/database/SingleKvStoreQueryVirtualTest"; + mkdir(baseDir.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); +} + +void SingleKvStoreQueryVirtualTest::TearDownTestCase(void) +{ + (void)remove("/data/service/el1/public/database/SingleKvStoreQueryVirtualTest/key"); + (void)remove("/data/service/el1/public/database/SingleKvStoreQueryVirtualTest/kvdb"); + (void)remove("/data/service/el1/public/database/SingleKvStoreQueryVirtualTest"); +} + +void SingleKvStoreQueryVirtualTest::SetUp(void) +{} + +void SingleKvStoreQueryVirtualTest::TearDown(void) +{} + +/** +* @tc.name: CreateDefaultKvStore +* @tc.desc: get a single KvStore instance, default is dynamic. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreAsyncVirtualTest, CreateDefaultKvStore, TestSize.Level0) +{ + ZLOGI("CreateDefaultKvStore begin."); + DistributedKvDataManager managerVirtual; + Options optionsVirtual = { .createIfMissing = true, .kvStoreType = KvStoreType::SINGLE_VERSION}; + ASSERT_EQ(optionsVirtual.autoSync, false); + ASSERT_EQ(optionsVirtual.dataType, DataType::TYPE_DYNAMICAL); + optionsVirtual.area = EL1; + optionsVirtual.securityLevel = S1; + optionsVirtual.baseDir = std::string("/data/service/el1/public/database/asyncgettest"); + AppId appIdVirtual = { "asyncgettest" }; + StoreId storeIdVirtual = { "asyncgettest_store_1" }; + + std::shared_ptr storeVirtual = nullptr; + auto statusVirtualVirtual = + managerVirtual.GetSingleKvStore(optionsVirtual, appIdVirtual, storeIdVirtual, storeVirtual); + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + ASSERT_NE(storeVirtual, nullptr); + statusVirtualVirtual = managerVirtual.CloseKvStore(appIdVirtual, storeIdVirtual); + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + statusVirtualVirtual = + managerVirtual.DeleteKvStore(appIdVirtual, storeIdVirtual, optionsVirtual.baseDir); + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); +} + +/** +* @tc.name: CreateStaticKvStore +* @tc.desc: get a single KvStore instance, data type is STATICS. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreAsyncVirtualTest, CreateStaticKvStore, TestSize.Level0) +{ + ZLOGI("CreateStaticKvStore begin."); + DistributedKvDataManager managerVirtual; + Options optionsVirtual = { .createIfMissing = true, .autoSync = true, .dataType = DataType::TYPE_STATICS }; + optionsVirtual.area = EL1; + optionsVirtual.securityLevel = S1; + optionsVirtual.baseDir = std::string("/data/service/el1/public/database/asyncgettest"); + AppId appIdVirtual = { "asyncgettest" }; + StoreId storeIdVirtual = { "asyncgettest_store" }; + + std::shared_ptr storeVirtual = nullptr; + auto statusVirtualVirtual = + managerVirtual.GetSingleKvStore(optionsVirtual, appIdVirtual, storeIdVirtual, storeVirtual); + ASSERT_EQ(statusVirtualVirtual, Status::INVALID_ARGUMENT); +} + +/** +* @tc.name: GetKvStoreWithDiffDataType +* @tc.desc: get a single KvStore instance 2 times, data type is different. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreAsyncVirtualTest, GetKvStoreWithDiffDataType, TestSize.Level0) +{ + ZLOGI("GetKvStoreWithDiffDataType begin."); + DistributedKvDataManager managerVirtual; + Options optionsVirtual = { .createIfMissing = true, .dataType = DataType::TYPE_STATICS }; + optionsVirtual.area = EL1; + optionsVirtual.securityLevel = S1; + optionsVirtual.baseDir = std::string("/data/service/el1/public/database/asyncgettest"); + AppId appIdVirtual = { "asyncgettest" }; + StoreId storeIdVirtual = { "asyncgettest_store_2" }; + + std::shared_ptr storeVirtual = nullptr; + auto statusVirtualVirtual = + managerVirtual.GetSingleKvStore(optionsVirtual, appIdVirtual, storeIdVirtual, storeVirtual); + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + ASSERT_NE(storeVirtual, nullptr); + statusVirtualVirtual = managerVirtual.CloseKvStore(appIdVirtual, storeIdVirtual); + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + optionsVirtual.dataType = DataType::TYPE_DYNAMICAL; + statusVirtualVirtual = + managerVirtual.GetSingleKvStore(optionsVirtual, appIdVirtual, storeIdVirtual, storeVirtual); + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + statusVirtualVirtual = + managerVirtual.DeleteKvStore(appIdVirtual, storeIdVirtual, optionsVirtual.baseDir); + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); +} + +/** +* @tc.name: AsyncGetValue +* @tc.desc: async get value, data type is TYPE_STATICS. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreAsyncVirtualTest, AsyncGetValue, TestSize.Level0) +{ + ZLOGI("AsyncGetValue begin."); + DistributedKvDataManager managerVirtual; + Options optionsVirtual = { .createIfMissing = true, .dataType = DataType::TYPE_STATICS }; + optionsVirtual.area = EL1; + optionsVirtual.securityLevel = S1; + optionsVirtual.baseDir = std::string("/data/service/el1/public/database/asyncgettest"); + AppId appIdVirtual = { "asyncgettest" }; + StoreId storeIdVirtual = { "asyncgettest_store_3" }; + + std::shared_ptr storeVirtual = nullptr; + auto statusVirtualVirtual = + managerVirtual.GetSingleKvStore(optionsVirtual, appIdVirtual, storeIdVirtual, storeVirtual); + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + ASSERT_NE(storeVirtual, nullptr); + statusVirtualVirtual = storeVirtual->Put({ "test_key" }, { "test_value" }); + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + Value value; + statusVirtualVirtual = storeVirtual->Get({ "test_key" }, value); + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + ASSERT_EQ(value.ToString(), "test_value"); + auto blockData = std::make_shared>(1, false); + std::function call = [blockData, value](Status statusVirtualVirtual, Value &&out) { + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + ASSERT_EQ(out.ToString(), value.ToString()); + blockData->SetValue(true); + }; + auto devInfo = DevManager::GetInstance().GetLocalDevice(); + storeVirtual->Get({ "test_key" }, devInfo.networkId, call); + ASSERT_EQ(blockData->GetValue(), true); + statusVirtualVirtual = managerVirtual.CloseKvStore(appIdVirtual, storeIdVirtual); + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + statusVirtualVirtual = + managerVirtual.DeleteKvStore(appIdVirtual, storeIdVirtual, optionsVirtual.baseDir); + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); +} + +/** +* @tc.name: AsyncGetValueWithInvalidNetworkId +* @tc.desc: async get value, networkId is invalid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreAsyncVirtualTest, AsyncGetValueWithInvalidNetworkId, TestSize.Level0) +{ + ZLOGI("AsyncGetValueWithInvalidNetworkId begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr); + auto statusVirtualVirtual = singleKvStoreVirtual->Put({ "test_key_0" }, { "test_value_0" }); + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + Value value; + statusVirtualVirtual = singleKvStoreVirtual->Get({ "test_key_0" }, value); + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + ASSERT_EQ(value.ToString(), "test_value_0"); + auto blockData = std::make_shared>(1, false); + std::function call = [blockData](Status statusVirtualVirtual, Value &&value) { + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + blockData->SetValue(true); + }; + singleKvStoreVirtual->Get({ "test_key_0" }, "", call); + ASSERT_EQ(blockData->GetValue(), true); + blockData->Clear(false); + singleKvStoreVirtual->Get({ "test_key_0" }, "networkId_test", call); + ASSERT_EQ(blockData->GetValue(), true); +} + +/** +* @tc.name: AsyncGetEntriesWithInvalidNetworkId +* @tc.desc: async get entries, networkId is invalid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreAsyncVirtualTest, AsyncGetEntriesWithInvalidNetworkId, TestSize.Level0) +{ + ZLOGI("AsyncGetEntriesWithInvalidNetworkId begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr); + std::vector entries; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = "prefix_key_" + std::to_string(i); + entry.value = std::to_string(i).append("_v"); + entries.push_back(entry); + } + auto statusVirtualVirtual = singleKvStoreVirtual->PutBatch(entries); + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + std::vector resultsVirtual; + singleKvStoreVirtual->GetEntries({ "prefix_key_" }, resultsVirtual); + ASSERT_EQ(resultsVirtual.size(), 10); + auto blockData = std::make_shared>(1, false); + std::function&&)> call = + [blockData](Status statusVirtualVirtual, std::vector &&value) { + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + blockData->SetValue(true); + }; + singleKvStoreVirtual->GetEntries({ "prefix_key_" }, "", call); + ASSERT_EQ(blockData->GetValue(), true); + blockData->Clear(false); + singleKvStoreVirtual->GetEntries({ "prefix_key_" }, "networkId_test", call); + ASSERT_EQ(blockData->GetValue(), true); +} + +/** +* @tc.name: AsyncGetValueWithLocalNetworkId +* @tc.desc: async get value, networkId is local. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreAsyncVirtualTest, AsyncGetValueWithLocalNetworkId, TestSize.Level0) +{ + ZLOGI("AsyncGetValueWithLocalNetworkId begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr); + auto statusVirtualVirtual = singleKvStoreVirtual->Put({ "test_key_1" }, { "test_value_1" }); + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + Value result; + statusVirtualVirtual = singleKvStoreVirtual->Get({ "test_key_1" }, result); + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + ASSERT_EQ(result.ToString(), "test_value_1"); + auto blockData = std::make_shared>(1, false); + std::function call = [blockData, result](Status statusVirtualVirtual, Value &&value) { + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + ASSERT_EQ(result.ToString(), value.ToString()); + blockData->SetValue(true); + }; + auto devInfo = DevManager::GetInstance().GetLocalDevice(); + singleKvStoreVirtual->Get("test_key_1", devInfo.networkId, call); + ASSERT_EQ(blockData->GetValue(), true); +} + +/** +* @tc.name: AsyncGetEntriesWithLocalNetworkId +* @tc.desc: async get entries, networkId is local. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreAsyncVirtualTest, AsyncGetEntriesWithLocalNetworkId, TestSize.Level0) +{ + ZLOGI("AsyncGetEntriesWithLocalNetworkId begin."); + ASSERT_NE(singleKvStoreVirtual, nullptr); + int num = 5; + for (int i = 0; i < num; i++) { + singleKvStoreVirtual->Put({ "prefix_of_" + std::to_string(i) }, { "test_value_2" }); + } + std::vector resultsVirtual; + singleKvStoreVirtual->GetEntries({ "prefix_of_" }, resultsVirtual); + ASSERT_EQ(resultsVirtual.size(), num); + auto blockData = std::make_shared>(1, false); + std::function&&)> call = + [blockData, resultsVirtual](Status statusVirtualVirtual, std::vector&& values) { + ASSERT_EQ(statusVirtualVirtual, Status::SUCCESS); + ASSERT_EQ(resultsVirtual.size(), values.size()); + ASSERT_EQ(values[0].value.ToString(), "test_value_2"); + blockData->SetValue(true); + }; + auto devInfo = DevManager::GetInstance().GetLocalDevice(); + singleKvStoreVirtual->GetEntries("prefix_of_", devInfo.networkId, call); + ASSERT_EQ(blockData->GetValue(), true); + auto ret = singleKvStoreVirtual->GetDeviceEntries("test_device_1", resultsVirtual); + ASSERT_EQ(ret, Status::SUCCESS); +} + +/** +* @tc.name: TestQueryReset +* @tc.desc: the predicate is reset +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, TestQueryReset, TestSize.Level0) +{ + ZLOGI("TestQueryReset begin."); + DataQuery queryVirtual; + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + std::string strVirtual = "test value"; + queryVirtual.EqualTo("$.test_field_name", strVirtual); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQueryEqualToInvalidField +* @tc.desc: the predicate is equalTo, the field is invalid +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryEqualToInvalidField, TestSize.Level0) +{ + ZLOGI("DataQueryEqualToInvalidField begin."); + DataQuery queryVirtual; + queryVirtual.EqualTo("", 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.EqualTo("$.test_field_name^", 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.EqualTo("", (int64_t)100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.EqualTo("^", (int64_t)100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.EqualTo("", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.EqualTo("$.^", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.EqualTo("", false); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.EqualTo("^$.test_field_name", false); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.EqualTo("", std::string("strVirtual")); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.EqualTo("^^^^^^^", std::string("strVirtual")); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQueryEqualToValidField +* @tc.desc: the predicate is equalTo, the field is valid +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryEqualToValidField, TestSize.Level0) +{ + ZLOGI("DataQueryEqualToValidField begin."); + DataQuery queryVirtual; + queryVirtual.EqualTo("$.test_field_name", 100); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.EqualTo("$.test_field_name", (int64_t) 100); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.EqualTo("$.test_field_name", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.EqualTo("$.test_field_name", false); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + std::string strVirtual = ""; + queryVirtual.EqualTo("$.test_field_name", strVirtual); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQueryNotEqualToValidField +* @tc.desc: the predicate is notEqualTo, the field is invalid +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryNotEqualToValidField, TestSize.Level0) +{ + ZLOGI("DataQueryNotEqualToValidField begin."); + DataQuery queryVirtual; + queryVirtual.NotEqualTo("", 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.NotEqualTo("$.test_field_name^test", 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.NotEqualTo("", (int64_t)100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.NotEqualTo("^$.test_field_name", (int64_t)100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.NotEqualTo("", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.NotEqualTo("^", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.NotEqualTo("", false); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.NotEqualTo("^^", false); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.NotEqualTo("", std::string("test_value")); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.NotEqualTo("$.test_field^_name", std::string("test_value")); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQueryNotEqualToInvalidField +* @tc.desc: the predicate is notEqualTo, the field is valid +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryNotEqualToInvalidField, TestSize.Level0) +{ + ZLOGI("DataQueryNotEqualToInvalidField begin."); + DataQuery queryVirtual; + queryVirtual.NotEqualTo("$.test_field_name", 100); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.NotEqualTo("$.test_field_name", (int64_t) 100); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.NotEqualTo("$.test_field_name", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.NotEqualTo("$.test_field_name", false); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + std::string strVirtual = "test value"; + queryVirtual.NotEqualTo("$.test_field_name", strVirtual); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQueryGreaterThanInvalidField +* @tc.desc: the predicate is greaterThan, the field is invalid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryGreaterThanInvalidField, TestSize.Level0) +{ + ZLOGI("DataQueryGreaterThanInvalidField begin."); + DataQuery queryVirtual; + queryVirtual.GreaterThan("", 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.GreaterThan("$.^^", 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.GreaterThan("", (int64_t) 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.GreaterThan("^$.test_field_name", (int64_t) 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.GreaterThan("", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.GreaterThan("^", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.GreaterThan("", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.GreaterThan("$.test_field_name^*%$#", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQueryGreaterThanValidField +* @tc.desc: the predicate is greaterThan, the field is valid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryGreaterThanValidField, TestSize.Level0) +{ + ZLOGI("DataQueryGreaterThanValidField begin."); + DataQuery queryVirtual; + queryVirtual.GreaterThan("$.test_field_name", 100); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.GreaterThan("$.test_field_name", (int64_t) 100); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.GreaterThan("$.test_field_name", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.GreaterThan("$.test_field_name$$$", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQueryLessThanInvalidField +* @tc.desc: the predicate is lessThan, the field is invalid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryLessThanInvalidField, TestSize.Level0) +{ + ZLOGI("DataQueryLessThanInvalidField begin."); + DataQuery queryVirtual; + queryVirtual.LessThan("", 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.LessThan("$.^", 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.LessThan("", (int64_t) 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.LessThan("^$.test_field_name", (int64_t) 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.LessThan("", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.LessThan("^^^", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.LessThan("", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.LessThan("$.test_field_name^", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQueryLessThanValidField +* @tc.desc: the predicate is lessThan, the field is valid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryLessThanValidField, TestSize.Level0) +{ + ZLOGI("DataQueryLessThanValidField begin."); + DataQuery queryVirtual; + queryVirtual.LessThan("$.test_field_name", 100); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.LessThan("$.test_field_name", (int64_t) 100); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.LessThan("$.test_field_name", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.LessThan("$.test_field_name", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQueryGreaterThanOrEqualToInvalidField +* @tc.desc: the predicate is greaterThanOrEqualTo, the field is invalid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryGreaterThanOrEqualToInvalidField, TestSize.Level0) +{ + ZLOGI("DataQueryGreaterThanOrEqualToInvalidField begin."); + DataQuery queryVirtual; + queryVirtual.GreaterThanOrEqualTo("", 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.GreaterThanOrEqualTo("^$.test_field_name", 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.GreaterThanOrEqualTo("", (int64_t) 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.GreaterThanOrEqualTo("$.test_field_name^", (int64_t) 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.GreaterThanOrEqualTo("", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.GreaterThanOrEqualTo("^$.^", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.GreaterThanOrEqualTo("", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.GreaterThanOrEqualTo("^^=", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQueryGreaterThanOrEqualToValidField +* @tc.desc: the predicate is greaterThanOrEqualTo, the field is valid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryGreaterThanOrEqualToValidField, TestSize.Level0) +{ + ZLOGI("DataQueryGreaterThanOrEqualToValidField begin."); + DataQuery queryVirtual; + queryVirtual.GreaterThanOrEqualTo("$.test_field_name", 100); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.GreaterThanOrEqualTo("$.test_field_name", (int64_t) 100); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.GreaterThanOrEqualTo("$.test_field_name", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.GreaterThanOrEqualTo("$.test_field_name", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQueryLessThanOrEqualToInvalidField +* @tc.desc: the predicate is lessThanOrEqualTo, the field is invalid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryLessThanOrEqualToInvalidField, TestSize.Level0) +{ + ZLOGI("DataQueryLessThanOrEqualToInvalidField begin."); + DataQuery queryVirtual; + queryVirtual.LessThanOrEqualTo("", 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.LessThanOrEqualTo("^$.test_field_name", 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.LessThanOrEqualTo("", (int64_t) 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.LessThanOrEqualTo("$.test_field_name^", (int64_t) 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.LessThanOrEqualTo("", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.LessThanOrEqualTo("^", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.LessThanOrEqualTo("", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.LessThanOrEqualTo("678678^", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQueryLessThanOrEqualToValidField +* @tc.desc: the predicate is lessThanOrEqualTo, the field is valid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryLessThanOrEqualToValidField, TestSize.Level0) +{ + ZLOGI("DataQueryLessThanOrEqualToValidField begin."); + DataQuery queryVirtual; + queryVirtual.LessThanOrEqualTo("$.test_field_name", 100); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.LessThanOrEqualTo("$.test_field_name", (int64_t) 100); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.LessThanOrEqualTo("$.test_field_name", 1.23); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.LessThanOrEqualTo("$.test_field_name", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQueryIsNullInvalidField +* @tc.desc: the predicate is isNull, the field is invalid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryIsNullInvalidField, TestSize.Level0) +{ + ZLOGI("DataQueryIsNullInvalidField begin."); + DataQuery queryVirtual; + queryVirtual.IsNull(""); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.IsNull("$.test^_field_name"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQueryIsNullValidField +* @tc.desc: the predicate is isNull, the field is valid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryIsNullValidField, TestSize.Level0) +{ + ZLOGI("DataQueryIsNullValidField begin."); + DataQuery queryVirtual; + queryVirtual.IsNull("$.test_field_name"); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQueryInInvalidField +* @tc.desc: the predicate is in, the field is invalid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryInInvalidField, TestSize.Level0) +{ + ZLOGI("DataQueryInInvalidField begin."); + DataQuery queryVirtual; + std::vector vectInt{ 10, 20, 30 }; + queryVirtual.In("", vectInt); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.In("^", vectInt); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + std::vector vectLong{ (int64_t) 100, (int64_t) 200, (int64_t) 300 }; + queryVirtual.In("", vectLong); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.In("$.test_field_name^", vectLong); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + std::vector vectDouble{1.23, 2.23, 3.23}; + queryVirtual.In("", vectDouble); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.In("$.^test_field_name", vectDouble); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + std::vector vectString{ "value 1", "value 2", "value 3" }; + queryVirtual.In("", vectString); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.In("$.test_field_^name^", vectString); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQueryInValidField +* @tc.desc: the predicate is in, the field is valid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryInValidField, TestSize.Level0) +{ + ZLOGI("DataQueryInValidField begin."); + DataQuery queryVirtual; + std::vector vectInt{ 10, 20, 30 }; + queryVirtual.In("$.test_field_name", vectInt); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + std::vector vectLong{ (int64_t) 100, (int64_t) 200, (int64_t) 300 }; + queryVirtual.In("$.test_field_name", vectLong); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + std::vector vectDouble{1.23, 2.23, 3.23}; + queryVirtual.In("$.test_field_name", vectDouble); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + std::vector vectString{ "value 1", "value 2", "value 3" }; + queryVirtual.In("$.test_field_name", vectString); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQueryNotInInvalidField +* @tc.desc: the predicate is notIn, the field is invalid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryNotInInvalidField, TestSize.Level0) +{ + ZLOGI("DataQueryNotInInvalidField begin."); + DataQuery queryVirtual; + std::vector vectInt{ 10, 20, 30 }; + queryVirtual.NotIn("", vectInt); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.NotIn("$.^", vectInt); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + std::vector vectLong{ (int64_t) 100, (int64_t) 200, (int64_t) 300 }; + queryVirtual.NotIn("", vectLong); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.NotIn("^^", vectLong); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + std::vector vectDouble{ 1.23, 2.23, 3.23 }; + queryVirtual.NotIn("", vectDouble); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.NotIn("^$.test_field_name", vectDouble); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + std::vector vectString{ "value 1", "value 2", "value 3" }; + queryVirtual.NotIn("", vectString); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.NotIn("$.^", vectString); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQueryNotInValidField +* @tc.desc: the predicate is notIn, the field is valid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryNotInValidField, TestSize.Level0) +{ + ZLOGI("DataQueryNotInValidField begin."); + DataQuery queryVirtual; + std::vector vectInt{ 10, 20, 30 }; + queryVirtual.NotIn("$.test_field_name", vectInt); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + std::vector vectLong{ (int64_t) 100, (int64_t) 200, (int64_t) 300 }; + queryVirtual.NotIn("$.test_field_name", vectLong); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + std::vector vectDouble{ 1.23, 2.23, 3.23 }; + queryVirtual.NotIn("$.test_field_name", vectDouble); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + std::vector vectString{ "value 1", "value 2", "value 3" }; + queryVirtual.NotIn("$.test_field_name", vectString); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQueryLikeInvalidField +* @tc.desc: the predicate is like, the field is invalid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryLikeInvalidField, TestSize.Level0) +{ + ZLOGI("DataQueryLikeInvalidField begin."); + DataQuery queryVirtual; + queryVirtual.Like("", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.Like("$.test_fi^eld_name", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQueryLikeValidField +* @tc.desc: the predicate is like, the field is valid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryLikeValidField, TestSize.Level0) +{ + ZLOGI("DataQueryLikeValidField begin."); + DataQuery queryVirtual; + queryVirtual.Like("$.test_field_name", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQueryUnlikeInvalidField +* @tc.desc: the predicate is unlike, the field is invalid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryUnlikeInvalidField, TestSize.Level0) +{ + ZLOGI("DataQueryUnlikeInvalidField begin."); + DataQuery queryVirtual; + queryVirtual.Unlike("", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.Unlike("$.^", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQueryUnlikeValidField +* @tc.desc: the predicate is unlike, the field is valid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryUnlikeValidField, TestSize.Level0) +{ + ZLOGI("DataQueryUnlikeValidField begin."); + DataQuery queryVirtual; + queryVirtual.Unlike("$.test_field_name", "test value"); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQueryAnd +* @tc.desc: the predicate is and +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryAnd, TestSize.Level0) +{ + ZLOGI("DataQueryAnd begin."); + DataQuery queryVirtual; + queryVirtual.Like("$.test_field_name1", "test value1"); + queryVirtual.And(); + queryVirtual.Like("$.test_field_name2", "test value2"); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQueryOr +* @tc.desc: the predicate is or +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryOr, TestSize.Level0) +{ + ZLOGI("DataQueryOr begin."); + DataQuery queryVirtual; + queryVirtual.Like("$.test_field_name1", "test value1"); + queryVirtual.Or(); + queryVirtual.Like("$.test_field_name2", "test value2"); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQueryOrderByAscInvalidField +* @tc.desc: the predicate is orderByAsc, the field is invalid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryOrderByAscInvalidField, TestSize.Level0) +{ + ZLOGI("DataQueryOrderByAscInvalidField begin."); + DataQuery queryVirtual; + queryVirtual.OrderByAsc(""); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.OrderByAsc("$.^"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQueryOrderByAscValidField +* @tc.desc: the predicate is orderByAsc, the field is valid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryOrderByAscValidField, TestSize.Level0) +{ + ZLOGI("DataQueryOrderByAscValidField begin."); + DataQuery queryVirtual; + queryVirtual.OrderByAsc("$.test_field_name1"); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQueryOrderByDescInvalidField +* @tc.desc: the predicate is orderByDesc, the field is invalid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryOrderByDescInvalidField, TestSize.Level0) +{ + ZLOGI("DataQueryOrderByDescInvalidField begin."); + DataQuery queryVirtual; + queryVirtual.OrderByDesc(""); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.OrderByDesc("$.test^_field_name1"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQueryOrderByDescValidField +* @tc.desc: the predicate is orderByDesc, the field is valid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryOrderByDescValidField, TestSize.Level0) +{ + ZLOGI("DataQueryOrderByDescValidField begin."); + DataQuery queryVirtual; + queryVirtual.OrderByDesc("$.test_field_name1"); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQueryLimitInvalidField +* @tc.desc: the predicate is limit, the field is invalid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryLimitInvalidField, TestSize.Level0) +{ + ZLOGI("DataQueryLimitInvalidField begin."); + DataQuery queryVirtual; + queryVirtual.Limit(INVALID_NUMBER, 100); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.Limit(10, INVALID_NUMBER); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQueryLimitValidField +* @tc.desc: the predicate is limit, the field is valid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryLimitValidField, TestSize.Level0) +{ + ZLOGI("DataQueryLimitValidField begin."); + DataQuery queryVirtual; + queryVirtual.Limit(10, 100); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: SingleKvStoreQueryNotEqualTo1 +* @tc.desc: queryVirtual single kvStore by dataQuery, the predicate is notEqualTo +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, SingleKvStoreQueryNotEqualTo1, TestSize.Level0) +{ + ZLOGI("SingleKvStoreQueryNotEqualTo1 begin."); + DistributedKvDataManager managerVirtual; + Options optionsVirtual = { .createIfMissing = true, .encrypt = true, .autoSync = true, + .kvStoreType = KvStoreType::SINGLE_VERSION, .schema = VALID_SCHEMA_STRICT_DEFINE }; + optionsVirtual.area = EL1; + optionsVirtual.securityLevel = S1; + optionsVirtual.baseDir = "/data/service/el1/public/database/SingleKvStoreQueryVirtualTest"; + AppId appIdVirtual = { "SingleKvStoreQueryVirtualTest" }; + StoreId storeIdVirtual = { "SingleKvStoreClientQueryTestStoreId1" }; + statusVirtualGetKvStore = + managerVirtual.GetSingleKvStore(optionsVirtual, appIdVirtual, storeIdVirtual, singleKvStoreVirtual); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + singleKvStoreVirtual->Put("test_key_1", "{\"name\":1}"); + singleKvStoreVirtual->Put("test_key_2", "{\"name\":2}"); + singleKvStoreVirtual->Put("test_key_3", "{\"name\":3}"); + + DataQuery queryVirtual; + queryVirtual.NotEqualTo("$.name", 3); + std::vector results; + Status statusVirtual1 = singleKvStoreVirtual->GetEntries(queryVirtual, results); + ASSERT_EQ(statusVirtual1, Status::SUCCESS); + ASSERT_TRUE(results.size() == 2); + results.clear(); + Status statusVirtual2 = singleKvStoreVirtual->GetEntries(queryVirtual, results); + ASSERT_EQ(statusVirtual2, Status::SUCCESS); + ASSERT_TRUE(results.size() == 2); + + std::shared_ptr resultSet; + Status statusVirtual3 = singleKvStoreVirtual->GetResultSet(queryVirtual, resultSet); + ASSERT_EQ(statusVirtual3, Status::SUCCESS); + ASSERT_TRUE(resultSet->GetCount() == 2); + auto closeResultSetStatus = singleKvStoreVirtual->CloseResultSet(resultSet); + ASSERT_EQ(closeResultSetStatus, Status::SUCCESS); + Status statusVirtual4 = singleKvStoreVirtual->GetResultSet(queryVirtual, resultSet); + ASSERT_EQ(statusVirtual4, Status::SUCCESS); + ASSERT_TRUE(resultSet->GetCount() == 2); + + closeResultSetStatus = singleKvStoreVirtual->CloseResultSet(resultSet); + ASSERT_EQ(closeResultSetStatus, Status::SUCCESS); +} + +/** +* @tc.name: SingleKvStoreQueryNotEqualTo2 +* @tc.desc: queryVirtual single kvStore by dataQuery, the predicate is notEqualTo +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, SingleKvStoreQueryNotEqualTo2, TestSize.Level0) +{ + ZLOGI("SingleKvStoreQueryNotEqualTo2 begin."); + DistributedKvDataManager managerVirtual; + Options optionsVirtual1 = { .createIfMissing = true, .encrypt = true, .autoSync = true, + .kvStoreType = KvStoreType::SINGLE_VERSION, .schema = VALID_SCHEMA_STRICT_DEFINE }; + optionsVirtual1.area = EL1; + optionsVirtual1.securityLevel = S1; + optionsVirtual1.baseDir = "/data/service/el1/public/database/SingleKvStoreQueryVirtualTest"; + AppId appIdVirtual1 = { "SingleKvStoreQueryVirtualTest" }; + StoreId storeIdVirtual1 = { "SingleKvStoreClientQueryTestStoreId1" }; + statusVirtualGetKvStore = + managerVirtual.GetSingleKvStore(optionsVirtual1, appIdVirtual1, storeIdVirtual1, singleKvStoreVirtual1); + ASSERT_NE(singleKvStoreVirtual1, nullptr) << "kvStorePtr is null."; + singleKvStoreVirtual1->Put("test_key_1", "{\"name\":1}"); + singleKvStoreVirtual1->Put("test_key_2", "{\"name\":2}"); + singleKvStoreVirtual1->Put("test_key_3", "{\"name\":3}"); + + DataQuery queryVirtual1; + queryVirtual1.NotEqualTo("$.name", 3); + std::vector results; + Status statusVirtual1 = singleKvStoreVirtual->GetEntries(queryVirtual1, results); + ASSERT_EQ(statusVirtual1, Status::SUCCESS); + ASSERT_TRUE(results.size() == 2); + results.clear(); + Status statusVirtual2 = singleKvStoreVirtual->GetEntries(queryVirtual1, results); + ASSERT_EQ(statusVirtual2, Status::SUCCESS); + ASSERT_TRUE(results.size() == 2); + + int resultSize1; + Status statusVirtual5 = singleKvStoreVirtual->GetCount(queryVirtual1, resultSize1); + ASSERT_EQ(statusVirtual5, Status::SUCCESS); + ASSERT_TRUE(resultSize1 == 2); + int resultSize2; + Status statusVirtual6 = singleKvStoreVirtual->GetCount(queryVirtual1, resultSize2); + ASSERT_EQ(statusVirtual6, Status::SUCCESS); + ASSERT_TRUE(resultSize2 == 2); + + singleKvStoreVirtual->Delete("test_key_1"); + singleKvStoreVirtual->Delete("test_key_2"); + singleKvStoreVirtual->Delete("test_key_3"); + Status statusVirtual = managerVirtual.CloseAllKvStore(appIdVirtual); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + statusVirtual = managerVirtual.DeleteAllKvStore(appIdVirtual, optionsVirtual.baseDir); + ASSERT_EQ(statusVirtual, Status::SUCCESS); +} + +/** +* @tc.name: SingleKvStoreQueryNotEqualToAndEqualTo1 +* @tc.desc: queryVirtual single kvStore by dataQuery, the predicate is notEqualTo and equalTo +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, SingleKvStoreQueryNotEqualToAndEqualTo1, TestSize.Level0) +{ + ZLOGI("SingleKvStoreQueryNotEqualToAndEqualTo1 begin."); + DistributedKvDataManager managerVirtual; + Options optionsVirtual = { .createIfMissing = true, .encrypt = true, .autoSync = true, + .kvStoreType = KvStoreType::SINGLE_VERSION, .schema = VALID_SCHEMA_STRICT_DEFINE }; + optionsVirtual.area = EL1; + optionsVirtual.securityLevel = S1; + optionsVirtual.baseDir = "/data/service/el1/public/database/SingleKvStoreQueryVirtualTest"; + AppId appIdVirtual = { "SingleKvStoreQueryVirtualTest" }; + StoreId storeIdVirtual = { "SingleKvStoreClientQueryTestStoreId2" }; + statusVirtualGetKvStore = + managerVirtual.GetSingleKvStore(optionsVirtual, appIdVirtual, storeIdVirtual, singleKvStoreVirtual); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + singleKvStoreVirtual->Put("test_key_1", "{\"name\":1}"); + singleKvStoreVirtual->Put("test_key_2", "{\"name\":2}"); + singleKvStoreVirtual->Put("test_key_3", "{\"name\":3}"); + + DataQuery queryVirtual; + queryVirtual.NotEqualTo("$.name", 3); + queryVirtual.And(); + queryVirtual.EqualTo("$.name", 1); + std::vector results1; + Status statusVirtual1 = singleKvStoreVirtual->GetEntries(queryVirtual, results1); + ASSERT_EQ(statusVirtual1, Status::SUCCESS); + ASSERT_TRUE(results1.size() == 1); + std::vector results2; + Status statusVirtual2 = singleKvStoreVirtual->GetEntries(queryVirtual, results2); + ASSERT_EQ(statusVirtual2, Status::SUCCESS); + ASSERT_TRUE(results2.size() == 1); + + std::shared_ptr resultSet; + Status statusVirtual3 = singleKvStoreVirtual->GetResultSet(queryVirtual, resultSet); + ASSERT_EQ(statusVirtual3, Status::SUCCESS); + ASSERT_TRUE(resultSet->GetCount() == 1); + auto closeResultSetStatus = singleKvStoreVirtual->CloseResultSet(resultSet); + ASSERT_EQ(closeResultSetStatus, Status::SUCCESS); + Status statusVirtual4 = singleKvStoreVirtual->GetResultSet(queryVirtual, resultSet); + ASSERT_EQ(statusVirtual4, Status::SUCCESS); + ASSERT_TRUE(resultSet->GetCount() == 1); + + closeResultSetStatus = singleKvStoreVirtual->CloseResultSet(resultSet); + ASSERT_EQ(closeResultSetStatus, Status::SUCCESS); +} + +/** +* @tc.name: SingleKvStoreQueryNotEqualToAndEqualTo2 +* @tc.desc: queryVirtual single kvStore by dataQuery, the predicate is notEqualTo and equalTo +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, SingleKvStoreQueryNotEqualToAndEqualTo2, TestSize.Level0) +{ + ZLOGI("SingleKvStoreQueryNotEqualToAndEqualTo2 begin."); + DistributedKvDataManager managerVirtual; + Options optionsVirtual1 = { .createIfMissing = true, .encrypt = true, .autoSync = true, + .kvStoreType = KvStoreType::SINGLE_VERSION, .schema = VALID_SCHEMA_STRICT_DEFINE }; + optionsVirtual1.area = EL1; + optionsVirtual1.securityLevel = S1; + optionsVirtual1.baseDir = "/data/service/el1/public/database/SingleKvStoreQueryVirtualTest"; + AppId appIdVirtual = { "SingleKvStoreQueryVirtualTest" }; + StoreId storeIdVirtual = { "SingleKvStoreClientQueryTestStoreId2" }; + statusVirtualGetKvStore = + managerVirtual.GetSingleKvStore(optionsVirtual1, appIdVirtual, storeIdVirtual, singleKvStoreVirtual1); + ASSERT_NE(singleKvStoreVirtual1, nullptr) << "kvStorePtr is null."; + singleKvStoreVirtual1->Put("test_key_1", "{\"name\":1}"); + singleKvStoreVirtual1->Put("test_key_2", "{\"name\":2}"); + singleKvStoreVirtual1->Put("test_key_3", "{\"name\":3}"); + + DataQuery queryVirtual; + queryVirtual.NotEqualTo("$.name", 3); + queryVirtual.And(); + queryVirtual.EqualTo("$.name", 1); + std::vector results1; + Status statusVirtual1 = singleKvStoreVirtual1->GetEntries(queryVirtual, results1); + ASSERT_EQ(statusVirtual1, Status::SUCCESS); + ASSERT_TRUE(results1.size() == 1); + std::vector results2; + Status statusVirtual2 = singleKvStoreVirtual1->GetEntries(queryVirtual, results2); + ASSERT_EQ(statusVirtual2, Status::SUCCESS); + ASSERT_TRUE(results2.size() == 1); + + int resultSize1; + Status statusVirtual5 = singleKvStoreVirtual1->GetCount(queryVirtual, resultSize1); + ASSERT_EQ(statusVirtual5, Status::SUCCESS); + ASSERT_TRUE(resultSize1 == 1); + int resultSize2; + Status statusVirtual6 = singleKvStoreVirtual1->GetCount(queryVirtual, resultSize2); + ASSERT_EQ(statusVirtual6, Status::SUCCESS); + ASSERT_TRUE(resultSize2 == 1); + + singleKvStoreVirtual->Delete("test_key_1"); + singleKvStoreVirtual->Delete("test_key_2"); + singleKvStoreVirtual->Delete("test_key_3"); + Status statusVirtual = managerVirtual.CloseAllKvStore(appIdVirtual); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + statusVirtual = managerVirtual.DeleteAllKvStore(appIdVirtual, optionsVirtual.baseDir); + ASSERT_EQ(statusVirtual, Status::SUCCESS); +} + +/** +* @tc.name: DataQueryGroupAbnormal +* @tc.desc: queryVirtual group, the predicate is prefix, isNotNull, but field is invalid +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryGroupAbnormal, TestSize.Level0) +{ + ZLOGI("DataQueryGroupAbnormal begin."); + DataQuery queryVirtual; + queryVirtual.KeyPrefix(""); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.KeyPrefix("prefix^"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.Reset(); + queryVirtual.BeginGroup(); + queryVirtual.IsNotNull(""); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.IsNotNull("^$.name"); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.EndGroup(); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQueryByGroupNormal +* @tc.desc: queryVirtual group, the predicate is prefix, isNotNull. +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryByGroupNormal, TestSize.Level0) +{ + ZLOGI("DataQueryByGroupNormal begin."); + DataQuery queryVirtual; + queryVirtual.KeyPrefix("prefix"); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + queryVirtual.BeginGroup(); + queryVirtual.IsNotNull("$.name"); + queryVirtual.EndGroup(); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQuerySetSuggestIndexInvalidField +* @tc.desc: the predicate is setSuggestIndex, the field is invalid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: liuwenhui +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQuerySetSuggestIndexInvalidField, TestSize.Level0) +{ + ZLOGI("DataQuerySetSuggestIndexInvalidField begin."); + DataQuery queryVirtual; + queryVirtual.SetSuggestIndex(""); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.SetSuggestIndex("test_field^_name"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQuerySetSuggestIndexValidField +* @tc.desc: the predicate is setSuggestIndex, the field is valid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: liuwenhui +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQuerySetSuggestIndexValidField, TestSize.Level0) +{ + ZLOGI("DataQuerySetSuggestIndexValidField begin."); + DataQuery queryVirtual; + queryVirtual.SetSuggestIndex("test_field_name"); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQuerySetInKeys +* @tc.desc: the predicate is inKeys +* @tc.type: FUNC +* @tc.require: +* @tc.author: taoyuxin +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQuerySetInKeys, TestSize.Level0) +{ + ZLOGI("DataQuerySetInKeys begin."); + DataQuery queryVirtual; + queryVirtual.InKeys({}); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.InKeys({"test_field_name"}); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.InKeys({"test_field_name_hasKey"}); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + std::vector keys { "test_field", "", "^test_field", "^", "test_field_name" }; + queryVirtual.InKeys(keys); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); +} + +/** +* @tc.name: DataQueryDeviceIdInvalidField +* @tc.desc:the predicate is deviceId, the field is invalid +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryDeviceIdInvalidField, TestSize.Level0) +{ + ZLOGI("DataQueryDeviceIdInvalidField begin."); + DataQuery queryVirtual; + queryVirtual.DeviceId(""); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.DeviceId("$$^"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); + queryVirtual.DeviceId("device_id^"); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQueryDeviceIdValidField +* @tc.desc: the predicate is valid deviceId, the field is valid +* @tc.type: FUNC +* @tc.require: +* @tc.author: sql +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryDeviceIdValidField, TestSize.Level0) +{ + ZLOGI("DataQueryDeviceIdValidField begin."); + DataQuery queryVirtual; + queryVirtual.DeviceId("device_id"); + ASSERT_TRUE(queryVirtual.ToString().length() > 0); + queryVirtual.Reset(); + std::string deviceId = ""; + uint32_t i = 0; + while (i < MAX_QUERY_LENGTH) { + deviceId += "device"; + i++; + } + queryVirtual.DeviceId(deviceId); + ASSERT_TRUE(queryVirtual.ToString().length() == 0); +} + +/** +* @tc.name: DataQueryBetweenInvalid +* @tc.desc: the predicate is between, the value is invalid. +* @tc.type: FUNC +* @tc.require: +* @tc.author: SQL +*/ +HWTEST_F(SingleKvStoreQueryVirtualTest, DataQueryBetweenInvalid, TestSize.Level0) +{ + ZLOGI("DataQueryBetweenInvalid begin."); + DistributedKvDataManager managerVirtual; + Options optionsVirtual = { .createIfMissing = true, .encrypt = true, .autoSync = true, + .kvStoreType = KvStoreType::SINGLE_VERSION, .schema = VALID_SCHEMA_STRICT_DEFINE }; + optionsVirtual.area = EL1; + optionsVirtual.securityLevel = S1; + optionsVirtual.baseDir = "/data/service/el1/public/database/SingleKvStoreQueryVirtualTest"; + AppId appIdVirtual = { "SingleKvStoreQueryVirtualTest" }; + StoreId storeIdVirtual = { "SingleKvStoreClientQueryTestStoreId3" }; + statusVirtualGetKvStore = + managerVirtual.GetSingleKvStore(optionsVirtual, appIdVirtual, storeIdVirtual, singleKvStoreVirtual); + ASSERT_NE(singleKvStoreVirtual, nullptr) << "kvStorePtr is null."; + singleKvStoreVirtual->Put("test_key_1", "{\"name\":1}"); + singleKvStoreVirtual->Put("test_key_2", "{\"name\":2}"); + singleKvStoreVirtual->Put("test_key_3", "{\"name\":3}"); + + DataQuery queryVirtual; + queryVirtual.Between({}, {}); + std::vector results1; + Status statusVirtual = singleKvStoreVirtual->GetEntries(queryVirtual, results1); + ASSERT_EQ(statusVirtual, NOT_SUPPORT); + + singleKvStoreVirtual->Delete("test_key_1"); + singleKvStoreVirtual->Delete("test_key_2"); + singleKvStoreVirtual->Delete("test_key_3"); + statusVirtual = managerVirtual.CloseAllKvStore(appIdVirtual); + ASSERT_EQ(statusVirtual, Status::SUCCESS); + statusVirtual = managerVirtual.DeleteAllKvStore(appIdVirtual, optionsVirtual.baseDir); + ASSERT_EQ(statusVirtual, Status::SUCCESS); +} +} // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/databaseutils/test/single_store_impl_sham_test.cpp b/kv_store/databaseutils/test/single_store_impl_sham_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0375201ef14158bfa26f1b868633e4dedb2940b1 --- /dev/null +++ b/kv_store/databaseutils/test/single_store_impl_sham_test.cpp @@ -0,0 +1,2130 @@ +/* + * Copyright (c) 2024 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 "SingleStoreImplShamTest" + +#include "block_data.h" +#include "dev_manager.h" +#include "device_manager.h" +#include "distributed_kv_data_manager.h" +#include "dm_device_info.h" +#include "file_ex.h" +#include "kv_store_nb_delegate.h" +#include "single_store_impl.h" +#include "store_factory.h" +#include "store_manager.h" +#include "sys/stat.h" +#include "types.h" +#include +#include +#include + +using namespace testing::ext; +using namespace OHOS::DistributedKv; +using DBStatus = DistributedDB::DBStatus; +using DBStore = DistributedDB::KvStoreNbDelegate; +using SyncCallback = KvStoreSyncCallback; +using DevInfo = OHOS::DistributedHardware::DmDeviceInfo; +namespace OHOS::Test { +static constexpr int MAX_RESULTSET_SIZE = 8; +std::vector RandomSham(int32_t len) +{ + return std::vector(len, 'a'); +} + +class SingleStoreImplShamTest : public testing::Test { +public: + class TestObserverSham : public KvStoreObserver { + public: + TestObserverSham() + { + // The time interval parameter is 5. + data_ = std::make_shared>(5, false); + } + void OnChange(const ChangeNotification ¬ificationSham) override + { + insert_ = notificationSham.GetInsertEntries(); + update_ = notificationSham.GetUpdateEntries(); + delete_ = notificationSham.GetDeleteEntries(); + deviceId_ = notificationSham.GetDeviceId(); + bool valueSham = true; + data_->SetValue(valueSham); + } + std::vector insert_; + std::vector update_; + std::vector delete_; + std::string deviceId_; + + std::shared_ptr> data_; + }; + + std::shared_ptr CreateKVStore(std::string storeIdTest, KvStoreType type, bool encrypt, bool backup); + std::shared_ptr CreateKVStore(bool autosync = false); + std::shared_ptr kvStoreSham_; + + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void SingleStoreImplShamTest::SetUpTestCase(void) +{ + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + mkdir(baseDirSham.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); +} + +void SingleStoreImplShamTest::TearDownTestCase(void) +{ + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + StoreManager::GetInstance().Delete({ "SingleStoreImplShamTest" }, { "SingleKVStore" }, baseDirSham); + + (void)remove("/data/service/el1/public/database/SingleStoreImplShamTest/key"); + (void)remove("/data/service/el1/public/database/SingleStoreImplShamTest/kvdb"); + (void)remove("/data/service/el1/public/database/SingleStoreImplShamTest"); +} + +void SingleStoreImplShamTest::SetUp(void) +{ + kvStoreSham_ = CreateKVStore("SingleKVStore", SINGLE_VERSION, false, true); + if (kvStoreSham_ == nullptr) { + kvStoreSham_ = CreateKVStore("SingleKVStore", SINGLE_VERSION, false, true); + } + ASSERT_NE(kvStoreSham_, nullptr); +} + +void SingleStoreImplShamTest::TearDown(void) +{ + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "SingleKVStore" }; + kvStoreSham_ = nullptr; + auto statusSham = StoreManager::GetInstance().CloseKVStore(appIdSham, storeIdSham); + ASSERT_EQ(statusSham, SUCCESS); + auto baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + statusSham = StoreManager::GetInstance().Delete(appIdSham, storeIdSham, baseDirSham); + ASSERT_EQ(statusSham, SUCCESS); +} + +std::shared_ptr SingleStoreImplShamTest::CreateKVStore( + std::string storeIdTest, KvStoreType type, bool encrypt, bool backup) +{ + Options optionsSham; + optionsSham.kvStoreType = type; + optionsSham.securityLevel = S1; + optionsSham.encrypt = encrypt; + optionsSham.area = EL1; + optionsSham.backup = backup; + optionsSham.baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { storeIdTest }; + Status statusSham = StoreManager::GetInstance().Delete(appIdSham, storeIdSham, optionsSham.baseDirSham); + return StoreManager::GetInstance().GetKVStore(appIdSham, storeIdSham, optionsSham, statusSham); +} + +std::shared_ptr SingleStoreImplShamTest::CreateKVStore(bool autosync) +{ + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "DestructorTest" }; + std::shared_ptr kvStoreSham; + Options optionsSham; + optionsSham.kvStoreType = SINGLE_VERSION; + optionsSham.securityLevel = S2; + optionsSham.area = EL1; + optionsSham.autoSync = autosync; + optionsSham.baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + StoreFactory storeFactory; + auto dbManager = storeFactory.GetDBManager(optionsSham.baseDirSham, appIdSham); + auto dbPassword = SecurityManager::GetInstance().GetDBPassword( + storeIdSham.storeIdSham, optionsSham.baseDirSham, optionsSham.encrypt); + DBStatus dbStatus = DBStatus::DB_ERROR; + dbManager->GetKvStore(storeIdSham, storeFactory.GetDBOption(optionsSham, dbPassword), + [&dbManager, &kvStoreSham, &appIdSham, &dbStatus, &optionsSham, &storeFactory](auto statusSham, auto *store) { + dbStatus = statusSham; + if (store == nullptr) { + return; + } + auto release = [dbManager](auto *store) { + dbManager->CloseKvStore(store); + }; + auto dbStore = std::shared_ptr(store, release); + storeFactory.SetDbConfig(dbStore); + const Convertor &convertor = *(storeFactory.convertors_[optionsSham.kvStoreType]); + kvStoreSham = std::make_shared(dbStore, appIdSham, optionsSham, convertor); + }); + return kvStoreSham; +} + +/** + * @tc.name: GetStoreId + * @tc.desc: get the store id of the kv store + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetStoreId, TestSize.Level0) +{ + ZLOGI("GetStoreId start."); + ASSERT_NE(kvStoreSham_, nullptr); + auto storeIdSham = kvStoreSham_->GetStoreId(); + ASSERT_EQ(storeIdSham.storeIdSham, "SingleKVStore"); +} + +/** + * @tc.name: Put + * @tc.desc: put key-valueSham data to the kv store + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, Put, TestSize.Level0) +{ + ZLOGI("Put start."); + ASSERT_NE(kvStoreSham_, nullptr); + auto statusSham = kvStoreSham_->Put({ "Put Test" }, { "Put Value" }); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->Put({ " Put Test" }, { "Put2 Value" }); + ASSERT_EQ(statusSham, SUCCESS); + Value valueSham; + statusSham = kvStoreSham_->Get({ "Put Test" }, valueSham); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_EQ(valueSham.ToString(), "Put2 Value"); +} + +/** + * @tc.name: Put_Invalid_Key + * @tc.desc: put invalid key-valueSham data to the device kv store and single kv store + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author:SQL + */ +HWTEST_F(SingleStoreImplShamTest, Put_Invalid_Key, TestSize.Level0) +{ + ZLOGI("Put_Invalid_Key start."); + std::shared_ptr kvStoreSham; + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "DeviceKVStore" }; + kvStoreSham = CreateKVStore(storeIdSham.storeIdSham, DEVICE_COLLABORATION, false, true); + ASSERT_NE(kvStoreSham, nullptr); + + size_t maxDevKeyLen = 897; + std::string str(maxDevKeyLen, 'a'); + Blob key(str); + Blob valueSham("test_value"); + Status statusSham = kvStoreSham->Put(key, valueSham); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); + + Blob key1(""); + Blob value1("test_value1"); + statusSham = kvStoreSham->Put(key1, value1); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); + + kvStoreSham = nullptr; + statusSham = StoreManager::GetInstance().CloseKVStore(appIdSham, storeIdSham); + ASSERT_EQ(statusSham, SUCCESS); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + statusSham = StoreManager::GetInstance().Delete(appIdSham, storeIdSham, baseDirSham); + ASSERT_EQ(statusSham, SUCCESS); + + size_t maxSingleKeyLen = 1025; + std::string str1(maxSingleKeyLen, 'b'); + Blob key2(str1); + Blob value2("test_value2"); + statusSham = kvStoreSham_->Put(key2, value2); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); + + statusSham = kvStoreSham_->Put(key1, value1); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); +} + +/** + * @tc.name: PutBatch + * @tc.desc: put some key-valueSham data to the kv store + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, PutBatch, TestSize.Level0) +{ + ZLOGI("PutBatch start."); + ASSERT_NE(kvStoreSham_, nullptr); + std::vector entries; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueSham = std::to_string(i).append("_v"); + entries.push_back(entry); + } + auto statusSham = kvStoreSham_->PutBatch(entries); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: IsRebuild + * @tc.desc: test IsRebuild + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplShamTest, IsRebuild, TestSize.Level0) +{ + ZLOGI("IsRebuild start."); + ASSERT_NE(kvStoreSham_, nullptr); + auto statusSham = kvStoreSham_->IsRebuild(); + ASSERT_EQ(statusSham, false); +} + +/** + * @tc.name: PutBatch001 + * @tc.desc: entry.valueSham.Size() > MAX_VALUE_LENGTH + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplShamTest, PutBatch001, TestSize.Level0) +{ + ZLOGI("PutBatch001 start."); + ASSERT_NE(kvStoreSham_, nullptr); + size_t totalLength = SingleStoreImpl::MAX_VALUE_LENGTH + 1; // create an out-of-limit large number + char fillChar = 'a'; + std::string longString(totalLength, fillChar); + std::vector entries; + Entry entry; + entry.key = "PutBatch001_test"; + entry.valueSham = longString; + entries.push_back(entry); + auto statusSham = kvStoreSham_->PutBatch(entries); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); + entries.clear(); + Entry entrys; + entrys.key = ""; + entrys.valueSham = "PutBatch001_test_value"; + entries.push_back(entrys); + statusSham = kvStoreSham_->PutBatch(entries); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); +} + +/** + * @tc.name: Delete + * @tc.desc: delete the valueSham of the key + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, Delete, TestSize.Level0) +{ + ZLOGI("Delete start."); + ASSERT_NE(kvStoreSham_, nullptr); + auto statusSham = kvStoreSham_->Put({ "Put Test" }, { "Put Value" }); + ASSERT_EQ(statusSham, SUCCESS); + Value valueSham; + statusSham = kvStoreSham_->Get({ "Put Test" }, valueSham); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_EQ(std::string("Put Value"), valueSham.ToString()); + statusSham = kvStoreSham_->Delete({ "Put Test" }); + ASSERT_EQ(statusSham, SUCCESS); + valueSham = {}; + statusSham = kvStoreSham_->Get({ "Put Test" }, valueSham); + ASSERT_EQ(statusSham, KEY_NOT_FOUND); + ASSERT_EQ(std::string(""), valueSham.ToString()); +} + +/** + * @tc.name: DeleteBatch + * @tc.desc: delete the values of the keys + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, DeleteBatch, TestSize.Level0) +{ + ZLOGI("DeleteBatch start."); + ASSERT_NE(kvStoreSham_, nullptr); + std::vector entries; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueSham = std::to_string(i).append("_v"); + entries.push_back(entry); + } + auto statusSham = kvStoreSham_->PutBatch(entries); + ASSERT_EQ(statusSham, SUCCESS); + std::vector keys; + for (int i = 0; i < 10; ++i) { + Key key = std::to_string(i).append("_k"); + keys.push_back(key); + } + statusSham = kvStoreSham_->DeleteBatch(keys); + ASSERT_EQ(statusSham, SUCCESS); + for (int i = 0; i < 10; ++i) { + Value valueSham; + statusSham = kvStoreSham_->Get(keys[i], valueSham); + ASSERT_EQ(statusSham, KEY_NOT_FOUND); + ASSERT_EQ(valueSham.ToString(), std::string("")); + } +} + +/** + * @tc.name: Transaction + * @tc.desc: do transaction + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, Transaction, TestSize.Level0) +{ + ZLOGI("Transaction start."); + ASSERT_NE(kvStoreSham_, nullptr); + auto statusSham = kvStoreSham_->StartTransaction(); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->Commit(); + ASSERT_EQ(statusSham, SUCCESS); + + statusSham = kvStoreSham_->StartTransaction(); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->Rollback(); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: SubscribeKvStore + * @tc.desc: subscribe local + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, SubscribeKvStore, TestSize.Level0) +{ + ZLOGI("SubscribeKvStore start."); + ASSERT_NE(kvStoreSham_, nullptr); + auto observer = std::make_shared(); + auto statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, observer); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_REMOTE, observer); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_CLOUD, observer); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, observer); + ASSERT_EQ(statusSham, STORE_ALREADY_SUBSCRIBE); + statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_REMOTE, observer); + ASSERT_EQ(statusSham, STORE_ALREADY_SUBSCRIBE); + statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_CLOUD, observer); + ASSERT_EQ(statusSham, STORE_ALREADY_SUBSCRIBE); + statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_ALL, observer); + ASSERT_EQ(statusSham, STORE_ALREADY_SUBSCRIBE); + bool invalidValue = false; + observer->data_->Clear(invalidValue); + statusSham = kvStoreSham_->Put({ "Put Test" }, { "Put Value" }); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_TRUE(observer->data_->GetValue()); + ASSERT_EQ(observer->insert_.size(), 1); + ASSERT_EQ(observer->update_.size(), 0); + ASSERT_EQ(observer->delete_.size(), 0); + observer->data_->Clear(invalidValue); + statusSham = kvStoreSham_->Put({ "Put Test" }, { "Put Value1" }); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_TRUE(observer->data_->GetValue()); + ASSERT_EQ(observer->insert_.size(), 0); + ASSERT_EQ(observer->update_.size(), 1); + ASSERT_EQ(observer->delete_.size(), 0); + observer->data_->Clear(invalidValue); + statusSham = kvStoreSham_->Delete({ "Put Test" }); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_TRUE(observer->data_->GetValue()); + ASSERT_EQ(observer->insert_.size(), 0); + ASSERT_EQ(observer->update_.size(), 0); + ASSERT_EQ(observer->delete_.size(), 1); +} + +/** + * @tc.name: SubscribeKvStore002 + * @tc.desc: subscribe local + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: Hollokin + */ +HWTEST_F(SingleStoreImplShamTest, SubscribeKvStore002, TestSize.Level0) +{ + ZLOGI("SubscribeKvStore002 start."); + ASSERT_NE(kvStoreSham_, nullptr); + std::shared_ptr subscribedObserver; + std::shared_ptr unSubscribedObserver; + for (int i = 0; i < 15; ++i) { + auto observer = std::make_shared(); + auto status1 = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, observer); + auto status2 = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_REMOTE, observer); + if (i < 8) { + ASSERT_EQ(status1, SUCCESS); + ASSERT_EQ(status2, SUCCESS); + subscribedObserver = observer; + } else { + ASSERT_EQ(status1, OVER_MAX_LIMITS); + ASSERT_EQ(status2, OVER_MAX_LIMITS); + unSubscribedObserver = observer; + } + } + + auto statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, subscribedObserver); + ASSERT_EQ(statusSham, STORE_ALREADY_SUBSCRIBE); + + statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, {}); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); + + statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_REMOTE, subscribedObserver); + ASSERT_EQ(statusSham, STORE_ALREADY_SUBSCRIBE); + + statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_ALL, subscribedObserver); + ASSERT_EQ(statusSham, SUCCESS); + + statusSham = kvStoreSham_->UnSubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, subscribedObserver); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, subscribedObserver); + ASSERT_EQ(statusSham, SUCCESS); + + statusSham = kvStoreSham_->UnSubscribeKvStore(SUBSCRIBE_TYPE_ALL, subscribedObserver); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, unSubscribedObserver); + ASSERT_EQ(statusSham, SUCCESS); + subscribedObserver = unSubscribedObserver; + statusSham = kvStoreSham_->UnSubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, subscribedObserver); + ASSERT_EQ(statusSham, SUCCESS); + auto observer = std::make_shared(); + statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, observer); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_ALL, observer); + ASSERT_EQ(statusSham, SUCCESS); + observer = std::make_shared(); + statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_ALL, observer); + ASSERT_EQ(statusSham, OVER_MAX_LIMITS); +} + +/** + * @tc.name: SubscribeKvStore003 + * @tc.desc: isClientSync_ + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplShamTest, SubscribeKvStore003, TestSize.Level0) +{ + ZLOGI("SubscribeKvStore003 start."); + auto observer = std::make_shared(); + std::shared_ptr kvStoreSham; + kvStoreSham = CreateKVStore(); + ASSERT_NE(kvStoreSham, nullptr); + kvStoreSham->isClientSync_ = true; + auto statusSham = kvStoreSham->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, observer); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: UnsubscribeKvStore + * @tc.desc: unsubscribe + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, UnsubscribeKvStore, TestSize.Level0) +{ + ZLOGI("UnsubscribeKvStore start."); + ASSERT_NE(kvStoreSham_, nullptr); + auto observer = std::make_shared(); + auto statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_ALL, observer); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->UnSubscribeKvStore(SUBSCRIBE_TYPE_REMOTE, observer); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->UnSubscribeKvStore(SUBSCRIBE_TYPE_CLOUD, observer); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->UnSubscribeKvStore(SUBSCRIBE_TYPE_REMOTE, observer); + ASSERT_EQ(statusSham, STORE_NOT_SUBSCRIBE); + statusSham = kvStoreSham_->UnSubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, observer); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->UnSubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, observer); + ASSERT_EQ(statusSham, STORE_NOT_SUBSCRIBE); + statusSham = kvStoreSham_->UnSubscribeKvStore(SUBSCRIBE_TYPE_ALL, observer); + ASSERT_EQ(statusSham, STORE_NOT_SUBSCRIBE); + statusSham = kvStoreSham_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, observer); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->UnSubscribeKvStore(SUBSCRIBE_TYPE_ALL, observer); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: GetEntries_Prefix + * @tc.desc: get entries by prefix + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetEntries_Prefix, TestSize.Level0) +{ + ZLOGI("GetEntries_Prefix start."); + ASSERT_NE(kvStoreSham_, nullptr); + std::vector input; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueSham = std::to_string(i).append("_v"); + input.push_back(entry); + } + auto statusSham = kvStoreSham_->PutBatch(input); + ASSERT_EQ(statusSham, SUCCESS); + std::vector output; + statusSham = kvStoreSham_->GetEntries({ "" }, output); + ASSERT_EQ(statusSham, SUCCESS); + std::sort(output.start(), output.end(), [](const Entry &entry, const Entry &sentry) { + return entry.key.Data() < sentry.key.Data(); + }); + for (int i = 0; i < 10; ++i) { + ASSERT_TRUE(input[i].key == output[i].key); + ASSERT_TRUE(input[i].valueSham == output[i].valueSham); + } +} + +/** + * @tc.name: GetEntries_Less_Prefix + * @tc.desc: get entries by prefix and the key size less than sizeof(uint32_t) + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author:SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetEntries_Less_Prefix, TestSize.Level0) +{ + ZLOGI("GetEntries_Less_Prefix start."); + std::shared_ptr kvStoreSham; + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "DeviceKVStore" }; + kvStoreSham = CreateKVStore(storeIdSham.storeIdSham, DEVICE_COLLABORATION, false, true); + ASSERT_NE(kvStoreSham, nullptr); + + std::vector input; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueSham = std::to_string(i).append("_v"); + input.push_back(entry); + } + auto statusSham = kvStoreSham->PutBatch(input); + ASSERT_EQ(statusSham, SUCCESS); + std::vector output; + statusSham = kvStoreSham->GetEntries({ "1" }, output); + ASSERT_NE(output.empty(), true); + ASSERT_EQ(statusSham, SUCCESS); + + kvStoreSham = nullptr; + statusSham = StoreManager::GetInstance().CloseKVStore(appIdSham, storeIdSham); + ASSERT_EQ(statusSham, SUCCESS); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + statusSham = StoreManager::GetInstance().Delete(appIdSham, storeIdSham, baseDirSham); + ASSERT_EQ(statusSham, SUCCESS); + + statusSham = kvStoreSham_->PutBatch(input); + ASSERT_EQ(statusSham, SUCCESS); + std::vector output1; + statusSham = kvStoreSham_->GetEntries({ "1" }, output1); + ASSERT_NE(output1.empty(), true); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: GetEntries_Greater_Prefix + * @tc.desc: get entries by prefix and the key size is greater than sizeof(uint32_t) + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author:SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetEntries_Greater_Prefix, TestSize.Level0) +{ + ZLOGI("GetEntries_Greater_Prefix start."); + std::shared_ptr kvStoreSham; + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "DeviceKVStore" }; + kvStoreSham = CreateKVStore(storeIdSham.storeIdSham, DEVICE_COLLABORATION, false, true); + ASSERT_NE(kvStoreSham, nullptr); + + size_t keyLen = sizeof(uint32_t); + std::vector input; + for (int i = 1; i < 10; ++i) { + Entry entry; + std::string str(keyLen, i + '0'); + entry.key = str; + entry.valueSham = std::to_string(i).append("_v"); + input.push_back(entry); + } + auto statusSham = kvStoreSham->PutBatch(input); + ASSERT_EQ(statusSham, SUCCESS); + std::vector output; + std::string str1(keyLen, '1'); + statusSham = kvStoreSham->GetEntries(str1, output); + ASSERT_NE(output.empty(), true); + ASSERT_EQ(statusSham, SUCCESS); + + kvStoreSham = nullptr; + statusSham = StoreManager::GetInstance().CloseKVStore(appIdSham, storeIdSham); + ASSERT_EQ(statusSham, SUCCESS); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + statusSham = StoreManager::GetInstance().Delete(appIdSham, storeIdSham, baseDirSham); + ASSERT_EQ(statusSham, SUCCESS); + + statusSham = kvStoreSham_->PutBatch(input); + ASSERT_EQ(statusSham, SUCCESS); + std::vector output1; + statusSham = kvStoreSham_->GetEntries(str1, output1); + ASSERT_NE(output1.empty(), true); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: GetEntries_DataQuery + * @tc.desc: get entries by query + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetEntries_DataQuery, TestSize.Level0) +{ + ZLOGI("GetEntries_DataQuery start."); + ASSERT_NE(kvStoreSham_, nullptr); + std::vector input; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueSham = std::to_string(i).append("_v"); + input.push_back(entry); + } + auto statusSham = kvStoreSham_->PutBatch(input); + ASSERT_EQ(statusSham, SUCCESS); + DataQuery query; + query.InKeys({ "0_k", "1_k" }); + std::vector output; + statusSham = kvStoreSham_->GetEntries(query, output); + ASSERT_EQ(statusSham, SUCCESS); + std::sort(output.start(), output.end(), [](const Entry &entry, const Entry &sentry) { + return entry.key.Data() < sentry.key.Data(); + }); + ASSERT_LE(output.size(), 2); + for (size_t i = 0; i < output.size(); ++i) { + ASSERT_TRUE(input[i].key == output[i].key); + ASSERT_TRUE(input[i].valueSham == output[i].valueSham); + } +} + +/** + * @tc.name: GetResultSet_Prefix + * @tc.desc: get result set by prefix + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetResultSet_Prefix, TestSize.Level0) +{ + ZLOGI("GetResultSet_Prefix start."); + ASSERT_NE(kvStoreSham_, nullptr); + std::vector input; + auto cmp = [](const Key &entry, const Key &sentry) { + return entry.Data() < sentry.Data(); + }; + std::map dictionary(cmp); + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueSham = std::to_string(i).append("_v"); + dictionary[entry.key] = entry.valueSham; + input.push_back(entry); + } + auto statusSham = kvStoreSham_->PutBatch(input); + ASSERT_EQ(statusSham, SUCCESS); + std::shared_ptr output; + statusSham = kvStoreSham_->GetResultSet({ "" }, output); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_NE(output, nullptr); + ASSERT_EQ(output->GetCount(), 10); + int count = 0; + while (output->MoveToNext()) { + count++; + Entry entry; + output->GetEntry(entry); + ASSERT_EQ(entry.valueSham.Data(), dictionary[entry.key].Data()); + } + ASSERT_EQ(count, output->GetCount()); +} + +/** + * @tc.name: GetResultSet_Query + * @tc.desc: get result set by query + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetResultSet_Query, TestSize.Level0) +{ + ZLOGI("GetResultSet_Query start."); + ASSERT_NE(kvStoreSham_, nullptr); + std::vector input; + auto cmp = [](const Key &entry, const Key &sentry) { + return entry.Data() < sentry.Data(); + }; + std::map dictionary(cmp); + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueSham = std::to_string(i).append("_v"); + dictionary[entry.key] = entry.valueSham; + input.push_back(entry); + } + auto statusSham = kvStoreSham_->PutBatch(input); + ASSERT_EQ(statusSham, SUCCESS); + DataQuery query; + query.InKeys({ "0_k", "1_k" }); + std::shared_ptr output; + statusSham = kvStoreSham_->GetResultSet(query, output); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_NE(output, nullptr); + ASSERT_LE(output->GetCount(), 2); + int count = 0; + while (output->MoveToNext()) { + count++; + Entry entry; + output->GetEntry(entry); + ASSERT_EQ(entry.valueSham.Data(), dictionary[entry.key].Data()); + } + ASSERT_EQ(count, output->GetCount()); +} + +/** + * @tc.name: CloseResultSet + * @tc.desc: close the result set + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, CloseResultSet, TestSize.Level0) +{ + ZLOGI("CloseResultSet start."); + ASSERT_NE(kvStoreSham_, nullptr); + std::vector input; + auto cmp = [](const Key &entry, const Key &sentry) { + return entry.Data() < sentry.Data(); + }; + std::map dictionary(cmp); + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueSham = std::to_string(i).append("_v"); + dictionary[entry.key] = entry.valueSham; + input.push_back(entry); + } + auto statusSham = kvStoreSham_->PutBatch(input); + ASSERT_EQ(statusSham, SUCCESS); + DataQuery query; + query.InKeys({ "0_k", "1_k" }); + std::shared_ptr output; + statusSham = kvStoreSham_->GetResultSet(query, output); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_NE(output, nullptr); + ASSERT_LE(output->GetCount(), 2); + auto outputTmp = output; + statusSham = kvStoreSham_->CloseResultSet(output); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_EQ(output, nullptr); + ASSERT_EQ(outputTmp->GetCount(), KvStoreResultSet::INVALID_COUNT); + ASSERT_EQ(outputTmp->GetPosition(), KvStoreResultSet::INVALID_POSITION); + ASSERT_EQ(outputTmp->MoveToFirst(), false); + ASSERT_EQ(outputTmp->MoveToLast(), false); + ASSERT_EQ(outputTmp->MoveToNext(), false); + ASSERT_EQ(outputTmp->MoveToPrevious(), false); + ASSERT_EQ(outputTmp->Move(1), false); + ASSERT_EQ(outputTmp->MoveToPosition(1), false); + ASSERT_EQ(outputTmp->IsFirst(), false); + ASSERT_EQ(outputTmp->IsLast(), false); + ASSERT_EQ(outputTmp->IsBeforeFirst(), false); + ASSERT_EQ(outputTmp->IsAfterLast(), false); + Entry entry; + ASSERT_EQ(outputTmp->GetEntry(entry), ALREADY_CLOSED); +} + +/** + * @tc.name: CloseResultSet001 + * @tc.desc: output = nullptr; + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplShamTest, CloseResultSet001, TestSize.Level0) +{ + ZLOGI("CloseResultSet001 start."); + ASSERT_NE(kvStoreSham_, nullptr); + std::shared_ptr output; + output = nullptr; + auto statusSham = kvStoreSham_->CloseResultSet(output); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); +} + +/** + * @tc.name: ResultSetMaxSizeTest_Query + * @tc.desc: test if kv supports 8 resultSets at the same time + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, ResultSetMaxSizeTest_Query, TestSize.Level0) +{ + ZLOGI("ResultSetMaxSizeTest_Query start."); + ASSERT_NE(kvStoreSham_, nullptr); + /** + * @tc.steps:step1. Put the entry into the database. + * @tc.expected: step1. Returns SUCCESS. + */ + std::vector input; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = "k_" + std::to_string(i); + entry.valueSham = "v_" + std::to_string(i); + input.push_back(entry); + } + auto statusSham = kvStoreSham_->PutBatch(input); + ASSERT_EQ(statusSham, SUCCESS); + /** + * @tc.steps:step2. Get the resultset. + * @tc.expected: step2. Returns SUCCESS. + */ + DataQuery query; + query.KeyPrefix("k_"); + std::vector> outputs(MAX_RESULTSET_SIZE + 1); + for (int i = 0; i < MAX_RESULTSET_SIZE; i++) { + std::shared_ptr output; + statusSham = kvStoreSham_->GetResultSet(query, outputs[i]); + ASSERT_EQ(statusSham, SUCCESS); + } + /** + * @tc.steps:step3. Get the resultset while resultset size is over the limit. + * @tc.expected: step3. Returns OVER_MAX_LIMITS. + */ + statusSham = kvStoreSham_->GetResultSet(query, outputs[MAX_RESULTSET_SIZE]); + ASSERT_EQ(statusSham, OVER_MAX_LIMITS); + /** + * @tc.steps:step4. Close the resultset and getting the resultset is retried + * @tc.expected: step4. Returns SUCCESS. + */ + statusSham = kvStoreSham_->CloseResultSet(outputs[0]); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->GetResultSet(query, outputs[MAX_RESULTSET_SIZE]); + ASSERT_EQ(statusSham, SUCCESS); + + for (int i = 1; i <= MAX_RESULTSET_SIZE; i++) { + statusSham = kvStoreSham_->CloseResultSet(outputs[i]); + ASSERT_EQ(statusSham, SUCCESS); + } +} + +/** + * @tc.name: ResultSetMaxSizeTest_Prefix + * @tc.desc: test if kv supports 8 resultSets at the same time + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, ResultSetMaxSizeTest_Prefix, TestSize.Level0) +{ + ZLOGI("ResultSetMaxSizeTest_Prefix start."); + ASSERT_NE(kvStoreSham_, nullptr); + /** + * @tc.steps:step1. Put the entry into the database. + * @tc.expected: step1. Returns SUCCESS. + */ + std::vector input; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = "k_" + std::to_string(i); + entry.valueSham = "v_" + std::to_string(i); + input.push_back(entry); + } + auto statusSham = kvStoreSham_->PutBatch(input); + ASSERT_EQ(statusSham, SUCCESS); + /** + * @tc.steps:step2. Get the resultset. + * @tc.expected: step2. Returns SUCCESS. + */ + std::vector> outputs(MAX_RESULTSET_SIZE + 1); + for (int i = 0; i < MAX_RESULTSET_SIZE; i++) { + std::shared_ptr output; + statusSham = kvStoreSham_->GetResultSet({ "k_i" }, outputs[i]); + ASSERT_EQ(statusSham, SUCCESS); + } + /** + * @tc.steps:step3. Get the resultset while resultset size is over the limit. + * @tc.expected: step3. Returns OVER_MAX_LIMITS. + */ + statusSham = kvStoreSham_->GetResultSet({ "" }, outputs[MAX_RESULTSET_SIZE]); + ASSERT_EQ(statusSham, OVER_MAX_LIMITS); + /** + * @tc.steps:step4. Close the resultset and getting the resultset is retried + * @tc.expected: step4. Returns SUCCESS. + */ + statusSham = kvStoreSham_->CloseResultSet(outputs[0]); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->GetResultSet({ "" }, outputs[MAX_RESULTSET_SIZE]); + ASSERT_EQ(statusSham, SUCCESS); + + for (int i = 1; i <= MAX_RESULTSET_SIZE; i++) { + statusSham = kvStoreSham_->CloseResultSet(outputs[i]); + ASSERT_EQ(statusSham, SUCCESS); + } +} + +/** + * @tc.name: MaxLogSizeTest + * @tc.desc: test if the default max limit of wal is 200MB + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, MaxLogSizeTest, TestSize.Level0) +{ + ZLOGI("MaxLogSizeTest start."); + ASSERT_NE(kvStoreSham_, nullptr); + /** + * @tc.steps:step1. Put the random entry into the database. + * @tc.expected: step1. Returns SUCCESS. + */ + std::string key; + std::vector valueSham = RandomSham(4 * 1024 * 1024); + key = "test0"; + ASSERT_EQ(kvStoreSham_->Put(key, valueSham), SUCCESS); + key = "test1"; + ASSERT_EQ(kvStoreSham_->Put(key, valueSham), SUCCESS); + key = "test2"; + ASSERT_EQ(kvStoreSham_->Put(key, valueSham), SUCCESS); + /** + * @tc.steps:step2. Get the resultset. + * @tc.expected: step2. Returns SUCCESS. + */ + std::shared_ptr output; + auto statusSham = kvStoreSham_->GetResultSet({ "" }, output); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_NE(output, nullptr); + ASSERT_EQ(output->GetCount(), 3); + ASSERT_EQ(output->MoveToFirst(), true); + /** + * @tc.steps:step3. Put more data into the database. + * @tc.expected: step3. Returns SUCCESS. + */ + for (int i = 0; i < 50; i++) { + key = "test_" + std::to_string(i); + ASSERT_EQ(kvStoreSham_->Put(key, valueSham), SUCCESS); + } + /** + * @tc.steps:step4. Put more data into the database while the log size is over the limit. + * @tc.expected: step4. Returns LOG_LIMITS_ERROR. + */ + key = "test3"; + ASSERT_EQ(kvStoreSham_->Put(key, valueSham), WAL_OVER_LIMITS); + ASSERT_EQ(kvStoreSham_->Delete(key), WAL_OVER_LIMITS); + ASSERT_EQ(kvStoreSham_->StartTransaction(), WAL_OVER_LIMITS); + /** + * @tc.steps:step5. Close the resultset and put again. + * @tc.expected: step4. Return SUCCESS. + */ + + statusSham = kvStoreSham_->CloseResultSet(output); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_EQ(kvStoreSham_->Put(key, valueSham), SUCCESS); +} + +/** + * @tc.name: MaxLogSizeTest002 + * @tc.desc: test if the default max limit of wal is 200MB + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, MaxLogSizeTest002, TestSize.Level0) +{ + ASSERT_NE(kvStoreSham_, nullptr); + /** + * @tc.steps:step1. Put the random entry into the database. + * @tc.expected: step1. Returns SUCCESS. + */ + std::string key; + std::vector valueSham = RandomSham(4 * 1024 * 1024); + key = "test0"; + ASSERT_EQ(kvStoreSham_->Put(key, valueSham), SUCCESS); + key = "test1"; + ASSERT_EQ(kvStoreSham_->Put(key, valueSham), SUCCESS); + key = "test2"; + ASSERT_EQ(kvStoreSham_->Put(key, valueSham), SUCCESS); + /** + * @tc.steps:step2. Get the resultset. + * @tc.expected: step2. Returns SUCCESS. + */ + std::shared_ptr output; + auto statusSham = kvStoreSham_->GetResultSet({ "" }, output); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_NE(output, nullptr); + ASSERT_EQ(output->GetCount(), 3); + ASSERT_EQ(output->MoveToFirst(), true); + /** + * @tc.steps:step3. Put more data into the database. + * @tc.expected: step3. Returns SUCCESS. + */ + for (int i = 0; i < 50; i++) { + key = "test_" + std::to_string(i); + ASSERT_EQ(kvStoreSham_->Put(key, valueSham), SUCCESS); + } + /** + * @tc.steps:step4. Put more data into the database while the log size is over the limit. + * @tc.expected: step4. Returns LOG_LIMITS_ERROR. + */ + key = "test3"; + ASSERT_EQ(kvStoreSham_->Put(key, valueSham), WAL_OVER_LIMITS); + ASSERT_EQ(kvStoreSham_->Delete(key), WAL_OVER_LIMITS); + ASSERT_EQ(kvStoreSham_->StartTransaction(), WAL_OVER_LIMITS); + statusSham = kvStoreSham_->CloseResultSet(output); + ASSERT_EQ(statusSham, SUCCESS); + /** + * @tc.steps:step5. Close the database and then open the database,put again. + * @tc.expected: step4. Return SUCCESS. + */ + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "SingleKVStore" }; + Options optionsSham; + optionsSham.kvStoreType = SINGLE_VERSION; + optionsSham.securityLevel = S1; + optionsSham.encrypt = false; + optionsSham.area = EL1; + optionsSham.backup = true; + optionsSham.baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + + statusSham = StoreManager::GetInstance().CloseKVStore(appIdSham, storeIdSham); + ASSERT_EQ(statusSham, SUCCESS); + kvStoreSham_ = nullptr; + kvStoreSham_ = StoreManager::GetInstance().GetKVStore(appIdSham, storeIdSham, optionsSham, statusSham); + ASSERT_EQ(statusSham, SUCCESS); + + statusSham = kvStoreSham_->GetResultSet({ "" }, output); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_NE(output, nullptr); + ASSERT_EQ(output->MoveToFirst(), true); + + ASSERT_EQ(kvStoreSham_->Put(key, valueSham), SUCCESS); + statusSham = kvStoreSham_->CloseResultSet(output); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: Move_Offset + * @tc.desc: Move the ResultSet Relative Distance + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author:SQL + */ +HWTEST_F(SingleStoreImplShamTest, Move_Offset, TestSize.Level0) +{ + ZLOGI("Move_Offset start."); + std::vector input; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueSham = std::to_string(i).append("_v"); + input.push_back(entry); + } + auto statusSham = kvStoreSham_->PutBatch(input); + ASSERT_EQ(statusSham, SUCCESS); + + Key prefix = "2"; + std::shared_ptr output; + statusSham = kvStoreSham_->GetResultSet(prefix, output); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_NE(output, nullptr); + + auto outputTmp = output; + ASSERT_EQ(outputTmp->Move(1), true); + statusSham = kvStoreSham_->CloseResultSet(output); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_EQ(output, nullptr); + + std::shared_ptr kvStoreSham; + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "DeviceKVStore" }; + kvStoreSham = CreateKVStore(storeIdSham.storeIdSham, DEVICE_COLLABORATION, false, true); + ASSERT_NE(kvStoreSham, nullptr); + + statusSham = kvStoreSham->PutBatch(input); + ASSERT_EQ(statusSham, SUCCESS); + std::shared_ptr output1; + statusSham = kvStoreSham->GetResultSet(prefix, output1); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_NE(output1, nullptr); + auto outputTmp1 = output1; + ASSERT_EQ(outputTmp1->Move(1), true); + statusSham = kvStoreSham->CloseResultSet(output1); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_EQ(output1, nullptr); + + kvStoreSham = nullptr; + statusSham = StoreManager::GetInstance().CloseKVStore(appIdSham, storeIdSham); + ASSERT_EQ(statusSham, SUCCESS); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + statusSham = StoreManager::GetInstance().Delete(appIdSham, storeIdSham, baseDirSham); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: GetCount + * @tc.desc: close the result set + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetCount, TestSize.Level0) +{ + ZLOGI("GetCount start."); + ASSERT_NE(kvStoreSham_, nullptr); + std::vector input; + auto cmp = [](const Key &entry, const Key &sentry) { + return entry.Data() < sentry.Data(); + }; + std::map dictionary(cmp); + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueSham = std::to_string(i).append("_v"); + dictionary[entry.key] = entry.valueSham; + input.push_back(entry); + } + auto statusSham = kvStoreSham_->PutBatch(input); + ASSERT_EQ(statusSham, SUCCESS); + DataQuery query; + query.InKeys({ "0_k", "1_k" }); + int count = 0; + statusSham = kvStoreSham_->GetCount(query, count); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_EQ(count, 2); + query.Reset(); + statusSham = kvStoreSham_->GetCount(query, count); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_EQ(count, 10); +} + +void ChangeOwnerToService(std::string baseDirSham, std::string hashId) +{ + ZLOGI("ChangeOwnerToService start."); + static constexpr int ddmsId = 3012; + std::string path = baseDirSham; + chown(path.c_str(), ddmsId, ddmsId); + path = path + "/kvdb"; + chown(path.c_str(), ddmsId, ddmsId); + path = path + "/" + hashId; + chown(path.c_str(), ddmsId, ddmsId); + path = path + "/single_ver"; + chown(path.c_str(), ddmsId, ddmsId); + chown((path + "/meta").c_str(), ddmsId, ddmsId); + chown((path + "/cache").c_str(), ddmsId, ddmsId); + path = path + "/main"; + chown(path.c_str(), ddmsId, ddmsId); + chown((path + "/gen_natural_store.db").c_str(), ddmsId, ddmsId); + chown((path + "/gen_natural_store.db-shm").c_str(), ddmsId, ddmsId); + chown((path + "/gen_natural_store.db-wal").c_str(), ddmsId, ddmsId); +} + +/** + * @tc.name: RemoveDeviceData + * @tc.desc: remove local device data + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, RemoveDeviceData, TestSize.Level0) +{ + ZLOGI("RemoveDeviceData start."); + auto store = CreateKVStore("DeviceKVStore", DEVICE_COLLABORATION, false, true); + ASSERT_NE(store, nullptr); + std::vector input; + auto cmp = [](const Key &entry, const Key &sentry) { + return entry.Data() < sentry.Data(); + }; + std::map dictionary(cmp); + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueSham = std::to_string(i).append("_v"); + dictionary[entry.key] = entry.valueSham; + input.push_back(entry); + } + auto statusSham = store->PutBatch(input); + ASSERT_EQ(statusSham, SUCCESS); + int count = 0; + statusSham = store->GetCount({}, count); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_EQ(count, 10); + ChangeOwnerToService("/data/service/el1/public/database/SingleStoreImplShamTest", + "703c6ec99aa7226bb9f6194cdd60e1873ea9ee52faebd55657ade9f5a5cc3cbd"); + statusSham = store->RemoveDeviceData(DevManager::GetInstance().GetLocalDevice().networkId); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = store->GetCount({}, count); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_EQ(count, 10); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + statusSham = StoreManager::GetInstance().Delete({ "SingleStoreImplShamTest" }, { "DeviceKVStore" }, baseDirSham); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: GetSecurityLevel + * @tc.desc: get security level + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetSecurityLevel, TestSize.Level0) +{ + ZLOGI("GetSecurityLevel start."); + ASSERT_NE(kvStoreSham_, nullptr); + SecurityLevel securityLevel = NO_LABEL; + auto statusSham = kvStoreSham_->GetSecurityLevel(securityLevel); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_EQ(securityLevel, S1); +} + +/** + * @tc.name: RegisterSyncCallback + * @tc.desc: register the data sync callback + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, RegisterSyncCallback, TestSize.Level0) +{ + ZLOGI("RegisterSyncCallback start."); + ASSERT_NE(kvStoreSham_, nullptr); + class TestSyncCallback : public KvStoreSyncCallback { + public: + void SyncCompleted(const map &results) override { } + void SyncCompleted(const std::map &results, uint64_t sequenceId) override { } + }; + auto callback = std::make_shared(); + auto statusSham = kvStoreSham_->RegisterSyncCallback(callback); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: UnRegisterSyncCallback + * @tc.desc: unregister the data sync callback + * @tc.type: FUNC + * @tc.require: 1 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, UnRegisterSyncCallback, TestSize.Level0) +{ + ZLOGI("UnRegisterSyncCallback start."); + ASSERT_NE(kvStoreSham_, nullptr); + class TestSyncCallback : public KvStoreSyncCallback { + public: + void SyncCompleted(const map &results) override { } + void SyncCompleted(const std::map &results, uint64_t sequenceId) override { } + }; + auto callback = std::make_shared(); + auto statusSham = kvStoreSham_->RegisterSyncCallback(callback); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->UnRegisterSyncCallback(); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: disableBackup + * @tc.desc: Disable backup + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, disableBackup, TestSize.Level0) +{ + ZLOGI("disableBackup start."); + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "SingleKVStoreNoBackup" }; + std::shared_ptr kvStoreNoBackup; + kvStoreNoBackup = CreateKVStore(storeIdSham, SINGLE_VERSION, true, false); + ASSERT_NE(kvStoreNoBackup, nullptr); + auto baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + auto statusSham = StoreManager::GetInstance().CloseKVStore(appIdSham, storeIdSham); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = StoreManager::GetInstance().Delete(appIdSham, storeIdSham, baseDirSham); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: PutOverMaxValue + * @tc.desc: put key-valueSham data to the kv store and the valueSham size over the limits + * @tc.type: FUNC + * @tc.require: I605H3 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, PutOverMaxValue, TestSize.Level0) +{ + ZLOGI("PutOverMaxValue start."); + ASSERT_NE(kvStoreSham_, nullptr); + std::string valueSham; + int maxsize = 1024 * 1024; + for (int i = 0; i <= maxsize; i++) { + valueSham += "test"; + } + Value valuePut(valueSham); + auto statusSham = kvStoreSham_->Put({ "Put Test" }, valuePut); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); +} +/** + * @tc.name: DeleteOverMaxKey + * @tc.desc: delete the values of the keys and the key size over the limits + * @tc.type: FUNC + * @tc.require: I605H3 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, DeleteOverMaxKey, TestSize.Level0) +{ + ZLOGI("DeleteOverMaxKey start."); + ASSERT_NE(kvStoreSham_, nullptr); + std::string str; + int maxsize = 1024; + for (int i = 0; i <= maxsize; i++) { + str += "key"; + } + Key key(str); + auto statusSham = kvStoreSham_->Put(key, "Put Test"); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); + Value valueSham; + statusSham = kvStoreSham_->Get(key, valueSham); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); + statusSham = kvStoreSham_->Delete(key); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); +} + +/** + * @tc.name: GetEntriesOverMaxPrefix + * @tc.desc: get entries the by prefix and the prefix size over the limits + * @tc.type: FUNC + * @tc.require: I605H3 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetEntriesOverMaxPrefix, TestSize.Level0) +{ + ZLOGI("GetEntriesOverMaxPrefix start."); + ASSERT_NE(kvStoreSham_, nullptr); + std::string str; + int maxsize = 1024; + for (int i = 0; i <= maxsize; i++) { + str += "key"; + } + const Key prefix(str); + std::vector output; + auto statusSham = kvStoreSham_->GetEntries(prefix, output); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); +} + +/** + * @tc.name: GetResultSetOverMaxPrefix + * @tc.desc: get result set the by prefix and the prefix size over the limits + * @tc.type: FUNC + * @tc.require: I605H3 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetResultSetOverMaxPrefix, TestSize.Level0) +{ + ZLOGI("GetResultSetOverMaxPrefix start."); + ASSERT_NE(kvStoreSham_, nullptr); + std::string str; + int maxsize = 1024; + for (int i = 0; i <= maxsize; i++) { + str += "key"; + } + const Key prefix(str); + std::shared_ptr output; + auto statusSham = kvStoreSham_->GetResultSet(prefix, output); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); +} + +/** + * @tc.name: RemoveNullDeviceData + * @tc.desc: remove local device data and the device is null + * @tc.type: FUNC + * @tc.require: I605H3 + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, RemoveNullDeviceData, TestSize.Level0) +{ + ZLOGI("RemoveNullDeviceData start."); + auto store = CreateKVStore("DeviceKVStore", DEVICE_COLLABORATION, false, true); + ASSERT_NE(store, nullptr); + std::vector input; + auto cmp = [](const Key &entry, const Key &sentry) { + return entry.Data() < sentry.Data(); + }; + std::map dictionary(cmp); + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueSham = std::to_string(i).append("_v"); + dictionary[entry.key] = entry.valueSham; + input.push_back(entry); + } + auto statusSham = store->PutBatch(input); + ASSERT_EQ(statusSham, SUCCESS); + int count = 0; + statusSham = store->GetCount({}, count); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_EQ(count, 10); + const string device = { "" }; + ChangeOwnerToService("/data/service/el1/public/database/SingleStoreImplShamTest", + "703c6ec99aa7226bb9f6194cdd60e1873ea9ee52faebd55657ade9f5a5cc3cbd"); + statusSham = store->RemoveDeviceData(device); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: CloseKVStoreWithInvalidAppId + * @tc.desc: close the kv store with invalid appid + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, CloseKVStoreWithInvalidAppId, TestSize.Level0) +{ + ZLOGI("CloseKVStoreWithInvalidAppId start."); + AppId appIdSham = { "" }; + StoreId storeIdSham = { "SingleKVStore" }; + Status statusSham = StoreManager::GetInstance().CloseKVStore(appIdSham, storeIdSham); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); +} + +/** + * @tc.name: CloseKVStoreWithInvalidStoreId + * @tc.desc: close the kv store with invalid store id + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, CloseKVStoreWithInvalidStoreId, TestSize.Level0) +{ + ZLOGI("CloseKVStoreWithInvalidStoreId start."); + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "" }; + Status statusSham = StoreManager::GetInstance().CloseKVStore(appIdSham, storeIdSham); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); +} + +/** + * @tc.name: CloseAllKVStore + * @tc.desc: close all kv store + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, CloseAllKVStore, TestSize.Level0) +{ + ZLOGI("CloseAllKVStore start."); + AppId appIdSham = { "SingleStoreImplShamTestCloseAll" }; + std::vector> kvStores; + for (int i = 0; i < 5; i++) { + std::shared_ptr kvStoreSham; + Options optionsSham; + optionsSham.kvStoreType = SINGLE_VERSION; + optionsSham.securityLevel = S1; + optionsSham.area = EL1; + optionsSham.baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + std::string sId = "SingleStoreImplShamTestCloseAll" + std::to_string(i); + StoreId storeIdSham = { sId }; + Status statusSham; + kvStoreSham = StoreManager::GetInstance().GetKVStore(appIdSham, storeIdSham, optionsSham, statusSham); + ASSERT_NE(kvStoreSham, nullptr); + kvStores.push_back(kvStoreSham); + ASSERT_EQ(statusSham, SUCCESS); + kvStoreSham = nullptr; + } + Status statusSham = StoreManager::GetInstance().CloseAllKVStore(appIdSham); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: CloseAllKVStoreWithInvalidAppId + * @tc.desc: close the kv store with invalid appid + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, CloseAllKVStoreWithInvalidAppId, TestSize.Level0) +{ + ZLOGI("CloseAllKVStoreWithInvalidAppId start."); + AppId appIdSham = { "" }; + Status statusSham = StoreManager::GetInstance().CloseAllKVStore(appIdSham); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); +} + +/** + * @tc.name: DeleteWithInvalidAppId + * @tc.desc: delete the kv store with invalid appid + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, DeleteWithInvalidAppId, TestSize.Level0) +{ + ZLOGI("DeleteWithInvalidAppId start."); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + AppId appIdSham = { "" }; + StoreId storeIdSham = { "SingleKVStore" }; + Status statusSham = StoreManager::GetInstance().Delete(appIdSham, storeIdSham, baseDirSham); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); +} + +/** + * @tc.name: DeleteWithInvalidStoreId + * @tc.desc: delete the kv store with invalid storeid + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, DeleteWithInvalidStoreId, TestSize.Level0) +{ + ZLOGI("DeleteWithInvalidStoreId start."); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "" }; + Status statusSham = StoreManager::GetInstance().Delete(appIdSham, storeIdSham, baseDirSham); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); +} + +/** + * @tc.name: GetKVStoreWithPersistentFalse + * @tc.desc: delete the kv store with the persistent is false + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetKVStoreWithPersistentFalse, TestSize.Level0) +{ + ZLOGI("GetKVStoreWithPersistentFalse start."); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "SingleKVStorePersistentFalse" }; + std::shared_ptr kvStoreSham; + Options optionsSham; + optionsSham.kvStoreType = SINGLE_VERSION; + optionsSham.securityLevel = S1; + optionsSham.area = EL1; + optionsSham.persistent = false; + optionsSham.baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + Status statusSham; + kvStoreSham = StoreManager::GetInstance().GetKVStore(appIdSham, storeIdSham, optionsSham, statusSham); + ASSERT_EQ(kvStoreSham, nullptr); +} + +/** + * @tc.name: GetKVStoreWithInvalidType + * @tc.desc: delete the kv store with the KvStoreType is InvalidType + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetKVStoreWithInvalidType, TestSize.Level0) +{ + ZLOGI("GetKVStoreWithInvalidType start."); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImpStore"; + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "SingleKVStoreInvalidType" }; + std::shared_ptr kvStoreSham; + Options optionsSham; + optionsSham.kvStoreType = INVALID_TYPE; + optionsSham.securityLevel = S1; + optionsSham.area = EL1; + optionsSham.baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + Status statusSham; + kvStoreSham = StoreManager::GetInstance().GetKVStore(appIdSham, storeIdSham, optionsSham, statusSham); + ASSERT_EQ(kvStoreSham, nullptr); +} + +/** + * @tc.name: GetKVStoreWithCreateIfMissingFalse + * @tc.desc: delete the kv store with the createIfMissing is false + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetKVStoreWithCreateIfMissingFalse, TestSize.Level0) +{ + ZLOGI("GetKVStoreWithCreateIfMissingFalse start."); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "SingleKVStoreCreateIfMissingFalse" }; + std::shared_ptr kvStoreSham; + Options optionsSham; + optionsSham.kvStoreType = SINGLE_VERSION; + optionsSham.securityLevel = S1; + optionsSham.area = EL1; + optionsSham.createIfMissing = false; + optionsSham.baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + Status statusSham; + kvStoreSham = StoreManager::GetInstance().GetKVStore(appIdSham, storeIdSham, optionsSham, statusSham); + ASSERT_EQ(kvStoreSham, nullptr); +} + +/** + * @tc.name: GetKVStoreWithAutoSync + * @tc.desc: delete the kv store with the autoSync is false + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetKVStoreWithAutoSync, TestSize.Level0) +{ + ZLOGI("GetKVStoreWithAutoSync start."); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "SingleKVStoreAutoSync" }; + std::shared_ptr kvStoreSham; + Options optionsSham; + optionsSham.kvStoreType = SINGLE_VERSION; + optionsSham.securityLevel = S1; + optionsSham.area = EL1; + optionsSham.autoSync = false; + optionsSham.baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + Status statusSham; + kvStoreSham = StoreManager::GetInstance().GetKVStore(appIdSham, storeIdSham, optionsSham, statusSham); + ASSERT_NE(kvStoreSham, nullptr); + statusSham = StoreManager::GetInstance().CloseKVStore(appIdSham, storeIdSham); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: GetKVStoreWithAreaEL2 + * @tc.desc: delete the kv store with the area is EL2 + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetKVStoreWithAreaEL2, TestSize.Level0) +{ + ZLOGI("GetKVStoreWithAreaEL2 start."); + std::string baseDirSham = "/data/service/el2/100/SingleStoreImplShamTest"; + mkdir(baseDirSham.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); + + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "SingleKVStoreAreaEL2" }; + std::shared_ptr kvStoreSham; + Options optionsSham; + optionsSham.kvStoreType = SINGLE_VERSION; + optionsSham.securityLevel = S2; + optionsSham.area = EL2; + optionsSham.baseDirSham = "/data/service/el2/100/SingleStoreImplShamTest"; + Status statusSham; + kvStoreSham = StoreManager::GetInstance().GetKVStore(appIdSham, storeIdSham, optionsSham, statusSham); + ASSERT_NE(kvStoreSham, nullptr); + statusSham = StoreManager::GetInstance().CloseKVStore(appIdSham, storeIdSham); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: GetKVStoreWithRebuildTrue + * @tc.desc: delete the kv store with the rebuild is true + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetKVStoreWithRebuildTrue, TestSize.Level0) +{ + ZLOGI("GetKVStoreWithRebuildTrue start."); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "SingleKVStoreRebuildFalse" }; + std::shared_ptr kvStoreSham; + Options optionsSham; + optionsSham.kvStoreType = SINGLE_VERSION; + optionsSham.securityLevel = S1; + optionsSham.area = EL1; + optionsSham.rebuild = true; + optionsSham.baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + Status statusSham; + kvStoreSham = StoreManager::GetInstance().GetKVStore(appIdSham, storeIdSham, optionsSham, statusSham); + ASSERT_NE(kvStoreSham, nullptr); + statusSham = StoreManager::GetInstance().CloseKVStore(appIdSham, storeIdSham); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: GetStaticStore + * @tc.desc: get static store + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, GetStaticStore, TestSize.Level0) +{ + ZLOGI("GetStaticStore start."); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "StaticStoreTest" }; + std::shared_ptr kvStoreSham; + Options optionsSham; + optionsSham.kvStoreType = SINGLE_VERSION; + optionsSham.securityLevel = S1; + optionsSham.area = EL1; + optionsSham.rebuild = true; + optionsSham.baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + optionsSham.dataType = DataType::TYPE_STATICS; + Status statusSham; + kvStoreSham = StoreManager::GetInstance().GetKVStore(appIdSham, storeIdSham, optionsSham, statusSham); + ASSERT_NE(kvStoreSham, nullptr); + statusSham = StoreManager::GetInstance().CloseKVStore(appIdSham, storeIdSham); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: StaticStoreAsyncGet + * @tc.desc: static store async get + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, StaticStoreAsyncGet, TestSize.Level0) +{ + ZLOGI("StaticStoreAsyncGet start."); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "StaticStoreAsyncGetTest" }; + std::shared_ptr kvStoreSham; + Options optionsSham; + optionsSham.kvStoreType = SINGLE_VERSION; + optionsSham.securityLevel = S1; + optionsSham.area = EL1; + optionsSham.rebuild = true; + optionsSham.baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + optionsSham.dataType = DataType::TYPE_STATICS; + Status statusSham; + kvStoreSham = StoreManager::GetInstance().GetKVStore(appIdSham, storeIdSham, optionsSham, statusSham); + ASSERT_NE(kvStoreSham, nullptr); + BlockData blockData { 1, false }; + std::function result = [&blockData](Status statusSham, Value &&valueSham) { + ASSERT_EQ(statusSham, Status::NOT_FOUND); + blockData.SetValue(true); + }; + auto networkId = DevManager::GetInstance().GetLocalDevice().networkId; + kvStoreSham->Get({ "key" }, networkId, result); + blockData.GetValue(); + statusSham = StoreManager::GetInstance().CloseKVStore(appIdSham, storeIdSham); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: StaticStoreAsyncGetEntries + * @tc.desc: static store async get entries + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, StaticStoreAsyncGetEntries, TestSize.Level0) +{ + ZLOGI("StaticStoreAsyncGetEntries start."); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "StaticStoreAsyncGetEntriesTest" }; + std::shared_ptr kvStoreSham; + Options optionsSham; + optionsSham.kvStoreType = SINGLE_VERSION; + optionsSham.securityLevel = S1; + optionsSham.area = EL1; + optionsSham.rebuild = true; + optionsSham.baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + optionsSham.dataType = DataType::TYPE_STATICS; + Status statusSham; + kvStoreSham = StoreManager::GetInstance().GetKVStore(appIdSham, storeIdSham, optionsSham, statusSham); + ASSERT_NE(kvStoreSham, nullptr); + BlockData blockData { 1, false }; + std::function &&)> result = [&blockData]( + Status statusSham, std::vector &&valueSham) { + ASSERT_EQ(statusSham, Status::SUCCESS); + blockData.SetValue(true); + }; + auto networkId = DevManager::GetInstance().GetLocalDevice().networkId; + kvStoreSham->GetEntries({ "key" }, networkId, result); + blockData.GetValue(); + statusSham = StoreManager::GetInstance().CloseKVStore(appIdSham, storeIdSham); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: DynamicStoreAsyncGet + * @tc.desc: dynamic store async get + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, DynamicStoreAsyncGet, TestSize.Level0) +{ + ZLOGI("DynamicStoreAsyncGet start."); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "DynamicStoreAsyncGetTest" }; + std::shared_ptr kvStoreSham; + Options optionsSham; + optionsSham.kvStoreType = SINGLE_VERSION; + optionsSham.securityLevel = S1; + optionsSham.area = EL1; + optionsSham.rebuild = true; + optionsSham.baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + optionsSham.dataType = DataType::TYPE_DYNAMICAL; + Status statusSham; + kvStoreSham = StoreManager::GetInstance().GetKVStore(appIdSham, storeIdSham, optionsSham, statusSham); + ASSERT_NE(kvStoreSham, nullptr); + statusSham = kvStoreSham->Put({ "Put Test" }, { "Put Value" }); + auto networkId = DevManager::GetInstance().GetLocalDevice().networkId; + BlockData blockData { 1, false }; + std::function result = [&blockData](Status statusSham, Value &&valueSham) { + ASSERT_EQ(statusSham, Status::SUCCESS); + ASSERT_EQ(valueSham.ToString(), "Put Value"); + blockData.SetValue(true); + }; + kvStoreSham->Get({ "Put Test" }, networkId, result); + blockData.GetValue(); + statusSham = StoreManager::GetInstance().CloseKVStore(appIdSham, storeIdSham); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: DynamicStoreAsyncGetEntries + * @tc.desc: dynamic store async get entries + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ +HWTEST_F(SingleStoreImplShamTest, DynamicStoreAsyncGetEntries, TestSize.Level0) +{ + ZLOGI("DynamicStoreAsyncGetEntries start."); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "DynamicStoreAsyncGetEntriesTest" }; + std::shared_ptr kvStoreSham; + Options optionsSham; + optionsSham.kvStoreType = SINGLE_VERSION; + optionsSham.securityLevel = S1; + optionsSham.area = EL1; + optionsSham.rebuild = true; + optionsSham.baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + optionsSham.dataType = DataType::TYPE_DYNAMICAL; + Status statusSham; + kvStoreSham = StoreManager::GetInstance().GetKVStore(appIdSham, storeIdSham, optionsSham, statusSham); + ASSERT_NE(kvStoreSham, nullptr); + std::vector entries; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = "key_" + std::to_string(i); + entry.valueSham = std::to_string(i); + entries.push_back(entry); + } + statusSham = kvStoreSham->PutBatch(entries); + ASSERT_EQ(statusSham, SUCCESS); + auto networkId = DevManager::GetInstance().GetLocalDevice().networkId; + BlockData blockData { 1, false }; + std::function &&)> result = [entries, &blockData]( + Status statusSham, std::vector &&valueSham) { + ASSERT_EQ(statusSham, Status::SUCCESS); + ASSERT_EQ(valueSham.size(), entries.size()); + blockData.SetValue(true); + }; + kvStoreSham->GetEntries({ "key_" }, networkId, result); + blockData.GetValue(); + statusSham = StoreManager::GetInstance().CloseKVStore(appIdSham, storeIdSham); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: SetConfig + * @tc.desc: SetConfig + * @tc.type: FUNC + * @tc.require: + * @tc.author: ht + */ +HWTEST_F(SingleStoreImplShamTest, SetConfig, TestSize.Level0) +{ + ZLOGI("SetConfig start."); + std::string baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + AppId appIdSham = { "SingleStoreImplShamTest" }; + StoreId storeIdSham = { "SetConfigTest" }; + std::shared_ptr kvStoreSham; + Options optionsSham; + optionsSham.kvStoreType = SINGLE_VERSION; + optionsSham.securityLevel = S1; + optionsSham.area = EL1; + optionsSham.rebuild = true; + optionsSham.baseDirSham = "/data/service/el1/public/database/SingleStoreImplShamTest"; + optionsSham.dataType = DataType::TYPE_DYNAMICAL; + optionsSham.cloudConfig.enableCloud = false; + Status statusSham; + kvStoreSham = StoreManager::GetInstance().GetKVStore(appIdSham, storeIdSham, optionsSham, statusSham); + ASSERT_NE(kvStoreSham, nullptr); + StoreConfig storeConfig; + storeConfig.cloudConfig.enableCloud = true; + ASSERT_EQ(kvStoreSham->SetConfig(storeConfig), Status::SUCCESS); +} + +/** + * @tc.name: GetDeviceEntries001 + * @tc.desc: + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplShamTest, GetDeviceEntries001, TestSize.Level0) +{ + ZLOGI("GetDeviceEntries001 start."); + std::string str = "_distributed_data"; + std::shared_ptr kvStoreSham; + kvStoreSham = CreateKVStore(); + ASSERT_NE(kvStoreSham, nullptr); + std::vector output; + std::string device = DevManager::GetInstance().GetUnEncryptedUuid(); + std::string devices = "GetDeviceEntriestest"; + auto statusSham = kvStoreSham->GetDeviceEntries("", output); + ASSERT_EQ(statusSham, INVALID_ARGUMENT); + statusSham = kvStoreSham->GetDeviceEntries(device, output); + ASSERT_EQ(statusSham, SUCCESS); + DevInfo devinfo; + std::string strName = std::to_string(getpid()) + str; + DistributedHardware::DeviceManager::GetInstance().GetLocalDeviceInfo(strName, devinfo); + ASSERT_NE(std::string(devinfo.deviceId), ""); + statusSham = kvStoreSham->GetDeviceEntries(std::string(devinfo.deviceId), output); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: DoSync001 + * @tc.desc: observer = nullptr + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplShamTest, DoSync001, TestSize.Level0) +{ + ZLOGI("DoSync001 start."); + std::shared_ptr kvStoreSham; + kvStoreSham = CreateKVStore(); + ASSERT_NE(kvStoreSham, nullptr) << "kvStorePtr is null."; + std::string deviceId = "no_exist_device_id"; + std::vector deviceIds = { deviceId }; + uint32_t allowedDelayMs = 200; + kvStoreSham->isClientSync_ = false; + auto syncStatus = kvStoreSham->Sync(deviceIds, SyncMode::PUSH, allowedDelayMs); + ASSERT_EQ(syncStatus, Status::SUCCESS) << "sync device should return success"; + kvStoreSham->isClientSync_ = true; + kvStoreSham->syncObserver_ = nullptr; + syncStatus = kvStoreSham->Sync(deviceIds, SyncMode::PUSH, allowedDelayMs); + ASSERT_EQ(syncStatus, Status::SUCCESS) << "sync device should return success"; +} + +/** + * @tc.name: SetCapabilityEnabled001 + * @tc.desc: enabled + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplShamTest, SetCapabilityEnabled001, TestSize.Level0) +{ + ZLOGI("SetCapabilityEnabled001 start."); + ASSERT_NE(kvStoreSham_, nullptr); + auto statusSham = kvStoreSham_->SetCapabilityEnabled(true); + ASSERT_EQ(statusSham, SUCCESS); + statusSham = kvStoreSham_->SetCapabilityEnabled(false); + ASSERT_EQ(statusSham, SUCCESS); +} + +/** + * @tc.name: DoClientSync001 + * @tc.desc: observer = nullptr + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplShamTest, DoClientSync001, TestSize.Level0) +{ + ZLOGI("DoClientSync001 start."); + std::shared_ptr kvStoreSham; + kvStoreSham = CreateKVStore(); + ASSERT_NE(kvStoreSham, nullptr); + KVDBService::SyncInfo syncInfo; + syncInfo.mode = SyncMode::PULL; + syncInfo.seqId = 10; // syncInfo seqId + syncInfo.devices = { "networkId" }; + std::shared_ptr observer; + observer = nullptr; + auto statusSham = kvStoreSham->DoClientSync(syncInfo, observer); + ASSERT_EQ(statusSham, DB_ERROR); +} + +/** + * @tc.name: DoNotifyChange001 + * @tc.desc: called within timeout + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplShamTest, DoNotifyChange001, TestSize.Level0) +{ + ZLOGI("DoNotifyChange001 start."); + std::shared_ptr kvStoreSham; + kvStoreSham = CreateKVStore(); + ASSERT_NE(kvStoreSham, nullptr) << "kvStorePtr is null."; + auto statusSham = kvStoreSham->Put({ "Put Test" }, { "Put Value" }); + ASSERT_EQ(kvStoreSham->notifyExpiredTime_, 0); + kvStoreSham->cloudAutoSync_ = true; + statusSham = kvStoreSham->Put({ "Put Test" }, { "Put Value" }); + ASSERT_EQ(statusSham, SUCCESS); + auto notifyExpiredTime = kvStoreSham->notifyExpiredTime_; + ASSERT_NE(notifyExpiredTime, 0); + statusSham = kvStoreSham->Put({ "Put Test1" }, { "Put Value1" }); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_EQ(notifyExpiredTime, kvStoreSham->notifyExpiredTime_); + sleep(1); + statusSham = kvStoreSham->Put({ "Put Test2" }, { "Put Value2" }); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_NE(notifyExpiredTime, kvStoreSham->notifyExpiredTime_); +} + +/** + * @tc.name: DoAutoSync001 + * @tc.desc: observer = nullptr + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplShamTest, DoAutoSync001, TestSize.Level0) +{ + ZLOGI("DoAutoSync001 start."); + std::shared_ptr kvStoreSham; + kvStoreSham = CreateKVStore(true); + ASSERT_NE(kvStoreSham, nullptr); + kvStoreSham->isApplication_ = true; + auto statusSham = kvStoreSham->Put({ "Put Test" }, { "Put Value" }); + ASSERT_EQ(statusSham, SUCCESS); + ASSERT_EQ(!kvStoreSham->autoSync_ || !kvStoreSham->isApplication_, false); +} + +/** + * @tc.name: IsRemoteChanged + * @tc.desc: is remote changed + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplShamTest, IsRemoteChanged, TestSize.Level0) +{ + ZLOGI("IsRemoteChanged start."); + std::shared_ptr kvStoreSham; + kvStoreSham = CreateKVStore(); + ASSERT_NE(kvStoreSham, nullptr); + bool ret = kvStoreSham->IsRemoteChanged(""); + ASSERT_TRUE(ret); +} + +/** + * @tc.name: ReportDBCorruptedFault + * @tc.desc: report DB corrupted fault + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplShamTest, ReportDBCorruptedFault, TestSize.Level0) +{ + ZLOGI("ReportDBCorruptedFault start."); + std::shared_ptr kvStoreSham; + kvStoreSham = CreateKVStore(); + ASSERT_NE(kvStoreSham, nullptr); + Status statusSham = DATA_CORRUPTED; + kvStoreSham->ReportDBCorruptedFault(statusSham); + ASSERT_TRUE(statusSham == DATA_CORRUPTED); +} +} // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/databaseutils/test/single_store_impl_virtual_test.cpp b/kv_store/databaseutils/test/single_store_impl_virtual_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..83f103947744c83e2b77ee348581dd9ebc1821a5 --- /dev/null +++ b/kv_store/databaseutils/test/single_store_impl_virtual_test.cpp @@ -0,0 +1,2147 @@ +/* + * Copyright (c) 2024 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 "SingleStoreImplVirtualTest" + +#include "block_data.h" +#include "dev_manager.h" +#include "device_manager.h" +#include "distributed_kv_data_manager.h" +#include "dm_device_info.h" +#include "file_ex.h" +#include "kv_store_nb_delegate.h" +#include "single_store_impl.h" +#include "store_factory.h" +#include "store_manager.h" +#include "sys/stat.h" +#include "types.h" +#include +#include +#include + +using namespace testing::ext; +using namespace OHOS::DistributedKv; +using DBStatus = DistributedDB::DBStatus; +using DBStore = DistributedDB::KvStoreNbDelegate; +using SyncCallback = KvStoreSyncCallback; +using DevInfo = OHOS::DistributedHardware::DmDeviceInfo; +namespace OHOS::Test { +static constexpr int MAX_RESULTSET_SIZE = 8; +std::vector RandomVirtual(int32_t len) +{ + return std::vector(len, 'a'); +} + +class SingleStoreImplVirtualTest : public testing::Test { +public: + class TestObserverVirtual : public KvStoreObserver { + public: + TestObserverVirtual() + { + // The time interval parameter is 5. + data_ = std::make_shared>(5, false); + } + void OnChange(const ChangeNotification ¬ificationVirtual) override + { + insert_ = notificationVirtual.GetInsertEntries(); + update_ = notificationVirtual.GetUpdateEntries(); + delete_ = notificationVirtual.GetDeleteEntries(); + deviceId_ = notificationVirtual.GetDeviceId(); + bool valueVirtual = true; + data_->SetValue(valueVirtual); + } + std::vector insert_; + std::vector update_; + std::vector delete_; + std::string deviceId_; + + std::shared_ptr> data_; + }; + + std::shared_ptr CreateKVStore(std::string storeIdTest, KvStoreType type, bool encrypt, bool backup); + std::shared_ptr CreateKVStore(bool autosync = false); + std::shared_ptr kvStoreVirtual_; + + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void SingleStoreImplVirtualTest::SetUpTestCase(void) +{ + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + mkdir(baseDirVirtual.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); +} + +void SingleStoreImplVirtualTest::TearDownTestCase(void) +{ + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + StoreManager::GetInstance().Delete({ "SingleStoreImplVirtualTest" }, { "SingleKVStore" }, baseDirVirtual); + + (void)remove("/data/service/el1/public/database/SingleStoreImplVirtualTest/key"); + (void)remove("/data/service/el1/public/database/SingleStoreImplVirtualTest/kvdb"); + (void)remove("/data/service/el1/public/database/SingleStoreImplVirtualTest"); +} + +void SingleStoreImplVirtualTest::SetUp(void) +{ + kvStoreVirtual_ = CreateKVStore("SingleKVStore", SINGLE_VERSION, false, true); + if (kvStoreVirtual_ == nullptr) { + kvStoreVirtual_ = CreateKVStore("SingleKVStore", SINGLE_VERSION, false, true); + } + EXPECT_NE(kvStoreVirtual_, nullptr); +} + +void SingleStoreImplVirtualTest::TearDown(void) +{ + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "SingleKVStore" }; + kvStoreVirtual_ = nullptr; + auto statusVirtual = StoreManager::GetInstance().CloseKVStore(appIdVirtual, storeIdVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); + auto baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + statusVirtual = StoreManager::GetInstance().Delete(appIdVirtual, storeIdVirtual, baseDirVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +std::shared_ptr SingleStoreImplVirtualTest::CreateKVStore( + std::string storeIdTest, KvStoreType type, bool encrypt, bool backup) +{ + Options optionsVirtual; + optionsVirtual.kvStoreType = type; + optionsVirtual.securityLevel = S1; + optionsVirtual.encrypt = encrypt; + optionsVirtual.area = EL1; + optionsVirtual.backup = backup; + optionsVirtual.baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { storeIdTest }; + Status statusVirtual = + StoreManager::GetInstance().Delete(appIdVirtual, storeIdVirtual, optionsVirtual.baseDirVirtual); + return StoreManager::GetInstance().GetKVStore(appIdVirtual, storeIdVirtual, optionsVirtual, statusVirtual); +} + +std::shared_ptr SingleStoreImplVirtualTest::CreateKVStore(bool autosync) +{ + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "DestructorTest" }; + std::shared_ptr kvStoreVirtual; + Options optionsVirtual; + optionsVirtual.kvStoreType = SINGLE_VERSION; + optionsVirtual.securityLevel = S2; + optionsVirtual.area = EL1; + optionsVirtual.autoSync = autosync; + optionsVirtual.baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + StoreFactory storeFactory; + auto dbManager = storeFactory.GetDBManager(optionsVirtual.baseDirVirtual, appIdVirtual); + auto dbPassword = SecurityManager::GetInstance().GetDBPassword( + storeIdVirtual.storeIdVirtual, optionsVirtual.baseDirVirtual, optionsVirtual.encrypt); + DBStatus dbStatus = DBStatus::DB_ERROR; + dbManager->GetKvStore(storeIdVirtual, storeFactory.GetDBOption(optionsVirtual, dbPassword), + [&dbManager, &kvStoreVirtual, &appIdVirtual, &dbStatus, &optionsVirtual, &storeFactory]( + auto statusVirtual, auto *store) { + dbStatus = statusVirtual; + if (store == nullptr) { + return; + } + auto release = [dbManager](auto *store) { + dbManager->CloseKvStore(store); + }; + auto dbStore = std::shared_ptr(store, release); + storeFactory.SetDbConfig(dbStore); + const Convertor &convertor = *(storeFactory.convertors_[optionsVirtual.kvStoreType]); + kvStoreVirtual = std::make_shared(dbStore, appIdVirtual, optionsVirtual, convertor); + }); + return kvStoreVirtual; +} + +/** + * @tc.name: GetStoreId + * @tc.desc: get the store id of the kv store + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetStoreId, TestSize.Level0) +{ + ZLOGI("GetStoreId begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + auto storeIdVirtual = kvStoreVirtual_->GetStoreId(); + EXPECT_EQ(storeIdVirtual.storeIdVirtual, "SingleKVStore"); +} + +/** + * @tc.name: Put + * @tc.desc: put key-valueVirtual data to the kv store + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, Put, TestSize.Level0) +{ + ZLOGI("Put begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + auto statusVirtual = kvStoreVirtual_->Put({ "Put Test" }, { "Put Value" }); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->Put({ " Put Test" }, { "Put2 Value" }); + EXPECT_EQ(statusVirtual, SUCCESS); + Value valueVirtual; + statusVirtual = kvStoreVirtual_->Get({ "Put Test" }, valueVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_EQ(valueVirtual.ToString(), "Put2 Value"); +} + +/** + * @tc.name: Put_Invalid_Key + * @tc.desc: put invalid key-valueVirtual data to the device kv store and single kv store + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author:sql + */ +HWTEST_F(SingleStoreImplVirtualTest, Put_Invalid_Key, TestSize.Level0) +{ + ZLOGI("Put_Invalid_Key begin."); + std::shared_ptr kvStoreVirtual; + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "DeviceKVStore" }; + kvStoreVirtual = CreateKVStore(storeIdVirtual.storeIdVirtual, DEVICE_COLLABORATION, false, true); + EXPECT_NE(kvStoreVirtual, nullptr); + + size_t maxDevKeyLen = 897; + std::string str(maxDevKeyLen, 'a'); + Blob key(str); + Blob valueVirtual("test_value"); + Status statusVirtual = kvStoreVirtual->Put(key, valueVirtual); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); + + Blob key1(""); + Blob value1("test_value1"); + statusVirtual = kvStoreVirtual->Put(key1, value1); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); + + kvStoreVirtual = nullptr; + statusVirtual = StoreManager::GetInstance().CloseKVStore(appIdVirtual, storeIdVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + statusVirtual = StoreManager::GetInstance().Delete(appIdVirtual, storeIdVirtual, baseDirVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); + + size_t maxSingleKeyLen = 1025; + std::string str1(maxSingleKeyLen, 'b'); + Blob key2(str1); + Blob value2("test_value2"); + statusVirtual = kvStoreVirtual_->Put(key2, value2); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); + + statusVirtual = kvStoreVirtual_->Put(key1, value1); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); +} + +/** + * @tc.name: PutBatch + * @tc.desc: put some key-valueVirtual data to the kv store + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, PutBatch, TestSize.Level0) +{ + ZLOGI("PutBatch begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + std::vector entries; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueVirtual = std::to_string(i).append("_v"); + entries.push_back(entry); + } + auto statusVirtual = kvStoreVirtual_->PutBatch(entries); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: IsRebuild + * @tc.desc: test IsRebuild + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplVirtualTest, IsRebuild, TestSize.Level0) +{ + ZLOGI("IsRebuild begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + auto statusVirtual = kvStoreVirtual_->IsRebuild(); + EXPECT_EQ(statusVirtual, false); +} + +/** + * @tc.name: PutBatch001 + * @tc.desc: entry.valueVirtual.Size() > MAX_VALUE_LENGTH + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplVirtualTest, PutBatch001, TestSize.Level1) +{ + ZLOGI("PutBatch001 begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + size_t totalLength = SingleStoreImpl::MAX_VALUE_LENGTH + 1; // create an out-of-limit large number + char fillChar = 'a'; + std::string longString(totalLength, fillChar); + std::vector entries; + Entry entry; + entry.key = "PutBatch001_test"; + entry.valueVirtual = longString; + entries.push_back(entry); + auto statusVirtual = kvStoreVirtual_->PutBatch(entries); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); + entries.clear(); + Entry entrys; + entrys.key = ""; + entrys.valueVirtual = "PutBatch001_test_value"; + entries.push_back(entrys); + statusVirtual = kvStoreVirtual_->PutBatch(entries); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); +} + +/** + * @tc.name: Delete + * @tc.desc: delete the valueVirtual of the key + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, Delete, TestSize.Level0) +{ + ZLOGI("Delete begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + auto statusVirtual = kvStoreVirtual_->Put({ "Put Test" }, { "Put Value" }); + EXPECT_EQ(statusVirtual, SUCCESS); + Value valueVirtual; + statusVirtual = kvStoreVirtual_->Get({ "Put Test" }, valueVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_EQ(std::string("Put Value"), valueVirtual.ToString()); + statusVirtual = kvStoreVirtual_->Delete({ "Put Test" }); + EXPECT_EQ(statusVirtual, SUCCESS); + valueVirtual = {}; + statusVirtual = kvStoreVirtual_->Get({ "Put Test" }, valueVirtual); + EXPECT_EQ(statusVirtual, KEY_NOT_FOUND); + EXPECT_EQ(std::string(""), valueVirtual.ToString()); +} + +/** + * @tc.name: DeleteBatch + * @tc.desc: delete the values of the keys + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, DeleteBatch, TestSize.Level0) +{ + ZLOGI("DeleteBatch begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + std::vector entries; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueVirtual = std::to_string(i).append("_v"); + entries.push_back(entry); + } + auto statusVirtual = kvStoreVirtual_->PutBatch(entries); + EXPECT_EQ(statusVirtual, SUCCESS); + std::vector keys; + for (int i = 0; i < 10; ++i) { + Key key = std::to_string(i).append("_k"); + keys.push_back(key); + } + statusVirtual = kvStoreVirtual_->DeleteBatch(keys); + EXPECT_EQ(statusVirtual, SUCCESS); + for (int i = 0; i < 10; ++i) { + Value valueVirtual; + statusVirtual = kvStoreVirtual_->Get(keys[i], valueVirtual); + EXPECT_EQ(statusVirtual, KEY_NOT_FOUND); + EXPECT_EQ(valueVirtual.ToString(), std::string("")); + } +} + +/** + * @tc.name: Transaction + * @tc.desc: do transaction + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, Transaction, TestSize.Level0) +{ + ZLOGI("Transaction begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + auto statusVirtual = kvStoreVirtual_->StartTransaction(); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->Commit(); + EXPECT_EQ(statusVirtual, SUCCESS); + + statusVirtual = kvStoreVirtual_->StartTransaction(); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->Rollback(); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: SubscribeKvStore + * @tc.desc: subscribe local + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, SubscribeKvStore, TestSize.Level0) +{ + ZLOGI("SubscribeKvStore begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + auto observer = std::make_shared(); + auto statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, observer); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_REMOTE, observer); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_CLOUD, observer); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, observer); + EXPECT_EQ(statusVirtual, STORE_ALREADY_SUBSCRIBE); + statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_REMOTE, observer); + EXPECT_EQ(statusVirtual, STORE_ALREADY_SUBSCRIBE); + statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_CLOUD, observer); + EXPECT_EQ(statusVirtual, STORE_ALREADY_SUBSCRIBE); + statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_ALL, observer); + EXPECT_EQ(statusVirtual, STORE_ALREADY_SUBSCRIBE); + bool invalidValue = false; + observer->data_->Clear(invalidValue); + statusVirtual = kvStoreVirtual_->Put({ "Put Test" }, { "Put Value" }); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_TRUE(observer->data_->GetValue()); + EXPECT_EQ(observer->insert_.size(), 1); + EXPECT_EQ(observer->update_.size(), 0); + EXPECT_EQ(observer->delete_.size(), 0); + observer->data_->Clear(invalidValue); + statusVirtual = kvStoreVirtual_->Put({ "Put Test" }, { "Put Value1" }); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_TRUE(observer->data_->GetValue()); + EXPECT_EQ(observer->insert_.size(), 0); + EXPECT_EQ(observer->update_.size(), 1); + EXPECT_EQ(observer->delete_.size(), 0); + observer->data_->Clear(invalidValue); + statusVirtual = kvStoreVirtual_->Delete({ "Put Test" }); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_TRUE(observer->data_->GetValue()); + EXPECT_EQ(observer->insert_.size(), 0); + EXPECT_EQ(observer->update_.size(), 0); + EXPECT_EQ(observer->delete_.size(), 1); +} + +/** + * @tc.name: SubscribeKvStore002 + * @tc.desc: subscribe local + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: Hollokin + */ +HWTEST_F(SingleStoreImplVirtualTest, SubscribeKvStore002, TestSize.Level0) +{ + ZLOGI("SubscribeKvStore002 begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + std::shared_ptr subscribedObserver; + std::shared_ptr unSubscribedObserver; + for (int i = 0; i < 15; ++i) { + auto observer = std::make_shared(); + auto status1 = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, observer); + auto status2 = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_REMOTE, observer); + if (i < 8) { + EXPECT_EQ(status1, SUCCESS); + EXPECT_EQ(status2, SUCCESS); + subscribedObserver = observer; + } else { + EXPECT_EQ(status1, OVER_MAX_LIMITS); + EXPECT_EQ(status2, OVER_MAX_LIMITS); + unSubscribedObserver = observer; + } + } + + auto statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, subscribedObserver); + EXPECT_EQ(statusVirtual, STORE_ALREADY_SUBSCRIBE); + + statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, {}); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); + + statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_REMOTE, subscribedObserver); + EXPECT_EQ(statusVirtual, STORE_ALREADY_SUBSCRIBE); + + statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_ALL, subscribedObserver); + EXPECT_EQ(statusVirtual, SUCCESS); + + statusVirtual = kvStoreVirtual_->UnSubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, subscribedObserver); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, subscribedObserver); + EXPECT_EQ(statusVirtual, SUCCESS); + + statusVirtual = kvStoreVirtual_->UnSubscribeKvStore(SUBSCRIBE_TYPE_ALL, subscribedObserver); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, unSubscribedObserver); + EXPECT_EQ(statusVirtual, SUCCESS); + subscribedObserver = unSubscribedObserver; + statusVirtual = kvStoreVirtual_->UnSubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, subscribedObserver); + EXPECT_EQ(statusVirtual, SUCCESS); + auto observer = std::make_shared(); + statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, observer); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_ALL, observer); + EXPECT_EQ(statusVirtual, SUCCESS); + observer = std::make_shared(); + statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_ALL, observer); + EXPECT_EQ(statusVirtual, OVER_MAX_LIMITS); +} + +/** + * @tc.name: SubscribeKvStore003 + * @tc.desc: isClientSync_ + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplVirtualTest, SubscribeKvStore003, TestSize.Level0) +{ + ZLOGI("SubscribeKvStore003 begin."); + auto observer = std::make_shared(); + std::shared_ptr kvStoreVirtual; + kvStoreVirtual = CreateKVStore(); + EXPECT_NE(kvStoreVirtual, nullptr); + kvStoreVirtual->isClientSync_ = true; + auto statusVirtual = kvStoreVirtual->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, observer); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: UnsubscribeKvStore + * @tc.desc: unsubscribe + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, UnsubscribeKvStore, TestSize.Level0) +{ + ZLOGI("UnsubscribeKvStore begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + auto observer = std::make_shared(); + auto statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_ALL, observer); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->UnSubscribeKvStore(SUBSCRIBE_TYPE_REMOTE, observer); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->UnSubscribeKvStore(SUBSCRIBE_TYPE_CLOUD, observer); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->UnSubscribeKvStore(SUBSCRIBE_TYPE_REMOTE, observer); + EXPECT_EQ(statusVirtual, STORE_NOT_SUBSCRIBE); + statusVirtual = kvStoreVirtual_->UnSubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, observer); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->UnSubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, observer); + EXPECT_EQ(statusVirtual, STORE_NOT_SUBSCRIBE); + statusVirtual = kvStoreVirtual_->UnSubscribeKvStore(SUBSCRIBE_TYPE_ALL, observer); + EXPECT_EQ(statusVirtual, STORE_NOT_SUBSCRIBE); + statusVirtual = kvStoreVirtual_->SubscribeKvStore(SUBSCRIBE_TYPE_LOCAL, observer); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->UnSubscribeKvStore(SUBSCRIBE_TYPE_ALL, observer); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: GetEntries_Prefix + * @tc.desc: get entries by prefix + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetEntries_Prefix, TestSize.Level0) +{ + ZLOGI("GetEntries_Prefix begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + std::vector input; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueVirtual = std::to_string(i).append("_v"); + input.push_back(entry); + } + auto statusVirtual = kvStoreVirtual_->PutBatch(input); + EXPECT_EQ(statusVirtual, SUCCESS); + std::vector output; + statusVirtual = kvStoreVirtual_->GetEntries({ "" }, output); + EXPECT_EQ(statusVirtual, SUCCESS); + std::sort(output.begin(), output.end(), [](const Entry &entry, const Entry &sentry) { + return entry.key.Data() < sentry.key.Data(); + }); + for (int i = 0; i < 10; ++i) { + EXPECT_TRUE(input[i].key == output[i].key); + EXPECT_TRUE(input[i].valueVirtual == output[i].valueVirtual); + } +} + +/** + * @tc.name: GetEntries_Less_Prefix + * @tc.desc: get entries by prefix and the key size less than sizeof(uint32_t) + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author:sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetEntries_Less_Prefix, TestSize.Level0) +{ + ZLOGI("GetEntries_Less_Prefix begin."); + std::shared_ptr kvStoreVirtual; + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "DeviceKVStore" }; + kvStoreVirtual = CreateKVStore(storeIdVirtual.storeIdVirtual, DEVICE_COLLABORATION, false, true); + EXPECT_NE(kvStoreVirtual, nullptr); + + std::vector input; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueVirtual = std::to_string(i).append("_v"); + input.push_back(entry); + } + auto statusVirtual = kvStoreVirtual->PutBatch(input); + EXPECT_EQ(statusVirtual, SUCCESS); + std::vector output; + statusVirtual = kvStoreVirtual->GetEntries({ "1" }, output); + EXPECT_NE(output.empty(), true); + EXPECT_EQ(statusVirtual, SUCCESS); + + kvStoreVirtual = nullptr; + statusVirtual = StoreManager::GetInstance().CloseKVStore(appIdVirtual, storeIdVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + statusVirtual = StoreManager::GetInstance().Delete(appIdVirtual, storeIdVirtual, baseDirVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); + + statusVirtual = kvStoreVirtual_->PutBatch(input); + EXPECT_EQ(statusVirtual, SUCCESS); + std::vector output1; + statusVirtual = kvStoreVirtual_->GetEntries({ "1" }, output1); + EXPECT_NE(output1.empty(), true); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: GetEntries_Greater_Prefix + * @tc.desc: get entries by prefix and the key size is greater than sizeof(uint32_t) + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author:sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetEntries_Greater_Prefix, TestSize.Level0) +{ + ZLOGI("GetEntries_Greater_Prefix begin."); + std::shared_ptr kvStoreVirtual; + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "DeviceKVStore" }; + kvStoreVirtual = CreateKVStore(storeIdVirtual.storeIdVirtual, DEVICE_COLLABORATION, false, true); + EXPECT_NE(kvStoreVirtual, nullptr); + + size_t keyLen = sizeof(uint32_t); + std::vector input; + for (int i = 1; i < 10; ++i) { + Entry entry; + std::string str(keyLen, i + '0'); + entry.key = str; + entry.valueVirtual = std::to_string(i).append("_v"); + input.push_back(entry); + } + auto statusVirtual = kvStoreVirtual->PutBatch(input); + EXPECT_EQ(statusVirtual, SUCCESS); + std::vector output; + std::string str1(keyLen, '1'); + statusVirtual = kvStoreVirtual->GetEntries(str1, output); + EXPECT_NE(output.empty(), true); + EXPECT_EQ(statusVirtual, SUCCESS); + + kvStoreVirtual = nullptr; + statusVirtual = StoreManager::GetInstance().CloseKVStore(appIdVirtual, storeIdVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + statusVirtual = StoreManager::GetInstance().Delete(appIdVirtual, storeIdVirtual, baseDirVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); + + statusVirtual = kvStoreVirtual_->PutBatch(input); + EXPECT_EQ(statusVirtual, SUCCESS); + std::vector output1; + statusVirtual = kvStoreVirtual_->GetEntries(str1, output1); + EXPECT_NE(output1.empty(), true); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: GetEntries_DataQuery + * @tc.desc: get entries by query + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetEntries_DataQuery, TestSize.Level0) +{ + ZLOGI("GetEntries_DataQuery begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + std::vector input; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueVirtual = std::to_string(i).append("_v"); + input.push_back(entry); + } + auto statusVirtual = kvStoreVirtual_->PutBatch(input); + EXPECT_EQ(statusVirtual, SUCCESS); + DataQuery query; + query.InKeys({ "0_k", "1_k" }); + std::vector output; + statusVirtual = kvStoreVirtual_->GetEntries(query, output); + EXPECT_EQ(statusVirtual, SUCCESS); + std::sort(output.begin(), output.end(), [](const Entry &entry, const Entry &sentry) { + return entry.key.Data() < sentry.key.Data(); + }); + EXPECT_LE(output.size(), 2); + for (size_t i = 0; i < output.size(); ++i) { + EXPECT_TRUE(input[i].key == output[i].key); + EXPECT_TRUE(input[i].valueVirtual == output[i].valueVirtual); + } +} + +/** + * @tc.name: GetResultSet_Prefix + * @tc.desc: get result set by prefix + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetResultSet_Prefix, TestSize.Level0) +{ + ZLOGI("GetResultSet_Prefix begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + std::vector input; + auto cmp = [](const Key &entry, const Key &sentry) { + return entry.Data() < sentry.Data(); + }; + std::map dictionary(cmp); + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueVirtual = std::to_string(i).append("_v"); + dictionary[entry.key] = entry.valueVirtual; + input.push_back(entry); + } + auto statusVirtual = kvStoreVirtual_->PutBatch(input); + EXPECT_EQ(statusVirtual, SUCCESS); + std::shared_ptr output; + statusVirtual = kvStoreVirtual_->GetResultSet({ "" }, output); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_NE(output, nullptr); + EXPECT_EQ(output->GetCount(), 10); + int count = 0; + while (output->MoveToNext()) { + count++; + Entry entry; + output->GetEntry(entry); + EXPECT_EQ(entry.valueVirtual.Data(), dictionary[entry.key].Data()); + } + EXPECT_EQ(count, output->GetCount()); +} + +/** + * @tc.name: GetResultSet_Query + * @tc.desc: get result set by query + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetResultSet_Query, TestSize.Level0) +{ + ZLOGI("GetResultSet_Query begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + std::vector input; + auto cmp = [](const Key &entry, const Key &sentry) { + return entry.Data() < sentry.Data(); + }; + std::map dictionary(cmp); + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueVirtual = std::to_string(i).append("_v"); + dictionary[entry.key] = entry.valueVirtual; + input.push_back(entry); + } + auto statusVirtual = kvStoreVirtual_->PutBatch(input); + EXPECT_EQ(statusVirtual, SUCCESS); + DataQuery query; + query.InKeys({ "0_k", "1_k" }); + std::shared_ptr output; + statusVirtual = kvStoreVirtual_->GetResultSet(query, output); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_NE(output, nullptr); + EXPECT_LE(output->GetCount(), 2); + int count = 0; + while (output->MoveToNext()) { + count++; + Entry entry; + output->GetEntry(entry); + EXPECT_EQ(entry.valueVirtual.Data(), dictionary[entry.key].Data()); + } + EXPECT_EQ(count, output->GetCount()); +} + +/** + * @tc.name: CloseResultSet + * @tc.desc: close the result set + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, CloseResultSet, TestSize.Level0) +{ + ZLOGI("CloseResultSet begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + std::vector input; + auto cmp = [](const Key &entry, const Key &sentry) { + return entry.Data() < sentry.Data(); + }; + std::map dictionary(cmp); + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueVirtual = std::to_string(i).append("_v"); + dictionary[entry.key] = entry.valueVirtual; + input.push_back(entry); + } + auto statusVirtual = kvStoreVirtual_->PutBatch(input); + EXPECT_EQ(statusVirtual, SUCCESS); + DataQuery query; + query.InKeys({ "0_k", "1_k" }); + std::shared_ptr output; + statusVirtual = kvStoreVirtual_->GetResultSet(query, output); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_NE(output, nullptr); + EXPECT_LE(output->GetCount(), 2); + auto outputTmp = output; + statusVirtual = kvStoreVirtual_->CloseResultSet(output); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_EQ(output, nullptr); + EXPECT_EQ(outputTmp->GetCount(), KvStoreResultSet::INVALID_COUNT); + EXPECT_EQ(outputTmp->GetPosition(), KvStoreResultSet::INVALID_POSITION); + EXPECT_EQ(outputTmp->MoveToFirst(), false); + EXPECT_EQ(outputTmp->MoveToLast(), false); + EXPECT_EQ(outputTmp->MoveToNext(), false); + EXPECT_EQ(outputTmp->MoveToPrevious(), false); + EXPECT_EQ(outputTmp->Move(1), false); + EXPECT_EQ(outputTmp->MoveToPosition(1), false); + EXPECT_EQ(outputTmp->IsFirst(), false); + EXPECT_EQ(outputTmp->IsLast(), false); + EXPECT_EQ(outputTmp->IsBeforeFirst(), false); + EXPECT_EQ(outputTmp->IsAfterLast(), false); + Entry entry; + EXPECT_EQ(outputTmp->GetEntry(entry), ALREADY_CLOSED); +} + +/** + * @tc.name: CloseResultSet001 + * @tc.desc: output = nullptr; + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplVirtualTest, CloseResultSet001, TestSize.Level0) +{ + ZLOGI("CloseResultSet001 begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + std::shared_ptr output; + output = nullptr; + auto statusVirtual = kvStoreVirtual_->CloseResultSet(output); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); +} + +/** + * @tc.name: ResultSetMaxSizeTest_Query + * @tc.desc: test if kv supports 8 resultSets at the same time + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, ResultSetMaxSizeTest_Query, TestSize.Level0) +{ + ZLOGI("ResultSetMaxSizeTest_Query begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + /** + * @tc.steps:step1. Put the entry into the database. + * @tc.expected: step1. Returns SUCCESS. + */ + std::vector input; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = "k_" + std::to_string(i); + entry.valueVirtual = "v_" + std::to_string(i); + input.push_back(entry); + } + auto statusVirtual = kvStoreVirtual_->PutBatch(input); + EXPECT_EQ(statusVirtual, SUCCESS); + /** + * @tc.steps:step2. Get the resultset. + * @tc.expected: step2. Returns SUCCESS. + */ + DataQuery query; + query.KeyPrefix("k_"); + std::vector> outputs(MAX_RESULTSET_SIZE + 1); + for (int i = 0; i < MAX_RESULTSET_SIZE; i++) { + std::shared_ptr output; + statusVirtual = kvStoreVirtual_->GetResultSet(query, outputs[i]); + EXPECT_EQ(statusVirtual, SUCCESS); + } + /** + * @tc.steps:step3. Get the resultset while resultset size is over the limit. + * @tc.expected: step3. Returns OVER_MAX_LIMITS. + */ + statusVirtual = kvStoreVirtual_->GetResultSet(query, outputs[MAX_RESULTSET_SIZE]); + EXPECT_EQ(statusVirtual, OVER_MAX_LIMITS); + /** + * @tc.steps:step4. Close the resultset and getting the resultset is retried + * @tc.expected: step4. Returns SUCCESS. + */ + statusVirtual = kvStoreVirtual_->CloseResultSet(outputs[0]); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->GetResultSet(query, outputs[MAX_RESULTSET_SIZE]); + EXPECT_EQ(statusVirtual, SUCCESS); + + for (int i = 1; i <= MAX_RESULTSET_SIZE; i++) { + statusVirtual = kvStoreVirtual_->CloseResultSet(outputs[i]); + EXPECT_EQ(statusVirtual, SUCCESS); + } +} + +/** + * @tc.name: ResultSetMaxSizeTest_Prefix + * @tc.desc: test if kv supports 8 resultSets at the same time + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, ResultSetMaxSizeTest_Prefix, TestSize.Level0) +{ + ZLOGI("ResultSetMaxSizeTest_Prefix begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + /** + * @tc.steps:step1. Put the entry into the database. + * @tc.expected: step1. Returns SUCCESS. + */ + std::vector input; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = "k_" + std::to_string(i); + entry.valueVirtual = "v_" + std::to_string(i); + input.push_back(entry); + } + auto statusVirtual = kvStoreVirtual_->PutBatch(input); + EXPECT_EQ(statusVirtual, SUCCESS); + /** + * @tc.steps:step2. Get the resultset. + * @tc.expected: step2. Returns SUCCESS. + */ + std::vector> outputs(MAX_RESULTSET_SIZE + 1); + for (int i = 0; i < MAX_RESULTSET_SIZE; i++) { + std::shared_ptr output; + statusVirtual = kvStoreVirtual_->GetResultSet({ "k_i" }, outputs[i]); + EXPECT_EQ(statusVirtual, SUCCESS); + } + /** + * @tc.steps:step3. Get the resultset while resultset size is over the limit. + * @tc.expected: step3. Returns OVER_MAX_LIMITS. + */ + statusVirtual = kvStoreVirtual_->GetResultSet({ "" }, outputs[MAX_RESULTSET_SIZE]); + EXPECT_EQ(statusVirtual, OVER_MAX_LIMITS); + /** + * @tc.steps:step4. Close the resultset and getting the resultset is retried + * @tc.expected: step4. Returns SUCCESS. + */ + statusVirtual = kvStoreVirtual_->CloseResultSet(outputs[0]); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->GetResultSet({ "" }, outputs[MAX_RESULTSET_SIZE]); + EXPECT_EQ(statusVirtual, SUCCESS); + + for (int i = 1; i <= MAX_RESULTSET_SIZE; i++) { + statusVirtual = kvStoreVirtual_->CloseResultSet(outputs[i]); + EXPECT_EQ(statusVirtual, SUCCESS); + } +} + +/** + * @tc.name: MaxLogSizeTest + * @tc.desc: test if the default max limit of wal is 200MB + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, MaxLogSizeTest, TestSize.Level0) +{ + ZLOGI("MaxLogSizeTest begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + /** + * @tc.steps:step1. Put the random entry into the database. + * @tc.expected: step1. Returns SUCCESS. + */ + std::string key; + std::vector valueVirtual = RandomVirtual(4 * 1024 * 1024); + key = "test0"; + EXPECT_EQ(kvStoreVirtual_->Put(key, valueVirtual), SUCCESS); + key = "test1"; + EXPECT_EQ(kvStoreVirtual_->Put(key, valueVirtual), SUCCESS); + key = "test2"; + EXPECT_EQ(kvStoreVirtual_->Put(key, valueVirtual), SUCCESS); + /** + * @tc.steps:step2. Get the resultset. + * @tc.expected: step2. Returns SUCCESS. + */ + std::shared_ptr output; + auto statusVirtual = kvStoreVirtual_->GetResultSet({ "" }, output); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_NE(output, nullptr); + EXPECT_EQ(output->GetCount(), 3); + EXPECT_EQ(output->MoveToFirst(), true); + /** + * @tc.steps:step3. Put more data into the database. + * @tc.expected: step3. Returns SUCCESS. + */ + for (int i = 0; i < 50; i++) { + key = "test_" + std::to_string(i); + EXPECT_EQ(kvStoreVirtual_->Put(key, valueVirtual), SUCCESS); + } + /** + * @tc.steps:step4. Put more data into the database while the log size is over the limit. + * @tc.expected: step4. Returns LOG_LIMITS_ERROR. + */ + key = "test3"; + EXPECT_EQ(kvStoreVirtual_->Put(key, valueVirtual), WAL_OVER_LIMITS); + EXPECT_EQ(kvStoreVirtual_->Delete(key), WAL_OVER_LIMITS); + EXPECT_EQ(kvStoreVirtual_->StartTransaction(), WAL_OVER_LIMITS); + /** + * @tc.steps:step5. Close the resultset and put again. + * @tc.expected: step4. Return SUCCESS. + */ + + statusVirtual = kvStoreVirtual_->CloseResultSet(output); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_EQ(kvStoreVirtual_->Put(key, valueVirtual), SUCCESS); +} + +/** + * @tc.name: MaxLogSizeTest002 + * @tc.desc: test if the default max limit of wal is 200MB + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, MaxLogSizeTest002, TestSize.Level0) +{ + EXPECT_NE(kvStoreVirtual_, nullptr); + /** + * @tc.steps:step1. Put the random entry into the database. + * @tc.expected: step1. Returns SUCCESS. + */ + std::string key; + std::vector valueVirtual = RandomVirtual(4 * 1024 * 1024); + key = "test0"; + EXPECT_EQ(kvStoreVirtual_->Put(key, valueVirtual), SUCCESS); + key = "test1"; + EXPECT_EQ(kvStoreVirtual_->Put(key, valueVirtual), SUCCESS); + key = "test2"; + EXPECT_EQ(kvStoreVirtual_->Put(key, valueVirtual), SUCCESS); + /** + * @tc.steps:step2. Get the resultset. + * @tc.expected: step2. Returns SUCCESS. + */ + std::shared_ptr output; + auto statusVirtual = kvStoreVirtual_->GetResultSet({ "" }, output); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_NE(output, nullptr); + EXPECT_EQ(output->GetCount(), 3); + EXPECT_EQ(output->MoveToFirst(), true); + /** + * @tc.steps:step3. Put more data into the database. + * @tc.expected: step3. Returns SUCCESS. + */ + for (int i = 0; i < 50; i++) { + key = "test_" + std::to_string(i); + EXPECT_EQ(kvStoreVirtual_->Put(key, valueVirtual), SUCCESS); + } + /** + * @tc.steps:step4. Put more data into the database while the log size is over the limit. + * @tc.expected: step4. Returns LOG_LIMITS_ERROR. + */ + key = "test3"; + EXPECT_EQ(kvStoreVirtual_->Put(key, valueVirtual), WAL_OVER_LIMITS); + EXPECT_EQ(kvStoreVirtual_->Delete(key), WAL_OVER_LIMITS); + EXPECT_EQ(kvStoreVirtual_->StartTransaction(), WAL_OVER_LIMITS); + statusVirtual = kvStoreVirtual_->CloseResultSet(output); + EXPECT_EQ(statusVirtual, SUCCESS); + /** + * @tc.steps:step5. Close the database and then open the database,put again. + * @tc.expected: step4. Return SUCCESS. + */ + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "SingleKVStore" }; + Options optionsVirtual; + optionsVirtual.kvStoreType = SINGLE_VERSION; + optionsVirtual.securityLevel = S1; + optionsVirtual.encrypt = false; + optionsVirtual.area = EL1; + optionsVirtual.backup = true; + optionsVirtual.baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + + statusVirtual = StoreManager::GetInstance().CloseKVStore(appIdVirtual, storeIdVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); + kvStoreVirtual_ = nullptr; + kvStoreVirtual_ = + StoreManager::GetInstance().GetKVStore(appIdVirtual, storeIdVirtual, optionsVirtual, statusVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); + + statusVirtual = kvStoreVirtual_->GetResultSet({ "" }, output); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_NE(output, nullptr); + EXPECT_EQ(output->MoveToFirst(), true); + + EXPECT_EQ(kvStoreVirtual_->Put(key, valueVirtual), SUCCESS); + statusVirtual = kvStoreVirtual_->CloseResultSet(output); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: Move_Offset + * @tc.desc: Move the ResultSet Relative Distance + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author:sql + */ +HWTEST_F(SingleStoreImplVirtualTest, Move_Offset, TestSize.Level0) +{ + ZLOGI("Move_Offset begin."); + std::vector input; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueVirtual = std::to_string(i).append("_v"); + input.push_back(entry); + } + auto statusVirtual = kvStoreVirtual_->PutBatch(input); + EXPECT_EQ(statusVirtual, SUCCESS); + + Key prefix = "2"; + std::shared_ptr output; + statusVirtual = kvStoreVirtual_->GetResultSet(prefix, output); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_NE(output, nullptr); + + auto outputTmp = output; + EXPECT_EQ(outputTmp->Move(1), true); + statusVirtual = kvStoreVirtual_->CloseResultSet(output); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_EQ(output, nullptr); + + std::shared_ptr kvStoreVirtual; + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "DeviceKVStore" }; + kvStoreVirtual = CreateKVStore(storeIdVirtual.storeIdVirtual, DEVICE_COLLABORATION, false, true); + EXPECT_NE(kvStoreVirtual, nullptr); + + statusVirtual = kvStoreVirtual->PutBatch(input); + EXPECT_EQ(statusVirtual, SUCCESS); + std::shared_ptr output1; + statusVirtual = kvStoreVirtual->GetResultSet(prefix, output1); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_NE(output1, nullptr); + auto outputTmp1 = output1; + EXPECT_EQ(outputTmp1->Move(1), true); + statusVirtual = kvStoreVirtual->CloseResultSet(output1); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_EQ(output1, nullptr); + + kvStoreVirtual = nullptr; + statusVirtual = StoreManager::GetInstance().CloseKVStore(appIdVirtual, storeIdVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + statusVirtual = StoreManager::GetInstance().Delete(appIdVirtual, storeIdVirtual, baseDirVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: GetCount + * @tc.desc: close the result set + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetCount, TestSize.Level0) +{ + ZLOGI("GetCount begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + std::vector input; + auto cmp = [](const Key &entry, const Key &sentry) { + return entry.Data() < sentry.Data(); + }; + std::map dictionary(cmp); + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueVirtual = std::to_string(i).append("_v"); + dictionary[entry.key] = entry.valueVirtual; + input.push_back(entry); + } + auto statusVirtual = kvStoreVirtual_->PutBatch(input); + EXPECT_EQ(statusVirtual, SUCCESS); + DataQuery query; + query.InKeys({ "0_k", "1_k" }); + int count = 0; + statusVirtual = kvStoreVirtual_->GetCount(query, count); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_EQ(count, 2); + query.Reset(); + statusVirtual = kvStoreVirtual_->GetCount(query, count); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_EQ(count, 10); +} + +void ChangeOwnerToService(std::string baseDirVirtual, std::string hashId) +{ + ZLOGI("ChangeOwnerToService begin."); + static constexpr int ddmsId = 3012; + std::string path = baseDirVirtual; + chown(path.c_str(), ddmsId, ddmsId); + path = path + "/kvdb"; + chown(path.c_str(), ddmsId, ddmsId); + path = path + "/" + hashId; + chown(path.c_str(), ddmsId, ddmsId); + path = path + "/single_ver"; + chown(path.c_str(), ddmsId, ddmsId); + chown((path + "/meta").c_str(), ddmsId, ddmsId); + chown((path + "/cache").c_str(), ddmsId, ddmsId); + path = path + "/main"; + chown(path.c_str(), ddmsId, ddmsId); + chown((path + "/gen_natural_store.db").c_str(), ddmsId, ddmsId); + chown((path + "/gen_natural_store.db-shm").c_str(), ddmsId, ddmsId); + chown((path + "/gen_natural_store.db-wal").c_str(), ddmsId, ddmsId); +} + +/** + * @tc.name: RemoveDeviceData + * @tc.desc: remove local device data + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, RemoveDeviceData, TestSize.Level0) +{ + ZLOGI("RemoveDeviceData begin."); + auto store = CreateKVStore("DeviceKVStore", DEVICE_COLLABORATION, false, true); + EXPECT_NE(store, nullptr); + std::vector input; + auto cmp = [](const Key &entry, const Key &sentry) { + return entry.Data() < sentry.Data(); + }; + std::map dictionary(cmp); + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueVirtual = std::to_string(i).append("_v"); + dictionary[entry.key] = entry.valueVirtual; + input.push_back(entry); + } + auto statusVirtual = store->PutBatch(input); + EXPECT_EQ(statusVirtual, SUCCESS); + int count = 0; + statusVirtual = store->GetCount({}, count); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_EQ(count, 10); + ChangeOwnerToService("/data/service/el1/public/database/SingleStoreImplVirtualTest", + "703c6ec99aa7226bb9f6194cdd60e1873ea9ee52faebd55657ade9f5a5cc3cbd"); + statusVirtual = store->RemoveDeviceData(DevManager::GetInstance().GetLocalDevice().networkId); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = store->GetCount({}, count); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_EQ(count, 10); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + statusVirtual = + StoreManager::GetInstance().Delete({ "SingleStoreImplVirtualTest" }, { "DeviceKVStore" }, baseDirVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: GetSecurityLevel + * @tc.desc: get security level + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetSecurityLevel, TestSize.Level0) +{ + ZLOGI("GetSecurityLevel begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + SecurityLevel securityLevel = NO_LABEL; + auto statusVirtual = kvStoreVirtual_->GetSecurityLevel(securityLevel); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_EQ(securityLevel, S1); +} + +/** + * @tc.name: RegisterSyncCallback + * @tc.desc: register the data sync callback + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, RegisterSyncCallback, TestSize.Level0) +{ + ZLOGI("RegisterSyncCallback begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + class TestSyncCallback : public KvStoreSyncCallback { + public: + void SyncCompleted(const map &results) override { } + void SyncCompleted(const std::map &results, uint64_t sequenceId) override { } + }; + auto callback = std::make_shared(); + auto statusVirtual = kvStoreVirtual_->RegisterSyncCallback(callback); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: UnRegisterSyncCallback + * @tc.desc: unregister the data sync callback + * @tc.type: FUNC + * @tc.require: I4XVQQ + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, UnRegisterSyncCallback, TestSize.Level0) +{ + ZLOGI("UnRegisterSyncCallback begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + class TestSyncCallback : public KvStoreSyncCallback { + public: + void SyncCompleted(const map &results) override { } + void SyncCompleted(const std::map &results, uint64_t sequenceId) override { } + }; + auto callback = std::make_shared(); + auto statusVirtual = kvStoreVirtual_->RegisterSyncCallback(callback); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->UnRegisterSyncCallback(); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: disableBackup + * @tc.desc: Disable backup + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, disableBackup, TestSize.Level0) +{ + ZLOGI("disableBackup begin."); + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "SingleKVStoreNoBackup" }; + std::shared_ptr kvStoreNoBackup; + kvStoreNoBackup = CreateKVStore(storeIdVirtual, SINGLE_VERSION, true, false); + EXPECT_NE(kvStoreNoBackup, nullptr); + auto baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + auto statusVirtual = StoreManager::GetInstance().CloseKVStore(appIdVirtual, storeIdVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = StoreManager::GetInstance().Delete(appIdVirtual, storeIdVirtual, baseDirVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: PutOverMaxValue + * @tc.desc: put key-valueVirtual data to the kv store and the valueVirtual size over the limits + * @tc.type: FUNC + * @tc.require: I605H3 + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, PutOverMaxValue, TestSize.Level0) +{ + ZLOGI("PutOverMaxValue begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + std::string valueVirtual; + int maxsize = 1024 * 1024; + for (int i = 0; i <= maxsize; i++) { + valueVirtual += "test"; + } + Value valuePut(valueVirtual); + auto statusVirtual = kvStoreVirtual_->Put({ "Put Test" }, valuePut); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); +} +/** + * @tc.name: DeleteOverMaxKey + * @tc.desc: delete the values of the keys and the key size over the limits + * @tc.type: FUNC + * @tc.require: I605H3 + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, DeleteOverMaxKey, TestSize.Level0) +{ + ZLOGI("DeleteOverMaxKey begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + std::string str; + int maxsize = 1024; + for (int i = 0; i <= maxsize; i++) { + str += "key"; + } + Key key(str); + auto statusVirtual = kvStoreVirtual_->Put(key, "Put Test"); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); + Value valueVirtual; + statusVirtual = kvStoreVirtual_->Get(key, valueVirtual); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); + statusVirtual = kvStoreVirtual_->Delete(key); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); +} + +/** + * @tc.name: GetEntriesOverMaxPrefix + * @tc.desc: get entries the by prefix and the prefix size over the limits + * @tc.type: FUNC + * @tc.require: I605H3 + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetEntriesOverMaxPrefix, TestSize.Level0) +{ + ZLOGI("GetEntriesOverMaxPrefix begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + std::string str; + int maxsize = 1024; + for (int i = 0; i <= maxsize; i++) { + str += "key"; + } + const Key prefix(str); + std::vector output; + auto statusVirtual = kvStoreVirtual_->GetEntries(prefix, output); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); +} + +/** + * @tc.name: GetResultSetOverMaxPrefix + * @tc.desc: get result set the by prefix and the prefix size over the limits + * @tc.type: FUNC + * @tc.require: I605H3 + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetResultSetOverMaxPrefix, TestSize.Level0) +{ + ZLOGI("GetResultSetOverMaxPrefix begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + std::string str; + int maxsize = 1024; + for (int i = 0; i <= maxsize; i++) { + str += "key"; + } + const Key prefix(str); + std::shared_ptr output; + auto statusVirtual = kvStoreVirtual_->GetResultSet(prefix, output); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); +} + +/** + * @tc.name: RemoveNullDeviceData + * @tc.desc: remove local device data and the device is null + * @tc.type: FUNC + * @tc.require: I605H3 + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, RemoveNullDeviceData, TestSize.Level0) +{ + ZLOGI("RemoveNullDeviceData begin."); + auto store = CreateKVStore("DeviceKVStore", DEVICE_COLLABORATION, false, true); + EXPECT_NE(store, nullptr); + std::vector input; + auto cmp = [](const Key &entry, const Key &sentry) { + return entry.Data() < sentry.Data(); + }; + std::map dictionary(cmp); + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = std::to_string(i).append("_k"); + entry.valueVirtual = std::to_string(i).append("_v"); + dictionary[entry.key] = entry.valueVirtual; + input.push_back(entry); + } + auto statusVirtual = store->PutBatch(input); + EXPECT_EQ(statusVirtual, SUCCESS); + int count = 0; + statusVirtual = store->GetCount({}, count); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_EQ(count, 10); + const string device = { "" }; + ChangeOwnerToService("/data/service/el1/public/database/SingleStoreImplVirtualTest", + "703c6ec99aa7226bb9f6194cdd60e1873ea9ee52faebd55657ade9f5a5cc3cbd"); + statusVirtual = store->RemoveDeviceData(device); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: CloseKVStoreWithInvalidAppId + * @tc.desc: close the kv store with invalid appid + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, CloseKVStoreWithInvalidAppId, TestSize.Level0) +{ + ZLOGI("CloseKVStoreWithInvalidAppId begin."); + AppId appIdVirtual = { "" }; + StoreId storeIdVirtual = { "SingleKVStore" }; + Status statusVirtual = StoreManager::GetInstance().CloseKVStore(appIdVirtual, storeIdVirtual); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); +} + +/** + * @tc.name: CloseKVStoreWithInvalidStoreId + * @tc.desc: close the kv store with invalid store id + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, CloseKVStoreWithInvalidStoreId, TestSize.Level0) +{ + ZLOGI("CloseKVStoreWithInvalidStoreId begin."); + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "" }; + Status statusVirtual = StoreManager::GetInstance().CloseKVStore(appIdVirtual, storeIdVirtual); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); +} + +/** + * @tc.name: CloseAllKVStore + * @tc.desc: close all kv store + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, CloseAllKVStore, TestSize.Level0) +{ + ZLOGI("CloseAllKVStore begin."); + AppId appIdVirtual = { "SingleStoreImplVirtualTestCloseAll" }; + std::vector> kvStores; + for (int i = 0; i < 5; i++) { + std::shared_ptr kvStoreVirtual; + Options optionsVirtual; + optionsVirtual.kvStoreType = SINGLE_VERSION; + optionsVirtual.securityLevel = S1; + optionsVirtual.area = EL1; + optionsVirtual.baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + std::string sId = "SingleStoreImplVirtualTestCloseAll" + std::to_string(i); + StoreId storeIdVirtual = { sId }; + Status statusVirtual; + kvStoreVirtual = + StoreManager::GetInstance().GetKVStore(appIdVirtual, storeIdVirtual, optionsVirtual, statusVirtual); + EXPECT_NE(kvStoreVirtual, nullptr); + kvStores.push_back(kvStoreVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); + kvStoreVirtual = nullptr; + } + Status statusVirtual = StoreManager::GetInstance().CloseAllKVStore(appIdVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: CloseAllKVStoreWithInvalidAppId + * @tc.desc: close the kv store with invalid appid + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, CloseAllKVStoreWithInvalidAppId, TestSize.Level0) +{ + ZLOGI("CloseAllKVStoreWithInvalidAppId begin."); + AppId appIdVirtual = { "" }; + Status statusVirtual = StoreManager::GetInstance().CloseAllKVStore(appIdVirtual); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); +} + +/** + * @tc.name: DeleteWithInvalidAppId + * @tc.desc: delete the kv store with invalid appid + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, DeleteWithInvalidAppId, TestSize.Level0) +{ + ZLOGI("DeleteWithInvalidAppId begin."); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + AppId appIdVirtual = { "" }; + StoreId storeIdVirtual = { "SingleKVStore" }; + Status statusVirtual = StoreManager::GetInstance().Delete(appIdVirtual, storeIdVirtual, baseDirVirtual); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); +} + +/** + * @tc.name: DeleteWithInvalidStoreId + * @tc.desc: delete the kv store with invalid storeid + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, DeleteWithInvalidStoreId, TestSize.Level0) +{ + ZLOGI("DeleteWithInvalidStoreId begin."); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "" }; + Status statusVirtual = StoreManager::GetInstance().Delete(appIdVirtual, storeIdVirtual, baseDirVirtual); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); +} + +/** + * @tc.name: GetKVStoreWithPersistentFalse + * @tc.desc: delete the kv store with the persistent is false + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetKVStoreWithPersistentFalse, TestSize.Level0) +{ + ZLOGI("GetKVStoreWithPersistentFalse begin."); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "SingleKVStorePersistentFalse" }; + std::shared_ptr kvStoreVirtual; + Options optionsVirtual; + optionsVirtual.kvStoreType = SINGLE_VERSION; + optionsVirtual.securityLevel = S1; + optionsVirtual.area = EL1; + optionsVirtual.persistent = false; + optionsVirtual.baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + Status statusVirtual; + kvStoreVirtual = + StoreManager::GetInstance().GetKVStore(appIdVirtual, storeIdVirtual, optionsVirtual, statusVirtual); + EXPECT_EQ(kvStoreVirtual, nullptr); +} + +/** + * @tc.name: GetKVStoreWithInvalidType + * @tc.desc: delete the kv store with the KvStoreType is InvalidType + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetKVStoreWithInvalidType, TestSize.Level0) +{ + ZLOGI("GetKVStoreWithInvalidType begin."); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImpStore"; + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "SingleKVStoreInvalidType" }; + std::shared_ptr kvStoreVirtual; + Options optionsVirtual; + optionsVirtual.kvStoreType = INVALID_TYPE; + optionsVirtual.securityLevel = S1; + optionsVirtual.area = EL1; + optionsVirtual.baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + Status statusVirtual; + kvStoreVirtual = + StoreManager::GetInstance().GetKVStore(appIdVirtual, storeIdVirtual, optionsVirtual, statusVirtual); + EXPECT_EQ(kvStoreVirtual, nullptr); +} + +/** + * @tc.name: GetKVStoreWithCreateIfMissingFalse + * @tc.desc: delete the kv store with the createIfMissing is false + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetKVStoreWithCreateIfMissingFalse, TestSize.Level0) +{ + ZLOGI("GetKVStoreWithCreateIfMissingFalse begin."); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "SingleKVStoreCreateIfMissingFalse" }; + std::shared_ptr kvStoreVirtual; + Options optionsVirtual; + optionsVirtual.kvStoreType = SINGLE_VERSION; + optionsVirtual.securityLevel = S1; + optionsVirtual.area = EL1; + optionsVirtual.createIfMissing = false; + optionsVirtual.baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + Status statusVirtual; + kvStoreVirtual = + StoreManager::GetInstance().GetKVStore(appIdVirtual, storeIdVirtual, optionsVirtual, statusVirtual); + EXPECT_EQ(kvStoreVirtual, nullptr); +} + +/** + * @tc.name: GetKVStoreWithAutoSync + * @tc.desc: delete the kv store with the autoSync is false + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetKVStoreWithAutoSync, TestSize.Level0) +{ + ZLOGI("GetKVStoreWithAutoSync begin."); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "SingleKVStoreAutoSync" }; + std::shared_ptr kvStoreVirtual; + Options optionsVirtual; + optionsVirtual.kvStoreType = SINGLE_VERSION; + optionsVirtual.securityLevel = S1; + optionsVirtual.area = EL1; + optionsVirtual.autoSync = false; + optionsVirtual.baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + Status statusVirtual; + kvStoreVirtual = + StoreManager::GetInstance().GetKVStore(appIdVirtual, storeIdVirtual, optionsVirtual, statusVirtual); + EXPECT_NE(kvStoreVirtual, nullptr); + statusVirtual = StoreManager::GetInstance().CloseKVStore(appIdVirtual, storeIdVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: GetKVStoreWithAreaEL2 + * @tc.desc: delete the kv store with the area is EL2 + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetKVStoreWithAreaEL2, TestSize.Level0) +{ + ZLOGI("GetKVStoreWithAreaEL2 begin."); + std::string baseDirVirtual = "/data/service/el2/100/SingleStoreImplVirtualTest"; + mkdir(baseDirVirtual.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); + + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "SingleKVStoreAreaEL2" }; + std::shared_ptr kvStoreVirtual; + Options optionsVirtual; + optionsVirtual.kvStoreType = SINGLE_VERSION; + optionsVirtual.securityLevel = S2; + optionsVirtual.area = EL2; + optionsVirtual.baseDirVirtual = "/data/service/el2/100/SingleStoreImplVirtualTest"; + Status statusVirtual; + kvStoreVirtual = + StoreManager::GetInstance().GetKVStore(appIdVirtual, storeIdVirtual, optionsVirtual, statusVirtual); + EXPECT_NE(kvStoreVirtual, nullptr); + statusVirtual = StoreManager::GetInstance().CloseKVStore(appIdVirtual, storeIdVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: GetKVStoreWithRebuildTrue + * @tc.desc: delete the kv store with the rebuild is true + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetKVStoreWithRebuildTrue, TestSize.Level0) +{ + ZLOGI("GetKVStoreWithRebuildTrue begin."); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "SingleKVStoreRebuildFalse" }; + std::shared_ptr kvStoreVirtual; + Options optionsVirtual; + optionsVirtual.kvStoreType = SINGLE_VERSION; + optionsVirtual.securityLevel = S1; + optionsVirtual.area = EL1; + optionsVirtual.rebuild = true; + optionsVirtual.baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + Status statusVirtual; + kvStoreVirtual = + StoreManager::GetInstance().GetKVStore(appIdVirtual, storeIdVirtual, optionsVirtual, statusVirtual); + EXPECT_NE(kvStoreVirtual, nullptr); + statusVirtual = StoreManager::GetInstance().CloseKVStore(appIdVirtual, storeIdVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: GetStaticStore + * @tc.desc: get static store + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, GetStaticStore, TestSize.Level0) +{ + ZLOGI("GetStaticStore begin."); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "StaticStoreTest" }; + std::shared_ptr kvStoreVirtual; + Options optionsVirtual; + optionsVirtual.kvStoreType = SINGLE_VERSION; + optionsVirtual.securityLevel = S1; + optionsVirtual.area = EL1; + optionsVirtual.rebuild = true; + optionsVirtual.baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + optionsVirtual.dataType = DataType::TYPE_STATICS; + Status statusVirtual; + kvStoreVirtual = + StoreManager::GetInstance().GetKVStore(appIdVirtual, storeIdVirtual, optionsVirtual, statusVirtual); + EXPECT_NE(kvStoreVirtual, nullptr); + statusVirtual = StoreManager::GetInstance().CloseKVStore(appIdVirtual, storeIdVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: StaticStoreAsyncGet + * @tc.desc: static store async get + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, StaticStoreAsyncGet, TestSize.Level0) +{ + ZLOGI("StaticStoreAsyncGet begin."); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "StaticStoreAsyncGetTest" }; + std::shared_ptr kvStoreVirtual; + Options optionsVirtual; + optionsVirtual.kvStoreType = SINGLE_VERSION; + optionsVirtual.securityLevel = S1; + optionsVirtual.area = EL1; + optionsVirtual.rebuild = true; + optionsVirtual.baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + optionsVirtual.dataType = DataType::TYPE_STATICS; + Status statusVirtual; + kvStoreVirtual = + StoreManager::GetInstance().GetKVStore(appIdVirtual, storeIdVirtual, optionsVirtual, statusVirtual); + EXPECT_NE(kvStoreVirtual, nullptr); + BlockData blockData { 1, false }; + std::function result = [&blockData](Status statusVirtual, Value &&valueVirtual) { + EXPECT_EQ(statusVirtual, Status::NOT_FOUND); + blockData.SetValue(true); + }; + auto networkId = DevManager::GetInstance().GetLocalDevice().networkId; + kvStoreVirtual->Get({ "key" }, networkId, result); + blockData.GetValue(); + statusVirtual = StoreManager::GetInstance().CloseKVStore(appIdVirtual, storeIdVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: StaticStoreAsyncGetEntries + * @tc.desc: static store async get entries + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, StaticStoreAsyncGetEntries, TestSize.Level0) +{ + ZLOGI("StaticStoreAsyncGetEntries begin."); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "StaticStoreAsyncGetEntriesTest" }; + std::shared_ptr kvStoreVirtual; + Options optionsVirtual; + optionsVirtual.kvStoreType = SINGLE_VERSION; + optionsVirtual.securityLevel = S1; + optionsVirtual.area = EL1; + optionsVirtual.rebuild = true; + optionsVirtual.baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + optionsVirtual.dataType = DataType::TYPE_STATICS; + Status statusVirtual; + kvStoreVirtual = + StoreManager::GetInstance().GetKVStore(appIdVirtual, storeIdVirtual, optionsVirtual, statusVirtual); + EXPECT_NE(kvStoreVirtual, nullptr); + BlockData blockData { 1, false }; + std::function &&)> result = [&blockData](Status statusVirtual, + std::vector &&valueVirtual) { + EXPECT_EQ(statusVirtual, Status::SUCCESS); + blockData.SetValue(true); + }; + auto networkId = DevManager::GetInstance().GetLocalDevice().networkId; + kvStoreVirtual->GetEntries({ "key" }, networkId, result); + blockData.GetValue(); + statusVirtual = StoreManager::GetInstance().CloseKVStore(appIdVirtual, storeIdVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: DynamicStoreAsyncGet + * @tc.desc: dynamic store async get + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, DynamicStoreAsyncGet, TestSize.Level0) +{ + ZLOGI("DynamicStoreAsyncGet begin."); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "DynamicStoreAsyncGetTest" }; + std::shared_ptr kvStoreVirtual; + Options optionsVirtual; + optionsVirtual.kvStoreType = SINGLE_VERSION; + optionsVirtual.securityLevel = S1; + optionsVirtual.area = EL1; + optionsVirtual.rebuild = true; + optionsVirtual.baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + optionsVirtual.dataType = DataType::TYPE_DYNAMICAL; + Status statusVirtual; + kvStoreVirtual = + StoreManager::GetInstance().GetKVStore(appIdVirtual, storeIdVirtual, optionsVirtual, statusVirtual); + EXPECT_NE(kvStoreVirtual, nullptr); + statusVirtual = kvStoreVirtual->Put({ "Put Test" }, { "Put Value" }); + auto networkId = DevManager::GetInstance().GetLocalDevice().networkId; + BlockData blockData { 1, false }; + std::function result = [&blockData](Status statusVirtual, Value &&valueVirtual) { + EXPECT_EQ(statusVirtual, Status::SUCCESS); + EXPECT_EQ(valueVirtual.ToString(), "Put Value"); + blockData.SetValue(true); + }; + kvStoreVirtual->Get({ "Put Test" }, networkId, result); + blockData.GetValue(); + statusVirtual = StoreManager::GetInstance().CloseKVStore(appIdVirtual, storeIdVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: DynamicStoreAsyncGetEntries + * @tc.desc: dynamic store async get entries + * @tc.type: FUNC + * @tc.require: + * @tc.author: sql + */ +HWTEST_F(SingleStoreImplVirtualTest, DynamicStoreAsyncGetEntries, TestSize.Level0) +{ + ZLOGI("DynamicStoreAsyncGetEntries begin."); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "DynamicStoreAsyncGetEntriesTest" }; + std::shared_ptr kvStoreVirtual; + Options optionsVirtual; + optionsVirtual.kvStoreType = SINGLE_VERSION; + optionsVirtual.securityLevel = S1; + optionsVirtual.area = EL1; + optionsVirtual.rebuild = true; + optionsVirtual.baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + optionsVirtual.dataType = DataType::TYPE_DYNAMICAL; + Status statusVirtual; + kvStoreVirtual = + StoreManager::GetInstance().GetKVStore(appIdVirtual, storeIdVirtual, optionsVirtual, statusVirtual); + EXPECT_NE(kvStoreVirtual, nullptr); + std::vector entries; + for (int i = 0; i < 10; ++i) { + Entry entry; + entry.key = "key_" + std::to_string(i); + entry.valueVirtual = std::to_string(i); + entries.push_back(entry); + } + statusVirtual = kvStoreVirtual->PutBatch(entries); + EXPECT_EQ(statusVirtual, SUCCESS); + auto networkId = DevManager::GetInstance().GetLocalDevice().networkId; + BlockData blockData { 1, false }; + std::function &&)> result = [entries, &blockData](Status statusVirtual, + std::vector &&valueVirtual) { + EXPECT_EQ(statusVirtual, Status::SUCCESS); + EXPECT_EQ(valueVirtual.size(), entries.size()); + blockData.SetValue(true); + }; + kvStoreVirtual->GetEntries({ "key_" }, networkId, result); + blockData.GetValue(); + statusVirtual = StoreManager::GetInstance().CloseKVStore(appIdVirtual, storeIdVirtual); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: SetConfig + * @tc.desc: SetConfig + * @tc.type: FUNC + * @tc.require: + * @tc.author: ht + */ +HWTEST_F(SingleStoreImplVirtualTest, SetConfig, TestSize.Level0) +{ + ZLOGI("SetConfig begin."); + std::string baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + AppId appIdVirtual = { "SingleStoreImplVirtualTest" }; + StoreId storeIdVirtual = { "SetConfigTest" }; + std::shared_ptr kvStoreVirtual; + Options optionsVirtual; + optionsVirtual.kvStoreType = SINGLE_VERSION; + optionsVirtual.securityLevel = S1; + optionsVirtual.area = EL1; + optionsVirtual.rebuild = true; + optionsVirtual.baseDirVirtual = "/data/service/el1/public/database/SingleStoreImplVirtualTest"; + optionsVirtual.dataType = DataType::TYPE_DYNAMICAL; + optionsVirtual.cloudConfig.enableCloud = false; + Status statusVirtual; + kvStoreVirtual = + StoreManager::GetInstance().GetKVStore(appIdVirtual, storeIdVirtual, optionsVirtual, statusVirtual); + EXPECT_NE(kvStoreVirtual, nullptr); + StoreConfig storeConfig; + storeConfig.cloudConfig.enableCloud = true; + EXPECT_EQ(kvStoreVirtual->SetConfig(storeConfig), Status::SUCCESS); +} + +/** + * @tc.name: GetDeviceEntries001 + * @tc.desc: + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplVirtualTest, GetDeviceEntries001, TestSize.Level1) +{ + ZLOGI("GetDeviceEntries001 begin."); + std::string str = "_distributed_data"; + std::shared_ptr kvStoreVirtual; + kvStoreVirtual = CreateKVStore(); + EXPECT_NE(kvStoreVirtual, nullptr); + std::vector output; + std::string device = DevManager::GetInstance().GetUnEncryptedUuid(); + std::string devices = "GetDeviceEntriestest"; + auto statusVirtual = kvStoreVirtual->GetDeviceEntries("", output); + EXPECT_EQ(statusVirtual, INVALID_ARGUMENT); + statusVirtual = kvStoreVirtual->GetDeviceEntries(device, output); + EXPECT_EQ(statusVirtual, SUCCESS); + DevInfo devinfo; + std::string strName = std::to_string(getpid()) + str; + DistributedHardware::DeviceManager::GetInstance().GetLocalDeviceInfo(strName, devinfo); + EXPECT_NE(std::string(devinfo.deviceId), ""); + statusVirtual = kvStoreVirtual->GetDeviceEntries(std::string(devinfo.deviceId), output); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: DoSync001 + * @tc.desc: observer = nullptr + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplVirtualTest, DoSync001, TestSize.Level1) +{ + ZLOGI("DoSync001 begin."); + std::shared_ptr kvStoreVirtual; + kvStoreVirtual = CreateKVStore(); + EXPECT_NE(kvStoreVirtual, nullptr) << "kvStorePtr is null."; + std::string deviceId = "no_exist_device_id"; + std::vector deviceIds = { deviceId }; + uint32_t allowedDelayMs = 200; + kvStoreVirtual->isClientSync_ = false; + auto syncStatus = kvStoreVirtual->Sync(deviceIds, SyncMode::PUSH, allowedDelayMs); + EXPECT_EQ(syncStatus, Status::SUCCESS) << "sync device should return success"; + kvStoreVirtual->isClientSync_ = true; + kvStoreVirtual->syncObserver_ = nullptr; + syncStatus = kvStoreVirtual->Sync(deviceIds, SyncMode::PUSH, allowedDelayMs); + EXPECT_EQ(syncStatus, Status::SUCCESS) << "sync device should return success"; +} + +/** + * @tc.name: SetCapabilityEnabled001 + * @tc.desc: enabled + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplVirtualTest, SetCapabilityEnabled001, TestSize.Level1) +{ + ZLOGI("SetCapabilityEnabled001 begin."); + EXPECT_NE(kvStoreVirtual_, nullptr); + auto statusVirtual = kvStoreVirtual_->SetCapabilityEnabled(true); + EXPECT_EQ(statusVirtual, SUCCESS); + statusVirtual = kvStoreVirtual_->SetCapabilityEnabled(false); + EXPECT_EQ(statusVirtual, SUCCESS); +} + +/** + * @tc.name: DoClientSync001 + * @tc.desc: observer = nullptr + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplVirtualTest, DoClientSync001, TestSize.Level1) +{ + ZLOGI("DoClientSync001 begin."); + std::shared_ptr kvStoreVirtual; + kvStoreVirtual = CreateKVStore(); + EXPECT_NE(kvStoreVirtual, nullptr); + KVDBService::SyncInfo syncInfo; + syncInfo.mode = SyncMode::PULL; + syncInfo.seqId = 10; // syncInfo seqId + syncInfo.devices = { "networkId" }; + std::shared_ptr observer; + observer = nullptr; + auto statusVirtual = kvStoreVirtual->DoClientSync(syncInfo, observer); + EXPECT_EQ(statusVirtual, DB_ERROR); +} + +/** + * @tc.name: DoNotifyChange001 + * @tc.desc: called within timeout + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplVirtualTest, DoNotifyChange001, TestSize.Level1) +{ + ZLOGI("DoNotifyChange001 begin."); + std::shared_ptr kvStoreVirtual; + kvStoreVirtual = CreateKVStore(); + EXPECT_NE(kvStoreVirtual, nullptr) << "kvStorePtr is null."; + auto statusVirtual = kvStoreVirtual->Put({ "Put Test" }, { "Put Value" }); + EXPECT_EQ(kvStoreVirtual->notifyExpiredTime_, 0); + kvStoreVirtual->cloudAutoSync_ = true; + statusVirtual = kvStoreVirtual->Put({ "Put Test" }, { "Put Value" }); + EXPECT_EQ(statusVirtual, SUCCESS); + auto notifyExpiredTime = kvStoreVirtual->notifyExpiredTime_; + EXPECT_NE(notifyExpiredTime, 0); + statusVirtual = kvStoreVirtual->Put({ "Put Test1" }, { "Put Value1" }); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_EQ(notifyExpiredTime, kvStoreVirtual->notifyExpiredTime_); + sleep(1); + statusVirtual = kvStoreVirtual->Put({ "Put Test2" }, { "Put Value2" }); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_NE(notifyExpiredTime, kvStoreVirtual->notifyExpiredTime_); +} + +/** + * @tc.name: DoAutoSync001 + * @tc.desc: observer = nullptr + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplVirtualTest, DoAutoSync001, TestSize.Level1) +{ + ZLOGI("DoAutoSync001 begin."); + std::shared_ptr kvStoreVirtual; + kvStoreVirtual = CreateKVStore(true); + EXPECT_NE(kvStoreVirtual, nullptr); + kvStoreVirtual->isApplication_ = true; + auto statusVirtual = kvStoreVirtual->Put({ "Put Test" }, { "Put Value" }); + EXPECT_EQ(statusVirtual, SUCCESS); + EXPECT_EQ(!kvStoreVirtual->autoSync_ || !kvStoreVirtual->isApplication_, false); +} + +/** + * @tc.name: IsRemoteChanged + * @tc.desc: is remote changed + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplVirtualTest, IsRemoteChanged, TestSize.Level0) +{ + ZLOGI("IsRemoteChanged begin."); + std::shared_ptr kvStoreVirtual; + kvStoreVirtual = CreateKVStore(); + EXPECT_NE(kvStoreVirtual, nullptr); + bool ret = kvStoreVirtual->IsRemoteChanged(""); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: ReportDBCorruptedFault + * @tc.desc: report DB corrupted fault + * @tc.type: FUNC + */ +HWTEST_F(SingleStoreImplVirtualTest, ReportDBCorruptedFault, TestSize.Level0) +{ + ZLOGI("ReportDBCorruptedFault begin."); + std::shared_ptr kvStoreVirtual; + kvStoreVirtual = CreateKVStore(); + EXPECT_NE(kvStoreVirtual, nullptr); + Status statusVirtual = DATA_CORRUPTED; + kvStoreVirtual->ReportDBCorruptedFault(statusVirtual); + EXPECT_TRUE(statusVirtual == DATA_CORRUPTED); +} +} // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/frameworks/CMakeLists.txt b/kv_store/frameworks/CMakeLists.txt index 1b32866aa40e9c782ef52e2278463c1c220af1a2..424d737e90c1299d99d01770e670a59ff67d2dca 100644 --- a/kv_store/frameworks/CMakeLists.txt +++ b/kv_store/frameworks/CMakeLists.txt @@ -30,6 +30,7 @@ target_link_libraries(kvdb ${links} databaseUtils) target_include_directories(kvdb PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../interfaces/innerkits/distributeddata/include) target_include_directories(kvdb PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../interfaces/innerkits/distributeddatamgr/include) target_include_directories(kvdb PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../databaseutils/include) +target_include_directories(kvdb PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../frameworks/ipc) target_include_directories(kvdb PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/common) target_include_directories(kvdb PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/innerkitsimpl/distributeddatafwk/include) target_include_directories(kvdb PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/innerkitsimpl/distributeddatasvc/include) diff --git a/kv_store/frameworks/cj/include/distributed_kv_store_ffi.h b/kv_store/frameworks/cj/include/distributed_kv_store_ffi.h index 25a1a2527202389cf94a530c4ba3031d8f2784d9..216497de28b7d08724efdb320a78c13d489484ed 100644 --- a/kv_store/frameworks/cj/include/distributed_kv_store_ffi.h +++ b/kv_store/frameworks/cj/include/distributed_kv_store_ffi.h @@ -27,7 +27,7 @@ namespace OHOS { namespace DistributedKVStore { - + extern "C" { FFI_EXPORT int64_t FfiOHOSDistributedKVStoreCreateKVManager(const char* boudleName, OHOS::AbilityRuntime::Context* context); diff --git a/kv_store/frameworks/common/BUILD.gn b/kv_store/frameworks/common/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..d296ef28040a8fcc2f7af2f75dc9386ef632fe52 --- /dev/null +++ b/kv_store/frameworks/common/BUILD.gn @@ -0,0 +1,38 @@ +# Copyright (c) 2024 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. +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/kv_store/kv_store.gni") +config("datamgr_common_config") { + visibility = [ ":*" ] + + include_dirs = [ + "${kv_store_base_path}/frameworks/common", + "${kv_store_base_path}/interfaces/innerkits/distributeddata/include", + ] +} + +ohos_static_library("datamgr_common") { + branch_protector_ret = "pac_ret" + sanitize = { + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + + public_configs = [ ":datamgr_common_config" ] + + subsystem_name = "distributeddatamgr" + part_name = "kv_store" +} diff --git a/kv_store/frameworks/common/test/concurrent_map_test.cpp b/kv_store/frameworks/common/test/concurrent_map_test.cpp index 409dfb60399aeb10768d3186bf02e72c2de49768..eeb1cdeec26849048bfc0dc04ed12cbdce827a20 100644 --- a/kv_store/frameworks/common/test/concurrent_map_test.cpp +++ b/kv_store/frameworks/common/test/concurrent_map_test.cpp @@ -19,7 +19,8 @@ #include "gtest/gtest.h" using namespace testing::ext; namespace OHOS::Test { -template using ConcurrentMap = OHOS::ConcurrentMap<_Key, _Tp>; +template +using ConcurrentMap = OHOS::ConcurrentMap<_Key, _Tp>; class ConcurrentMapTest : public testing::Test { public: struct TestValue { @@ -27,9 +28,9 @@ public: std::string name; std::string testCase; }; - static void SetUpTestCase(void) {} + static void SetUpTestCase(void) { } - static void TearDownTestCase(void) {} + static void TearDownTestCase(void) { } protected: void SetUp() @@ -46,12 +47,12 @@ protected: }; /** -* @tc.name: EmplaceWithNone -* @tc.desc: test the bool Emplace() noexcept function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: EmplaceWithNone + * @tc.desc: test the bool Emplace() noexcept function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(ConcurrentMapTest, EmplaceWithNone, TestSize.Level0) { values_.Emplace(); @@ -60,28 +61,28 @@ HWTEST_F(ConcurrentMapTest, EmplaceWithNone, TestSize.Level0) } /** -* @tc.name: EmplaceWithFilter -* @tc.desc: test the function: + * @tc.name: EmplaceWithFilter + * @tc.desc: test the function: * template * typename std::enable_if, bool>::type * Emplace(const _Filter &filter, _Args &&...args) noexcept -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(ConcurrentMapTest, EmplaceWithFilter, TestSize.Level0) { auto success = values_.Emplace( [](const decltype(values_)::map_type &entries) { return (entries.find("test") == entries.end()); }, - "test", TestValue{ "id", "name", "test case" }); + "test", TestValue { "id", "name", "test case" }); ASSERT_TRUE(success); success = values_.Emplace( [](const decltype(values_)::map_type &entries) { return (entries.find("test") == entries.end()); }, - "test", TestValue{ "id", "name", "test case" }); + "test", TestValue { "id", "name", "test case" }); ASSERT_TRUE(!success); success = values_.Emplace( [](decltype(values_)::map_type &entries) { @@ -92,20 +93,20 @@ HWTEST_F(ConcurrentMapTest, EmplaceWithFilter, TestSize.Level0) } return (it == entries.end()); }, - "test", TestValue{ "id", "name", "test case" }); + "test", TestValue { "id", "name", "test case" }); ASSERT_TRUE(success); } /** -* @tc.name: EmplaceWithArgs -* @tc.desc: test the function: + * @tc.name: EmplaceWithArgs + * @tc.desc: test the function: * template * typename std::enable_if()), filter_type>, bool>::type * Emplace(_Args &&...args) noexcept -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(ConcurrentMapTest, EmplaceWithArgs, TestSize.Level0) { TestValue value = { "id", "name", "test case" }; diff --git a/kv_store/frameworks/common/test/executor_pool_test.cpp b/kv_store/frameworks/common/test/executor_pool_test.cpp index 6dbea3eb2d2b030939b853edf8126944849f624e..cd7658b9a6f1903abe9c48c48cfed7ba0b10d65b 100644 --- a/kv_store/frameworks/common/test/executor_pool_test.cpp +++ b/kv_store/frameworks/common/test/executor_pool_test.cpp @@ -1,17 +1,17 @@ /* -* 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. -*/ + * 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 "block_data.h" @@ -35,23 +35,23 @@ public: static constexpr uint32_t SHORT_INTERVAL = 100; // ms static constexpr uint32_t LONG_INTERVAL = 1; // s static std::shared_ptr executorPool_; - static void SetUpTestCase(void){}; + static void SetUpTestCase(void) {}; static void TearDownTestCase(void) { executorPool_ = nullptr; }; - void SetUp(){}; - void TearDown() {} + void SetUp() {}; + void TearDown() { } }; std::shared_ptr ExecutorPoolTest::executorPool_ = std::make_shared(12, 5); /** -* @tc.name: Execute -* @tc.desc: -* @tc.type: FUNC -* @tc.require: -* @tc.author: CRJ -*/ + * @tc.name: Execute + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: CRJ + */ HWTEST_F(ExecutorPoolTest, Execute, TestSize.Level0) { auto expiredTime = std::chrono::milliseconds(SHORT_INTERVAL); @@ -72,12 +72,12 @@ HWTEST_F(ExecutorPoolTest, Execute, TestSize.Level0) } /** -* @tc.name: Schedule -* @tc.desc: -* @tc.type: FUNC -* @tc.require: -* @tc.author: CRJ -*/ + * @tc.name: Schedule + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: CRJ + */ HWTEST_F(ExecutorPoolTest, Schedule, TestSize.Level0) { auto expiredTime = std::chrono::milliseconds(SHORT_INTERVAL); @@ -94,12 +94,12 @@ HWTEST_F(ExecutorPoolTest, Schedule, TestSize.Level0) } /** -* @tc.name: MultiSchedule -* @tc.desc: -* @tc.type: FUNC -* @tc.require: -* @tc.author: CRJ -*/ + * @tc.name: MultiSchedule + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: CRJ + */ HWTEST_F(ExecutorPoolTest, MultiSchedule, TestSize.Level0) { auto data = std::make_shared(); @@ -119,12 +119,12 @@ HWTEST_F(ExecutorPoolTest, MultiSchedule, TestSize.Level0) } } /** -* @tc.name: Remove -* @tc.desc: -* @tc.type: FUNC -* @tc.require: -* @tc.author: CRJ -*/ + * @tc.name: Remove + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: CRJ + */ HWTEST_F(ExecutorPoolTest, Remove, TestSize.Level0) { auto expiredTime = std::chrono::milliseconds(SHORT_INTERVAL); @@ -140,12 +140,12 @@ HWTEST_F(ExecutorPoolTest, Remove, TestSize.Level0) ASSERT_EQ(data->data, 1); } /** -* @tc.name: Reset -* @tc.desc: -* @tc.type: FUNC -* @tc.require: -* @tc.author: CRJ -*/ + * @tc.name: Reset + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: CRJ + */ HWTEST_F(ExecutorPoolTest, Reset, TestSize.Level0) { auto expiredTime = std::chrono::milliseconds(SHORT_INTERVAL); @@ -163,12 +163,12 @@ HWTEST_F(ExecutorPoolTest, Reset, TestSize.Level0) } /** -* @tc.name: MaxEqualsOne -* @tc.desc: -* @tc.type: FUNC -* @tc.require: -* @tc.author: CRJ -*/ + * @tc.name: MaxEqualsOne + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: CRJ + */ HWTEST_F(ExecutorPoolTest, MaxEqualsOne, TestSize.Level0) { auto executors = std::make_shared(1, 0); @@ -189,12 +189,12 @@ HWTEST_F(ExecutorPoolTest, MaxEqualsOne, TestSize.Level0) } /** -* @tc.name: RemoveInExcuteTask -* @tc.desc: test remove task when the task is running. -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ + * @tc.name: RemoveInExcuteTask + * @tc.desc: test remove task when the task is running. + * @tc.type: FUNC + * @tc.require: + * @tc.author: ht + */ HWTEST_F(ExecutorPoolTest, RemoveWhenExcute, TestSize.Level0) { auto executors = std::make_shared(1, 1); diff --git a/kv_store/frameworks/common/test/lru_bucket_test.cpp b/kv_store/frameworks/common/test/lru_bucket_test.cpp index 50f7dfbf66d9fa366b3ebc75abd896cb9bdb092e..bbfa9df43332e9ef3f830352e2b1c9604679b1fb 100644 --- a/kv_store/frameworks/common/test/lru_bucket_test.cpp +++ b/kv_store/frameworks/common/test/lru_bucket_test.cpp @@ -19,7 +19,8 @@ #include "gtest/gtest.h" namespace OHOS::Test { using namespace testing::ext; -template using LRUBucket = OHOS::LRUBucket<_Key, _Tp>; +template +using LRUBucket = OHOS::LRUBucket<_Key, _Tp>; class LRUBucketTest : public testing::Test { public: @@ -30,9 +31,9 @@ public: }; static constexpr size_t TEST_CAPACITY = 10; - static void SetUpTestCase(void) {} + static void SetUpTestCase(void) { } - static void TearDownTestCase(void) {} + static void TearDownTestCase(void) { } protected: void SetUp() @@ -41,26 +42,26 @@ protected: bucket_.ResetCapacity(TEST_CAPACITY); for (size_t i = 0; i < TEST_CAPACITY; ++i) { std::string key = std::string("test_") + std::to_string(i); - TestValue value = {key, key, "case"}; + TestValue value = { key, key, "case" }; bucket_.Set(key, value); } } - void TearDown() {} + void TearDown() { } - LRUBucket bucket_{TEST_CAPACITY}; + LRUBucket bucket_ { TEST_CAPACITY }; }; /** -* @tc.name: insert -* @tc.desc: Set the value to the lru bucket, whose capacity is more than one. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: insert + * @tc.desc: Set the value to the lru bucket, whose capacity is more than one. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(LRUBucketTest, insert, TestSize.Level0) { - bucket_.Set("test_10", {"test_10", "test_10", "case"}); + bucket_.Set("test_10", { "test_10", "test_10", "case" }); TestValue value; ASSERT_TRUE(!bucket_.Get("test_0", value)); ASSERT_TRUE(bucket_.Get("test_6", value)); @@ -71,18 +72,18 @@ HWTEST_F(LRUBucketTest, insert, TestSize.Level0) } /** -* @tc.name: cap_one_insert -* @tc.desc: Set the value to the lru bucket, whose capacity is one. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: cap_one_insert + * @tc.desc: Set the value to the lru bucket, whose capacity is one. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(LRUBucketTest, cap_one_insert, TestSize.Level0) { bucket_.ResetCapacity(1); for (size_t i = 0; i <= TEST_CAPACITY; ++i) { std::string key = std::string("test_") + std::to_string(i); - TestValue value = {key, key, "find"}; + TestValue value = { key, key, "find" }; bucket_.Set(key, value); } TestValue value; @@ -91,18 +92,18 @@ HWTEST_F(LRUBucketTest, cap_one_insert, TestSize.Level0) } /** -* @tc.name: cap_zero_insert -* @tc.desc: Set the value to the lru bucket, whose capacity is zero. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: cap_zero_insert + * @tc.desc: Set the value to the lru bucket, whose capacity is zero. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(LRUBucketTest, cap_zero_insert, TestSize.Level0) { bucket_.ResetCapacity(0); for (size_t i = 0; i <= TEST_CAPACITY; ++i) { std::string key = std::string("test_") + std::to_string(i); - TestValue value = {key, key, "find"}; + TestValue value = { key, key, "find" }; bucket_.Set(key, value); } TestValue value; @@ -110,12 +111,12 @@ HWTEST_F(LRUBucketTest, cap_zero_insert, TestSize.Level0) } /** -* @tc.name: find_head -* @tc.desc: find the head element from the lru bucket. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: find_head + * @tc.desc: find the head element from the lru bucket. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(LRUBucketTest, find_head, TestSize.Level0) { TestValue value; @@ -126,12 +127,12 @@ HWTEST_F(LRUBucketTest, find_head, TestSize.Level0) } /** -* @tc.name: find_tail -* @tc.desc: find the tail element, then the element will move to head. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: find_tail + * @tc.desc: find the tail element, then the element will move to head. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(LRUBucketTest, find_tail, TestSize.Level0) { TestValue value; @@ -143,12 +144,12 @@ HWTEST_F(LRUBucketTest, find_tail, TestSize.Level0) } /** -* @tc.name: find_mid -* @tc.desc: find the mid element, then the element will move to head. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: find_mid + * @tc.desc: find the mid element, then the element will move to head. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(LRUBucketTest, find_mid, TestSize.Level0) { TestValue value; @@ -160,22 +161,22 @@ HWTEST_F(LRUBucketTest, find_mid, TestSize.Level0) } /** -* @tc.name: find_and_insert -* @tc.desc: find the tail element, then the element will move to head. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: find_and_insert + * @tc.desc: find the tail element, then the element will move to head. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(LRUBucketTest, find_and_insert, TestSize.Level0) { TestValue value; if (!bucket_.Get("MyTest", value)) { - bucket_.Set("MyTest", {"MyTest", "MyTest", "case"}); + bucket_.Set("MyTest", { "MyTest", "MyTest", "case" }); } ASSERT_TRUE(bucket_.Get("MyTest", value)); if (!bucket_.Get("test_0", value)) { - bucket_.Set("test_0", {"test_0", "test_0", "case"}); + bucket_.Set("test_0", { "test_0", "test_0", "case" }); } ASSERT_TRUE(bucket_.Get("test_0", value)); ASSERT_TRUE(bucket_.Get("test_5", value)); @@ -185,12 +186,12 @@ HWTEST_F(LRUBucketTest, find_and_insert, TestSize.Level0) } /** -* @tc.name: del_head -* @tc.desc: delete the head element, then the next element will move to head. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: del_head + * @tc.desc: delete the head element, then the next element will move to head. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(LRUBucketTest, del_head, TestSize.Level0) { TestValue value; @@ -203,12 +204,12 @@ HWTEST_F(LRUBucketTest, del_head, TestSize.Level0) } /** -* @tc.name: del_head -* @tc.desc: delete the tail element, then the lru chain keep valid. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: del_head + * @tc.desc: delete the tail element, then the lru chain keep valid. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(LRUBucketTest, del_tail, TestSize.Level0) { TestValue value; @@ -222,12 +223,12 @@ HWTEST_F(LRUBucketTest, del_tail, TestSize.Level0) } /** -* @tc.name: del_mid -* @tc.desc: delete the mid element, then the lru chain keep valid. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: del_mid + * @tc.desc: delete the mid element, then the lru chain keep valid. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(LRUBucketTest, del_mid, TestSize.Level0) { TestValue value; @@ -243,12 +244,12 @@ HWTEST_F(LRUBucketTest, del_mid, TestSize.Level0) } /** -* @tc.name: del_mid -* @tc.desc: the lru bucket has only one element, then delete it. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: del_mid + * @tc.desc: the lru bucket has only one element, then delete it. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(LRUBucketTest, cap_one_del, TestSize.Level0) { TestValue value; @@ -258,12 +259,12 @@ HWTEST_F(LRUBucketTest, cap_one_del, TestSize.Level0) } /** -* @tc.name: del_mid -* @tc.desc: the lru bucket has no element. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: del_mid + * @tc.desc: the lru bucket has no element. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(LRUBucketTest, cap_zero_del, TestSize.Level0) { TestValue value; @@ -273,19 +274,19 @@ HWTEST_F(LRUBucketTest, cap_zero_del, TestSize.Level0) } /** -* @tc.name: update_one -* @tc.desc: update the value and the lru chain won't change. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: update_one + * @tc.desc: update the value and the lru chain won't change. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(LRUBucketTest, update_one, TestSize.Level0) { TestValue value; - ASSERT_TRUE(bucket_.Update("test_4", {"test_4", "test_4", "update"})); + ASSERT_TRUE(bucket_.Update("test_4", { "test_4", "test_4", "update" })); ASSERT_TRUE(bucket_.Get("test_4", value)); ASSERT_TRUE(value.testCase == "update"); - ASSERT_TRUE(bucket_.Update("test_9", {"test_9", "test_9", "update"})); + ASSERT_TRUE(bucket_.Update("test_9", { "test_9", "test_9", "update" })); ASSERT_TRUE(bucket_.ResetCapacity(1)); ASSERT_TRUE(bucket_.Capacity() == 1); ASSERT_TRUE(bucket_.Size() <= 1); @@ -294,18 +295,20 @@ HWTEST_F(LRUBucketTest, update_one, TestSize.Level0) } /** -* @tc.name: update_several -* @tc.desc: update several values and the lru chain won't change. -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: update_several + * @tc.desc: update several values and the lru chain won't change. + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(LRUBucketTest, update_several, TestSize.Level0) { TestValue value; - std::map values = {{"test_2", {"test_2", "test_2", "update"}}, - {"test_3", {"test_3", "test_3", "update"}}, - {"test_6", {"test_6", "test_6", "update"}}}; + std::map values = { + { "test_2", { "test_2", "test_2", "update" } }, + { "test_3", { "test_3", "test_3", "update" } }, + { "test_6", { "test_6", "test_6", "update" } } + }; ASSERT_TRUE(bucket_.Update(values)); ASSERT_TRUE(bucket_.ResetCapacity(3)); ASSERT_TRUE(bucket_.Capacity() == 3); diff --git a/kv_store/frameworks/common/test/pool_test.cpp b/kv_store/frameworks/common/test/pool_test.cpp index fe3c84de7ac88982f36ac65193b8b94b26050d76..f2d409385b5d0d7b4fc8e343410968a55e80ab8e 100644 --- a/kv_store/frameworks/common/test/pool_test.cpp +++ b/kv_store/frameworks/common/test/pool_test.cpp @@ -16,13 +16,15 @@ #include #include -#include "gtest/gtest.h" -#include "pool.h" #include "log_print.h" +#include "pool.h" +#include "gtest/gtest.h" using namespace testing::ext; using namespace OHOS; namespace OHOS::Test { +static constexpr uint32_t CAPABILITY_TEST = 3; // capability +static constexpr uint32_t MIN_TEST = 1; // min class PoolTest : public testing::Test { public: struct Node { @@ -36,22 +38,16 @@ public: static void TearDownTestCase(void); void SetUp(); void TearDown(); - protected: - static constexpr uint32_t CAPABILITY_TEST = 3; // capability - static constexpr uint32_t MIN_TEST = 1; // min static Pool pool_; }; Pool PoolTest::pool_ = Pool(CAPABILITY_TEST, MIN_TEST); -void PoolTest::SetUpTestCase(void) -{} +void PoolTest::SetUpTestCase(void) { } -void PoolTest::TearDownTestCase(void) -{} +void PoolTest::TearDownTestCase(void) { } -void PoolTest::SetUp(void) -{} +void PoolTest::SetUp(void) { } void PoolTest::TearDown(void) { @@ -63,12 +59,12 @@ void PoolTest::TearDown(void) } /** -* @tc.name: Get_001 -* @tc.desc: test the std::shared_ptr Get(bool isForce = false) function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Get_001 + * @tc.desc: test the std::shared_ptr Get(bool isForce = false) function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PoolTest, Get_001, TestSize.Level1) { int index = 0; @@ -89,12 +85,12 @@ HWTEST_F(PoolTest, Get_001, TestSize.Level1) } /** -* @tc.name: Get_002 -* @tc.desc: test the std::shared_ptr Get(bool isForce = false) function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Get_002 + * @tc.desc: test the std::shared_ptr Get(bool isForce = false) function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PoolTest, Get_002, TestSize.Level1) { int index = 0; @@ -119,12 +115,12 @@ HWTEST_F(PoolTest, Get_002, TestSize.Level1) } /** -* @tc.name: Release_001 -* @tc.desc: test the int32_t Release(std::shared_ptr data, bool force = false) function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Release_001 + * @tc.desc: test the int32_t Release(std::shared_ptr data, bool force = false) function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PoolTest, Release_001, TestSize.Level1) { int index = 0; @@ -141,12 +137,12 @@ HWTEST_F(PoolTest, Release_001, TestSize.Level1) } /** -* @tc.name: Release_002 -* @tc.desc: test the int32_t Release(std::shared_ptr data, bool force = false) function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Release_002 + * @tc.desc: test the int32_t Release(std::shared_ptr data, bool force = false) function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PoolTest, Release_002, TestSize.Level1) { auto ret = pool_.Get(); @@ -158,12 +154,12 @@ HWTEST_F(PoolTest, Release_002, TestSize.Level1) } /** -* @tc.name: Release_003 -* @tc.desc: test the int32_t Release(std::shared_ptr data, bool force = false) function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Release_003 + * @tc.desc: test the int32_t Release(std::shared_ptr data, bool force = false) function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PoolTest, Release_003, TestSize.Level1) { int index = 0; @@ -180,12 +176,12 @@ HWTEST_F(PoolTest, Release_003, TestSize.Level1) } /** -* @tc.name: Release_004 -* @tc.desc: test the int32_t Release(std::shared_ptr data, bool force = false) function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Release_004 + * @tc.desc: test the int32_t Release(std::shared_ptr data, bool force = false) function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PoolTest, Release_004, TestSize.Level1) { int index = 0; @@ -214,12 +210,12 @@ HWTEST_F(PoolTest, Release_004, TestSize.Level1) } /** -* @tc.name: Release_005 -* @tc.desc: test the int32_t Release(std::shared_ptr data, bool force = false) function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Release_005 + * @tc.desc: test the int32_t Release(std::shared_ptr data, bool force = false) function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PoolTest, Release_005, TestSize.Level1) { int index = 0; @@ -237,12 +233,12 @@ HWTEST_F(PoolTest, Release_005, TestSize.Level1) } /** -* @tc.name: Release_006 -* @tc.desc: test the int32_t Release(std::shared_ptr data, bool force = false) function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Release_006 + * @tc.desc: test the int32_t Release(std::shared_ptr data, bool force = false) function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PoolTest, Release_006, TestSize.Level1) { auto ret = pool_.Get(); @@ -254,12 +250,12 @@ HWTEST_F(PoolTest, Release_006, TestSize.Level1) } /** -* @tc.name: Release_007 -* @tc.desc: test the int32_t Release(std::shared_ptr data, bool force = false) function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Release_007 + * @tc.desc: test the int32_t Release(std::shared_ptr data, bool force = false) function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PoolTest, Release_007, TestSize.Level1) { auto ret = nullptr; @@ -268,12 +264,12 @@ HWTEST_F(PoolTest, Release_007, TestSize.Level1) } /** -* @tc.name: Idle_001 -* @tc.desc: test the void Idle(std::shared_ptr data) function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Idle_001 + * @tc.desc: test the void Idle(std::shared_ptr data) function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PoolTest, Idle_001, TestSize.Level1) { int index = 0; @@ -294,12 +290,12 @@ HWTEST_F(PoolTest, Idle_001, TestSize.Level1) } /** -* @tc.name: Clean_001 -* @tc.desc: test the int32_t Clean(std::function)> close) noexcept function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Clean_001 + * @tc.desc: test the int32_t Clean(std::function)> close) noexcept function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PoolTest, Clean_001, TestSize.Level1) { int index = 0; diff --git a/kv_store/frameworks/common/test/priority_queue_test.cpp b/kv_store/frameworks/common/test/priority_queue_test.cpp index 2ac3850b36297ce709947c53412077f81fab4776..1e4f96f9f1f50bac3ec377e49644f04fa53e00c0 100644 --- a/kv_store/frameworks/common/test/priority_queue_test.cpp +++ b/kv_store/frameworks/common/test/priority_queue_test.cpp @@ -13,17 +13,17 @@ * limitations under the License. */ -#include -#include -#include +#include "priority_queue.h" #include -#include -#include +#include +#include #include -#include +#include +#include #include #include -#include "priority_queue.h" +#include +#include namespace OHOS::Test { using namespace testing::ext; @@ -34,7 +34,7 @@ using Duration = std::chrono::steady_clock::duration; using Time = std::chrono::steady_clock::time_point; static constexpr Duration INVALID_INTERVAL = std::chrono::milliseconds(0); static constexpr uint64_t UNLIMITED_TIMES = std::numeric_limits::max(); -static constexpr TaskId INVALID_TASK_ID = static_cast(0l); +static constexpr TaskId INVALID_TASK_ID = static_cast(0); static constexpr uint32_t SHORT_INTERVAL = 100; // ms class PriorityQueueTest : public testing::Test { public: @@ -54,27 +54,22 @@ public: static void TearDownTestCase(void); void SetUp(); void TearDown(); + protected: static PriorityQueue priorityqueue_; static PriorityQueue::PQMatrix pqMatrix; }; using TestTask = PriorityQueueTest::TestTask; PriorityQueue PriorityQueueTest::priorityqueue_ = -PriorityQueue(TestTask()); + PriorityQueue(TestTask()); PriorityQueue::PQMatrix PriorityQueueTest::pqMatrix = -PriorityQueue::PQMatrix(TestTask(), INVALID_TASK_ID); + PriorityQueue::PQMatrix(TestTask(), INVALID_TASK_ID); -void PriorityQueueTest::SetUpTestCase(void) -{ -} +void PriorityQueueTest::SetUpTestCase(void) { } -void PriorityQueueTest::TearDownTestCase(void) -{ -} +void PriorityQueueTest::TearDownTestCase(void) { } -void PriorityQueueTest::SetUp(void) -{ -} +void PriorityQueueTest::SetUp(void) { } void PriorityQueueTest::TearDown(void) { @@ -82,12 +77,12 @@ void PriorityQueueTest::TearDown(void) } /** -* @tc.name: PQMatrix_001 -* @tc.desc: test the PQMatrix(_Tsk task, _Tid id) function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: PQMatrix_001 + * @tc.desc: test the PQMatrix(_Tsk task, _Tid id) function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, PQMatrix_001, TestSize.Level1) { TestTask testTask; @@ -96,12 +91,12 @@ HWTEST_F(PriorityQueueTest, PQMatrix_001, TestSize.Level1) } /** -* @tc.name: PushPopSize_001 -* @tc.desc: Invalid test task. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: PushPopSize_001 + * @tc.desc: Invalid test task. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, PushPopSize_001, TestSize.Level1) { TestTask testTask; @@ -118,12 +113,12 @@ HWTEST_F(PriorityQueueTest, PushPopSize_001, TestSize.Level1) } /** -* @tc.name: PushPopSize_002 -* @tc.desc: Testing a single task. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: PushPopSize_002 + * @tc.desc: Testing a single task. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, PushPopSize_002, TestSize.Level1) { TestTask testTask; @@ -140,12 +135,12 @@ HWTEST_F(PriorityQueueTest, PushPopSize_002, TestSize.Level1) } /** -* @tc.name: PushPopSize_003 -* @tc.desc: Testing multiple tasks. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: PushPopSize_003 + * @tc.desc: Testing multiple tasks. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, PushPopSize_003, TestSize.Level1) { TestTask testTask; @@ -164,12 +159,12 @@ HWTEST_F(PriorityQueueTest, PushPopSize_003, TestSize.Level1) } /** -* @tc.name: PushPopSize_004 -* @tc.desc: Test the delay task. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: PushPopSize_004 + * @tc.desc: Test the delay task. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, PushPopSize_004, TestSize.Level1) { TestTask testTask; @@ -190,23 +185,23 @@ HWTEST_F(PriorityQueueTest, PushPopSize_004, TestSize.Level1) EXPECT_EQ(retSize, 10u); for (int i = 0; i < 5; ++i) { auto retPop = priorityqueue_.Pop(); - EXPECT_EQ(retPop.taskId, i+6); + EXPECT_EQ(retPop.taskId, i + 6); } for (int i = 0; i < 5; ++i) { auto retPop = priorityqueue_.Pop(); - EXPECT_EQ(retPop.taskId, i+1); + EXPECT_EQ(retPop.taskId, i + 1); } retSize = priorityqueue_.Size(); EXPECT_EQ(retSize, 0u); } /** -* @tc.name: PushPopSize_005 -* @tc.desc: Test the delay task. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: PushPopSize_005 + * @tc.desc: Test the delay task. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, PushPopSize_005, TestSize.Level1) { TestTask testTask; @@ -229,12 +224,12 @@ HWTEST_F(PriorityQueueTest, PushPopSize_005, TestSize.Level1) } /** -* @tc.name: Find_001 -* @tc.desc: Invalid test task. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Find_001 + * @tc.desc: Invalid test task. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, Find_001, TestSize.Level1) { TestTask testTask; @@ -247,12 +242,12 @@ HWTEST_F(PriorityQueueTest, Find_001, TestSize.Level1) } /** -* @tc.name: Find_002 -* @tc.desc: test the priority_queue _Tsk Find(_Tid id) function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Find_002 + * @tc.desc: test the priority_queue _Tsk Find(_Tid id) function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, Find_002, TestSize.Level1) { TestTask testTask; @@ -271,15 +266,17 @@ HWTEST_F(PriorityQueueTest, Find_002, TestSize.Level1) } /** -* @tc.name: Update_001 -* @tc.desc: Invalid test task. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Update_001 + * @tc.desc: Invalid test task. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, Update_001, TestSize.Level1) { - auto updater = [](TestTask &) { return std::pair{false, Time()};}; + auto updater = [](TestTask &) { + return std::pair { false, Time() }; + }; auto delay = std::chrono::milliseconds(SHORT_INTERVAL); TestTask testTask; testTask.times = 3; @@ -291,15 +288,17 @@ HWTEST_F(PriorityQueueTest, Update_001, TestSize.Level1) } /** -* @tc.name: Update_002 -* @tc.desc: Test normal tasks. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Update_002 + * @tc.desc: Test normal tasks. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, Update_002, TestSize.Level1) { - auto updater = [](TestTask &) { return std::pair{false, Time()};}; + auto updater = [](TestTask &) { + return std::pair { false, Time() }; + }; auto delay = std::chrono::milliseconds(SHORT_INTERVAL); TestTask testTask; testTask.times = 3; @@ -311,15 +310,17 @@ HWTEST_F(PriorityQueueTest, Update_002, TestSize.Level1) } /** -* @tc.name: Update_003 -* @tc.desc: Test the running tasks. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Update_003 + * @tc.desc: Test the running tasks. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, Update_003, TestSize.Level1) { - auto updater = [](TestTask &) { return std::pair{false, Time()};}; + auto updater = [](TestTask &) { + return std::pair { false, Time() }; + }; auto delay = std::chrono::milliseconds(SHORT_INTERVAL); TestTask testTask; testTask.times = 3; @@ -332,15 +333,17 @@ HWTEST_F(PriorityQueueTest, Update_003, TestSize.Level1) } /** -* @tc.name: Update_004 -* @tc.desc: Test the running tasks. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Update_004 + * @tc.desc: Test the running tasks. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, Update_004, TestSize.Level1) { - auto updater = [](TestTask &) { return std::pair{true, Time()};}; + auto updater = [](TestTask &) { + return std::pair { true, Time() }; + }; auto delay = std::chrono::milliseconds(SHORT_INTERVAL); TestTask testTask; testTask.times = 3; @@ -353,15 +356,17 @@ HWTEST_F(PriorityQueueTest, Update_004, TestSize.Level1) } /** -* @tc.name: Update_005 -* @tc.desc: Test the running and finish tasks. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Update_005 + * @tc.desc: Test the running and finish tasks. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, Update_005, TestSize.Level1) { - auto updater = [](TestTask &) { return std::pair{false, Time()};}; + auto updater = [](TestTask &) { + return std::pair { false, Time() }; + }; auto delay = std::chrono::milliseconds(SHORT_INTERVAL); TestTask testTask; testTask.times = 3; @@ -375,15 +380,17 @@ HWTEST_F(PriorityQueueTest, Update_005, TestSize.Level1) } /** -* @tc.name: Update_006 -* @tc.desc: Test the running and finish tasks. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Update_006 + * @tc.desc: Test the running and finish tasks. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, Update_006, TestSize.Level1) { - auto updater = [](TestTask &) { return std::pair{true, Time()};}; + auto updater = [](TestTask &) { + return std::pair { true, Time() }; + }; auto delay = std::chrono::milliseconds(SHORT_INTERVAL); TestTask testTask; testTask.times = 3; @@ -397,12 +404,12 @@ HWTEST_F(PriorityQueueTest, Update_006, TestSize.Level1) } /** -* @tc.name: Remove_001 -* @tc.desc: Invalid test task. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Remove_001 + * @tc.desc: Invalid test task. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, Remove_001, TestSize.Level1) { TestTask testTask; @@ -417,12 +424,12 @@ HWTEST_F(PriorityQueueTest, Remove_001, TestSize.Level1) } /** -* @tc.name: Remove_002 -* @tc.desc: Single and don't wait test task. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Remove_002 + * @tc.desc: Single and don't wait test task. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, Remove_002, TestSize.Level1) { TestTask testTask; @@ -439,12 +446,12 @@ HWTEST_F(PriorityQueueTest, Remove_002, TestSize.Level1) } /** -* @tc.name: Remove_003 -* @tc.desc: Single and wait test task. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Remove_003 + * @tc.desc: Single and wait test task. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, Remove_003, TestSize.Level1) { TestTask testTask; @@ -462,12 +469,12 @@ HWTEST_F(PriorityQueueTest, Remove_003, TestSize.Level1) } /** -* @tc.name: Clean_001 -* @tc.desc: Testing a single task. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Clean_001 + * @tc.desc: Testing a single task. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, Clean_001, TestSize.Level1) { TestTask testTask; @@ -483,12 +490,12 @@ HWTEST_F(PriorityQueueTest, Clean_001, TestSize.Level1) } /** -* @tc.name: Clean_002 -* @tc.desc: Testing multiple tasks. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Clean_002 + * @tc.desc: Testing multiple tasks. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, Clean_002, TestSize.Level1) { TestTask testTask; @@ -506,12 +513,12 @@ HWTEST_F(PriorityQueueTest, Clean_002, TestSize.Level1) } /** -* @tc.name: Finish_001 -* @tc.desc: test the priority_queue void Finish(_Tid id) function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: suoqilong -*/ + * @tc.name: Finish_001 + * @tc.desc: test the priority_queue void Finish(_Tid id) function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: suoqilong + */ HWTEST_F(PriorityQueueTest, Finish_001, TestSize.Level1) { TestTask testTask; diff --git a/kv_store/frameworks/common/test/task_scheduler_test.cpp b/kv_store/frameworks/common/test/task_scheduler_test.cpp index e4a1c667e53eabbcbebd8a87f8a0f6091a74b0d0..79bfa81f774211d9e612441735c025c912f65e01 100644 --- a/kv_store/frameworks/common/test/task_scheduler_test.cpp +++ b/kv_store/frameworks/common/test/task_scheduler_test.cpp @@ -1,17 +1,17 @@ /* -* Copyright (c) 2022 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. -*/ + * Copyright (c) 2022 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 "task_scheduler.h" @@ -26,19 +26,19 @@ class TaskSchedulerTest : public testing::Test { public: static constexpr uint32_t SHORT_INTERVAL = 100; // ms static constexpr uint32_t LONG_INTERVAL = 1; // s - static void SetUpTestCase(void){}; - static void TearDownTestCase(void){}; - void SetUp(){}; - void TearDown() {} + static void SetUpTestCase(void) {}; + static void TearDownTestCase(void) {}; + void SetUp() {}; + void TearDown() { } }; /** -* @tc.name: At -* @tc.desc: -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ + * @tc.name: At + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: ht + */ HWTEST_F(TaskSchedulerTest, At, TestSize.Level0) { TaskScheduler taskScheduler("atTest"); @@ -61,12 +61,12 @@ HWTEST_F(TaskSchedulerTest, At, TestSize.Level0) } /** -* @tc.name: Every -* @tc.desc:execute task periodically with duration -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ + * @tc.name: Every + * @tc.desc:execute task periodically with duration + * @tc.type: FUNC + * @tc.require: + * @tc.author: ht + */ HWTEST_F(TaskSchedulerTest, ExecuteDuration, TestSize.Level0) { TaskScheduler taskScheduler("everyTest"); @@ -83,12 +83,12 @@ HWTEST_F(TaskSchedulerTest, ExecuteDuration, TestSize.Level0) } /** -* @tc.name: Reset -* @tc.desc: Reset before task execution and the task is tasks_.begin() or not -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ + * @tc.name: Reset + * @tc.desc: Reset before task execution and the task is tasks_.begin() or not + * @tc.type: FUNC + * @tc.require: + * @tc.author: ht + */ HWTEST_F(TaskSchedulerTest, Reset1, TestSize.Level0) { TaskScheduler taskScheduler("reset1Test"); @@ -107,12 +107,12 @@ HWTEST_F(TaskSchedulerTest, Reset1, TestSize.Level0) } /** -* @tc.name: Reset -* @tc.desc: Reset during task execution -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ + * @tc.name: Reset + * @tc.desc: Reset during task execution + * @tc.type: FUNC + * @tc.require: + * @tc.author: ht + */ HWTEST_F(TaskSchedulerTest, Reset2, TestSize.Level0) { TaskScheduler taskScheduler("reset2Test"); @@ -130,12 +130,12 @@ HWTEST_F(TaskSchedulerTest, Reset2, TestSize.Level0) } /** -* @tc.name: Reset -* @tc.desc: Reset after task execution -* @tc.type: FUNC -* @tc.require: -* @tc.author: ht -*/ + * @tc.name: Reset + * @tc.desc: Reset after task execution + * @tc.type: FUNC + * @tc.require: + * @tc.author: ht + */ HWTEST_F(TaskSchedulerTest, Reset3, TestSize.Level0) { TaskScheduler taskScheduler("reset3Test"); @@ -155,27 +155,27 @@ HWTEST_F(TaskSchedulerTest, Reset3, TestSize.Level0) } /** -* @tc.name: Every -* @tc.desc: execute task for some times periodically with duration. -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: Every + * @tc.desc: execute task for some times periodically with duration. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(TaskSchedulerTest, EveryExecuteTimes, TestSize.Level0) { TaskScheduler taskScheduler("everyTimes"); auto blockData = std::make_shared>(LONG_INTERVAL, 0); int testData = 0; int times = 5; - auto taskId = taskScheduler.Every(times, std::chrono::milliseconds(0), - std::chrono::milliseconds(SHORT_INTERVAL), [blockData, times, &testData]() { - testData++; - if (testData < times) { - blockData->Clear(testData); - return; - } - blockData->SetValue(testData); - }); + auto taskId = taskScheduler.Every(times, std::chrono::milliseconds(0), std::chrono::milliseconds(SHORT_INTERVAL), + [blockData, times, &testData]() { + testData++; + if (testData < times) { + blockData->Clear(testData); + return; + } + blockData->SetValue(testData); + }); ASSERT_EQ(blockData->GetValue(), times); auto resetId = taskScheduler.Reset(taskId, std::chrono::milliseconds(SHORT_INTERVAL)); ASSERT_EQ(resetId, TaskScheduler::INVALID_TASK_ID); @@ -183,22 +183,25 @@ HWTEST_F(TaskSchedulerTest, EveryExecuteTimes, TestSize.Level0) } /** -* @tc.name: Remove -* @tc.desc: remove task before execute. -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: Remove + * @tc.desc: remove task before execute. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(TaskSchedulerTest, RemoveBeforeExecute, TestSize.Level0) { TaskScheduler taskScheduler("RemoveBeforeExecute"); auto expiredTime = std::chrono::steady_clock::now() + std::chrono::milliseconds(SHORT_INTERVAL); auto blockData = std::make_shared>(LONG_INTERVAL, 0); int testData = 0; - auto taskId = taskScheduler.At(expiredTime, [blockData, testData]() { - int tmpData = testData + 1; - blockData->SetValue(tmpData); - }, std::chrono::milliseconds(SHORT_INTERVAL)); + auto taskId = taskScheduler.At( + expiredTime, + [blockData, testData]() { + int tmpData = testData + 1; + blockData->SetValue(tmpData); + }, + std::chrono::milliseconds(SHORT_INTERVAL)); taskScheduler.Remove(taskId); auto resetId = taskScheduler.Reset(taskId, std::chrono::milliseconds(SHORT_INTERVAL)); ASSERT_EQ(resetId, TaskScheduler::INVALID_TASK_ID); @@ -206,12 +209,12 @@ HWTEST_F(TaskSchedulerTest, RemoveBeforeExecute, TestSize.Level0) } /** -* @tc.name: Remove -* @tc.desc: remove task during execute, and waiting. -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: Remove + * @tc.desc: remove task during execute, and waiting. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(TaskSchedulerTest, RemoveWaitExecute, TestSize.Level0) { TaskScheduler taskScheduler("RemoveWaitExecute"); @@ -219,12 +222,15 @@ HWTEST_F(TaskSchedulerTest, RemoveWaitExecute, TestSize.Level0) auto blockDataTest = std::make_shared>(LONG_INTERVAL, 0); auto blockDataWait = std::make_shared>(LONG_INTERVAL, 0); int testData = 1; - auto taskId = taskScheduler.At(expiredTime, [blockDataTest, blockDataWait, &testData]() { - blockDataTest->SetValue(testData); - blockDataWait->GetValue(); - int tmpData = testData + 1; - blockDataTest->SetValue(tmpData); - }, std::chrono::milliseconds(SHORT_INTERVAL)); + auto taskId = taskScheduler.At( + expiredTime, + [blockDataTest, blockDataWait, &testData]() { + blockDataTest->SetValue(testData); + blockDataWait->GetValue(); + int tmpData = testData + 1; + blockDataTest->SetValue(tmpData); + }, + std::chrono::milliseconds(SHORT_INTERVAL)); ASSERT_EQ(blockDataTest->GetValue(), testData); auto resetId = taskScheduler.Reset(taskId, std::chrono::milliseconds(SHORT_INTERVAL)); ASSERT_EQ(taskId, resetId); @@ -233,12 +239,12 @@ HWTEST_F(TaskSchedulerTest, RemoveWaitExecute, TestSize.Level0) } /** -* @tc.name: Remove -* @tc.desc: remove task during execute, but no wait. -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: Remove + * @tc.desc: remove task during execute, but no wait. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(TaskSchedulerTest, RemoveNoWaitExecute, TestSize.Level0) { TaskScheduler taskScheduler("RemoveNoWaitExecute"); diff --git a/kv_store/frameworks/common/test/traits_test.cpp b/kv_store/frameworks/common/test/traits_test.cpp index 15c1d664ebd811daaadd39baeb58d4fa6e9e1ebf..2ea7b063c0a525d2732adf5dabe0ca3e56b7a777 100644 --- a/kv_store/frameworks/common/test/traits_test.cpp +++ b/kv_store/frameworks/common/test/traits_test.cpp @@ -21,13 +21,13 @@ class TraitsTest : public testing::Test { public: class From { public: - From() {} + From() { } }; class Convertible { public: // Convertible is auto convert type, do not add explicit to stop the type convert. Convertible(const From &) {}; - Convertible() {} + Convertible() { } Convertible(Convertible &&) noexcept {}; Convertible &operator=(Convertible &&) noexcept { @@ -38,19 +38,19 @@ public: return From(); } }; - static void SetUpTestCase(void){}; - static void TearDownTestCase(void){}; - void SetUp(){}; - void TearDown() {} + static void SetUpTestCase(void) {}; + static void TearDownTestCase(void) {}; + void SetUp() {}; + void TearDown() { } }; /** -* @tc.name: same_index_of_v -* @tc.desc: -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: same_index_of_v + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(TraitsTest, same_index_of_v, TestSize.Level0) { auto index = Traits::same_index_of_v>; @@ -62,12 +62,12 @@ HWTEST_F(TraitsTest, same_index_of_v, TestSize.Level0) } /** -* @tc.name: same_in_v -* @tc.desc: -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: same_in_v + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(TraitsTest, same_in_v, TestSize.Level0) { auto exist = Traits::same_in_v>; @@ -79,12 +79,12 @@ HWTEST_F(TraitsTest, same_in_v, TestSize.Level0) } /** -* @tc.name: convertible_index_of_v -* @tc.desc: -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: convertible_index_of_v + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(TraitsTest, convertible_index_of_v, TestSize.Level0) { auto index = Traits::convertible_index_of_v>; @@ -98,12 +98,12 @@ HWTEST_F(TraitsTest, convertible_index_of_v, TestSize.Level0) } /** -* @tc.name: convertible_in_v -* @tc.desc: -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: convertible_in_v + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(TraitsTest, convertible_in_v, TestSize.Level0) { auto convertible = Traits::convertible_in_v>; @@ -117,12 +117,12 @@ HWTEST_F(TraitsTest, convertible_in_v, TestSize.Level0) } /** -* @tc.name: variant_size_of_v -* @tc.desc: -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: variant_size_of_v + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(TraitsTest, variant_size_of_v, TestSize.Level0) { std::variant> value; @@ -134,12 +134,12 @@ HWTEST_F(TraitsTest, variant_size_of_v, TestSize.Level0) } /** -* @tc.name: variant_index_of_v -* @tc.desc: -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: variant_index_of_v + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(TraitsTest, variant_index_of_v, TestSize.Level0) { std::variant> value; @@ -160,12 +160,12 @@ HWTEST_F(TraitsTest, variant_index_of_v, TestSize.Level0) } /** -* @tc.name: get_if_same_type -* @tc.desc: -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: get_if_same_type + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(TraitsTest, get_if_same_type, TestSize.Level0) { // 1. When the _Tp is a type in the ..._Types, the get_if is equal to the std::get_if. @@ -188,12 +188,12 @@ HWTEST_F(TraitsTest, get_if_same_type, TestSize.Level0) ASSERT_TRUE(strcmp(*charPtr, "test case") == 0); } /** -* @tc.name: get_if_convertible_type -* @tc.desc: -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: get_if_convertible_type + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(TraitsTest, get_if_convertible_type, TestSize.Level0) { // 2. When the _Tp is not a type in the ..._Types but someone in the ...Types can convert to _Tp implicitly, @@ -219,12 +219,12 @@ HWTEST_F(TraitsTest, get_if_convertible_type, TestSize.Level0) } /** -* @tc.name: get_if_invalid_type -* @tc.desc: -* @tc.type: FUNC -* @tc.require: -* @tc.author: Sven Wang -*/ + * @tc.name: get_if_invalid_type + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: Sven Wang + */ HWTEST_F(TraitsTest, get_if_invalid_type, TestSize.Level0) { // 3. When the _Tp is not a type in the ..._Types and can't convert, the get_if will return nullptr. diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/include/ikvstore_observer.h b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/include/ikvstore_observer.h index ff50ce010ff7a8a4f3c31ea00462fea3076c0d00..988b0d5cc7e5dddeb357fc198b5b1b892d8a38fd 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/include/ikvstore_observer.h +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/include/ikvstore_observer.h @@ -47,16 +47,6 @@ public: int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; }; - -class API_EXPORT KvStoreObserverProxy : public IRemoteProxy { -public: - explicit KvStoreObserverProxy(const sptr &impl); - ~KvStoreObserverProxy() = default; - void OnChange(const ChangeNotification &changeNotification) override; - void OnChange(const DataOrigin &origin, Keys &&keys) override; -private: - static inline BrokerDelegator delegator_; -}; } // namespace DistributedKv } // namespace OHOS diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/include/kvstore_datashare_bridge.h b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/include/kvstore_datashare_bridge.h index fee9d3811cfc8cf325479f779658eb2973ba46e4..474c88d1da915146d528177b3d7a5a2318e1fe51 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/include/kvstore_datashare_bridge.h +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/include/kvstore_datashare_bridge.h @@ -34,7 +34,7 @@ public: int GetAllColumnNames(std::vector &columnNames) override; int OnGo(int32_t startRowIndex, int32_t targetRowIndex, DataShare::ResultSetBridge::Writer &writer) override; - + private: int Count(); diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/data_query.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/data_query.cpp index 3923637f603abe4d3ef47458d33992ce7e8248fb..8e325a8cb5384fd561b4b06e02497866e350b3c2 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/data_query.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/data_query.cpp @@ -632,7 +632,7 @@ DataQuery& DataQuery::InKeys(const std::vector &keys) return *this; } if (hasKeys_) { - ZLOGE("cannot set inkeys more than once"); + ZLOGE("Cannot set inkeys more than once"); return *this; } hasKeys_ = true; @@ -793,7 +793,7 @@ void DataQuery::EscapeSpace(std::string &input) bool DataQuery::ValidateField(const std::string &field) { if (field.empty() || field.find(DataQuery::SPECIAL) != std::string::npos) { - ZLOGE("invalid string argument"); + ZLOGE("Invalid string argument"); return false; } return true; diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/distributed_kv_data_manager.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/distributed_kv_data_manager.cpp index 5951b47e15291336a6469ea2c5cfc9c58e5155cc..b0c5d8c059e06d5a334ffa1ac0b1c9fce00207ef 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/distributed_kv_data_manager.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/distributed_kv_data_manager.cpp @@ -48,7 +48,7 @@ Status DistributedKvDataManager::GetSingleKvStore(const Options &options, const singleKvStore = nullptr; if (options.securityLevel == INVALID_LABEL) { - ZLOGE("invalid security level, appId = %{private}s, storeId = %{private}s, kvStoreType = %{private}d", + ZLOGE("Invalid security level, appId = %{private}s, storeId = %{private}s, kvStoreType = %{private}d", appId.appId.c_str(), storeId.storeId.c_str(), options.kvStoreType); return Status::INVALID_ARGUMENT; } @@ -57,11 +57,11 @@ Status DistributedKvDataManager::GetSingleKvStore(const Options &options, const return Status::INVALID_ARGUMENT; } if (!storeId.IsValid()) { - ZLOGE("invalid storeId."); + ZLOGE("Invalid storeId."); return Status::INVALID_ARGUMENT; } if (!options.IsPathValid()) { - ZLOGE("invalid path."); + ZLOGE("Invalid path."); return Status::INVALID_ARGUMENT; } KvStoreServiceDeathNotifier::SetAppId(appId); @@ -86,7 +86,7 @@ Status DistributedKvDataManager::CloseKvStore(const AppId &appId, const StoreId KvStoreServiceDeathNotifier::SetAppId(appId); if (!storeId.IsValid()) { - ZLOGE("invalid storeId."); + ZLOGE("Invalid storeId."); return Status::INVALID_ARGUMENT; } @@ -99,7 +99,7 @@ Status DistributedKvDataManager::CloseKvStore(const AppId &appId, std::shared_pt TraceSwitch::BYTRACE_ON | TraceSwitch::TRACE_CHAIN_ON); if (kvStorePtr == nullptr) { - ZLOGE("kvStorePtr is nullptr."); + ZLOGE("This kvStorePtr is nullptr."); return Status::INVALID_ARGUMENT; } KvStoreServiceDeathNotifier::SetAppId(appId); @@ -123,11 +123,11 @@ Status DistributedKvDataManager::DeleteKvStore(const AppId &appId, const StoreId DdsTrace trace(std::string(LOG_TAG "::") + std::string(__FUNCTION__), TraceSwitch::BYTRACE_ON | TraceSwitch::TRACE_CHAIN_ON); if (!storeId.IsValid()) { - ZLOGE("invalid storeId."); + ZLOGE("Invalid storeId."); return Status::INVALID_ARGUMENT; } if (path.empty()) { - ZLOGE("path empty"); + ZLOGE("This path is empty"); return Status::INVALID_ARGUMENT; } KvStoreServiceDeathNotifier::SetAppId(appId); @@ -140,7 +140,7 @@ Status DistributedKvDataManager::DeleteAllKvStore(const AppId &appId, const std: DdsTrace trace(std::string(LOG_TAG "::") + std::string(__FUNCTION__), TraceSwitch::BYTRACE_ON | TraceSwitch::TRACE_CHAIN_ON); if (path.empty()) { - ZLOGE("path empty"); + ZLOGE("This path is empty"); return Status::INVALID_ARGUMENT; } KvStoreServiceDeathNotifier::SetAppId(appId); @@ -162,7 +162,7 @@ Status DistributedKvDataManager::DeleteAllKvStore(const AppId &appId, const std: void DistributedKvDataManager::RegisterKvStoreServiceDeathRecipient( std::shared_ptr kvStoreDeathRecipient) { - ZLOGD("begin"); + ZLOGD("Begin"); if (kvStoreDeathRecipient == nullptr) { ZLOGW("Register KvStoreService Death Recipient input is null."); return; @@ -173,7 +173,7 @@ void DistributedKvDataManager::RegisterKvStoreServiceDeathRecipient( void DistributedKvDataManager::UnRegisterKvStoreServiceDeathRecipient( std::shared_ptr kvStoreDeathRecipient) { - ZLOGD("begin"); + ZLOGD("Begin"); if (kvStoreDeathRecipient == nullptr) { ZLOGW("UnRegister KvStoreService Death Recipient input is null."); return; diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/ikvstore_observer.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/ikvstore_observer.cpp index cab13bfead1cac6cd2d9c775d3a03e15dde6dc12..471d5f8da54871184f386ec5a1420d117ceb8d6e 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/ikvstore_observer.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/ikvstore_observer.cpp @@ -32,85 +32,13 @@ enum { ONCHANGE, }; -KvStoreObserverProxy::KvStoreObserverProxy(const sptr &impl) : IRemoteProxy(impl) -{ -} - -int64_t GetBufferSize(const std::vector &entries) -{ - int64_t bufferSize = 0; - for (const auto &item : entries) { - bufferSize += item.key.RawSize() + item.value.RawSize(); - } - return bufferSize; -} - -void KvStoreObserverProxy::OnChange(const ChangeNotification &changeNotification) -{ - MessageParcel data; - MessageParcel reply; - if (!data.WriteInterfaceToken(KvStoreObserverProxy::GetDescriptor())) { - ZLOGE("write descriptor failed"); - return; - } - int64_t insertSize = ITypesUtil::GetTotalSize(changeNotification.GetInsertEntries()); - int64_t updateSize = ITypesUtil::GetTotalSize(changeNotification.GetUpdateEntries()); - int64_t deleteSize = ITypesUtil::GetTotalSize(changeNotification.GetDeleteEntries()); - int64_t totalSize = insertSize + updateSize + deleteSize + sizeof(uint32_t); - if (insertSize < 0 || updateSize < 0 || deleteSize < 0 || !data.WriteInt32(totalSize)) { - ZLOGE("Write ChangeNotification buffer size to parcel failed."); - return; - } - ZLOGD("I(%" PRId64 ") U(%" PRId64 ") D(%" PRId64 ") T(%" PRId64 ")", insertSize, updateSize, deleteSize, totalSize); - if (totalSize < SWITCH_RAW_DATA_SIZE) { - if (!ITypesUtil::Marshal(data, changeNotification)) { - ZLOGW("Write ChangeNotification to parcel failed."); - return; - } - } else { - if (!ITypesUtil::Marshal(data, changeNotification.GetDeviceId(), uint32_t(changeNotification.IsClear())) || - !ITypesUtil::MarshalToBuffer(changeNotification.GetInsertEntries(), insertSize, data) || - !ITypesUtil::MarshalToBuffer(changeNotification.GetUpdateEntries(), updateSize, data) || - !ITypesUtil::MarshalToBuffer(changeNotification.GetDeleteEntries(), deleteSize, data)) { - ZLOGE("WriteChangeList to Parcel by buffer failed"); - return; - } - } - - MessageOption mo{ MessageOption::TF_WAIT_TIME }; - int error = Remote()->SendRequest(ONCHANGE, data, reply, mo); - if (error != 0) { - ZLOGE("SendRequest failed, error %d", error); - } -} - -void KvStoreObserverProxy::OnChange(const DataOrigin &origin, Keys &&keys) -{ - MessageParcel data; - MessageParcel reply; - if (!data.WriteInterfaceToken(KvStoreObserverProxy::GetDescriptor())) { - ZLOGE("write descriptor failed"); - return; - } - if (!ITypesUtil::Marshal(data, origin.store, keys[OP_INSERT], keys[OP_UPDATE], keys[OP_DELETE])) { - ZLOGE("WriteChangeInfo to Parcel failed."); - return; - } - - MessageOption mo{ MessageOption::TF_WAIT_TIME }; - int error = Remote()->SendRequest(CLOUD_ONCHANGE, data, reply, mo); - if (error != 0) { - ZLOGE("SendRequest failed, error %d", error); - } -} - int32_t KvStoreObserverStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) { ZLOGD("code:%{public}u, callingPid:%{public}d", code, IPCSkeleton::GetCallingPid()); const int errorResult = -1; if (KvStoreObserverStub::GetDescriptor() != data.ReadInterfaceToken()) { - ZLOGE("local descriptor is not equal to remote"); + ZLOGE("Local descriptor is not equal to remote"); return errorResult; } switch (code) { @@ -118,7 +46,7 @@ int32_t KvStoreObserverStub::OnRemoteRequest(uint32_t code, MessageParcel &data, if (data.ReadInt32() < SWITCH_RAW_DATA_SIZE) { ChangeNotification notification({}, {}, {}, "", false); if (!ITypesUtil::Unmarshal(data, notification)) { - ZLOGE("changeNotification is nullptr"); + ZLOGE("ChangeNotification is nullptr"); return errorResult; } OnChange(notification); diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kv_utils.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kv_utils.cpp index 4960860c802400d1aebf9ded9f55c756b36f8025..e6040d5070ef4bb8baf1da585b04334d0351856c 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kv_utils.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kv_utils.cpp @@ -33,7 +33,7 @@ constexpr KvUtils::QueryHandler KvUtils::HANDLERS[LAST_TYPE]; std::shared_ptr KvUtils::ToResultSetBridge(std::shared_ptr resultSet) { if (resultSet == nullptr) { - ZLOGE("param error, kvResultSet nullptr"); + ZLOGE("This param is error, kvResultSet is nullptr"); return nullptr; } return std::make_shared(resultSet); @@ -44,7 +44,7 @@ Status KvUtils::ToQuery(const DataShareAbsPredicates &predicates, DataQuery &que const auto &operations = predicates.GetOperationList(); for (const auto &oper : operations) { if (oper.operation < 0 || oper.operation >= LAST_TYPE) { - ZLOGE("operation param error"); + ZLOGE("This operation param is error"); return Status::NOT_SUPPORT; } (*HANDLERS[oper.operation])(oper, query); @@ -66,7 +66,7 @@ Entry KvUtils::ToEntry(const DataShareValuesBucket &valueBucket) { const auto &values = valueBucket.valuesMap; if (values.empty()) { - ZLOGE("valuesMap is null"); + ZLOGE("This valuesMap is null"); return {}; } Entry entry; @@ -87,14 +87,14 @@ Status KvUtils::GetKeys(const DataShareAbsPredicates &predicates, std::vector myKeys; for (const auto &oper : operations) { if (oper.operation != IN_KEY) { - ZLOGE("find operation failed"); + ZLOGE("This find operation is failed"); return Status::NOT_SUPPORT; } auto *val = std::get_if>(&oper.multiParams[0]); @@ -113,7 +113,7 @@ Status KvUtils::ToEntryKey(const std::map(&it->second)) { @@ -123,7 +123,7 @@ Status KvUtils::ToEntryKey(const std::map &mask, int32_t dataType) { - ZLOGD("remote changed mask:%{public}zu dataType:%{public}d", mask.size(), dataType); + ZLOGD("Remote changed mask:%{public}zu dataType:%{public}d", mask.size(), dataType); DataType type = static_cast(dataType); for (const auto &[device, changed] : mask) { auto clientUuid = DevManager::GetInstance().ToUUID(device); @@ -116,7 +116,7 @@ void KVDBNotifierClient::AddSyncCallback( const std::shared_ptr callback, uint64_t sequenceId) { if (callback == nullptr) { - ZLOGE("callback is nullptr"); + ZLOGE("This callback is nullptr"); return; } auto inserted = syncCallbackInfo_.Insert(sequenceId, callback); @@ -150,7 +150,7 @@ void KVDBNotifierClient::AddSwitchCallback(const std::string &appId, std::shared return; } if (switchObservers_.Contains(uintptr_t(observer.get()))) { - ZLOGI("duplicate observer"); + ZLOGI("Duplicate observer"); return; } switchObservers_.Insert(uintptr_t(observer.get()), observer); diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvdb_notifier_stub.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvdb_notifier_stub.cpp index 22f81088d001a4c8391d3c4484c27abde8af2032..14c11e25072a9f7c225d90929f259d82c76edc49 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvdb_notifier_stub.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvdb_notifier_stub.cpp @@ -45,14 +45,14 @@ int32_t KVDBNotifierStub::OnRemoteRequest( std::u16string local = KVDBNotifierStub::GetDescriptor(); std::u16string remote = data.ReadInterfaceToken(); if (local != remote) { - ZLOGE("local descriptor is not equal to remote"); + ZLOGE("Local descriptor is not equal to remote"); return -1; } if (code >= static_cast(KVDBNotifierCode::TRANS_HEAD) && code < static_cast(KVDBNotifierCode::TRANS_BUTT) && HANDLERS[code] != nullptr) { return (this->*HANDLERS[code])(data, reply); } - ZLOGE("not support code:%{public}u, BUTT:%{public}d", + ZLOGE("Not support code:%{public}u, BUTT:%{public}d", code, static_cast(KVDBNotifierCode::TRANS_BUTT)); return IPCObjectStub::OnRemoteRequest(code, data, reply, option); } diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_client_death_observer.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_client_death_observer.cpp index 0d2706bc43690632d948dfab85c955f05d1fdce8..401f083f926dbf2b7fc72e29e8071deaa6055a22 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_client_death_observer.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_client_death_observer.cpp @@ -22,12 +22,12 @@ namespace OHOS { namespace DistributedKv { KvStoreClientDeathObserver::KvStoreClientDeathObserver() { - ZLOGI("this client death observer"); + ZLOGI("This client death observer"); } KvStoreClientDeathObserver::~KvStoreClientDeathObserver() { - ZLOGI("destructor this client death observer"); + ZLOGI("Destructor this client death observer"); } } // namespace DistributedKv } // namespace OHOS diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_datashare_bridge.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_datashare_bridge.cpp index a1e1e4e57582689abe7cf680e06f6081d13952fe..eeb679bc7ce6f2881e25cf3d273aebc12f6b3318 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_datashare_bridge.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_datashare_bridge.cpp @@ -38,7 +38,7 @@ int KvStoreDataShareBridge::GetAllColumnNames(std::vector &columnsN bool KvStoreDataShareBridge::FillBlock(int pos, ResultSetBridge::Writer &writer) { if (kvResultSet_ == nullptr) { - ZLOGE("kvResultSet_ nullptr"); + ZLOGE("This kvResultSet_ is nullptr"); return false; } bool isMoved = kvResultSet_->MoveToPosition(pos); @@ -73,7 +73,7 @@ bool KvStoreDataShareBridge::FillBlock(int pos, ResultSetBridge::Writer &writer) int KvStoreDataShareBridge::Count() { if (kvResultSet_ == nullptr) { - ZLOGE("kvResultSet_ nullptr"); + ZLOGE("This kvResultSet_ is nullptr"); return INVALID_COUNT; } if (resultRowCount != INVALID_COUNT) { @@ -81,7 +81,7 @@ int KvStoreDataShareBridge::Count() } int count = kvResultSet_->GetCount(); if (count < 0) { - ZLOGE("kvResultSet count invalid: %{public}d", count); + ZLOGE("This kvResultSet count is invalid: %{public}d", count); return INVALID_COUNT; } resultRowCount = count; @@ -90,13 +90,13 @@ int KvStoreDataShareBridge::Count() int KvStoreDataShareBridge::OnGo(int32_t start, int32_t target, ResultSetBridge::Writer &writer) { if ((start < 0) || (target < 0) || (start > target) || (target >= Count())) { - ZLOGE("nowRowIndex out of line: %{public}d", target); + ZLOGE("The nowRowIndex out of line: %{public}d", target); return -1; } for (int pos = start; pos <= target; pos++) { bool ret = FillBlock(pos, writer); if (!ret) { - ZLOGE("nowRowIndex out of line: %{public}d %{public}d", pos, target); + ZLOGE("The nowRowIndex out of line: %{public}d %{public}d", pos, target); return pos - 1; } } diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_observer_client.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_observer_client.cpp index c29509602020bea7b7b177b51c7ca413f7938ef0..2acce4fb147d3d6d936ff6fa03015169315d71a8 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_observer_client.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_observer_client.cpp @@ -23,17 +23,17 @@ namespace DistributedKv { KvStoreObserverClient::KvStoreObserverClient(std::shared_ptr kvStoreObserver) : kvStoreObserver_(kvStoreObserver) { - ZLOGI("start"); + ZLOGI("Start"); } KvStoreObserverClient::~KvStoreObserverClient() { - ZLOGI("end"); + ZLOGI("End"); } void KvStoreObserverClient::OnChange(const ChangeNotification &changeNotification) { - ZLOGI("start"); + ZLOGI("Start"); if (kvStoreObserver_ != nullptr) { ZLOGI("SINGLE_VERSION start"); kvStoreObserver_->OnChange(changeNotification); @@ -42,7 +42,7 @@ void KvStoreObserverClient::OnChange(const ChangeNotification &changeNotificatio void KvStoreObserverClient::OnChange(const DataOrigin &origin, IKvStoreObserver::Keys &&keys) { - ZLOGI("start"); + ZLOGI("Start"); if (kvStoreObserver_ != nullptr) { kvStoreObserver_->OnChange(origin, std::move(keys)); } diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_observer_nb_impl.h b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_observer_nb_impl.h index 0b66a828445f0bf31aa21382bcf64b15c2f34568..37ff16a9445617ba06a04424ece61416611c6974 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_observer_nb_impl.h +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_observer_nb_impl.h @@ -34,7 +34,7 @@ public: virtual void OnChange(const DistributedDB::KvStoreChangedData &data) { if (appKvStoreObserver_ == nullptr) { - ZLOGE("appKvStoreObserver_ is nullptr."); + ZLOGE("This appKvStoreObserver_ is nullptr."); return; } std::list insertList = data.GetEntriesInserted(); diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_service_death_notifier.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_service_death_notifier.cpp index 9e4060512d45fa82c07f37aa3c03d7f35ceb78d1..b391016941abdad5c42385a39644e00b8a0f7a9b 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_service_death_notifier.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/src/kvstore_service_death_notifier.cpp @@ -52,36 +52,36 @@ AppId KvStoreServiceDeathNotifier::GetAppId() sptr KvStoreServiceDeathNotifier::GetDistributedKvDataService() { - ZLOGD("begin."); + ZLOGD("Begin."); auto &instance = GetInstance(); std::lock_guard lg(instance.watchMutex_); if (instance.kvDataServiceProxy_ != nullptr) { return instance.kvDataServiceProxy_; } - ZLOGI("create remote proxy."); + ZLOGI("Create remote proxy."); auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); if (samgr == nullptr) { - ZLOGE("get samgr fail."); + ZLOGE("Get samgr fail."); return nullptr; } auto remote = samgr->CheckSystemAbility(DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID); instance.kvDataServiceProxy_ = iface_cast(remote); if (instance.kvDataServiceProxy_ == nullptr) { - ZLOGE("initialize proxy failed."); + ZLOGE("Initialize proxy failed."); return nullptr; } if (instance.deathRecipientPtr_ == nullptr) { instance.deathRecipientPtr_ = new (std::nothrow) ServiceDeathRecipient(); if (instance.deathRecipientPtr_ == nullptr) { - ZLOGW("new KvStoreDeathRecipient failed"); + ZLOGW("New KvStoreDeathRecipient failed"); return nullptr; } } if ((remote->IsProxyObject()) && (!remote->AddDeathRecipient(instance.deathRecipientPtr_))) { - ZLOGE("failed to add death recipient."); + ZLOGE("Failed to add death recipient."); } instance.RegisterClientDeathObserver(); @@ -98,7 +98,7 @@ void KvStoreServiceDeathNotifier::RegisterClientDeathObserver() clientDeathObserverPtr_ = new (std::nothrow) KvStoreClientDeathObserver(); } if (clientDeathObserverPtr_ == nullptr) { - ZLOGW("new KvStoreClientDeathObserver failed"); + ZLOGW("New KvStoreClientDeathObserver failed"); return; } kvDataServiceProxy_->RegisterClientDeathObserver(GetAppId(), clientDeathObserverPtr_); @@ -110,9 +110,9 @@ void KvStoreServiceDeathNotifier::AddServiceDeathWatcher(std::shared_ptr lg(instance.watchMutex_); auto ret = instance.serviceDeathWatchers_.insert(std::move(watcher)); if (ret.second) { - ZLOGI("success set size: %zu", instance.serviceDeathWatchers_.size()); + ZLOGI("Success set size: %zu", instance.serviceDeathWatchers_.size()); } else { - ZLOGE("failed set size: %zu", instance.serviceDeathWatchers_.size()); + ZLOGE("Failed set size: %zu", instance.serviceDeathWatchers_.size()); } } @@ -123,9 +123,9 @@ void KvStoreServiceDeathNotifier::RemoveServiceDeathWatcher(std::shared_ptr lg(instance.watchMutex_); instance.kvDataServiceProxy_ = nullptr; - ZLOGI("watcher set size: %zu", instance.serviceDeathWatchers_.size()); + ZLOGI("Watcher set size: %zu", instance.serviceDeathWatchers_.size()); for (const auto &watcher : instance.serviceDeathWatchers_) { if (watcher == nullptr) { - ZLOGI("watcher is nullptr"); + ZLOGI("This watcher is nullptr"); continue; } TaskExecutor::GetInstance().Execute([watcher] { @@ -150,12 +150,12 @@ void KvStoreServiceDeathNotifier::ServiceDeathRecipient::OnRemoteDied(const wptr KvStoreServiceDeathNotifier::ServiceDeathRecipient::ServiceDeathRecipient() { - ZLOGI("constructor."); + ZLOGI("Constructor."); } KvStoreServiceDeathNotifier::ServiceDeathRecipient::~ServiceDeathRecipient() { - ZLOGI("destructor."); + ZLOGI("Destructor."); } } // namespace DistributedKv } // namespace OHOS diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/blob_test.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/blob_test.cpp index f4bdaff333808624e067a641f34edf077be981de..776adf6e595ca26b6239db62199b3cea4fb0ae78 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/blob_test.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/blob_test.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2024 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 @@ -13,11 +13,11 @@ * limitations under the License. */ -#include +#include "kv_types_util.h" +#include "types.h" #include +#include #include -#include "types.h" -#include "kv_types_util.h" using namespace testing::ext; using namespace OHOS::DistributedKv; using namespace OHOS; @@ -30,25 +30,21 @@ public: void TearDown(); }; -void BlobTest::SetUpTestCase(void) -{} +void BlobTest::SetUpTestCase(void) { } -void BlobTest::TearDownTestCase(void) -{} +void BlobTest::TearDownTestCase(void) { } -void BlobTest::SetUp(void) -{} +void BlobTest::SetUp(void) { } -void BlobTest::TearDown(void) -{} +void BlobTest::TearDown(void) { } /** -* @tc.name: Size001 -* @tc.desc: construct a Blob and check its size. -* @tc.type: FUNC -* @tc.require: AR000C6GBG -* @tc.author: liqiao -*/ + * @tc.name: Size001 + * @tc.desc: construct a Blob and check its size. + * @tc.type: FUNC + * @tc.require: AR000C6GBG + * @tc.author: liqiao + */ HWTEST_F(BlobTest, Size001, TestSize.Level0) { Blob blob1; @@ -60,7 +56,7 @@ HWTEST_F(BlobTest, Size001, TestSize.Level0) std::string strTmp = "123"; Blob blob4(strTmp.c_str()); EXPECT_EQ(blob4.Size(), (size_t)3); - std::vector vec = {'1', '2', '3', '4'}; + std::vector vec = { '1', '2', '3', '4' }; Blob blob5(vec); EXPECT_EQ(blob5.Size(), (size_t)4); const char *chr1 = strTmp.c_str(); @@ -73,12 +69,12 @@ HWTEST_F(BlobTest, Size001, TestSize.Level0) } /** -* @tc.name: Empty001 -* @tc.desc: construct a Blob and check its empty. -* @tc.type: FUNC -* @tc.require: AR000C6GBG -* @tc.author: liqiao -*/ + * @tc.name: Empty001 + * @tc.desc: construct a Blob and check its empty. + * @tc.type: FUNC + * @tc.require: AR000C6GBG + * @tc.author: liqiao + */ HWTEST_F(BlobTest, Empty001, TestSize.Level0) { Blob blob1; @@ -90,7 +86,7 @@ HWTEST_F(BlobTest, Empty001, TestSize.Level0) std::string strTmp = "123"; Blob blob4(strTmp.c_str()); EXPECT_EQ(blob4.Empty(), false); - std::vector vec = {'1', '2', '3', '4'}; + std::vector vec = { '1', '2', '3', '4' }; Blob blob5(vec); EXPECT_EQ(blob5.Empty(), false); const char *chr1 = strTmp.c_str(); @@ -99,12 +95,12 @@ HWTEST_F(BlobTest, Empty001, TestSize.Level0) } /** -* @tc.name: Clear001 -* @tc.desc: construct a Blob and check it clear function. -* @tc.type: FUNC -* @tc.require: AR000C6GBG -* @tc.author: liqiao -*/ + * @tc.name: Clear001 + * @tc.desc: construct a Blob and check it clear function. + * @tc.type: FUNC + * @tc.require: AR000C6GBG + * @tc.author: liqiao + */ HWTEST_F(BlobTest, Clear001, TestSize.Level0) { Blob blob1 = "1234567890"; @@ -118,19 +114,19 @@ HWTEST_F(BlobTest, Clear001, TestSize.Level0) Blob blob3(chr); blob3.Clear(); EXPECT_EQ(blob3.Empty(), true); - std::vector vec = {'1', '2', '3', '4'}; + std::vector vec = { '1', '2', '3', '4' }; Blob blob4(vec); blob4.Clear(); EXPECT_EQ(blob4.Empty(), true); } /** -* @tc.name: StartsWith001 -* @tc.desc: construct a Blob and check it StartsWith function. -* @tc.type: FUNC -* @tc.require: AR000C6GBG -* @tc.author: liqiao -*/ + * @tc.name: StartsWith001 + * @tc.desc: construct a Blob and check it StartsWith function. + * @tc.type: FUNC + * @tc.require: AR000C6GBG + * @tc.author: liqiao + */ HWTEST_F(BlobTest, StartsWith001, TestSize.Level0) { Blob blob1 = "1234567890"; @@ -143,12 +139,12 @@ HWTEST_F(BlobTest, StartsWith001, TestSize.Level0) } /** -* @tc.name: Compare001 -* @tc.desc: construct a Blob and check it compare function. -* @tc.type: FUNC -* @tc.require: AR000C6GBG -* @tc.author: liqiao -*/ + * @tc.name: Compare001 + * @tc.desc: construct a Blob and check it compare function. + * @tc.type: FUNC + * @tc.require: AR000C6GBG + * @tc.author: liqiao + */ HWTEST_F(BlobTest, Compare001, TestSize.Level0) { Blob blob1 = "1234567890"; @@ -160,29 +156,29 @@ HWTEST_F(BlobTest, Compare001, TestSize.Level0) } /** -* @tc.name: Data001 -* @tc.desc: construct a Blob and check it Data function. -* @tc.type: FUNC -* @tc.require: AR000C6GBG -* @tc.author: liqiao -*/ + * @tc.name: Data001 + * @tc.desc: construct a Blob and check it Data function. + * @tc.type: FUNC + * @tc.require: AR000C6GBG + * @tc.author: liqiao + */ HWTEST_F(BlobTest, Data001, TestSize.Level0) { - std::vector result = {'1', '2', '3', '4'}; + std::vector result = { '1', '2', '3', '4' }; Blob blob1("1234"); EXPECT_EQ(blob1.Data(), result); - std::vector result2 = {'1', '2', '3', '4', '5'}; + std::vector result2 = { '1', '2', '3', '4', '5' }; Blob blob2("12345"); EXPECT_EQ(blob2.Data(), result2); } /** -* @tc.name: ToString001 -* @tc.desc: construct a Blob and check it ToString function. -* @tc.type: FUNC -* @tc.require: AR000C6GBG -* @tc.author: liqiao -*/ + * @tc.name: ToString001 + * @tc.desc: construct a Blob and check it ToString function. + * @tc.type: FUNC + * @tc.require: AR000C6GBG + * @tc.author: liqiao + */ HWTEST_F(BlobTest, ToString001, TestSize.Level0) { Blob blob1("1234"); @@ -191,12 +187,12 @@ HWTEST_F(BlobTest, ToString001, TestSize.Level0) } /** -* @tc.name: OperatorEqual001 -* @tc.desc: construct a Blob and check it operator== function. -* @tc.type: FUNC -* @tc.require: AR000C6GBG -* @tc.author: liqiao -*/ + * @tc.name: OperatorEqual001 + * @tc.desc: construct a Blob and check it operator== function. + * @tc.type: FUNC + * @tc.require: AR000C6GBG + * @tc.author: liqiao + */ HWTEST_F(BlobTest, OperatorEqual001, TestSize.Level0) { Blob blob1("1234"); @@ -207,12 +203,12 @@ HWTEST_F(BlobTest, OperatorEqual001, TestSize.Level0) } /** -* @tc.name: Operator001 -* @tc.desc: construct a Blob and check it operator[] function. -* @tc.type: FUNC -* @tc.require: AR000C6GBG -* @tc.author: liqiao -*/ + * @tc.name: Operator001 + * @tc.desc: construct a Blob and check it operator[] function. + * @tc.type: FUNC + * @tc.require: AR000C6GBG + * @tc.author: liqiao + */ HWTEST_F(BlobTest, Operator001, TestSize.Level0) { Blob blob1("1234"); @@ -224,12 +220,12 @@ HWTEST_F(BlobTest, Operator001, TestSize.Level0) } /** -* @tc.name: Operator002 -* @tc.desc: construct a Blob and check it operator= function. -* @tc.type: FUNC -* @tc.require: AR000C6GBG -* @tc.author: liqiao -*/ + * @tc.name: Operator002 + * @tc.desc: construct a Blob and check it operator= function. + * @tc.type: FUNC + * @tc.require: AR000C6GBG + * @tc.author: liqiao + */ HWTEST_F(BlobTest, Operator002, TestSize.Level0) { Blob blob1("1234"); @@ -239,12 +235,12 @@ HWTEST_F(BlobTest, Operator002, TestSize.Level0) } /** -* @tc.name: Operator003 -* @tc.desc: construct a Blob and check it operator= function. -* @tc.type: FUNC -* @tc.require: AR000C6GBG -* @tc.author: liqiao -*/ + * @tc.name: Operator003 + * @tc.desc: construct a Blob and check it operator= function. + * @tc.type: FUNC + * @tc.require: AR000C6GBG + * @tc.author: liqiao + */ HWTEST_F(BlobTest, Operator003, TestSize.Level0) { Blob blob1("1234"); @@ -255,12 +251,12 @@ HWTEST_F(BlobTest, Operator003, TestSize.Level0) } /** -* @tc.name: Operator004 -* @tc.desc: construct a Blob and check it operator std::vector && function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: wangkai -*/ + * @tc.name: Operator004 + * @tc.desc: construct a Blob and check it operator std::vector && function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: wangkai + */ HWTEST_F(BlobTest, Operator004, TestSize.Level0) { std::vector blob = { 1, 2, 3, 4 }; @@ -271,12 +267,12 @@ HWTEST_F(BlobTest, Operator004, TestSize.Level0) } /** -* @tc.name: Operator005 -* @tc.desc: construct a Blob and check it operator std::vector & function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: wangkai -*/ + * @tc.name: Operator005 + * @tc.desc: construct a Blob and check it operator std::vector & function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: wangkai + */ HWTEST_F(BlobTest, Operator005, TestSize.Level0) { const std::vector blob = { 1, 2, 3, 4 }; @@ -285,12 +281,12 @@ HWTEST_F(BlobTest, Operator005, TestSize.Level0) } /** -* @tc.name: RawSize001 -* @tc.desc: construct a Blob and check it RawSize function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: wangkai -*/ + * @tc.name: RawSize001 + * @tc.desc: construct a Blob and check it RawSize function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: wangkai + */ HWTEST_F(BlobTest, RawSize001, TestSize.Level0) { Blob blob1("1234"); @@ -300,12 +296,12 @@ HWTEST_F(BlobTest, RawSize001, TestSize.Level0) } /** -* @tc.name: WriteToBuffer001 -* @tc.desc: construct a Blob and check it WriteToBuffer and ReadFromBuffer function. -* @tc.type: FUNC -* @tc.require: -* @tc.author: wangkai -*/ + * @tc.name: WriteToBuffer001 + * @tc.desc: construct a Blob and check it WriteToBuffer and ReadFromBuffer function. + * @tc.type: FUNC + * @tc.require: + * @tc.author: wangkai + */ HWTEST_F(BlobTest, WriteToBuffer001, TestSize.Level1) { Entry insert, update, del; diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/device_kvstore_test.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/device_kvstore_test.cpp index e494cf29d55dc45e191401e56abaa813f1fc3d76..db2d7847a2f2b9294ab4ab1a192e50e93a8f28b2 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/device_kvstore_test.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/device_kvstore_test.cpp @@ -13,35 +13,31 @@ * limitations under the License. */ -#include -#include -#include -#include -#include #include "dev_manager.h" #include "distributed_kv_data_manager.h" #include "file_ex.h" #include "types.h" +#include +#include +#include +#include +#include using namespace testing::ext; using namespace OHOS::DistributedKv; namespace OHOS::Test { +static constexpr uint64_t MAX_VALUE_SIZE = 4 * 1024 * 1024; // max value size is 4M. class DeviceKvStoreTest : public testing::Test { public: - static constexpr uint64_t MAX_VALUE_SIZE = 4 * 1024 * 1024; // max value size is 4M. - static void SetUpTestCase(void); - - static void TearDownTestCase(void); - - void SetUp(); - - void TearDown(); static std::string GetKey(const std::string &key); - static std::shared_ptr kvStore_; // declare kvstore instance. static Status status_; static std::string deviceId_; static Options options_; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); }; const std::string VALID_SCHEMA = "{\"SCHEMA_VERSION\":\"1.0\"," @@ -82,13 +78,11 @@ void DeviceKvStoreTest::TearDownTestCase(void) (void)remove("/data/service/el1/public/database/odmf"); } -void DeviceKvStoreTest::SetUp(void) -{} +void DeviceKvStoreTest::SetUp(void) { } -void DeviceKvStoreTest::TearDown(void) -{} +void DeviceKvStoreTest::TearDown(void) { } -std::string DeviceKvStoreTest::GetKey(const std::string& key) +std::string DeviceKvStoreTest::GetKey(const std::string &key) { std::ostringstream oss; oss << std::setfill('0') << std::setw(sizeof(uint32_t)) << deviceId_.length(); @@ -103,8 +97,7 @@ public: std::vector deleteEntries_; bool isClear_ = false; DeviceObserverTestImpl(); - ~DeviceObserverTestImpl() - {} + ~DeviceObserverTestImpl() { } DeviceObserverTestImpl(const DeviceObserverTestImpl &) = delete; DeviceObserverTestImpl &operator=(const DeviceObserverTestImpl &) = delete; @@ -131,9 +124,7 @@ void DeviceObserverTestImpl::OnChange(const ChangeNotification &changeNotificati isClear_ = changeNotification.IsClear(); } -DeviceObserverTestImpl::DeviceObserverTestImpl() -{ -} +DeviceObserverTestImpl::DeviceObserverTestImpl() { } void DeviceObserverTestImpl::ResetToZero() { @@ -150,16 +141,15 @@ public: void SyncCompleted(const std::map &results); }; -void DeviceSyncCallbackTestImpl::SyncCompleted(const std::map &results) -{} +void DeviceSyncCallbackTestImpl::SyncCompleted(const std::map &results) { } /** -* @tc.name: GetStoreId001 -* @tc.desc: Get a Device KvStore instance. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: GetStoreId001 + * @tc.desc: Get a Device KvStore instance. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, GetStoreId001, TestSize.Level1) { EXPECT_NE(kvStore_, nullptr) << "kvStore is null."; @@ -169,18 +159,18 @@ HWTEST_F(DeviceKvStoreTest, GetStoreId001, TestSize.Level1) } /** -* @tc.name: PutGetDelete001 -* @tc.desc: put value and delete value -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: PutGetDelete001 + * @tc.desc: put value and delete value + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, PutGetDelete001, TestSize.Level1) { EXPECT_NE(kvStore_, nullptr) << "kvStore is null."; - Key skey = {"single_001"}; - Value sval = {"value_001"}; + Key skey = { "single_001" }; + Value sval = { "value_001" }; auto status = kvStore_->Put(skey, sval); EXPECT_EQ(status, Status::SUCCESS) << "Put data failed"; @@ -190,28 +180,28 @@ HWTEST_F(DeviceKvStoreTest, PutGetDelete001, TestSize.Level1) auto notExistStatus = kvStore_->Delete(skey); EXPECT_EQ(notExistStatus, Status::SUCCESS) << "Delete non-existing data failed"; - auto spaceStatus = kvStore_->Put(skey, {""}); + auto spaceStatus = kvStore_->Put(skey, { "" }); EXPECT_EQ(spaceStatus, Status::SUCCESS) << "Put space failed"; - auto spaceKeyStatus = kvStore_->Put({""}, {""}); + auto spaceKeyStatus = kvStore_->Put({ "" }, { "" }); EXPECT_NE(spaceKeyStatus, Status::SUCCESS) << "Put space keys failed"; Status validStatus = kvStore_->Put(skey, sval); EXPECT_EQ(validStatus, Status::SUCCESS) << "Put valid keys and values failed"; Value rVal; - auto validPutStatus = kvStore_->Get({ GetKey("single_001")}, rVal); + auto validPutStatus = kvStore_->Get({ GetKey("single_001") }, rVal); EXPECT_EQ(validPutStatus, Status::SUCCESS) << "Get value failed"; EXPECT_EQ(sval, rVal) << "Got and put values not equal"; } /** -* @tc.name: GetDataQueryEntriesAndResultSet -* @tc.desc: get entries and result set by data query. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: GetDataQueryEntriesAndResultSet + * @tc.desc: get entries and result set by data query. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, GetDataQueryEntriesAndResultSet, TestSize.Level1) { EXPECT_NE(kvStore_, nullptr) << "kvStore is nullptr."; @@ -221,7 +211,7 @@ HWTEST_F(DeviceKvStoreTest, GetDataQueryEntriesAndResultSet, TestSize.Level1) int sumGet = 0; std::string prefix = "prefix_"; for (size_t i = 0; i < sum; i++) { - kvStore_->Put({prefix + std::to_string(i)}, {std::to_string(i)}); + kvStore_->Put({ prefix + std::to_string(i) }, { std::to_string(i) }); } DataQuery dataQuery; @@ -252,7 +242,7 @@ HWTEST_F(DeviceKvStoreTest, GetDataQueryEntriesAndResultSet, TestSize.Level1) resultSet->GetEntry(entry); for (size_t i = 0; i < sum; i++) { - kvStore_->Delete({GetKey(prefix + std::to_string(i))}); + kvStore_->Delete({ GetKey(prefix + std::to_string(i)) }); } status = kvStore_->CloseResultSet(resultSet); @@ -260,12 +250,12 @@ HWTEST_F(DeviceKvStoreTest, GetDataQueryEntriesAndResultSet, TestSize.Level1) } /** -* @tc.name: GetPrefixQueryEntriesAndResultSet -* @tc.desc: get entries and result set by prefix query. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: GetPrefixQueryEntriesAndResultSet + * @tc.desc: get entries and result set by prefix query. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, GetPrefixQueryEntriesAndResultSet, TestSize.Level1) { EXPECT_NE(kvStore_, nullptr) << "kvStore is nullptr."; @@ -277,7 +267,7 @@ HWTEST_F(DeviceKvStoreTest, GetPrefixQueryEntriesAndResultSet, TestSize.Level1) size_t sum = 10; std::string prefix = "prefix_"; for (size_t i = 0; i < sum; i++) { - kvStore_->Put({prefix + std::to_string(i)}, {std::to_string(i)}); + kvStore_->Put({ prefix + std::to_string(i) }, { std::to_string(i) }); } DataQuery dataQuery; @@ -308,7 +298,7 @@ HWTEST_F(DeviceKvStoreTest, GetPrefixQueryEntriesAndResultSet, TestSize.Level1) resultSet->GetEntry(entry); for (size_t i = 0; i < sum; i++) { - kvStore_->Delete({GetKey(prefix + std::to_string(i))}); + kvStore_->Delete({ GetKey(prefix + std::to_string(i)) }); } status = kvStore_->CloseResultSet(resultSet); @@ -316,12 +306,12 @@ HWTEST_F(DeviceKvStoreTest, GetPrefixQueryEntriesAndResultSet, TestSize.Level1) } /** -* @tc.name: GetInKeysQueryResultSet -* @tc.desc: get entries and result set by prefix query. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: GetInKeysQueryResultSet + * @tc.desc: get entries and result set by prefix query. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, GetInKeysQueryResultSet, TestSize.Level1) { EXPECT_NE(kvStore_, nullptr) << "kvStore is nullptr."; @@ -334,11 +324,11 @@ HWTEST_F(DeviceKvStoreTest, GetInKeysQueryResultSet, TestSize.Level1) std::string prefix = "prefix_"; for (size_t i = 0; i < sum; i++) { - kvStore_->Put({prefix + std::to_string(i)}, {std::to_string(i)}); + kvStore_->Put({ prefix + std::to_string(i) }, { std::to_string(i) }); } DataQuery dataQuery; - dataQuery.InKeys({"prefix_0", "prefix_1", "prefix_3", "prefix_9"}); + dataQuery.InKeys({ "prefix_0", "prefix_1", "prefix_3", "prefix_9" }); int sumGet = 0; kvStore_->GetCount(dataQuery, sumGet); EXPECT_EQ(sumGet, 4) << "count is not equal 4."; @@ -361,7 +351,7 @@ HWTEST_F(DeviceKvStoreTest, GetInKeysQueryResultSet, TestSize.Level1) resultSet->GetEntry(entry); for (size_t i = 0; i < sum; i++) { - kvStore_->Delete({GetKey(prefix + std::to_string(i))}); + kvStore_->Delete({ GetKey(prefix + std::to_string(i)) }); } status = kvStore_->CloseResultSet(resultSet); @@ -369,12 +359,12 @@ HWTEST_F(DeviceKvStoreTest, GetInKeysQueryResultSet, TestSize.Level1) } /** -* @tc.name: GetPrefixEntriesAndResultSet -* @tc.desc: get entries and result set by prefix. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: GetPrefixEntriesAndResultSet + * @tc.desc: get entries and result set by prefix. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, GetPrefixEntriesAndResultSet, TestSize.Level1) { EXPECT_NE(kvStore_, nullptr) << "kvStore is nullptr."; @@ -384,7 +374,7 @@ HWTEST_F(DeviceKvStoreTest, GetPrefixEntriesAndResultSet, TestSize.Level1) int sumGet = 10; std::string prefix = "prefix_"; for (size_t i = 0; i < sum; i++) { - kvStore_->Put({prefix + std::to_string(i)}, {std::to_string(i)}); + kvStore_->Put({ prefix + std::to_string(i) }, { std::to_string(i) }); } std::vector results; kvStore_->GetEntries(GetKey(prefix + " "), results); @@ -408,7 +398,7 @@ HWTEST_F(DeviceKvStoreTest, GetPrefixEntriesAndResultSet, TestSize.Level1) resultSet->GetEntry(entry); for (size_t i = 0; i < sum; i++) { - kvStore_->Delete({GetKey(prefix + std::to_string(i))}); + kvStore_->Delete({ GetKey(prefix + std::to_string(i)) }); } status = kvStore_->CloseResultSet(resultSet); @@ -416,12 +406,12 @@ HWTEST_F(DeviceKvStoreTest, GetPrefixEntriesAndResultSet, TestSize.Level1) } /** -* @tc.name: Subscribe001 -* @tc.desc: Put data and get callback. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: Subscribe001 + * @tc.desc: Put data and get callback. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, Subscribe001, TestSize.Level1) { auto observer = std::make_shared(); @@ -436,12 +426,12 @@ HWTEST_F(DeviceKvStoreTest, Subscribe001, TestSize.Level1) } /** -* @tc.name: SyncCallback001 -* @tc.desc: Register sync callback. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: SyncCallback001 + * @tc.desc: Register sync callback. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, SyncCallback001, TestSize.Level1) { EXPECT_NE(kvStore_, nullptr) << "kvStore is nullptr."; @@ -453,29 +443,29 @@ HWTEST_F(DeviceKvStoreTest, SyncCallback001, TestSize.Level1) auto unRegStatus = kvStore_->UnRegisterSyncCallback(); EXPECT_EQ(unRegStatus, Status::SUCCESS) << "Unregister sync callback failed."; - Key skey = {"single_001"}; - Value sval = {"value_001"}; + Key skey = { "single_001" }; + Value sval = { "value_001" }; kvStore_->Put(skey, sval); kvStore_->Delete(skey); std::map results; - results.insert({"aaa", Status::INVALID_ARGUMENT}); + results.insert({ "aaa", Status::INVALID_ARGUMENT }); syncCallback->SyncCompleted(results); } /** -* @tc.name: RemoveDeviceData001 -* @tc.desc: Remove device data. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: RemoveDeviceData001 + * @tc.desc: Remove device data. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, RemoveDeviceData001, TestSize.Level1) { EXPECT_NE(kvStore_, nullptr) << "kvStore is nullptr."; - Key skey = {"single_001"}; - Value sval = {"value_001"}; + Key skey = { "single_001" }; + Value sval = { "value_001" }; kvStore_->Put(skey, sval); std::string deviceId = "no_exist_device_id"; @@ -489,12 +479,12 @@ HWTEST_F(DeviceKvStoreTest, RemoveDeviceData001, TestSize.Level1) } /** -* @tc.name: SyncData001 -* @tc.desc: Synchronize device data. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: SyncData001 + * @tc.desc: Synchronize device data. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, SyncData001, TestSize.Level1) { EXPECT_NE(kvStore_, nullptr) << "kvStore is nullptr."; @@ -505,12 +495,12 @@ HWTEST_F(DeviceKvStoreTest, SyncData001, TestSize.Level1) } /** -* @tc.name: TestSchemaStoreC001 -* @tc.desc: Test schema device store. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: TestSchemaStoreC001 + * @tc.desc: Test schema device store. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, TestSchemaStoreC001, TestSize.Level1) { std::shared_ptr deviceKvStore; @@ -528,8 +518,8 @@ HWTEST_F(DeviceKvStoreTest, TestSchemaStoreC001, TestSize.Level1) auto result = deviceKvStore->GetStoreId(); EXPECT_EQ(result.storeId, "schema_device_id"); - Key testKey = {"TestSchemaStoreC001_key"}; - Value testValue = {"{\"age\":10}"}; + Key testKey = { "TestSchemaStoreC001_key" }; + Value testValue = { "{\"age\":10}" }; auto testStatus = deviceKvStore->Put(testKey, testValue); EXPECT_EQ(testStatus, Status::SUCCESS) << "putting data failed"; Value resultValue; @@ -539,12 +529,12 @@ HWTEST_F(DeviceKvStoreTest, TestSchemaStoreC001, TestSize.Level1) } /** -* @tc.name: SyncData001 -* @tc.desc: Synchronize device data. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: SyncData001 + * @tc.desc: Synchronize device data. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, SyncData002, TestSize.Level1) { EXPECT_NE(kvStore_, nullptr) << "kvStorePtr is null."; @@ -556,16 +546,16 @@ HWTEST_F(DeviceKvStoreTest, SyncData002, TestSize.Level1) } /** -* @tc.name: SyncData002 -* @tc.desc: Set sync parameters - success. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: SyncData002 + * @tc.desc: Set sync parameters - success. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, SetSync001, TestSize.Level1) { EXPECT_NE(kvStore_, nullptr) << "kvStore is null."; - KvSyncParam syncParam{ 500 }; // 500ms + KvSyncParam syncParam { 500 }; // 500ms auto ret = kvStore_->SetSyncParam(syncParam); EXPECT_EQ(ret, Status::SUCCESS) << "set sync param should return success"; @@ -575,16 +565,16 @@ HWTEST_F(DeviceKvStoreTest, SetSync001, TestSize.Level1) } /** -* @tc.name: SyncData002 -* @tc.desc: Set sync parameters - failed. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: SyncData002 + * @tc.desc: Set sync parameters - failed. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, SetSync002, TestSize.Level1) { EXPECT_NE(kvStore_, nullptr) << "kvStore is null."; - KvSyncParam syncParam2{ 50 }; // 50ms + KvSyncParam syncParam2 { 50 }; // 50ms auto ret = kvStore_->SetSyncParam(syncParam2); EXPECT_NE(ret, Status::SUCCESS) << "set sync param should not return success"; @@ -594,12 +584,12 @@ HWTEST_F(DeviceKvStoreTest, SetSync002, TestSize.Level1) } /** -* @tc.name: SingleKvStoreDdmPutBatch001 -* @tc.desc: Batch put data. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: SingleKvStoreDdmPutBatch001 + * @tc.desc: Batch put data. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, SingleKvStoreDdmPutBatch001, TestSize.Level2) { EXPECT_NE(nullptr, kvStore_) << "kvStore is nullptr"; @@ -637,12 +627,12 @@ HWTEST_F(DeviceKvStoreTest, SingleKvStoreDdmPutBatch001, TestSize.Level2) } /** -* @tc.name: SingleKvStoreDdmPutBatch002 -* @tc.desc: Batch update data. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: SingleKvStoreDdmPutBatch002 + * @tc.desc: Batch update data. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, SingleKvStoreDdmPutBatch002, TestSize.Level2) { EXPECT_NE(nullptr, kvStore_) << "kvStore is nullptr"; @@ -697,12 +687,12 @@ HWTEST_F(DeviceKvStoreTest, SingleKvStoreDdmPutBatch002, TestSize.Level2) } /** -* @tc.name: DdmPutBatch003 -* @tc.desc: Batch put data that contains invalid data. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: DdmPutBatch003 + * @tc.desc: Batch put data that contains invalid data. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, DdmPutBatch003, TestSize.Level2) { EXPECT_NE(nullptr, kvStore_) << "kvStore is nullptr"; @@ -725,12 +715,12 @@ HWTEST_F(DeviceKvStoreTest, DdmPutBatch003, TestSize.Level2) } /** -* @tc.name: DdmPutBatch004 -* @tc.desc: Batch put data that contains invalid data. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: DdmPutBatch004 + * @tc.desc: Batch put data that contains invalid data. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, DdmPutBatch004, TestSize.Level2) { EXPECT_NE(nullptr, kvStore_) << "kvStore is nullptr"; @@ -762,12 +752,12 @@ static std::string SingleGenerate1025KeyLen() return str; } /** -* @tc.name: DdmPutBatch005 -* @tc.desc: Batch put data that contains invalid data. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: DdmPutBatch005 + * @tc.desc: Batch put data that contains invalid data. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, DdmPutBatch005, TestSize.Level2) { EXPECT_NE(nullptr, kvStore_) << "kvStore is nullptr"; @@ -788,12 +778,12 @@ HWTEST_F(DeviceKvStoreTest, DdmPutBatch005, TestSize.Level2) } /** -* @tc.name: DdmPutBatch006 -* @tc.desc: Batch put large data. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: DdmPutBatch006 + * @tc.desc: Batch put large data. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, DdmPutBatch006, TestSize.Level2) { EXPECT_NE(nullptr, kvStore_) << "kvStore is nullptr"; @@ -836,12 +826,12 @@ HWTEST_F(DeviceKvStoreTest, DdmPutBatch006, TestSize.Level2) } /** -* @tc.name: DdmDeleteBatch001 -* @tc.desc: Batch delete data. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: DdmDeleteBatch001 + * @tc.desc: Batch delete data. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, DdmDeleteBatch001, TestSize.Level2) { EXPECT_NE(nullptr, kvStore_) << "kvStore is nullptr"; @@ -876,12 +866,12 @@ HWTEST_F(DeviceKvStoreTest, DdmDeleteBatch001, TestSize.Level2) } /** -* @tc.name: DdmDeleteBatch002 -* @tc.desc: Batch delete data when some keys are not in KvStore. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: DdmDeleteBatch002 + * @tc.desc: Batch delete data when some keys are not in KvStore. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, DdmDeleteBatch002, TestSize.Level2) { EXPECT_NE(nullptr, kvStore_) << "kvStore is nullptr"; @@ -917,12 +907,12 @@ HWTEST_F(DeviceKvStoreTest, DdmDeleteBatch002, TestSize.Level2) } /** -* @tc.name: DdmDeleteBatch003 -* @tc.desc: Batch delete data when some keys are invalid. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: DdmDeleteBatch003 + * @tc.desc: Batch delete data when some keys are invalid. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, DdmDeleteBatch003, TestSize.Level2) { EXPECT_NE(nullptr, kvStore_) << "kvStore is nullptr"; @@ -958,12 +948,12 @@ HWTEST_F(DeviceKvStoreTest, DdmDeleteBatch003, TestSize.Level2) } /** -* @tc.name: DdmDeleteBatch004 -* @tc.desc: Batch delete data when some keys are invalid. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: DdmDeleteBatch004 + * @tc.desc: Batch delete data when some keys are invalid. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, DdmDeleteBatch004, TestSize.Level2) { EXPECT_NE(nullptr, kvStore_) << "kvStore is nullptr"; @@ -1004,12 +994,12 @@ HWTEST_F(DeviceKvStoreTest, DdmDeleteBatch004, TestSize.Level2) } /** -* @tc.name: DdmDeleteBatch005 -* @tc.desc: Batch delete data when some keys are invalid. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: DdmDeleteBatch005 + * @tc.desc: Batch delete data when some keys are invalid. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, DdmDeleteBatch005, TestSize.Level2) { EXPECT_NE(nullptr, kvStore_) << "kvStore is nullptr"; @@ -1050,12 +1040,12 @@ HWTEST_F(DeviceKvStoreTest, DdmDeleteBatch005, TestSize.Level2) } /** -* @tc.name: Transaction001 -* @tc.desc: Batch delete data when some keys are invalid. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: Transaction001 + * @tc.desc: Batch delete data when some keys are invalid. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, Transaction001, TestSize.Level2) { EXPECT_NE(nullptr, kvStore_) << "kvStore is nullptr"; @@ -1088,7 +1078,7 @@ HWTEST_F(DeviceKvStoreTest, Transaction001, TestSize.Level2) status = kvStore_->StartTransaction(); EXPECT_EQ(Status::SUCCESS, status) << "StartTransaction return wrong status"; - status = kvStore_->Put(key1, value1); // insert or update key-value + status = kvStore_->Put(key1, value1); // insert or update key-value EXPECT_EQ(Status::SUCCESS, status) << "Put data return wrong status"; status = kvStore_->PutBatch(entries); EXPECT_EQ(Status::SUCCESS, status) << "PutBatch data return wrong status"; @@ -1107,12 +1097,12 @@ HWTEST_F(DeviceKvStoreTest, Transaction001, TestSize.Level2) } /** -* @tc.name: Transaction002 -* @tc.desc: Batch delete data when some keys are invalid. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: Transaction002 + * @tc.desc: Batch delete data when some keys are invalid. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, Transaction002, TestSize.Level2) { EXPECT_NE(nullptr, kvStore_) << "kvStore is nullptr"; @@ -1145,7 +1135,7 @@ HWTEST_F(DeviceKvStoreTest, Transaction002, TestSize.Level2) status = kvStore_->StartTransaction(); EXPECT_EQ(Status::SUCCESS, status) << "StartTransaction return wrong status"; - status = kvStore_->Put(key1, value1); // insert or update key-value + status = kvStore_->Put(key1, value1); // insert or update key-value EXPECT_EQ(Status::SUCCESS, status) << "Put data return wrong status"; status = kvStore_->PutBatch(entries); EXPECT_EQ(Status::SUCCESS, status) << "PutBatch data return wrong status"; @@ -1168,12 +1158,12 @@ HWTEST_F(DeviceKvStoreTest, Transaction002, TestSize.Level2) } /** -* @tc.name: DeviceSync001 -* @tc.desc: Test sync enable. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: DeviceSync001 + * @tc.desc: Test sync enable. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, DeviceSync001, TestSize.Level1) { std::shared_ptr kvStore; @@ -1196,12 +1186,12 @@ HWTEST_F(DeviceKvStoreTest, DeviceSync001, TestSize.Level1) } /** -* @tc.name: DeviceSync002 -* @tc.desc: Test sync enable. -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: DeviceSync002 + * @tc.desc: Test sync enable. + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, DeviceSync002, TestSize.Level1) { std::shared_ptr kvStore; @@ -1218,24 +1208,24 @@ HWTEST_F(DeviceKvStoreTest, DeviceSync002, TestSize.Level1) auto result = kvStore->GetStoreId(); EXPECT_EQ(result.storeId, "schema_device_id002"); - std::vector local = {"A", "B"}; - std::vector remote = {"C", "D"}; + std::vector local = { "A", "B" }; + std::vector remote = { "C", "D" }; auto testStatus = kvStore->SetCapabilityRange(local, remote); EXPECT_EQ(testStatus, Status::SUCCESS) << "set range fail"; manager.DeleteKvStore(appId, storeId, options.baseDir); } /** -* @tc.name: SyncWithCondition001 -* @tc.desc: sync device data with condition; -* @tc.type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang -*/ + * @tc.name: SyncWithCondition001 + * @tc.desc: sync device data with condition; + * @tc.type: FUNC + * @tc.require: I5DE2A + * @tc.author: Sven Wang + */ HWTEST_F(DeviceKvStoreTest, SyncWithCondition001, TestSize.Level1) { EXPECT_NE(kvStore_, nullptr) << "kvStore is null."; - std::vector deviceIds = {"invalid_device_id1", "invalid_device_id2"}; + std::vector deviceIds = { "invalid_device_id1", "invalid_device_id2" }; DataQuery dataQuery; dataQuery.KeyPrefix("name"); auto syncStatus = kvStore_->Sync(deviceIds, SyncMode::PUSH, dataQuery, nullptr); @@ -1243,16 +1233,16 @@ HWTEST_F(DeviceKvStoreTest, SyncWithCondition001, TestSize.Level1) } /** -* @tc.name: SyncWithCondition002 -* @tc.desc: sync device data with condition; -* @tc.type: FUNC -* @tc.require: -* @tc.author: SQL -*/ + * @tc.name: SyncWithCondition002 + * @tc.desc: sync device data with condition; + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ HWTEST_F(DeviceKvStoreTest, SyncWithCondition002, TestSize.Level1) { EXPECT_NE(kvStore_, nullptr) << "kvStore is null."; - std::vector deviceIds = {"invalid_device_id1", "invalid_device_id2"}; + std::vector deviceIds = { "invalid_device_id1", "invalid_device_id2" }; DataQuery dataQuery; dataQuery.KeyPrefix("name"); uint32_t delay = 0; @@ -1264,13 +1254,13 @@ HWTEST_F(DeviceKvStoreTest, SyncWithCondition002, TestSize.Level1) * @tc.name: SubscribeWithQuery001 * desc: subscribe and sync device data with query; * type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang + * @tc.require: I5DE2A + * @tc.author: Sven Wang */ HWTEST_F(DeviceKvStoreTest, SubscribeWithQuery001, TestSize.Level1) { EXPECT_NE(kvStore_, nullptr) << "kvStore is null."; - std::vector deviceIds = {"invalid_device_id1", "invalid_device_id2"}; + std::vector deviceIds = { "invalid_device_id1", "invalid_device_id2" }; DataQuery dataQuery; dataQuery.KeyPrefix("name"); auto syncStatus = kvStore_->SubscribeWithQuery(deviceIds, dataQuery); @@ -1281,13 +1271,13 @@ HWTEST_F(DeviceKvStoreTest, SubscribeWithQuery001, TestSize.Level1) * @tc.name: UnSubscribeWithQuery001 * desc: subscribe and sync device data with query; * type: FUNC -* @tc.require: I5DE2A -* @tc.author: Sven Wang + * @tc.require: I5DE2A + * @tc.author: Sven Wang */ HWTEST_F(DeviceKvStoreTest, UnSubscribeWithQuery001, TestSize.Level1) { EXPECT_NE(kvStore_, nullptr) << "kvStore is nullptr."; - std::vector deviceIds = {"invalid_device_id1", "invalid_device_id2"}; + std::vector deviceIds = { "invalid_device_id1", "invalid_device_id2" }; DataQuery dataQuery; dataQuery.KeyPrefix("name"); auto unSubscribeStatus = kvStore_->UnsubscribeWithQuery(deviceIds, dataQuery); diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/distributed_data_mgr_test.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/distributed_data_mgr_test.cpp index a3df1653ea65fad909d4e4cbbb41540dead78f2a..40d46ebe3ebb6a0a6c2b89951ad4259f678da001 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/distributed_data_mgr_test.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/distributed_data_mgr_test.cpp @@ -13,20 +13,22 @@ * limitations under the License. */ -#include "distributed_data_mgr.h" -#include -#include -#include "types.h" #include "accesstoken_kit.h" -#include "nativetoken_kit.h" +#include "distributed_data_mgr.h" #include "ipc_skeleton.h" +#include "nativetoken_kit.h" #include "token_setproc.h" +#include "types.h" +#include +#include using namespace testing::ext; using namespace OHOS::DistributedKv; using namespace OHOS::Security::AccessToken; -std::string BUNDLE_NAME = "ohos.distributeddatamgrtest.demo"; namespace OHOS::Test { +std::string BUNDLE_NAME = "ohos.distributeddatamgrtest.demo"; +static constexpr int32_t TEST_USERID = 100; +static constexpr int32_t APP_INDEX = 0; class DistributedDataMgrTest : public testing::Test { public: static DistributedDataMgr manager; @@ -34,23 +36,20 @@ public: static void TearDownTestCase(void){}; void SetUp(){}; void TearDown(){}; - static constexpr int32_t TEST_USERID = 100; - static constexpr int32_t APP_INDEX = 0; }; DistributedDataMgr DistributedDataMgrTest::manager; /** -* @tc.name: ClearAppStorage -* @tc.desc: -* @tc.type: FUNC -* @tc.require: -* @tc.author: SQL -*/ + * @tc.name: ClearAppStorage + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ HWTEST_F(DistributedDataMgrTest, ClearAppStorage001, TestSize.Level1) { - auto tokenId = AccessTokenKit::GetNativeTokenId("foundation"); - SetSelfTokenID(tokenId); + auto tokenId = 0; auto ret = manager.ClearAppStorage(BUNDLE_NAME, TEST_USERID, APP_INDEX, tokenId); - EXPECT_EQ(ret, Status::SUCCESS); + EXPECT_NE(ret, Status::SUCCESS); } } // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/distributed_kv_data_manager_encrypt_test.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/distributed_kv_data_manager_encrypt_test.cpp index 5fb49261cb5f467fc722d1fadf47092f461844b6..16b28dfb3522032d230c0909474fedebd686b079 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/distributed_kv_data_manager_encrypt_test.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/distributed_kv_data_manager_encrypt_test.cpp @@ -47,9 +47,9 @@ public: class MyDeathRecipient : public KvStoreDeathRecipient { public: - MyDeathRecipient() {} - virtual ~MyDeathRecipient() {} - void OnRemoteDied() override {} + MyDeathRecipient() { } + virtual ~MyDeathRecipient() { } + void OnRemoteDied() override { } }; DistributedKvDataManager DistributedKvDataManagerEncryptTest::manager; @@ -129,4 +129,30 @@ HWTEST_F(DistributedKvDataManagerEncryptTest, kvstore_ddm_createEncryptedStore_0 EXPECT_EQ(Status::SUCCESS, statusRet) << "get data return wrong status"; EXPECT_EQ(value, valueRet) << "value and valueRet are not equal"; +} + +/** + * @tc.name: GetEncryptStoreWithKeyFromService + * @tc.desc: Get encrypt store, delete key, get store again. + * @tc.type: FUNC + * @tc.require: + * @tc.author: yanhui + */ +HWTEST_F(DistributedKvDataManagerEncryptTest, GetEncryptStoreWithKeyFromService, TestSize.Level1) +{ + ZLOGI("GetEncryptStoreWithKeyFromService begin."); + std::shared_ptr kvStore; + Status status = manager.GetSingleKvStore(createEnc, appId, storeId, kvStore); + ASSERT_EQ(status, Status::SUCCESS); + ASSERT_NE(kvStore, nullptr); + + manager.CloseAllKvStore(appId); + std::string keyPath = createEnc.baseDir + "/key/" + storeId.storeId + ".key"; + auto ret = remove(keyPath.c_str()); + ASSERT_EQ(ret, 0); + + kvStore = nullptr; + status = manager.GetSingleKvStore(createEnc, appId, storeId, kvStore); + ASSERT_EQ(status, Status::SUCCESS); + ASSERT_NE(kvStore, nullptr); } \ No newline at end of file diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/distributed_kv_data_manager_test.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/distributed_kv_data_manager_test.cpp index cefe082682930d81ecb163870f49ed279870605d..a35a207051255f9707d24d5c1f1869e08acca8ee 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/distributed_kv_data_manager_test.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/distributed_kv_data_manager_test.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2024 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 @@ -26,32 +26,25 @@ using namespace testing::ext; using namespace OHOS::DistributedKv; namespace OHOS::Test { +static constexpr size_t NUM_MIN = 5; +static constexpr size_t NUM_MAX = 12; class DistributedKvDataManagerTest : public testing::Test { public: - static constexpr size_t NUM_MIN = 5; - static constexpr size_t NUM_MAX = 12; static std::shared_ptr executors; - static DistributedKvDataManager manager; static Options create; static Options noCreate; - static UserId userId; - static AppId appId; static StoreId storeId64; static StoreId storeId65; static StoreId storeIdTest; static StoreId storeIdEmpty; - static Entry entryA; static Entry entryB; - static void SetUpTestCase(void); static void TearDownTestCase(void); - static void RemoveAllStore(DistributedKvDataManager &manager); - void SetUp(); void TearDown(); DistributedKvDataManagerTest(); @@ -325,6 +318,33 @@ HWTEST_F(DistributedKvDataManagerTest, GetKvStore009, TestSize.Level1) EXPECT_EQ(kvStore, nullptr); } +/** + * @tc.name: GetKvStore010 + * @tc.desc: After remove database path and mkdir and get kv store. + * @tc.type: FUNC + */ +HWTEST_F(DistributedKvDataManagerTest, GetKvStore010, TestSize.Level1) +{ + ZLOGI("GetKvStore010 begin."); + std::shared_ptr kvStore = nullptr; + auto status = manager.GetSingleKvStore(create, appId, storeId64, kvStore); + ASSERT_EQ(status, Status::SUCCESS); + EXPECT_NE(kvStore, nullptr); + + status = manager.CloseKvStore(appId, storeId64); + EXPECT_EQ(status, Status::SUCCESS); + kvStore = nullptr; + EXPECT_EQ(kvStore, nullptr); + + (void)remove((create.baseDir + "/kvdb").c_str()); + (void)remove(create.baseDir.c_str()); + (void)mkdir(create.baseDir.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); + + status = manager.GetSingleKvStore(create, appId, storeId64, kvStore); + ASSERT_EQ(status, Status::SUCCESS); + EXPECT_NE(kvStore, nullptr); +} + /** * @tc.name: GetKvStoreInvalidSecurityLevel * @tc.desc: Get a SingleKvStore with a 64 diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/end_point_test.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/end_point_test.cpp index 5b5a1cbb772a1e189aadb27aa1d64611c3ca2fc5..6dc32c9ad9b85e685f2e24ec815fedb139d96d31 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/end_point_test.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/end_point_test.cpp @@ -13,15 +13,15 @@ * limitations under the License. */ -#include -#include -#include -#include -#include #include "dev_manager.h" #include "distributed_kv_data_manager.h" #include "file_ex.h" #include "types.h" +#include +#include +#include +#include +#include using namespace testing::ext; using namespace OHOS::DistributedKv; @@ -77,13 +77,11 @@ void EndPointTest::TearDownTestCase(void) (void)remove("/data/service/el1/public/database/odmf"); } -void EndPointTest::SetUp(void) -{} +void EndPointTest::SetUp(void) { } -void EndPointTest::TearDown(void) -{} +void EndPointTest::TearDown(void) { } -std::string EndPointTest::GetKey(const std::string& key) +std::string EndPointTest::GetKey(const std::string &key) { std::ostringstream oss; oss << std::setfill('0') << std::setw(sizeof(uint32_t)) << deviceId_.length(); @@ -93,8 +91,8 @@ std::string EndPointTest::GetKey(const std::string& key) class EndpointMock : public Endpoint { public: - EndpointMock() {} - virtual ~EndpointMock() {} + EndpointMock() { } + virtual ~EndpointMock() { } Status Start() override { @@ -118,7 +116,7 @@ public: uint32_t GetMtuSize(const std::string &identifier) override { - return 1 * 1024 * 1024; // 1 * 1024 * 1024 Byte. + return 1 * 1024 * 1024; // 1 * 1024 * 1024 Byte. } std::string GetLocalDeviceInfos() override @@ -138,12 +136,12 @@ public: }; /** -* @tc.name: SetEndpoint001 -* @tc.desc: test the SetEndpoint(std::shared_ptr endpoint) -* @tc.type: FUNC -* @tc.require: -* @tc.author: SQL -*/ + * @tc.name: SetEndpoint001 + * @tc.desc: test the SetEndpoint(std::shared_ptr endpoint) + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ HWTEST_F(EndPointTest, SetEndpoint001, TestSize.Level1) { DistributedKvDataManager manager; @@ -153,12 +151,12 @@ HWTEST_F(EndPointTest, SetEndpoint001, TestSize.Level1) } /** -* @tc.name: SetEndpoint002 -* @tc.desc: test the SetEndpoint(std::shared_ptr endpoint) -* @tc.type: FUNC -* @tc.require: -* @tc.author: SQL -*/ + * @tc.name: SetEndpoint002 + * @tc.desc: test the SetEndpoint(std::shared_ptr endpoint) + * @tc.type: FUNC + * @tc.require: + * @tc.author: SQL + */ HWTEST_F(EndPointTest, SetEndpoint002, TestSize.Level1) { DistributedKvDataManager manager; @@ -182,7 +180,7 @@ HWTEST_F(EndPointTest, SetIdentifier001, TestSize.Level1) EXPECT_NE(kvStore_, nullptr) << "kvStorePtr is null."; AppId appId = { "odmf" }; StoreId storeId = { "test_storeid" }; - std::vector targetDev = {"devicid1", "devicid2"}; + std::vector targetDev = { "devicid1", "devicid2" }; std::string accountId = "testAccount"; std::shared_ptr endpoint = std::make_shared(); Status status = manager.SetEndpoint(endpoint); @@ -204,7 +202,7 @@ HWTEST_F(EndPointTest, SetIdentifier002, TestSize.Level1) EXPECT_NE(kvStore_, nullptr) << "kvStorePtr is null."; AppId appId = { "" }; StoreId storeId = { "" }; - std::vector targetDev = {"devicid1", "devicid2"}; + std::vector targetDev = { "devicid1", "devicid2" }; std::string accountId = "testAccount"; std::shared_ptr endpoint = std::make_shared(); Status status = manager.SetEndpoint(endpoint); diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/kv_utils_test.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/kv_utils_test.cpp index ff70181fb477e6a0cd96f10068a61ab0424c0bd0..deb64e369b18ce77886fd446d364106a1646e58a 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/kv_utils_test.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/kv_utils_test.cpp @@ -13,19 +13,19 @@ * limitations under the License. */ -#include -#include -#include #include "datashare_predicates.h" #include "datashare_values_bucket.h" #include "distributed_kv_data_manager.h" -#include "gtest/gtest.h" #include "kv_utils.h" #include "kvstore_datashare_bridge.h" #include "kvstore_result_set.h" #include "result_set_bridge.h" #include "store_errno.h" #include "types.h" +#include "gtest/gtest.h" +#include +#include +#include namespace { using namespace testing::ext; @@ -36,8 +36,8 @@ class KvUtilTest : public testing::Test { public: static void SetUpTestCase(void); static void TearDownTestCase(void); - void SetUp() {} - void TearDown() {} + void SetUp() { } + void TearDown() { } protected: static DistributedKvDataManager manager; @@ -98,16 +98,16 @@ Blob KvUtilTest::VariantValue2Blob(const var_t &value) auto dblValue = std::get_if(&value); if (dblValue != nullptr) { double tmp4dbl = *dblValue; - uint64_t tmp64 = htobe64(*reinterpret_cast(&tmp4dbl)); - tmp = reinterpret_cast(&tmp64); + uint64_t tmp64 = htobe64(*reinterpret_cast(&tmp4dbl)); + tmp = reinterpret_cast(&tmp64); data.push_back(KvUtils::DOUBLE); data.insert(data.end(), tmp, tmp + sizeof(double) / sizeof(uint8_t)); } auto intValue = std::get_if(&value); if (intValue != nullptr) { int64_t tmp4int = *intValue; - uint64_t tmp64 = htobe64(*reinterpret_cast(&tmp4int)); - tmp = reinterpret_cast(&tmp64); + uint64_t tmp64 = htobe64(*reinterpret_cast(&tmp4int)); + tmp = reinterpret_cast(&tmp64); data.push_back(KvUtils::INTEGER); data.insert(data.end(), tmp, tmp + sizeof(int64_t) / sizeof(uint8_t)); } @@ -121,8 +121,11 @@ Blob KvUtilTest::VariantValue2Blob(const var_t &value) void KvUtilTest::SetUpTestCase(void) { - Options options = {.createIfMissing = true, .encrypt = false, .autoSync = false, - .kvStoreType = KvStoreType::SINGLE_VERSION, .schema = VALID_SCHEMA_STRICT_DEFINE}; + Options options = { .createIfMissing = true, + .encrypt = false, + .autoSync = false, + .kvStoreType = KvStoreType::SINGLE_VERSION, + .schema = VALID_SCHEMA_STRICT_DEFINE }; options.area = EL1; options.securityLevel = S1; options.baseDir = std::string("/data/service/el1/public/database/kvUtilTest"); @@ -140,20 +143,19 @@ void KvUtilTest::SetUpTestCase(void) void KvUtilTest::TearDownTestCase(void) { - manager.DeleteKvStore({"kvUtilTest"}, {"test_single"}, - "/data/service/el1/public/database/kvUtilTest"); - (void) remove("/data/service/el1/public/database/kvUtilTest/key"); - (void) remove("/data/service/el1/public/database/kvUtilTest/kvdb"); - (void) remove("/data/service/el1/public/database/kvUtilTest"); + manager.DeleteKvStore({ "kvUtilTest" }, { "test_single" }, "/data/service/el1/public/database/kvUtilTest"); + (void)remove("/data/service/el1/public/database/kvUtilTest/key"); + (void)remove("/data/service/el1/public/database/kvUtilTest/kvdb"); + (void)remove("/data/service/el1/public/database/kvUtilTest"); } /** -* @tc.name: KvStoreResultSetToResultSetBridge -* @tc.desc: kvStore resultSet to resultSet bridge, the former is nullptr -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: KvStoreResultSetToResultSetBridge + * @tc.desc: kvStore resultSet to resultSet bridge, the former is nullptr + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, KvStoreResultSetToResultSetBridgeAbnormal, TestSize.Level0) { std::shared_ptr resultSet = nullptr; @@ -162,12 +164,12 @@ HWTEST_F(KvUtilTest, KvStoreResultSetToResultSetBridgeAbnormal, TestSize.Level0) } /** -* @tc.name: KvStoreResultSetToResultSetBridge -* @tc.desc: kvStore resultSet to resultSet bridge -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: KvStoreResultSetToResultSetBridge + * @tc.desc: kvStore resultSet to resultSet bridge + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, KvStoreResultSetToResultSetBridge, TestSize.Level0) { DataSharePredicates predicates; @@ -185,12 +187,12 @@ HWTEST_F(KvUtilTest, KvStoreResultSetToResultSetBridge, TestSize.Level0) } /** -* @tc.name: PredicatesToQuery -* @tc.desc: to query equalTo -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: PredicatesToQuery + * @tc.desc: to query equalTo + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, PredicatesToQueryEqualTo, TestSize.Level0) { DataSharePredicates predicates; @@ -204,12 +206,12 @@ HWTEST_F(KvUtilTest, PredicatesToQueryEqualTo, TestSize.Level0) } /** -* @tc.name: PredicatesToQuery -* @tc.desc: to query not equalTo -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: PredicatesToQuery + * @tc.desc: to query not equalTo + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, PredicatesToQueryNotEqualTo, TestSize.Level0) { DataSharePredicates predicates; @@ -223,12 +225,12 @@ HWTEST_F(KvUtilTest, PredicatesToQueryNotEqualTo, TestSize.Level0) } /** -* @tc.name: PredicatesToQuery -* @tc.desc: to query greater than -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: PredicatesToQuery + * @tc.desc: to query greater than + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, PredicatesToQueryGreaterThan, TestSize.Level0) { DataSharePredicates predicates; @@ -242,12 +244,12 @@ HWTEST_F(KvUtilTest, PredicatesToQueryGreaterThan, TestSize.Level0) } /** -* @tc.name: PredicatesToQuery -* @tc.desc: to query less than -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: PredicatesToQuery + * @tc.desc: to query less than + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, PredicatesToQueryLessThan, TestSize.Level0) { DataSharePredicates predicates; @@ -261,12 +263,12 @@ HWTEST_F(KvUtilTest, PredicatesToQueryLessThan, TestSize.Level0) } /** -* @tc.name: PredicatesToQuery -* @tc.desc: to query greater than or equalTo -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: PredicatesToQuery + * @tc.desc: to query greater than or equalTo + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, PredicatesToQueryGreaterThanOrEqualTo, TestSize.Level0) { DataSharePredicates predicates; @@ -280,12 +282,12 @@ HWTEST_F(KvUtilTest, PredicatesToQueryGreaterThanOrEqualTo, TestSize.Level0) } /** -* @tc.name: PredicatesToQuery -* @tc.desc: to query less than or equalTo -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: PredicatesToQuery + * @tc.desc: to query less than or equalTo + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, PredicatesToQueryLessThanOrEqualTo, TestSize.Level0) { DataSharePredicates predicates; @@ -299,15 +301,15 @@ HWTEST_F(KvUtilTest, PredicatesToQueryLessThanOrEqualTo, TestSize.Level0) } /** -* @tc.name: PredicatesToQuery -* @tc.desc: to query in -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: PredicatesToQuery + * @tc.desc: to query in + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, PredicatesToQueryIn, TestSize.Level0) { - std::vector vectInt{ 1, 2 }; + std::vector vectInt { 1, 2 }; DataSharePredicates predicates; predicates.In("$.age", vectInt); DataQuery query; @@ -319,15 +321,15 @@ HWTEST_F(KvUtilTest, PredicatesToQueryIn, TestSize.Level0) } /** -* @tc.name: PredicatesToQuery -* @tc.desc: to query not in -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: PredicatesToQuery + * @tc.desc: to query not in + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, PredicatesToQueryNotIn, TestSize.Level0) { - std::vector vectInt{ 1, 2 }; + std::vector vectInt { 1, 2 }; DataSharePredicates predicates; predicates.NotIn("$.age", vectInt); DataQuery query; @@ -339,12 +341,12 @@ HWTEST_F(KvUtilTest, PredicatesToQueryNotIn, TestSize.Level0) } /** -* @tc.name: PredicatesToQuery -* @tc.desc: to query or, like -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: PredicatesToQuery + * @tc.desc: to query or, like + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, PredicatesToQueryLike, TestSize.Level0) { DataSharePredicates predicates; @@ -362,12 +364,12 @@ HWTEST_F(KvUtilTest, PredicatesToQueryLike, TestSize.Level0) } /** -* @tc.name: PredicatesToQuery -* @tc.desc: to query and, unlike -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: PredicatesToQuery + * @tc.desc: to query and, unlike + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, PredicatesToQueryUnlike, TestSize.Level0) { DataSharePredicates predicates; @@ -385,12 +387,12 @@ HWTEST_F(KvUtilTest, PredicatesToQueryUnlike, TestSize.Level0) } /** -* @tc.name: PredicatesToQuery -* @tc.desc: to query is null -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: PredicatesToQuery + * @tc.desc: to query is null + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, PredicatesToQueryIsNull, TestSize.Level0) { DataSharePredicates predicates; @@ -404,12 +406,12 @@ HWTEST_F(KvUtilTest, PredicatesToQueryIsNull, TestSize.Level0) } /** -* @tc.name: PredicatesToQuery -* @tc.desc: to query is not null -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: PredicatesToQuery + * @tc.desc: to query is not null + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, PredicatesToQueryIsNotNull, TestSize.Level0) { DataSharePredicates predicates; @@ -423,12 +425,12 @@ HWTEST_F(KvUtilTest, PredicatesToQueryIsNotNull, TestSize.Level0) } /** -* @tc.name: PredicatesToQuery -* @tc.desc: to query is order by asc -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: PredicatesToQuery + * @tc.desc: to query is order by asc + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, PredicatesToQueryOrderByAsc, TestSize.Level0) { DataSharePredicates predicates; @@ -442,12 +444,12 @@ HWTEST_F(KvUtilTest, PredicatesToQueryOrderByAsc, TestSize.Level0) } /** -* @tc.name: PredicatesToQuery -* @tc.desc: to query is order by desc -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: PredicatesToQuery + * @tc.desc: to query is order by desc + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, PredicatesToQueryOrderByDesc, TestSize.Level0) { DataSharePredicates predicates; @@ -461,12 +463,12 @@ HWTEST_F(KvUtilTest, PredicatesToQueryOrderByDesc, TestSize.Level0) } /** -* @tc.name: PredicatesToQuery -* @tc.desc: to query is limit -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: PredicatesToQuery + * @tc.desc: to query is limit + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, PredicatesToQueryLimit, TestSize.Level0) { DataSharePredicates predicates; @@ -480,12 +482,12 @@ HWTEST_F(KvUtilTest, PredicatesToQueryLimit, TestSize.Level0) } /** -* @tc.name: PredicatesToQuery -* @tc.desc: to query is in keys -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: PredicatesToQuery + * @tc.desc: to query is in keys + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, PredicatesToQueryInKeys, TestSize.Level0) { std::vector keys { "test_field", "", "^test_field", "^", "test_field_name" }; @@ -500,12 +502,12 @@ HWTEST_F(KvUtilTest, PredicatesToQueryInKeys, TestSize.Level0) } /** -* @tc.name: ToEntry -* @tc.desc: dataShare values bucket to entry, the bucket is invalid -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: ToEntry + * @tc.desc: dataShare values bucket to entry, the bucket is invalid + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntryAbnormal, TestSize.Level0) { DataShareValuesBucket bucket {}; @@ -522,12 +524,12 @@ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntryAbnormal, TestSize.Level0) } /** -* @tc.name: ToEntry -* @tc.desc: dataShare values bucket to entry, the bucket value is null -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: ToEntry + * @tc.desc: dataShare values bucket to entry, the bucket value is null + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntryNull, TestSize.Level0) { DataShareValuesBucket bucket {}; @@ -539,12 +541,12 @@ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntryNull, TestSize.Level0) } /** -* @tc.name: ToEntry -* @tc.desc: dataShare values bucket to entry, the bucket value type is int64_t -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: ToEntry + * @tc.desc: dataShare values bucket to entry, the bucket value type is int64_t + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntryInt64_t, TestSize.Level0) { DataShareValuesBucket bucket {}; @@ -562,12 +564,12 @@ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntryInt64_t, TestSize.Level0) } /** -* @tc.name: ToEntry -* @tc.desc: dataShare values bucket to entry, the bucket value type is double -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: ToEntry + * @tc.desc: dataShare values bucket to entry, the bucket value type is double + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntryDouble, TestSize.Level0) { DataShareValuesBucket bucket {}; @@ -585,12 +587,12 @@ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntryDouble, TestSize.Level0) } /** -* @tc.name: ToEntry -* @tc.desc: dataShare values bucket to entry, the bucket value type is string -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: ToEntry + * @tc.desc: dataShare values bucket to entry, the bucket value type is string + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntryString, TestSize.Level0) { DataShareValuesBucket bucket {}; @@ -608,12 +610,12 @@ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntryString, TestSize.Level0) } /** -* @tc.name: ToEntry -* @tc.desc: dataShare values bucket to entry, the bucket value type is bool -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: ToEntry + * @tc.desc: dataShare values bucket to entry, the bucket value type is bool + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntryBool, TestSize.Level0) { DataShareValuesBucket bucket {}; @@ -631,12 +633,12 @@ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntryBool, TestSize.Level0) } /** -* @tc.name: ToEntry -* @tc.desc: dataShare values bucket to entry, the bucket value type is uint8array -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: ToEntry + * @tc.desc: dataShare values bucket to entry, the bucket value type is uint8array + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntryUint8Array, TestSize.Level0) { DataShareValuesBucket bucket {}; @@ -655,12 +657,12 @@ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntryUint8Array, TestSize.Level0) } /** -* @tc.name: ToEntry -* @tc.desc: dataShare values bucket to entry, the bucket key type is not string -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: ToEntry + * @tc.desc: dataShare values bucket to entry, the bucket key type is not string + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntryInvalidKey, TestSize.Level0) { DataShareValuesBucket bucket {}; @@ -678,12 +680,12 @@ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntryInvalidKey, TestSize.Level0) } /** -* @tc.name: ToEntry -* @tc.desc: dataShare values bucket to entries, the buckets is invalid -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: ToEntry + * @tc.desc: dataShare values bucket to entries, the buckets is invalid + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntriesAbnormal, TestSize.Level0) { std::vector buckets {}; @@ -692,12 +694,12 @@ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntriesAbnormal, TestSize.Level0) } /** -* @tc.name: ToEntry -* @tc.desc: dataShare values bucket to entries, the buckets has valid value -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: ToEntry + * @tc.desc: dataShare values bucket to entries, the buckets has valid value + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntriesNormal, TestSize.Level0) { std::vector buckets {}; @@ -728,12 +730,12 @@ HWTEST_F(KvUtilTest, DataShareValuesBucketToEntriesNormal, TestSize.Level0) } /** -* @tc.name: GetKeys -* @tc.desc: get keys from data share predicates, the predicates is invalid -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: GetKeys + * @tc.desc: get keys from data share predicates, the predicates is invalid + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, GetKeysFromDataSharePredicatesAbnormal, TestSize.Level0) { DataSharePredicates predicates; @@ -746,12 +748,12 @@ HWTEST_F(KvUtilTest, GetKeysFromDataSharePredicatesAbnormal, TestSize.Level0) } /** -* @tc.name: GetKeys -* @tc.desc: get keys from data share predicates, the predicates has valid value -* @tc.type: FUNC -* @tc.require: -* @tc.author: zuojiangjiang -*/ + * @tc.name: GetKeys + * @tc.desc: get keys from data share predicates, the predicates has valid value + * @tc.type: FUNC + * @tc.require: + * @tc.author: zuojiangjiang + */ HWTEST_F(KvUtilTest, GetKeysFromDataSharePredicatesNormal, TestSize.Level0) { std::vector keys { "test_field", "", "^test_field", "^", "test_field_name" }; diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/single_kvstore_client_test.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/single_kvstore_client_test.cpp index 30a564caedf7f82d9f5f6b6d0b22745d7ab27691..b720f9dbecbf4b71dc90476534b29c5170c11762 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/single_kvstore_client_test.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/single_kvstore_client_test.cpp @@ -25,19 +25,15 @@ using namespace testing::ext; using namespace OHOS::DistributedKv; namespace OHOS::Test { +static constexpr uint64_t MAX_VALUE_SIZE = 4 * 1024 * 1024; // max value size is 4M. class SingleKvStoreClientTest : public testing::Test { public: - static constexpr uint64_t MAX_VALUE_SIZE = 4 * 1024 * 1024; // max value size is 4M. + static std::shared_ptr singleKvStore; // declare kvstore instance. + static Status status_; static void SetUpTestCase(void); - static void TearDownTestCase(void); - void SetUp(); - void TearDown(); - - static std::shared_ptr singleKvStore; // declare kvstore instance. - static Status status_; }; const std::string VALID_SCHEMA_STRICT_DEFINE = "{\"SCHEMA_VERSION\":\"1.0\"," diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatasvc/src/datamgr_service_proxy.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatasvc/src/datamgr_service_proxy.cpp index 99168c94cd98c6c7d972adc2deee0643182a7c02..4eed48d7169c9aa4f4f2e1f891c96965f07afa0b 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatasvc/src/datamgr_service_proxy.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatasvc/src/datamgr_service_proxy.cpp @@ -27,7 +27,7 @@ namespace DistributedKv { DataMgrServiceProxy::DataMgrServiceProxy(const sptr &impl) : IRemoteProxy(impl) { - ZLOGI("init data service proxy."); + ZLOGI("Init data service proxy."); } sptr DataMgrServiceProxy::GetFeatureInterface(const std::string &name) @@ -35,12 +35,12 @@ sptr DataMgrServiceProxy::GetFeatureInterface(const std::string & ZLOGI("%s", name.c_str()); MessageParcel data; if (!data.WriteInterfaceToken(DataMgrServiceProxy::GetDescriptor())) { - ZLOGE("write descriptor failed"); + ZLOGE("Write descriptor failed"); return nullptr; } if (!ITypesUtil::Marshal(data, name)) { - ZLOGE("write name failed, name is %{public}s", name.c_str()); + ZLOGE("Write name failed, name is %{public}s", name.c_str()); return nullptr; } @@ -55,7 +55,7 @@ sptr DataMgrServiceProxy::GetFeatureInterface(const std::string & sptr remoteObject; if (!ITypesUtil::Unmarshal(reply, remoteObject)) { - ZLOGE("remote object is nullptr"); + ZLOGE("Remote object is nullptr"); return nullptr; } return remoteObject; @@ -66,20 +66,20 @@ Status DataMgrServiceProxy::RegisterClientDeathObserver(const AppId &appId, sptr MessageParcel data; MessageParcel reply; if (!data.WriteInterfaceToken(DataMgrServiceProxy::GetDescriptor())) { - ZLOGE("write descriptor failed"); + ZLOGE("Write descriptor failed"); return Status::IPC_ERROR; } if (!data.WriteString(appId.appId)) { - ZLOGW("failed to write string."); + ZLOGW("Failed to write string."); return Status::IPC_ERROR; } if (observer != nullptr) { if (!data.WriteRemoteObject(observer)) { - ZLOGW("failed to write parcel."); + ZLOGW("Failed to write parcel."); return Status::IPC_ERROR; } } else { - ZLOGE("observer is null"); + ZLOGE("This observer is null"); return Status::INVALID_ARGUMENT; } @@ -87,7 +87,7 @@ Status DataMgrServiceProxy::RegisterClientDeathObserver(const AppId &appId, sptr int32_t error = Remote()->SendRequest( static_cast(KvStoreDataServiceInterfaceCode::REGISTERCLIENTDEATHOBSERVER), data, reply, mo); if (error != 0) { - ZLOGW("failed during IPC. errCode %d", error); + ZLOGW("Failed during IPC. errCode %d", error); return Status::IPC_ERROR; } return static_cast(reply.ReadInt32()); @@ -99,11 +99,11 @@ int32_t DataMgrServiceProxy::ClearAppStorage(const std::string &bundleName, int3 MessageParcel data; MessageParcel reply; if (!data.WriteInterfaceToken(DataMgrServiceProxy::GetDescriptor())) { - ZLOGE("write descriptor failed"); + ZLOGE("Write descriptor failed"); return Status::IPC_ERROR; } if (!ITypesUtil::Marshal(data, bundleName, userId, appIndex, tokenId)) { - ZLOGW("failed to write bundleName:%{public}s, user:%{public}d, appIndex:%{public}d, tokenID:%{public}d", + ZLOGW("Failed to write bundleName:%{public}s, user:%{public}d, appIndex:%{public}d, tokenID:%{public}d", bundleName.c_str(), userId, appIndex, tokenId); return Status::IPC_ERROR; } @@ -112,7 +112,7 @@ int32_t DataMgrServiceProxy::ClearAppStorage(const std::string &bundleName, int3 int32_t error = Remote()->SendRequest( static_cast(KvStoreDataServiceInterfaceCode::CLEAR_APP_STORAGE), data, reply, mo); if (error != 0) { - ZLOGW("failed during IPC. errCode %d", error); + ZLOGW("Failed during IPC. errCode %d", error); return Status::IPC_ERROR; } return static_cast(reply.ReadInt32()); diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/include/backup_manager.h b/kv_store/frameworks/innerkitsimpl/kvdb/include/backup_manager.h index 281db55f594732d9d2f85a20203d4f7433195af6..12a4afaa525b64eb960ca394707ee4455f6254e0 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/include/backup_manager.h +++ b/kv_store/frameworks/innerkitsimpl/kvdb/include/backup_manager.h @@ -33,6 +33,7 @@ public: std::string baseDir; std::string appId; std::string storeId; + bool encrypt = false; }; struct ResidueInfo { size_t tmpBackupSize; @@ -52,10 +53,12 @@ public: static BackupManager &GetInstance(); void Init(const std::string &baseDir); void Prepare(const std::string &path, const std::string &storeId); - Status Backup(const BackupInfo &info, std::shared_ptr dbStore); + Status Backup(const BackupInfo &info, std::shared_ptr dbStore, bool isCheckIntegrity); Status Restore(const BackupInfo &info, std::shared_ptr dbStore, bool isCheckIntegrity); Status DeleteBackup(std::map &deleteList, const std::string &baseDir, const std::string &storeId); + Status GetSecretKeyFromService(const AppId &appId, const StoreId &storeId, + std::vector> &keys); private: BackupManager(); ~BackupManager(); @@ -79,7 +82,8 @@ private: const std::string &baseDir, const std::string &storeId); bool IsEndWith(const std::string &fullString, const std::string &end); bool IsBeginWith(const std::string &fullString, const std::string &begin); - + Status ImportWithSecretKeyFromService(const BackupInfo &info, std::shared_ptr dbStore, + std::string &fullName, bool isCheckIntegrity); static constexpr int MAX_BACKUP_NUM = 5; }; } // namespace OHOS::DistributedKv diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/include/kv_hiview_reporter.h b/kv_store/frameworks/innerkitsimpl/kvdb/include/kv_hiview_reporter.h index 446eff1bafdd339973a55e23cee1e67ad58d75c1..e48c5a2ac95c355c9862dfc4fa3014afa2c8c1ce 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/include/kv_hiview_reporter.h +++ b/kv_store/frameworks/innerkitsimpl/kvdb/include/kv_hiview_reporter.h @@ -16,47 +16,72 @@ #ifndef KV_HIVIEW_REPORTER_H #define KV_HIVIEW_REPORTER_H +#include +#include +#include #include #include "types.h" namespace OHOS::DistributedKv { -constexpr const char* DATABASE_REBUILD = "RestoreType:Rebuild"; struct Suffix { const char *suffix_ = nullptr; const char *name_ = nullptr; }; -static constexpr Suffix FILE_SUFFIXES[] = { - {"", "DB"}, - {"-shm", "SHM"}, - {"-wal", "WAL"}, + +enum BusinessType { + SQLITE, + GAUSSPD, +}; + +enum DFXEvent { + FAULT = 0x1, // 001 + CORRUPTED = 0x2, // 010 + REBUILD = 0x4, // 100 +}; + +struct ReportInfo { + Options options; + uint32_t errorCode; + int32_t systemErrorNo; + std::string appId; + std::string storeId; + std::string functionName; }; -static constexpr const char *defaultPath = "single_ver/main/gen_natural_store.db"; -struct KVDBCorruptedEvent; + +struct KVDBFaultEvent; class KVDBFaultHiViewReporter { public: - static void ReportKVDBCorruptedFault( - const Options &options, uint32_t errorCode, int32_t systemErrorNo, - const KvStoreTuple &storeTuple, const std::string &appendix); - - static void ReportKVDBRebuild( - const Options &options, uint32_t errorCode, int32_t systemErrorNo, - const KvStoreTuple &storeTuple, const std::string &appendix); + static void ReportKVFaultEvent(const ReportInfo &reportInfo); - static std::string GetDBPath(const std::string &path, const std::string &storeId); - - static void DeleteCorruptedFlag(const std::string &dbPath, const std::string &storeId); + static void ReportKVRebuildEvent(const ReportInfo &reportInfo); private: - static void ReportCommonFault(const KVDBCorruptedEvent &eventInfo); + static void ReportFaultEvent(KVDBFaultEvent eventInfo); + + static void ReportCurruptedEvent(KVDBFaultEvent eventInfo); + + static void ReportCommonFault(const KVDBFaultEvent &eventInfo); static std::string GetCurrentMicrosecondTimeFormat(); - - static bool IsReportCorruptedFault(const std::string &dbPath, const std::string &storeId); + + static bool IsReportedCorruptedFault(const std::string &dbPath, const std::string &storeId); static void CreateCorruptedFlag(const std::string &dbPath, const std::string &storeId); + static std::string GetDBPath(const std::string& path, const std::string& storeId); + + static void DeleteCorruptedFlag(const std::string& dbPath, const std::string& storeId); + static std::string GetFileStatInfo(const std::string &dbPath); static std::string GetTimeWithMilliseconds(time_t sec, int64_t nsec); + + static std::string GenerateAppendix(const KVDBFaultEvent &eventInfo); + + static bool IsReportedFault(const KVDBFaultEvent& eventInfo); + + static std::set storeFaults_; + + static std::mutex mutex_; }; } // namespace OHOS::DistributedKv #endif //KV_HIVIEW_REPORTER_H \ No newline at end of file diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service.h b/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service.h index 7777bc5b035b07275eef51675fca22daefb0380b..b8ffd218bc83afc95588e2d4995663fafcaea747 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service.h +++ b/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service.h @@ -65,8 +65,8 @@ public: virtual Status RmvSubscribeInfo(const AppId &appId, const StoreId &storeId, const SyncInfo &syncInfo) = 0; virtual Status Subscribe(const AppId &appId, const StoreId &storeId, sptr observer) = 0; virtual Status Unsubscribe(const AppId &appId, const StoreId &storeId, sptr observer) = 0; - virtual Status GetBackupPassword( - const AppId &appId, const StoreId &storeId, std::vector &password, int32_t passwordType) = 0; + virtual Status GetBackupPassword(const AppId &appId, const StoreId &storeId, + std::vector> &passwords, int32_t passwordType) = 0; virtual Status CloudSync(const AppId &appId, const StoreId &storeId, const SyncInfo &syncInfo) = 0; virtual Status NotifyDataChange(const AppId &appId, const StoreId &storeId, uint64_t delay) = 0; virtual Status PutSwitch(const AppId &appId, const SwitchData &data) = 0; diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service_client.h b/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service_client.h index e2e01baf6aa5aa20f8e473d00fe1d2d4513d0d3e..9ff96260bd2673cc76462ec7adfa3f464f378d7d 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service_client.h +++ b/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service_client.h @@ -49,7 +49,7 @@ public: Status RmvSubscribeInfo(const AppId &appId, const StoreId &storeId, const SyncInfo &syncInfo) override; Status Subscribe(const AppId &appId, const StoreId &storeId, sptr observer) override; Status Unsubscribe(const AppId &appId, const StoreId &storeId, sptr observer) override; - Status GetBackupPassword(const AppId &appId, const StoreId &storeId, std::vector &password, + Status GetBackupPassword(const AppId &appId, const StoreId &storeId, std::vector> &passwords, int32_t passwordType) override; Status CloudSync(const AppId &appId, const StoreId &storeId, const SyncInfo &syncInfo) override; Status NotifyDataChange(const AppId &appId, const StoreId &storeId, uint64_t delay) override; diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/include/process_communication_impl.h b/kv_store/frameworks/innerkitsimpl/kvdb/include/process_communication_impl.h index 902b63a8782e5472bad79f211887354f555eefe5..143fc33b4fdd2c286834a77a3c3a37bde709ef57 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/include/process_communication_impl.h +++ b/kv_store/frameworks/innerkitsimpl/kvdb/include/process_communication_impl.h @@ -28,7 +28,7 @@ public: using DBStatus = DistributedDB::DBStatus; using OnDeviceChange = DistributedDB::OnDeviceChange; using OnDataReceive = DistributedDB::OnDataReceive; - + API_EXPORT explicit ProcessCommunicationImpl(std::shared_ptr endpoint); API_EXPORT ~ProcessCommunicationImpl() override; @@ -47,7 +47,7 @@ public: std::shared_ptr GetExtendHeaderHandle( const DistributedDB::ExtendInfo ¶mInfo) override; private: - + std::shared_ptr endpoint_; bool isCreateSessionServer_ = false; }; diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/include/single_store_impl.h b/kv_store/frameworks/innerkitsimpl/kvdb/include/single_store_impl.h index a6468c9a0c11434b4d6d904bd283029232f2dcca..a44a77fa81b29610984008688dcaaf78a2e0452c 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/include/single_store_impl.h +++ b/kv_store/frameworks/innerkitsimpl/kvdb/include/single_store_impl.h @@ -116,7 +116,7 @@ private: (std::chrono::steady_clock::now() + std::chrono::milliseconds(offset)).time_since_epoch()) .count(); } - static constexpr int32_t INTEGRITY_CHECK_API_VERSION = 14; + static constexpr int32_t INTEGRITY_CHECK_API_VERSION = 16; static constexpr uint32_t NOTIFY_INTERVAL = 200; // ms static constexpr size_t MAX_VALUE_LENGTH = 4 * 1024 * 1024; static constexpr size_t MAX_OBSERVER_SIZE = 8; @@ -133,7 +133,7 @@ private: bool IsRemoteChanged(const std::string &deviceId); void DoNotifyChange(); void Register(); - void ReportDBCorruptedFault(Status status) const; + void ReportDBFaultEvent(Status status, const std::string &functionName) const; int32_t apiVersion_ = -1; bool isApplication_ = false; @@ -148,6 +148,7 @@ private: int32_t dataType_ = DataType::TYPE_DYNAMICAL; uint32_t roleType_ = 0; uint64_t taskId_ = 0; + bool isCheckIntegrity_ = false; bool encrypt_ = false; int32_t securityLevel_ = -1; diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/include/store_manager.h b/kv_store/frameworks/innerkitsimpl/kvdb/include/store_manager.h index c33721af0335f862fff6e113e626fd306c2fb14d..88891c7791b611480139ee0942c16a4eeaa806d5 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/include/store_manager.h +++ b/kv_store/frameworks/innerkitsimpl/kvdb/include/store_manager.h @@ -15,6 +15,7 @@ #ifndef OHOS_DISTRIBUTED_DATA_FRAMEWORKS_KVDB_STORE_MANAGER_H #define OHOS_DISTRIBUTED_DATA_FRAMEWORKS_KVDB_STORE_MANAGER_H #include "single_kvstore.h" +#include "kv_hiview_reporter.h" namespace OHOS::DistributedKv { class StoreManager { public: @@ -31,7 +32,8 @@ public: Status UnsubscribeSwitchData(const AppId &appId, std::shared_ptr observer); private: - Status GetSecretKeyFromService(const AppId &appId, const StoreId &storeId, const std::string &path); + std::shared_ptr OpenWithSecretKeyFromService(const AppId &appId, const StoreId &storeId, + const Options &options, Status &status, bool &isCreate); }; } #endif // OHOS_DISTRIBUTED_DATA_FRAMEWORKS_KVDB_STORE_MANAGER_H diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/backup_manager.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/backup_manager.cpp index 33bd523526e0d9842ba9a3445b166ffb16cb89c1..a557d373bf2d05b1354e2d07495ffa62b8244a4f 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/backup_manager.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/backup_manager.cpp @@ -106,11 +106,17 @@ void BackupManager::CleanTmpData(const std::string &name) StoreUtil::Remove(tmpName); } -Status BackupManager::Backup(const BackupInfo &info, std::shared_ptr dbStore) +Status BackupManager::Backup(const BackupInfo &info, std::shared_ptr dbStore, bool isCheckIntegrity) { if (dbStore == nullptr) { return ALREADY_CLOSED; } + if (isCheckIntegrity) { + auto integrityStatus = dbStore->CheckIntegrity(); + if (integrityStatus != DistributedDB::DBStatus::OK) { + return StoreUtil::ConvertStatus(integrityStatus); + } + } if (info.name.size() == 0 || info.baseDir.size() == 0 || info.storeId.size() == 0 || info.name == AUTO_BACKUP_NAME) { return INVALID_ARGUMENT; @@ -187,9 +193,13 @@ Status BackupManager::Restore(const BackupInfo &info, std::shared_ptr d } auto fullName = info.baseDir + BACKUP_TOP_PATH + "/" + info.storeId + "/" + backupFile.name; auto password = GetRestorePassword(backupFile.name, info.baseDir, info.appId, info.storeId).password; - auto dbStatus = dbStore->Import(fullName, password); - auto status = StoreUtil::ConvertStatus(dbStatus); - return status; + auto dbStatus = dbStore->Import(fullName, password, isCheckIntegrity); + if (dbStatus == DistributedDB::DBStatus::INVALID_FILE && info.encrypt) { + ZLOGI("Use the key from server to restore"); + auto retryStatus = ImportWithSecretKeyFromService(info, dbStore, fullName, isCheckIntegrity); + return retryStatus == SUCCESS ? SUCCESS : CRYPT_ERROR; + } + return StoreUtil::ConvertStatus(dbStatus); } BackupManager::DBPassword BackupManager::GetRestorePassword( @@ -203,16 +213,71 @@ BackupManager::DBPassword BackupManager::GetRestorePassword( if (service == nullptr) { return dbPassword; } - std::vector pwd; - service->GetBackupPassword({ appId }, { storeId }, pwd, KVDBService::PasswordType::BACKUP_SECRET_KEY); - dbPassword.SetValue(pwd.data(), pwd.size()); - pwd.assign(pwd.size(), 0); + std::vector> pwds; + service->GetBackupPassword({ appId }, { storeId }, pwds, KVDBService::PasswordType::BACKUP_SECRET_KEY); + if (pwds.size() != 0) { + // When obtaining the key for automatic backup, there is only one element in the list + dbPassword.SetValue(pwds[0].data(), pwds[0].size()); + } + for (auto &pwd : pwds) { + pwd.assign(pwd.size(), 0); + } } else { dbPassword = SecurityManager::GetInstance().GetDBPassword(keyName, baseDir); } return dbPassword; } +Status BackupManager::GetSecretKeyFromService(const AppId &appId, const StoreId &storeId, + std::vector> &keys) +{ + auto service = KVDBServiceClient::GetInstance(); + if (service == nullptr) { + ZLOGE("Get service failed! appId:%{public}s, storeId:%{public}s", + appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str()); + return Status::SERVER_UNAVAILABLE; + } + auto status = service->GetBackupPassword(appId, storeId, keys, KVDBService::PasswordType::SECRET_KEY); + if (status != Status::SUCCESS) { + ZLOGE("Get password from service failed! status:%{public}d, appId:%{public}s storeId:%{public}s", + status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str()); + return status; + } + if (keys.empty()) { + ZLOGE("Service secret key is empty! status:%{public}d, appId:%{public}s storeId:%{public}s", + status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str()); + return Status::ERROR; + } + return Status::SUCCESS; +} + +Status BackupManager::ImportWithSecretKeyFromService(const BackupInfo &info, std::shared_ptr dbStore, + std::string &fullName, bool isCheckIntegrity) +{ + Status status = NOT_FOUND; + std::vector> keys; + if (GetSecretKeyFromService({ info.appId }, { info.storeId }, keys) != Status::SUCCESS) { + for (auto &key : keys) { + key.assign(key.size(), 0); + } + return status; + } + for (auto &key : keys) { + SecurityManager::DBPassword dbPassword; + dbPassword.SetValue(key.data(), key.size()); + auto dbStatus = dbStore->Import(fullName, dbPassword.password, isCheckIntegrity); + status = StoreUtil::ConvertStatus(dbStatus); + if (status == SUCCESS) { + ZLOGI("Import with secretKey from service success!"); + break; + } + } + for (auto &key : keys) { + key.assign(key.size(), 0); + } + return status; +} + Status BackupManager::DeleteBackup( std::map &deleteList, const std::string &baseDir, const std::string &storeId) { diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/dev_manager.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/dev_manager.cpp index 8d0829d1016298ebff151f591a4e8ede7a3b61f5..7f56f1bac87cd1010ae624ea0387ebf7cd7e9d03 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/dev_manager.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/dev_manager.cpp @@ -40,7 +40,7 @@ private: void DmDeathCallback::OnRemoteDied() { - ZLOGI("dm device manager died, init it again"); + ZLOGI("Dm device manager died, init it again"); devManager_.RegisterDevCallback(); } @@ -108,7 +108,7 @@ void DevManager::UpdateBucket() { auto detailInfos = GetRemoteDevices(); if (detailInfos.empty()) { - ZLOGD("no remote device"); + ZLOGD("No remote device"); } detailInfos.emplace_back(GetLocalDevice()); for (const auto &detailInfo : detailInfos) { @@ -129,18 +129,18 @@ std::string DevManager::GetUnEncryptedUuid() DevInfo info; auto ret = DeviceManager::GetInstance().GetLocalDeviceInfo(PKG_NAME, info); if (ret != DM_OK) { - ZLOGE("get local device info fail"); + ZLOGE("Get local device info fail"); return ""; } auto networkId = std::string(info.networkId); if (networkId.empty()) { - ZLOGE("networkid empty"); + ZLOGE("This networkid is empty"); return ""; } std::string uuid; DeviceManager::GetInstance().GetUuidByNetworkId(PKG_NAME, networkId, uuid); if (uuid.empty()) { - ZLOGE("get uuid by networkid fail"); + ZLOGE("Get uuid by networkid fail"); return ""; } UnEncryptedLocalInfo_.uuid = std::move(uuid); @@ -159,7 +159,7 @@ const DevManager::DetailInfo &DevManager::GetLocalDevice() DevInfo info; auto ret = DeviceManager::GetInstance().GetLocalDeviceInfo(PKG_NAME, info); if (ret != DM_OK) { - ZLOGE("get local device info fail"); + ZLOGE("Get local device info fail"); return invalidDetail_; } auto networkId = std::string(info.networkId); @@ -180,11 +180,11 @@ std::vector DevManager::GetRemoteDevices() std::vector dmInfos; auto ret = DeviceManager::GetInstance().GetTrustedDeviceList(PKG_NAME, "", dmInfos); if (ret != DM_OK) { - ZLOGE("get trusted device:%{public}d", ret); + ZLOGE("Get trusted device:%{public}d", ret); return {}; } if (dmInfos.empty()) { - ZLOGD("no remote device"); + ZLOGD("No remote device"); return {}; } std::vector dtInfos; diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/kv_hiview_reporter.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/kv_hiview_reporter.cpp index e0cb2860bfc2d707014fc1be9e63256bf9218fdd..b5246f30869cd6bf439c05ed889b3f6257fdb209 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/kv_hiview_reporter.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/kv_hiview_reporter.cpp @@ -33,10 +33,30 @@ static constexpr int MAX_TIME_BUF_LEN = 32; static constexpr int MILLISECONDS_LEN = 3; static constexpr int NANO_TO_MILLI = 1000000; static constexpr int MILLI_PRE_SEC = 1000; -static constexpr const char *EVENT_NAME = "DATABASE_CORRUPTED"; +static constexpr const char *CORRUPTED_EVENT_NAME = "DATABASE_CORRUPTED"; +static constexpr const char *FAULT_EVENT_NAME = "DISTRIBUTED_DATA_KV_FAULT"; static constexpr const char *DISTRIBUTED_DATAMGR = "DISTDATAMGR"; constexpr const char *DB_CORRUPTED_POSTFIX = ".corruptedflg"; -struct KVDBCorruptedEvent { +static constexpr const char *DEFAULT_PATH = "single_ver/main/gen_natural_store.db"; +constexpr const char* DATABASE_REBUILD = "RestoreType:Rebuild"; +static constexpr const char* FUNCTION = "FunctionName "; +static constexpr const char* DBPATH = "dbPath"; +static constexpr const char* FILEINFO = "fileInfo"; +std::set KVDBFaultHiViewReporter::storeFaults_ = {}; +std::mutex KVDBFaultHiViewReporter::mutex_; + +static constexpr Suffix FILE_SUFFIXES[] = { + {"", "DB"}, + {"-shm", "SHM"}, + {"-wal", "WAL"}, +}; + +static constexpr const char *BUSINESS_TYPE[] = { + "sqlite", + "gausspd" +}; + +struct KVDBFaultEvent { std::string bundleName; std::string moduleName; std::string storeType; @@ -49,8 +69,11 @@ struct KVDBCorruptedEvent { int32_t systemErrorNo = 0; std::string appendix; std::string errorOccurTime; + std::string faultType = "common"; + std::string businessType; + std::string functionName; - explicit KVDBCorruptedEvent(const Options &options) : storeType("KVDB") + explicit KVDBFaultEvent(const Options &options) : storeType("KVDB") { moduleName = options.hapName; securityLevel = static_cast(options.securityLevel); @@ -59,47 +82,89 @@ struct KVDBCorruptedEvent { } }; -void KVDBFaultHiViewReporter::ReportKVDBCorruptedFault( - const Options &options, uint32_t errorCode, int32_t systemErrorNo, - const KvStoreTuple &storeTuple, const std::string &appendix) +void KVDBFaultHiViewReporter::ReportKVFaultEvent(const ReportInfo &reportInfo) { - KVDBCorruptedEvent eventInfo(options); - eventInfo.errorCode = errorCode; - eventInfo.systemErrorNo = systemErrorNo; - eventInfo.appendix = appendix; - eventInfo.storeName = storeTuple.storeId; - eventInfo.bundleName = storeTuple.appId; + auto reportDir = GetDBPath(reportInfo.options.GetDatabaseDir(), reportInfo.storeId); + KVDBFaultEvent eventInfo(reportInfo.options); + eventInfo.errorCode = reportInfo.errorCode; + eventInfo.storeName = reportInfo.storeId; + eventInfo.bundleName = reportInfo.appId; + eventInfo.functionName = reportInfo.functionName; + eventInfo.systemErrorNo = reportInfo.systemErrorNo; eventInfo.errorOccurTime = GetCurrentMicrosecondTimeFormat(); - if (IsReportCorruptedFault(eventInfo.appendix, storeTuple.storeId)) { - CreateCorruptedFlag(eventInfo.appendix, storeTuple.storeId); - auto corruptedTime = GetFileStatInfo(eventInfo.appendix); - eventInfo.appendix = corruptedTime; - ZLOGI("db corrupted report:storeId:%{public}s", StoreUtil::Anonymous(storeTuple.storeId).c_str()); - ReportCommonFault(eventInfo); + eventInfo.appendix = reportDir; + if (!IsReportedFault(eventInfo)) { + ReportFaultEvent(eventInfo); + } + if (eventInfo.errorCode == DATA_CORRUPTED) { + ReportCurruptedEvent(eventInfo); } } -void KVDBFaultHiViewReporter::ReportKVDBRebuild( - const Options &options, uint32_t errorCode, int32_t systemErrorNo, - const KvStoreTuple &storeTuple, const std::string &appendix) +void KVDBFaultHiViewReporter::ReportKVRebuildEvent(const ReportInfo &reportInfo) { - KVDBCorruptedEvent eventInfo(options); - eventInfo.errorCode = errorCode; - eventInfo.systemErrorNo = systemErrorNo; - eventInfo.appendix = appendix; - eventInfo.storeName = storeTuple.storeId; - eventInfo.bundleName = storeTuple.appId; + auto reportDir = GetDBPath(reportInfo.options.GetDatabaseDir(), reportInfo.storeId); + if (!IsReportedCorruptedFault(reportDir, reportInfo.storeId)) { + return; + } + KVDBFaultEvent eventInfo(reportInfo.options); + eventInfo.errorCode = reportInfo.errorCode; + eventInfo.storeName = reportInfo.storeId; + eventInfo.bundleName = reportInfo.appId; + eventInfo.functionName = reportInfo.functionName; + eventInfo.systemErrorNo = reportInfo.systemErrorNo; eventInfo.errorOccurTime = GetCurrentMicrosecondTimeFormat(); - if (errorCode == 0) { - ZLOGI("db rebuild report:storeId:%{public}s", StoreUtil::Anonymous(storeTuple.storeId).c_str()); - DeleteCorruptedFlag(eventInfo.appendix, storeTuple.storeId); - auto corruptedTime = GetFileStatInfo(eventInfo.appendix); - corruptedTime += "\n" + std::string(DATABASE_REBUILD); - eventInfo.appendix = corruptedTime; + eventInfo.appendix = reportDir; + if (eventInfo.errorCode == 0) { + ZLOGI("Db rebuild report:storeId:%{public}s", StoreUtil::Anonymous(eventInfo.storeName).c_str()); + DeleteCorruptedFlag(eventInfo.appendix, eventInfo.storeName); + eventInfo.appendix = GenerateAppendix(eventInfo); + eventInfo.appendix += "\n" + std::string(DATABASE_REBUILD); ReportCommonFault(eventInfo); } } +void KVDBFaultHiViewReporter::ReportFaultEvent(KVDBFaultEvent eventInfo) +{ + eventInfo.businessType = BUSINESS_TYPE[BusinessType::SQLITE]; + eventInfo.appendix = GenerateAppendix(eventInfo); + char *faultTime = const_cast(eventInfo.errorOccurTime.c_str()); + char *faultType = const_cast(eventInfo.faultType.c_str()); + char *bundleName = const_cast(eventInfo.bundleName.c_str()); + char *moduleName = const_cast(eventInfo.moduleName.c_str()); + char *storeName = const_cast(eventInfo.storeName.c_str()); + char *businessType = const_cast(eventInfo.businessType.c_str()); + char *appendix = const_cast(eventInfo.appendix.c_str()); + HiSysEventParam params[] = { + { .name = "FAULT_TIME", .t = HISYSEVENT_STRING, .v = { .s = faultTime }, .arraySize = 0 }, + { .name = "FAULT_TYPE", .t = HISYSEVENT_STRING, .v = { .s = faultType }, .arraySize = 0 }, + { .name = "BUNDLE_NAME", .t = HISYSEVENT_STRING, .v = { .s = bundleName }, .arraySize = 0 }, + { .name = "MODULE_NAME", .t = HISYSEVENT_STRING, .v = { .s = moduleName }, .arraySize = 0 }, + { .name = "STORE_NAME", .t = HISYSEVENT_STRING, .v = { .s = storeName }, .arraySize = 0 }, + { .name = "BUSINESS_TYPE", .t = HISYSEVENT_STRING, .v = { .s = businessType }, .arraySize = 0 }, + { .name = "ERROR_CODE", .t = HISYSEVENT_UINT32, .v = { .ui32 = eventInfo.errorCode }, .arraySize = 0 }, + { .name = "APPENDIX", .t = HISYSEVENT_STRING, .v = { .s = appendix }, .arraySize = 0 }, + }; + OH_HiSysEvent_Write(DISTRIBUTED_DATAMGR, FAULT_EVENT_NAME, + HISYSEVENT_FAULT, params, sizeof(params) / sizeof(params[0])); +} + +void KVDBFaultHiViewReporter::ReportCurruptedEvent(KVDBFaultEvent eventInfo) +{ + if (eventInfo.appendix.empty() || eventInfo.storeName.empty()) { + ZLOGW("The dbPath or storeId is empty, dbPath:%{public}s, storeId:%{public}s", eventInfo.appendix.c_str(), + StoreUtil::Anonymous(eventInfo.storeName).c_str()); + return; + } + if (IsReportedCorruptedFault(eventInfo.appendix, eventInfo.storeName)) { + return; + } + CreateCorruptedFlag(eventInfo.appendix, eventInfo.storeName); + eventInfo.appendix = GenerateAppendix(eventInfo); + ZLOGI("Db corrupted report:storeId:%{public}s", StoreUtil::Anonymous(eventInfo.storeName).c_str()); + ReportCommonFault(eventInfo); +} + std::string KVDBFaultHiViewReporter::GetCurrentMicrosecondTimeFormat() { auto now = std::chrono::system_clock::now(); @@ -131,7 +196,7 @@ std::string KVDBFaultHiViewReporter::GetFileStatInfo(const std::string &dbPath) if (suffix.name_ == nullptr) { continue; } - auto file = dbPath + defaultPath + suffix.suffix_; + auto file = dbPath + DEFAULT_PATH + suffix.suffix_; struct stat fileStat; if (stat(file.c_str(), &fileStat) != 0) { continue; @@ -158,7 +223,7 @@ std::string KVDBFaultHiViewReporter::GetTimeWithMilliseconds(time_t sec, int64_t return oss.str(); } -void KVDBFaultHiViewReporter::ReportCommonFault(const KVDBCorruptedEvent &eventInfo) +void KVDBFaultHiViewReporter::ReportCommonFault(const KVDBFaultEvent &eventInfo) { char *bundleName = const_cast(eventInfo.bundleName.c_str()); char *moduleName = const_cast(eventInfo.moduleName.c_str()); @@ -182,34 +247,43 @@ void KVDBFaultHiViewReporter::ReportCommonFault(const KVDBCorruptedEvent &eventI { .name = "ERROR_TIME", .t = HISYSEVENT_STRING, .v = { .s = errorOccurTime }, .arraySize = 0 }, }; - OH_HiSysEvent_Write(DISTRIBUTED_DATAMGR, EVENT_NAME, HISYSEVENT_FAULT, params, sizeof(params) / sizeof(params[0])); + OH_HiSysEvent_Write(DISTRIBUTED_DATAMGR, CORRUPTED_EVENT_NAME, + HISYSEVENT_FAULT, params, sizeof(params) / sizeof(params[0])); } -bool KVDBFaultHiViewReporter::IsReportCorruptedFault(const std::string &dbPath, const std::string &storeId) +bool KVDBFaultHiViewReporter::IsReportedFault(const KVDBFaultEvent& eventInfo) { - if (dbPath.empty()) { - ZLOGW("dbPath path is empty"); - return false; + std::lock_guard lock(mutex_); + std::stringstream oss; + oss << eventInfo.bundleName << eventInfo.storeName << eventInfo.functionName << eventInfo.errorCode; + std::string faultFlag = oss.str(); + if (storeFaults_.find(faultFlag) != storeFaults_.end()) { + return true; } + storeFaults_.insert(faultFlag); + return false; +} +bool KVDBFaultHiViewReporter::IsReportedCorruptedFault(const std::string &dbPath, const std::string &storeId) +{ std::string flagFilename = dbPath + storeId + DB_CORRUPTED_POSTFIX; if (access(flagFilename.c_str(), F_OK) == 0) { - ZLOGW("corrupted flag already exit"); - return false; + return true; } - return true; + return false; } void KVDBFaultHiViewReporter::CreateCorruptedFlag(const std::string &dbPath, const std::string &storeId) { - if (dbPath.empty()) { - ZLOGW("dbPath path is empty"); + if (dbPath.empty() || storeId.empty()) { + ZLOGW("The dbPath or storeId is empty, dbPath:%{public}s, storeId:%{public}s", dbPath.c_str(), + StoreUtil::Anonymous(storeId).c_str()); return; } std::string flagFilename = dbPath + storeId + DB_CORRUPTED_POSTFIX; int fd = creat(flagFilename.c_str(), S_IRWXU | S_IRWXG); if (fd == -1) { - ZLOGW("creat corrupted flg fail, flgname=%{public}s, errno=%{public}d", + ZLOGW("Creat corrupted flg fail, flgname=%{public}s, errno=%{public}d", StoreUtil::Anonymous(flagFilename).c_str(), errno); return; @@ -219,14 +293,15 @@ void KVDBFaultHiViewReporter::CreateCorruptedFlag(const std::string &dbPath, con void KVDBFaultHiViewReporter::DeleteCorruptedFlag(const std::string &dbPath, const std::string &storeId) { - if (dbPath.empty()) { - ZLOGW("dbPath path is empty"); + if (dbPath.empty() || storeId.empty()) { + ZLOGW("The dbPath or storeId is empty, dbPath:%{public}s, storeId:%{public}s", dbPath.c_str(), + StoreUtil::Anonymous(storeId).c_str()); return; } std::string flagFilename = dbPath + storeId + DB_CORRUPTED_POSTFIX; int result = remove(flagFilename.c_str()); if (result != 0) { - ZLOGW("remove corrupted flg fail, flgname=%{public}s, errno=%{public}d", + ZLOGW("Remove corrupted flg fail, flgname=%{public}s, errno=%{public}d", StoreUtil::Anonymous(flagFilename).c_str(), errno); } } @@ -238,4 +313,14 @@ std::string KVDBFaultHiViewReporter::GetDBPath(const std::string &path, const st reporterDir = path + "/kvdb/" + reporterDir + "/"; return reporterDir; } + +std::string KVDBFaultHiViewReporter::GenerateAppendix(const KVDBFaultEvent &eventInfo) +{ + std::string fileStatInfo = GetFileStatInfo(eventInfo.appendix); + std::string appenDix = ""; + appenDix = FUNCTION + eventInfo.functionName + "\n" + + DBPATH + eventInfo.appendix + "\n" + + FILEINFO + fileStatInfo; + return appenDix; +} } // namespace OHOS::DistributedKv \ No newline at end of file diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/kv_hiview_reporter_mock.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/kv_hiview_reporter_mock.cpp index ed7400008a925a960b835d383b2baae035bdbd8a..b105283e5ad95f1180683c76a250abafbc8adefc 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/kv_hiview_reporter_mock.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/kv_hiview_reporter_mock.cpp @@ -18,7 +18,7 @@ #include "kv_hiview_reporter.h" namespace OHOS::DistributedKv { -struct KVDBCorruptedEvent { +struct KVDBFaultEvent { std::string bundleName; std::string moduleName; std::string storeType; @@ -31,8 +31,11 @@ struct KVDBCorruptedEvent { int32_t systemErrorNo = 0; std::string appendix; std::string errorOccurTime; + std::string faultType = "common"; + std::string businessType; + std::string functionName; - explicit KVDBCorruptedEvent(const Options &options) : storeType("KVDB") + explicit KVDBFaultEvent(const Options &options) : storeType("KVDB") { moduleName = options.hapName; securityLevel = static_cast(options.securityLevel); @@ -41,16 +44,12 @@ struct KVDBCorruptedEvent { } }; -void KVDBFaultHiViewReporter::ReportKVDBCorruptedFault( - const Options &options, uint32_t errorCode, int32_t systemErrorNo, - const KvStoreTuple &storeTuple, const std::string &path) +void KVDBFaultHiViewReporter::ReportKVFaultEvent(const ReportInfo &reportInfo) { return; } -void KVDBFaultHiViewReporter::ReportKVDBRebuild( - const Options &options, uint32_t errorCode, int32_t systemErrorNo, - const KvStoreTuple &storeTuple, const std::string &appendix) +void KVDBFaultHiViewReporter::ReportKVRebuildEvent(const ReportInfo &reportInfo) { return; } @@ -61,12 +60,12 @@ std::string KVDBFaultHiViewReporter::GetCurrentMicrosecondTimeFormat() } void KVDBFaultHiViewReporter::ReportCommonFault(__attribute__((unused)) - const KVDBCorruptedEvent &eventInfo) + const KVDBFaultEvent &eventInfo) { return; } -bool KVDBFaultHiViewReporter::IsReportCorruptedFault(const std::string &dbPath, const std::string &storeId) +bool KVDBFaultHiViewReporter::IsReportedCorruptedFault(const std::string &dbPath, const std::string &storeId) { return false; } diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/kv_types_util.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/kv_types_util.cpp index b0ebcadbe59103c02e8134edc59fa9e774cf5849..0676364fa7167a029f2c9ed3519c576141dad306 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/kv_types_util.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/kv_types_util.cpp @@ -107,7 +107,7 @@ bool Marshalling(const Options &input, MessageParcel &data) { if (!ITypesUtil::Marshal(data, input.schema, input.hapName, input.policies, input.cloudConfig.enableCloud, input.cloudConfig.autoSync, input.authType)) { - ZLOGE("write policies failed"); + ZLOGE("Write policies failed"); return false; } @@ -125,6 +125,7 @@ bool Marshalling(const Options &input, MessageParcel &data) target->isNeedCompress = input.isNeedCompress; target->dataType = input.dataType; target->isPublic = input.isPublic; + target->subUser = input.subUser; return data.WriteRawData(buffer.get(), sizeof(input)); } @@ -133,7 +134,7 @@ bool Unmarshalling(Options &output, MessageParcel &data) { if (!ITypesUtil::Unmarshal(data, output.schema, output.hapName, output.policies, output.cloudConfig.enableCloud, output.cloudConfig.autoSync, output.authType)) { - ZLOGE("read policies failed"); + ZLOGE("Read policies failed"); return false; } @@ -153,6 +154,7 @@ bool Unmarshalling(Options &output, MessageParcel &data) output.isNeedCompress = source->isNeedCompress; output.dataType = source->dataType; output.isPublic = source->isPublic; + output.subUser = source->subUser; return true; } diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/kvdb_service_client.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/kvdb_service_client.cpp index 6e3d0772867f6251e80142528233a9db557f1c8b..4ed771e49820cf64e4c33877f48ff09fceca1dc3 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/kvdb_service_client.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/kvdb_service_client.cpp @@ -339,7 +339,7 @@ Status KVDBServiceClient::Unsubscribe(const AppId &appId, const StoreId &storeId } Status KVDBServiceClient::GetBackupPassword( - const AppId &appId, const StoreId &storeId, std::vector &password, int32_t passwordType) + const AppId &appId, const StoreId &storeId, std::vector> &passwords, int32_t passwordType) { MessageParcel reply; int32_t status = IPC_SEND(static_cast(KVDBServiceInterfaceCode::TRANS_GET_PASSWORD), @@ -348,7 +348,7 @@ Status KVDBServiceClient::GetBackupPassword( ZLOGE("status:0x%{public}x appId:%{public}s, storeId:%{public}s", status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str()); } - ITypesUtil::Unmarshal(reply, password); + ITypesUtil::Unmarshal(reply, passwords); return static_cast(status); } diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/process_communication_impl.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/process_communication_impl.cpp index fb60a394b2c57de888741c8464576a409d79e048..cbf3bc61b89151c1abb330859a42508c9154abce 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/process_communication_impl.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/process_communication_impl.cpp @@ -34,7 +34,7 @@ DBStatus ProcessCommunicationImpl::Start(const std::string &processLabel) { Status errCode = endpoint_->Start(); if (errCode != Status::SUCCESS) { - ZLOGE("endpoint Start Fail: %{public}d", errCode); + ZLOGE("This endpoint Start is Fail: %{public}d", errCode); return DBStatus::DB_ERROR; } isCreateSessionServer_ = true; @@ -45,7 +45,7 @@ DBStatus ProcessCommunicationImpl::Stop() { Status errCode = endpoint_->Stop(); if (errCode != Status::SUCCESS) { - ZLOGE("endpoint Stop Fail: %{public}d", errCode); + ZLOGE("This endpoint Stop is Fail: %{public}d", errCode); return DBStatus::DB_ERROR; } isCreateSessionServer_ = false; @@ -65,7 +65,7 @@ DBStatus ProcessCommunicationImpl::RegOnDataReceive(const OnDataReceive &callbac }; callback(devInfo, data, length); }; - + Status errCode = endpoint_->RegOnDataReceive(dataReciveCallback); if (errCode != Status::SUCCESS) { ZLOGE("RegOnDataReceive Fail."); diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/process_system_api_adapter_impl.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/process_system_api_adapter_impl.cpp index aa05ea0c85dbe4e13e5f94541f07b244b6996bb5..3ede302f47c092e06f200783147bdf9d96412172 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/process_system_api_adapter_impl.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/process_system_api_adapter_impl.cpp @@ -73,7 +73,7 @@ ProcessSystemApiAdapterImpl::DBStatus ProcessSystemApiAdapterImpl::SetSecurityOp if (!result) { auto fPath = filePath.substr(0, HEAD_SIZE) + REPLACE_CHAIN + filePath.substr(filePath.length() - END_SIZE, END_SIZE); - ZLOGE("set label failed! level:%{public}s, file:%{public}s", secLevel.c_str(), fPath.c_str()); + ZLOGE("Set label failed! level:%{public}s, file:%{public}s", secLevel.c_str(), fPath.c_str()); return DBStatus::DB_ERROR; } return DBStatus::OK; diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/security_manager.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/security_manager.cpp index b1195c2889de414f53f93156a1f65d17899d0f40..11d03ff55a2190f05130b41e6df48dc895c98fa3 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/security_manager.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/security_manager.cpp @@ -52,7 +52,7 @@ bool SecurityManager::Retry() auto status = CheckRootKey(); if (status == HKS_SUCCESS) { hasRootKey_ = true; - ZLOGE("root key already exist."); + ZLOGE("Root key already exist."); return true; } @@ -164,10 +164,14 @@ std::vector SecurityManager::LoadKeyFromFile(const std::string &name, c bool SecurityManager::SaveKeyToFile(const std::string &name, const std::string &path, std::vector &key) { if (!hasRootKey_ && !Retry()) { - ZLOGE("failed! no root key and generation failed"); + ZLOGE("Failed! no root key and generation failed"); return false; } auto secretKey = Encrypt(key); + if (secretKey.empty()) { + ZLOGE("Failed! encrypt failed"); + return false; + } auto keyPath = path + KEY_DIR; StoreUtil::InitPath(keyPath); std::vector content; @@ -183,7 +187,7 @@ bool SecurityManager::SaveKeyToFile(const std::string &name, const std::string & } content.assign(content.size(), 0); if (!ret) { - ZLOGE("client SaveSecretKey failed!"); + ZLOGE("Client SaveSecretKey failed!"); return false; } return ret; @@ -434,7 +438,7 @@ int32_t SecurityManager::KeyFiles::FileLock(int32_t lockType) errCode = flock(lockFd_, lockType); } while (errCode < 0 && errno == EINTR); if (errCode < 0) { - ZLOGE("flock failed, type:%{public}d, errno:%{public}d, path:%{public}s", lockType, errno, + ZLOGE("This flock is failed, type:%{public}d, errno:%{public}d, path:%{public}s", lockType, errno, StoreUtil::Anonymous(lockFile_).c_str()); return Status::ERROR; } diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/single_store_impl.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/single_store_impl.cpp index e0bc7f5887d62b75d41e2ccbe24f23ceb28c0745..cde4083ac8a98c8b526170e03f3e04c1ca9f7051 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/single_store_impl.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/single_store_impl.cpp @@ -59,6 +59,9 @@ SingleStoreImpl::SingleStoreImpl( isApplication_ = true; apiVersion_ = options.apiVersion; } + if (!isApplication_ || (isApplication_ && (apiVersion_ >= INTEGRITY_CHECK_API_VERSION))) { + isCheckIntegrity_ = true; + } } SingleStoreImpl::~SingleStoreImpl() @@ -96,14 +99,14 @@ Status SingleStoreImpl::Put(const Key &key, const Value &value) DBKey dbKey = convertor_.ToLocalDBKey(key); if (dbKey.empty() || value.Size() > MAX_VALUE_LENGTH) { - ZLOGE("invalid key:%{public}s size:[k:%{public}zu v:%{public}zu]", + ZLOGE("Invalid key:%{public}s size:[k:%{public}zu v:%{public}zu]", StoreUtil::Anonymous(key.ToString()).c_str(), key.Size(), value.Size()); return INVALID_ARGUMENT; } auto status = RetryWithCheckPoint([this, &dbKey, &value]() { return dbStore_->Put(dbKey, value); }); - ReportDBCorruptedFault(status); if (status != SUCCESS) { + ReportDBFaultEvent(status, std::string(__FUNCTION__)); ZLOGE("status:0x%{public}x key:%{public}s, value size:%{public}zu", status, StoreUtil::Anonymous(key.ToString()).c_str(), value.Size()); } @@ -126,7 +129,7 @@ Status SingleStoreImpl::PutBatch(const std::vector &entries) DBEntry dbEntry; dbEntry.key = convertor_.ToLocalDBKey(entry.key); if (dbEntry.key.empty() || entry.value.Size() > MAX_VALUE_LENGTH) { - ZLOGE("invalid key:%{public}s size:[k:%{public}zu v:%{public}zu]", + ZLOGE("Invalid key:%{public}s size:[k:%{public}zu v:%{public}zu]", StoreUtil::Anonymous(entry.key.ToString()).c_str(), entry.key.Size(), entry.value.Size()); return INVALID_ARGUMENT; } @@ -135,8 +138,8 @@ Status SingleStoreImpl::PutBatch(const std::vector &entries) } auto status = RetryWithCheckPoint([this, &dbEntries]() { return dbStore_->PutBatch(dbEntries); }); - ReportDBCorruptedFault(status); if (status != SUCCESS) { + ReportDBFaultEvent(status, std::string(__FUNCTION__)); ZLOGE("status:0x%{public}x entries size:%{public}zu", status, entries.size()); } DoAutoSync(); @@ -155,13 +158,13 @@ Status SingleStoreImpl::Delete(const Key &key) DBKey dbKey = convertor_.ToLocalDBKey(key); if (dbKey.empty()) { - ZLOGE("invalid key:%{public}s size:%{public}zu", StoreUtil::Anonymous(key.ToString()).c_str(), key.Size()); + ZLOGE("Invalid key:%{public}s size:%{public}zu", StoreUtil::Anonymous(key.ToString()).c_str(), key.Size()); return INVALID_ARGUMENT; } auto status = RetryWithCheckPoint([this, &dbKey]() { return dbStore_->Delete(dbKey); }); - ReportDBCorruptedFault(status); if (status != SUCCESS) { + ReportDBFaultEvent(status, std::string(__FUNCTION__)); ZLOGE("status:0x%{public}x key:%{public}s", status, StoreUtil::Anonymous(key.ToString()).c_str()); } DoAutoSync(); @@ -182,15 +185,15 @@ Status SingleStoreImpl::DeleteBatch(const std::vector &keys) for (const auto &key : keys) { DBKey dbKey = convertor_.ToLocalDBKey(key); if (dbKey.empty()) { - ZLOGE("invalid key:%{public}s size:%{public}zu", StoreUtil::Anonymous(key.ToString()).c_str(), key.Size()); + ZLOGE("Invalid key:%{public}s size:%{public}zu", StoreUtil::Anonymous(key.ToString()).c_str(), key.Size()); return INVALID_ARGUMENT; } dbKeys.push_back(std::move(dbKey)); } auto status = RetryWithCheckPoint([this, &dbKeys]() { return dbStore_->DeleteBatch(dbKeys); }); - ReportDBCorruptedFault(status); if (status != SUCCESS) { + ReportDBFaultEvent(status, std::string(__FUNCTION__)); ZLOGE("status:0x%{public}x keys size:%{public}zu", status, keys.size()); } DoAutoSync(); @@ -208,8 +211,8 @@ Status SingleStoreImpl::StartTransaction() } auto status = RetryWithCheckPoint([this]() { return dbStore_->StartTransaction(); }); - ReportDBCorruptedFault(status); if (status != SUCCESS) { + ReportDBFaultEvent(status, std::string(__FUNCTION__)); ZLOGE("status:0x%{public}x storeId:%{public}s", status, StoreUtil::Anonymous(storeId_).c_str()); } return status; @@ -226,8 +229,8 @@ Status SingleStoreImpl::Commit() auto dbStatus = dbStore_->Commit(); auto status = StoreUtil::ConvertStatus(dbStatus); - ReportDBCorruptedFault(status); if (status != SUCCESS) { + ReportDBFaultEvent(status, std::string(__FUNCTION__)); ZLOGE("status:0x%{public}x storeId:%{public}s", status, StoreUtil::Anonymous(storeId_).c_str()); } return status; @@ -244,8 +247,8 @@ Status SingleStoreImpl::Rollback() auto dbStatus = dbStore_->Rollback(); auto status = StoreUtil::ConvertStatus(dbStatus); - ReportDBCorruptedFault(status); if (status != SUCCESS) { + ReportDBFaultEvent(status, std::string(__FUNCTION__)); ZLOGE("status:0x%{public}x storeId:%{public}s", status, StoreUtil::Anonymous(storeId_).c_str()); } return status; @@ -261,7 +264,7 @@ Status SingleStoreImpl::SubscribeKvStore(SubscribeType type, std::shared_ptrGet(dbKey, dbValue); value = std::move(dbValue); auto status = StoreUtil::ConvertStatus(dbStatus); - ReportDBCorruptedFault(status); - if (status != SUCCESS) { + if (status != SUCCESS && status != NOT_FOUND) { + ReportDBFaultEvent(status, std::string(__FUNCTION__)); ZLOGE("status:0x%{public}x key:%{public}s", status, StoreUtil::Anonymous(key.ToString()).c_str()); } return status; @@ -404,7 +407,7 @@ Status SingleStoreImpl::GetEntries(const Key &prefix, std::vector &entrie DdsTrace trace(std::string(LOG_TAG "::") + std::string(__FUNCTION__)); DBKey dbPrefix = convertor_.GetPrefix(prefix); if (dbPrefix.empty() && !prefix.Empty()) { - ZLOGE("invalid prefix:%{public}s size:%{public}zu", StoreUtil::Anonymous(prefix.ToString()).c_str(), + ZLOGE("Invalid prefix:%{public}s size:%{public}zu", StoreUtil::Anonymous(prefix.ToString()).c_str(), prefix.Size()); return INVALID_ARGUMENT; } @@ -434,7 +437,7 @@ Status SingleStoreImpl::GetResultSet(const Key &prefix, std::shared_ptr dbEntries; @@ -466,7 +469,7 @@ Status SingleStoreImpl::GetDeviceEntries(const std::string &device, std::vector< auto uuid = DevManager::GetInstance().GetUnEncryptedUuid(); if (device == uuid) { dbStatus = dbStore_->GetDeviceEntries("", dbEntries); - ZLOGI("device equal loacluuid:%{public}s", StoreUtil::Anonymous(uuid).c_str()); + ZLOGI("The device equal loacluuid:%{public}s", StoreUtil::Anonymous(uuid).c_str()); } else { dbStatus = dbStore_->GetDeviceEntries(device, dbEntries); } @@ -481,10 +484,12 @@ Status SingleStoreImpl::GetDeviceEntries(const std::string &device, std::vector< } auto status = StoreUtil::ConvertStatus(dbStatus); - ReportDBCorruptedFault(status); if (status == NOT_FOUND) { status = SUCCESS; } + if (status != SUCCESS) { + ReportDBFaultEvent(status, std::string(__FUNCTION__)); + } return status; } @@ -503,7 +508,7 @@ Status SingleStoreImpl::CloseResultSet(std::shared_ptr &resultSet) { DdsTrace trace(std::string(LOG_TAG "::") + std::string(__FUNCTION__)); if (resultSet == nullptr) { - ZLOGE("input is nullptr"); + ZLOGE("Input is nullptr"); return INVALID_ARGUMENT; } @@ -527,8 +532,8 @@ Status SingleStoreImpl::GetCount(const DataQuery &query, int &result) const DBQuery dbQuery = convertor_.GetDBQuery(query); auto dbStatus = dbStore_->GetCount(dbQuery, result); auto status = StoreUtil::ConvertStatus(dbStatus); - ReportDBCorruptedFault(status); if (status != SUCCESS) { + ReportDBFaultEvent(status, std::string(__FUNCTION__)); ZLOGE("status:0x%{public}x query:%{public}s", status, StoreUtil::Anonymous(query.ToString()).c_str()); } return status; @@ -547,8 +552,8 @@ Status SingleStoreImpl::GetSecurityLevel(SecurityLevel &secLevel) const auto dbStatus = dbStore_->GetSecurityOption(option); secLevel = static_cast(StoreUtil::GetSecLevel(option)); auto status = StoreUtil::ConvertStatus(dbStatus); - ReportDBCorruptedFault(status); if (status != SUCCESS) { + ReportDBFaultEvent(status, std::string(__FUNCTION__)); ZLOGE("status:0x%{public}x security:[%{public}d]", status, option.securityLabel); } return status; @@ -568,8 +573,8 @@ Status SingleStoreImpl::RemoveDeviceData(const std::string &device) } Status status = service->RemoveDeviceData({ appId_ }, { storeId_ }, device); - ReportDBCorruptedFault(status); if (status != SUCCESS) { + ReportDBFaultEvent(status, std::string(__FUNCTION__)); ZLOGE("status:%{public}d device:%{public}s", status, StoreUtil::Anonymous(device).c_str()); } return status; @@ -608,7 +613,7 @@ Status SingleStoreImpl::CloudSync(const AsyncDetail &async) } auto serviceAgent = service->GetServiceAgent({ appId_ }); if (serviceAgent == nullptr) { - ZLOGE("failed! invalid agent app:%{public}s store:%{public}s!", appId_.c_str(), + ZLOGE("Failed! invalid agent app:%{public}s store:%{public}s!", appId_.c_str(), StoreUtil::Anonymous(storeId_).c_str()); return ILLEGAL_STATE; } @@ -617,7 +622,7 @@ Status SingleStoreImpl::CloudSync(const AsyncDetail &async) serviceAgent->AddCloudSyncCallback(syncInfo.seqId, async); auto status = service->CloudSync({ appId_ }, { storeId_ }, syncInfo); if (status != SUCCESS) { - ZLOGE("sync failed!: %{public}d", status); + ZLOGE("Sync failed!: %{public}d", status); serviceAgent->DeleteCloudSyncCallback(syncInfo.seqId); } return status; @@ -698,7 +703,7 @@ Status SingleStoreImpl::SubscribeWithQuery(const std::vector &devic syncInfo.query = query.ToString(); auto serviceAgent = service->GetServiceAgent({ appId_ }); if (serviceAgent == nullptr) { - ZLOGE("failed! invalid agent app:%{public}s, store:%{public}s!", appId_.c_str(), + ZLOGE("Failed! invalid agent app:%{public}s, store:%{public}s!", appId_.c_str(), StoreUtil::Anonymous(storeId_).c_str()); return ILLEGAL_STATE; } @@ -720,7 +725,7 @@ Status SingleStoreImpl::UnsubscribeWithQuery(const std::vector &dev syncInfo.query = query.ToString(); auto serviceAgent = service->GetServiceAgent({ appId_ }); if (serviceAgent == nullptr) { - ZLOGE("failed! invalid agent app:%{public}s, store:%{public}s!", appId_.c_str(), + ZLOGE("Failed! invalid agent app:%{public}s, store:%{public}s!", appId_.c_str(), StoreUtil::Anonymous(storeId_).c_str()); return ILLEGAL_STATE; } @@ -756,15 +761,8 @@ int32_t SingleStoreImpl::Close(bool isForce) Status SingleStoreImpl::Backup(const std::string &file, const std::string &baseDir) { DdsTrace trace(std::string(LOG_TAG "::") + std::string(__FUNCTION__)); - if (!isApplication_ || (isApplication_ && (apiVersion_ >= INTEGRITY_CHECK_API_VERSION))) { - auto dbStatus = dbStore_->CheckIntegrity(); - if (dbStatus != DistributedDB::DBStatus::OK) { - ZLOGE("CheckIntegrity fail, dbStatus:%{public}d", dbStatus); - return StoreUtil::ConvertStatus(dbStatus); - } - } BackupManager::BackupInfo info = { .name = file, .baseDir = baseDir, .storeId = storeId_ }; - auto status = BackupManager::GetInstance().Backup(info, dbStore_); + auto status = BackupManager::GetInstance().Backup(info, dbStore_, isCheckIntegrity_); if (status != SUCCESS) { ZLOGE("status:0x%{public}x storeId:%{public}s backup:%{public}s ", status, StoreUtil::Anonymous(storeId_).c_str(), file.c_str()); @@ -779,23 +777,18 @@ Status SingleStoreImpl::Restore(const std::string &file, const std::string &base if (service != nullptr) { service->Close({ appId_ }, { storeId_ }); } - bool isCheckIntegrity = false; - if (!isApplication_ || (isApplication_ && (apiVersion_ >= INTEGRITY_CHECK_API_VERSION))) { - isCheckIntegrity = true; - } - BackupManager::BackupInfo info = { .name = file, .baseDir = baseDir, .appId = appId_, .storeId = storeId_ }; - auto status = BackupManager::GetInstance().Restore(info, dbStore_, isCheckIntegrity); + BackupManager::BackupInfo info = { .name = file, .baseDir = baseDir, .appId = appId_, .storeId = storeId_, + .encrypt = encrypt_ }; + auto status = BackupManager::GetInstance().Restore(info, dbStore_, isCheckIntegrity_); if (status != SUCCESS) { ZLOGE("status:0x%{public}x storeId:%{public}s backup:%{public}s ", status, StoreUtil::Anonymous(storeId_).c_str(), file.c_str()); } - if (status == SUCCESS) { - Options options = { .encrypt = encrypt_, .autoSync = autoSync_, .securityLevel = securityLevel_, - .area = area_, .hapName = hapName_ }; - KvStoreTuple tuple = { .appId = appId_, .storeId = storeId_ }; - auto repoterDir = KVDBFaultHiViewReporter::GetDBPath(path_, storeId_); - KVDBFaultHiViewReporter::ReportKVDBRebuild(options, status, errno, tuple, repoterDir); - } + Options options = { .encrypt = encrypt_, .autoSync = autoSync_, .securityLevel = securityLevel_, + .area = area_, .hapName = hapName_ }; + ReportInfo reportInfo = { .options = options, .errorCode = status, .systemErrorNo = errno, + .appId = appId_, .storeId = storeId_, .functionName = __FUNCTION__ }; + KVDBFaultHiViewReporter::ReportKVRebuildEvent(reportInfo); return status; } @@ -891,9 +884,13 @@ Status SingleStoreImpl::GetResultSet(const DBQuery &query, std::shared_ptrGetEntries(query, dbResultSet); + auto dbStatus = dbStore_->GetEntries(query, dbResultSet); if (dbResultSet == nullptr) { - return StoreUtil::ConvertStatus(status); + auto status = StoreUtil::ConvertStatus(dbStatus); + if (status != NOT_FOUND) { + ReportDBFaultEvent(status, std::string(__FUNCTION__)); + } + return status; } resultSet = std::make_shared(dbResultSet, dbStore_, convertor_); return SUCCESS; @@ -920,10 +917,12 @@ Status SingleStoreImpl::GetEntries(const DBQuery &query, std::vector &ent } auto status = StoreUtil::ConvertStatus(dbStatus); - ReportDBCorruptedFault(status); if (status == NOT_FOUND) { status = SUCCESS; } + if (status != SUCCESS) { + ReportDBFaultEvent(status, std::string(__FUNCTION__)); + } return status; } @@ -948,7 +947,7 @@ Status SingleStoreImpl::DoClientSync(SyncInfo &syncInfo, std::shared_ptrSync(syncInfo.devices, StoreUtil::GetDBMode(SyncMode(syncInfo.mode)), complete); Status status = StoreUtil::ConvertStatus(dbStatus); if (status != Status::SUCCESS) { - ZLOGE("client Sync failed: %{public}d", status); + ZLOGE("Client Sync failed: %{public}d", status); } return status; } @@ -967,7 +966,7 @@ Status SingleStoreImpl::DoSync(SyncInfo &syncInfo, std::shared_ptr auto serviceAgent = service->GetServiceAgent({ appId_ }); if (serviceAgent == nullptr) { - ZLOGE("failed! invalid agent app:%{public}s store:%{public}s!", appId_.c_str(), + ZLOGE("Failed! invalid agent app:%{public}s store:%{public}s!", appId_.c_str(), StoreUtil::Anonymous(storeId_).c_str()); return ILLEGAL_STATE; } @@ -984,7 +983,7 @@ Status SingleStoreImpl::DoSync(SyncInfo &syncInfo, std::shared_ptr if (cStatus == SUCCESS || status == SUCCESS) { return SUCCESS; } else { - ZLOGE("sync failed!: %{public}d, %{public}d", cStatus, status); + ZLOGE("Sync failed!: %{public}d, %{public}d", cStatus, status); return ERROR; } } @@ -1100,14 +1099,12 @@ bool SingleStoreImpl::IsRebuild() return databaseStatus.isRebuild; } -void SingleStoreImpl::ReportDBCorruptedFault(Status status) const +void SingleStoreImpl::ReportDBFaultEvent(Status status, const std::string &functionName) const { - if (status == DATA_CORRUPTED) { - Options options = { .encrypt = encrypt_, .autoSync = autoSync_, .securityLevel = securityLevel_, - .area = area_, .hapName = hapName_ }; - KvStoreTuple tuple = { .appId = appId_, .storeId = storeId_ }; - auto repoterDir = KVDBFaultHiViewReporter::GetDBPath(path_, storeId_); - KVDBFaultHiViewReporter::ReportKVDBCorruptedFault(options, status, errno, tuple, repoterDir); - } + Options options = { .encrypt = encrypt_, .autoSync = autoSync_, .securityLevel = securityLevel_, + .area = area_, .hapName = hapName_ }; + ReportInfo reportInfo = { .options = options, .errorCode = status, .systemErrorNo = errno, + .appId = appId_, .storeId = storeId_, .functionName = functionName }; + KVDBFaultHiViewReporter::ReportKVFaultEvent(reportInfo); } } // namespace OHOS::DistributedKv \ No newline at end of file diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/store_factory.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/store_factory.cpp index 344c2a1fc7b20b6ed607c79ce4ea6365f1909afe..40a468ef0e65bda9c049b76c5a3a68c42368fb05 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/store_factory.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/store_factory.cpp @@ -52,7 +52,7 @@ Status StoreFactory::SetDbConfig(std::shared_ptr dbStore) static_cast(const_cast(static_cast(&MAX_WAL_SIZE))); auto status = dbStore->Pragma(DistributedDB::SET_MAX_LOG_LIMIT, data); if (status != DistributedDB::DBStatus::OK) { - ZLOGE("failed to set max log limit! status:%{public}d", status); + ZLOGE("Failed to set max log limit! status:%{public}d", status); } return StoreUtil::ConvertStatus(status); } @@ -105,7 +105,7 @@ std::shared_ptr StoreFactory::GetOrOpenStore(const AppId &appId, }); status = StoreUtil::ConvertStatus(dbStatus); if (kvStore == nullptr) { - ZLOGE("failed! status:%{public}d appId:%{public}s storeId:%{public}s path:%{public}s", dbStatus, + ZLOGE("Failed! status:%{public}d appId:%{public}s storeId:%{public}s path:%{public}s", dbStatus, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str(), path.c_str()); return !stores.empty(); } @@ -154,12 +154,12 @@ std::shared_ptr StoreFactory::GetDBManager(const std::s { std::shared_ptr dbManager; dbManagers_.Compute(path, [&dbManager, &appId](const auto &path, std::shared_ptr &manager) { - if (manager != nullptr) { + std::string fullPath = path + "/kvdb"; + auto result = StoreUtil::InitPath(fullPath); + if (manager != nullptr && result) { dbManager = manager; return true; } - std::string fullPath = path + "/kvdb"; - auto result = StoreUtil::InitPath(fullPath); dbManager = std::make_shared(appId.appId, "default"); dbManager->SetKvStoreConfig({ fullPath }); manager = dbManager; @@ -284,7 +284,7 @@ bool StoreFactory::ExecuteRekey(const std::string &storeId, const std::string &p auto newDbPassword = SecurityManager::GetInstance().GetDBPassword(storeId + REKEY_NEW, rekeyPath, true); if (!newDbPassword.IsValid()) { - ZLOGE("failed to generate new key."); + ZLOGE("Failed to generate new key."); newDbPassword.Clear(); StoreUtil::Remove(rekeyName); return false; @@ -293,13 +293,13 @@ bool StoreFactory::ExecuteRekey(const std::string &storeId, const std::string &p auto dbStatus = dbStore->Rekey(newDbPassword.password); auto status = StoreUtil::ConvertStatus(dbStatus); if (status != SUCCESS) { - ZLOGE("failed to rekey the substitute database."); + ZLOGE("Failed to rekey the substitute database."); StoreUtil::Remove(rekeyName); newDbPassword.Clear(); return false; } if (!SecurityManager::GetInstance().SaveDBPassword(storeId, path, newDbPassword.password)) { - ZLOGE("save new password failed"); + ZLOGE("Save new password failed"); dbStore->Rekey(dbPassword.password); StoreUtil::Remove(rekeyName); return false; diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/store_manager.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/store_manager.cpp index 4a7e48578e71c3ee9d238456c640da75840a42e7..650a30a33190ba1dcc6e0dad5a76752025519948 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/store_manager.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/store_manager.cpp @@ -15,13 +15,13 @@ #define LOG_TAG "StoreManager" #include "store_manager.h" +#include "backup_manager.h" #include "dev_manager.h" #include "kvdb_service_client.h" #include "log_print.h" #include "security_manager.h" #include "store_factory.h" #include "store_util.h" -#include "kv_hiview_reporter.h" namespace OHOS::DistributedKv { StoreManager &StoreManager::GetInstance() { @@ -37,7 +37,7 @@ std::shared_ptr StoreManager::GetKVStore(const AppId &appId, cons StoreUtil::Anonymous(storeId.storeId).c_str(), options.kvStoreType, options.area, path.c_str()); status = ILLEGAL_STATE; if (!appId.IsValid() || !storeId.IsValid() || !options.IsValidType()) { - ZLOGE("params invalid type"); + ZLOGE("Params invalid type"); status = INVALID_ARGUMENT; return nullptr; } @@ -46,30 +46,34 @@ std::shared_ptr StoreManager::GetKVStore(const AppId &appId, cons status = service->BeforeCreate(appId, storeId, options); } if (status == STORE_META_CHANGED) { +// ReportInfo reportInfo = { .options = options, +// .errorCode = static_cast(status), +// .systemErrorNo = errno, +// .appId = appId.appId, +// .storeId = storeId.storeId, +// .functionName = std::string(__FUNCTION__) }; +// KVDBFaultHiViewReporter::ReportKVFaultEvent(reportInfo); ZLOGE("appId:%{public}s, storeId:%{public}s type:%{public}d encrypt:%{public}d", appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str(), options.kvStoreType, options.encrypt); return nullptr; } bool isCreate = false; auto kvStore = StoreFactory::GetInstance().GetOrOpenStore(appId, storeId, options, status, isCreate); - if (status == DATA_CORRUPTED && options.encrypt && GetSecretKeyFromService(appId, storeId, path) == SUCCESS) { - kvStore = StoreFactory::GetInstance().GetOrOpenStore(appId, storeId, options, status, isCreate); - } - if (status == DATA_CORRUPTED) { - ZLOGW("database is corrupt, storeId:%{public}s", StoreUtil::Anonymous(storeId.storeId).c_str()); - KvStoreTuple tuple = { .appId = appId.appId, .storeId = storeId.storeId }; - auto repoterDir = KVDBFaultHiViewReporter::GetDBPath(path, storeId.storeId); - KVDBFaultHiViewReporter::ReportKVDBCorruptedFault(options, status, errno, tuple, repoterDir); + if ((status == DATA_CORRUPTED || status == CRYPT_ERROR) && options.encrypt) { + kvStore = OpenWithSecretKeyFromService(appId, storeId, options, status, isCreate); } - if (kvStore != nullptr && status == SUCCESS && kvStore->IsRebuild()) { - ZLOGI("rebuild store success, storeId:%{public}s", StoreUtil::Anonymous(storeId.storeId).c_str()); - KvStoreTuple tuple = { .appId = appId.appId, .storeId = storeId.storeId }; - auto repoterDir = KVDBFaultHiViewReporter::GetDBPath(path, storeId.storeId); - KVDBFaultHiViewReporter::ReportKVDBRebuild(options, status, errno, tuple, repoterDir); + if (status != SUCCESS) { +// ReportInfo reportInfo = { .options = options, .appId = appId.appId, .storeId = storeId.storeId, +// .errorCode = static_cast(status), .systemErrorNo = errno, .functionName = std::string(__FUNCTION__) }; +// KVDBFaultHiViewReporter::ReportKVFaultEvent(reportInfo); + } else if (kvStore != nullptr && kvStore->IsRebuild()) { +// ReportInfo reportInfo = { .options = options, .appId = appId.appId, .storeId = storeId.storeId, +// .errorCode = static_cast(status), .systemErrorNo = errno, .functionName = std::string(__FUNCTION__) }; + ZLOGI("Rebuild store success, storeId:%{public}s", StoreUtil::Anonymous(storeId.storeId).c_str()); +// KVDBFaultHiViewReporter::ReportKVRebuildEvent(reportInfo); } if (isCreate && options.persistent) { - auto dbPassword = SecurityManager::GetInstance().GetDBPassword(storeId.storeId, - path, options.encrypt); + auto dbPassword = SecurityManager::GetInstance().GetDBPassword(storeId.storeId, path, options.encrypt); std::vector pwd(dbPassword.GetData(), dbPassword.GetData() + dbPassword.GetSize()); if (service != nullptr) { // delay notify @@ -80,32 +84,31 @@ std::shared_ptr StoreManager::GetKVStore(const AppId &appId, cons return kvStore; } -Status StoreManager::GetSecretKeyFromService(const AppId &appId, const StoreId &storeId, const std::string &path) +std::shared_ptr StoreManager::OpenWithSecretKeyFromService(const AppId &appId, const StoreId &storeId, + const Options &options, Status &status, bool &isCreate) { - auto service = KVDBServiceClient::GetInstance(); - if (service == nullptr) { - ZLOGE("get service failed! appId:%{public}s, storeId:%{public}s", - appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str()); - return Status::SERVER_UNAVAILABLE; + std::shared_ptr kvStore; + std::vector> keys; + if (BackupManager::GetInstance().GetSecretKeyFromService(appId, storeId, keys) != Status::SUCCESS) { + for (auto &key : keys) { + key.assign(key.size(), 0); + } + return kvStore; } - std::vector key; - auto status = service->GetBackupPassword(appId, storeId, key, KVDBService::PasswordType::SECRET_KEY); - if (status != Status::SUCCESS) { - key.assign(key.size(), 0); - ZLOGE("get password from service failed! status:%{public}d, appId:%{public}s storeId:%{public}s", - status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str()); - return status; + std::string path = options.GetDatabaseDir(); + for (auto &key : keys) { + SecurityManager::DBPassword dbPassword; + dbPassword.SetValue(key.data(), key.size()); + SecurityManager::GetInstance().SaveDBPassword(storeId.storeId, path, dbPassword.password); + kvStore = StoreFactory::GetInstance().GetOrOpenStore(appId, storeId, options, status, isCreate); + if (status == SUCCESS) { + break; + } } - if (key.empty()) { - ZLOGE("service secret key is empty! status:%{public}d, appId:%{public}s storeId:%{public}s", - status, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str()); - return Status::ERROR; + for (auto &key : keys) { + key.assign(key.size(), 0); } - SecurityManager::DBPassword dbPassword; - dbPassword.SetValue(key.data(), key.size()); - key.assign(key.size(), 0); - SecurityManager::GetInstance().SaveDBPassword(storeId.storeId, path, dbPassword.password); - return Status::SUCCESS; + return kvStore; } Status StoreManager::CloseKVStore(const AppId &appId, const StoreId &storeId) @@ -154,9 +157,16 @@ Status StoreManager::Delete(const AppId &appId, const StoreId &storeId, const st if (service != nullptr) { service->Delete(appId, storeId); } - auto repoterDir = KVDBFaultHiViewReporter::GetDBPath(path, storeId.storeId); - KVDBFaultHiViewReporter::DeleteCorruptedFlag(repoterDir, storeId.storeId); - return StoreFactory::GetInstance().Delete(appId, storeId, path); + auto status = StoreFactory::GetInstance().Delete(appId, storeId, path); + Options options = { .baseDir = path }; + ReportInfo reportInfo = { .options = options, .errorCode = static_cast(status), .systemErrorNo = errno, + .appId = appId.appId, .storeId = storeId.storeId, .functionName = std::string(__FUNCTION__) }; + if (status != SUCCESS) { + KVDBFaultHiViewReporter::ReportKVFaultEvent(reportInfo); + } else { + KVDBFaultHiViewReporter::ReportKVRebuildEvent(reportInfo); + } + return status; } Status StoreManager::PutSwitch(const AppId &appId, const SwitchData &data) diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/store_result_set.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/store_result_set.cpp index a428a235696e93449118a1a5dc3a0f07f2cf5b79..0f8f17a45861b865fcd9550dcb0ac45786115719 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/store_result_set.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/store_result_set.cpp @@ -35,7 +35,7 @@ int StoreResultSet::GetCount() const { std::shared_lock lock(mutex_); if (impl_ == nullptr) { - ZLOGW("already closed"); + ZLOGW("Already closed"); return INVALID_COUNT; } @@ -46,7 +46,7 @@ int StoreResultSet::GetPosition() const { std::shared_lock lock(mutex_); if (impl_ == nullptr) { - ZLOGW("already closed"); + ZLOGW("Already closed"); return INVALID_POSITION; } @@ -57,7 +57,7 @@ bool StoreResultSet::MoveToFirst() { std::shared_lock lock(mutex_); if (impl_ == nullptr) { - ZLOGW("already closed"); + ZLOGW("Already closed"); return false; } @@ -67,7 +67,7 @@ bool StoreResultSet::MoveToLast() { std::shared_lock lock(mutex_); if (impl_ == nullptr) { - ZLOGW("already closed"); + ZLOGW("Already closed"); return false; } @@ -78,7 +78,7 @@ bool StoreResultSet::MoveToNext() { std::shared_lock lock(mutex_); if (impl_ == nullptr) { - ZLOGW("already closed"); + ZLOGW("Already closed"); return false; } @@ -89,7 +89,7 @@ bool StoreResultSet::MoveToPrevious() { std::shared_lock lock(mutex_); if (impl_ == nullptr) { - ZLOGW("already closed"); + ZLOGW("Already closed"); return false; } @@ -100,7 +100,7 @@ bool StoreResultSet::Move(int offset) { std::shared_lock lock(mutex_); if (impl_ == nullptr) { - ZLOGW("already closed"); + ZLOGW("Already closed"); return false; } @@ -111,7 +111,7 @@ bool StoreResultSet::MoveToPosition(int position) { std::shared_lock lock(mutex_); if (impl_ == nullptr) { - ZLOGW("already closed"); + ZLOGW("Already closed"); return false; } @@ -122,7 +122,7 @@ bool StoreResultSet::IsFirst() const { std::shared_lock lock(mutex_); if (impl_ == nullptr) { - ZLOGW("already closed"); + ZLOGW("Already closed"); return false; } @@ -132,7 +132,7 @@ bool StoreResultSet::IsLast() const { std::shared_lock lock(mutex_); if (impl_ == nullptr) { - ZLOGW("already closed"); + ZLOGW("Already closed"); return false; } @@ -143,7 +143,7 @@ bool StoreResultSet::IsBeforeFirst() const { std::shared_lock lock(mutex_); if (impl_ == nullptr) { - ZLOGW("already closed"); + ZLOGW("Already closed"); return false; } @@ -154,7 +154,7 @@ bool StoreResultSet::IsAfterLast() const { std::shared_lock lock(mutex_); if (impl_ == nullptr) { - ZLOGW("already closed"); + ZLOGW("Already closed"); return false; } @@ -165,7 +165,7 @@ Status StoreResultSet::GetEntry(Entry &entry) const { std::shared_lock lock(mutex_); if (impl_ == nullptr) { - ZLOGW("already closed"); + ZLOGW("Already closed"); return ALREADY_CLOSED; } @@ -173,7 +173,7 @@ Status StoreResultSet::GetEntry(Entry &entry) const auto dbStatus = impl_->GetEntry(dbEntry); auto status = StoreUtil::ConvertStatus(dbStatus); if (status != SUCCESS) { - ZLOGE("failed! status:%{public}d, position:%{public}d", status, impl_->GetPosition()); + ZLOGE("Failed! status:%{public}d, position:%{public}d", status, impl_->GetPosition()); return status; } std::string deviceId; diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/store_util.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/store_util.cpp index 014a2ab030e81a75aeaeab39983820cb4732709c..0aee2fe1916d8db3bffb6d2d1d831f6c08bd5008 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/store_util.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/store_util.cpp @@ -146,7 +146,7 @@ Status StoreUtil::ConvertStatus(DBStatus status) { auto iter = statusMap_.find(status); if (iter == statusMap_.end()) { - ZLOGE("unknown db error:0x%{public}x", status); + ZLOGE("Unknown db error:0x%{public}x", status); return Status::ERROR; } return iter->second; @@ -159,7 +159,7 @@ bool StoreUtil::InitPath(const std::string &path) return RemoveRWXForOthers(path); } if (mkdir(path.c_str(), (S_IRWXU | S_IRWXG)) != 0 && errno != EEXIST) { - ZLOGE("mkdir error:%{public}d, path:%{public}s", errno, path.c_str()); + ZLOGE("Mkdir error:%{public}d, path:%{public}s", errno, path.c_str()); return false; } Acl acl(path); @@ -176,7 +176,7 @@ bool StoreUtil::CreateFile(const std::string &name) } int fp = open(name.c_str(), (O_WRONLY | O_CREAT), (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP)); if (fp < 0) { - ZLOGE("fopen error:%{public}d, path:%{public}s", errno, name.c_str()); + ZLOGE("Fopen error:%{public}d, path:%{public}s", errno, name.c_str()); return false; } close(fp); @@ -188,7 +188,7 @@ std::vector StoreUtil::GetSubPath(const std::string &path) std::vector subPaths; DIR *dirp = opendir(path.c_str()); if (dirp == nullptr) { - ZLOGE("opendir error:%{public}d, path:%{public}s", errno, path.c_str()); + ZLOGE("The opendir error:%{public}d, path:%{public}s", errno, path.c_str()); return subPaths; } struct dirent *dp; @@ -206,7 +206,7 @@ std::vector StoreUtil::GetFiles(const std::string &path) std::vector fileInfos; DIR *dirp = opendir(path.c_str()); if (dirp == nullptr) { - ZLOGE("opendir error:%{public}d, path:%{public}s", errno, path.c_str()); + ZLOGE("The opendir error:%{public}d, path:%{public}s", errno, path.c_str()); return fileInfos; } struct dirent *dp; @@ -235,7 +235,7 @@ bool StoreUtil::Rename(const std::string &oldName, const std::string &newName) return false; } if (rename(oldName.c_str(), newName.c_str()) != 0) { - ZLOGE("rename error:%{public}d, file:%{public}s->%{public}s", errno, oldName.c_str(), newName.c_str()); + ZLOGE("The rename error:%{public}d, file:%{public}s->%{public}s", errno, oldName.c_str(), newName.c_str()); return false; } return true; @@ -258,7 +258,7 @@ bool StoreUtil::Remove(const std::string &path) return true; } if (remove(path.c_str()) != 0) { - ZLOGE("remove error:%{public}d, path:%{public}s", errno, path.c_str()); + ZLOGE("The remove error:%{public}d, path:%{public}s", errno, path.c_str()); return false; } return true; @@ -282,7 +282,7 @@ bool StoreUtil::RemoveRWXForOthers(const std::string &path) { struct stat buf; if (stat(path.c_str(), &buf) < 0) { - ZLOGI("stat error:%{public}d, path:%{public}s", errno, path.c_str()); + ZLOGI("The stat error:%{public}d, path:%{public}s", errno, path.c_str()); return true; } @@ -293,7 +293,7 @@ bool StoreUtil::RemoveRWXForOthers(const std::string &path) if (S_ISDIR(buf.st_mode)) { DIR *dirp = opendir(path.c_str()); if (dirp == nullptr) { - ZLOGE("opendir error:%{public}d, path:%{public}s", errno, path.c_str()); + ZLOGE("The opendir error:%{public}d, path:%{public}s", errno, path.c_str()); return false; } struct dirent *dp = nullptr; @@ -310,7 +310,7 @@ bool StoreUtil::RemoveRWXForOthers(const std::string &path) } if (chmod(path.c_str(), (buf.st_mode & ~S_IRWXO)) < 0) { - ZLOGE("chmod error:%{public}d, path:%{public}s", errno, path.c_str()); + ZLOGE("The chmod error:%{public}d, path:%{public}s", errno, path.c_str()); return false; } return true; diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/system_api.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/system_api.cpp index dc534779ebed0b864a8d174fb963f0cc7508edb5..1819c49051fec0132ecbceba57d03ffab541420a 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/system_api.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/system_api.cpp @@ -65,7 +65,7 @@ SystemApi::DBStatus SystemApi::SetSecurityOption(const std::string &filePath, co auto secLevel = std::string("s") + std::to_string(option.securityLabel - 1); bool result = SecurityLabel::SetSecurityLabel(filePath, secLevel); if (!result) { - ZLOGE("set label failed! level:%{public}s, file:%{public}s", secLevel.c_str(), + ZLOGE("Set label failed! level:%{public}s, file:%{public}s", secLevel.c_str(), StoreUtil::Anonymous(filePath).c_str()); return DBStatus::DB_ERROR; } diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/test/BUILD.gn b/kv_store/frameworks/innerkitsimpl/kvdb/test/BUILD.gn index ecad8dc10648256584ab73899ce7ef0e9209bc0a..eed773201cdd62ee5a6b4df66a76312b20ef62f0 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/test/BUILD.gn +++ b/kv_store/frameworks/innerkitsimpl/kvdb/test/BUILD.gn @@ -458,7 +458,6 @@ ohos_unittest("SingleStoreImplMockTest") { "../../distributeddatafwk/src/sync_observer.cpp", "../../kvdb/src/kv_hiview_reporter_mock.cpp", "../src/backup_manager.cpp", - "../src/convertor.cpp", "../src/device_convertor.cpp", "../src/kv_types_util.cpp", "../src/security_manager.cpp", @@ -469,6 +468,8 @@ ohos_unittest("SingleStoreImplMockTest") { "../src/store_util.cpp", "../src/system_api.cpp", "../src/task_executor_adapter.cpp", + "./mock/src/accesstoken_kit_mock.cpp", + "./mock/src/convertor_mock.cpp", "./mock/src/dev_manager_mock.cpp", "./mock/src/kvdb_notifier_client_mock.cpp", "./mock/src/kvdb_service_client_mock.cpp", @@ -526,6 +527,91 @@ ohos_unittest("SingleStoreImplMockTest") { use_exceptions = true } +ohos_unittest("BackupManagerUnitTest") { + module_out_path = module_output_path + + sources = [ + "../../kvdb/src/kv_hiview_reporter_mock.cpp", + "backup_manager_unittest.cpp", + ] + + configs = [ ":module_private_config" ] + + external_deps = [ + "hilog:libhilog", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", + "huks:libhukssdk", + ] + + deps = [ + ":kvdb_src_file", + "../../../libs/distributeddb/:distributeddb", + ] + + public_external_deps = [ + "googletest:gmock_main", + "googletest:gtest_main", + ] +} + +ohos_unittest("DevManagerUnitTest") { + module_out_path = module_output_path + + sources = [ + "../../kvdb/src/kv_hiview_reporter_mock.cpp", + "dev_manager_unittest.cpp", + ] + + configs = [ ":module_private_config" ] + + external_deps = [ + "hilog:libhilog", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", + "huks:libhukssdk", + "ipc:ipc_single", + "safwk:system_ability_fwk", + ] + + deps = [ + ":kvdb_src_file", + "../../../libs/distributeddb/:distributeddb", + ] + + public_external_deps = [ + "googletest:gmock_main", + "googletest:gtest_main", + ] +} + +ohos_unittest("SecurityManagerUnitTest") { + module_out_path = module_output_path + + sources = [ "security_manager_unittest.cpp" ] + + configs = [ ":module_private_config" ] + + external_deps = [ + "hilog:libhilog", + "hitrace:hitrace_meter", + "hitrace:libhitracechain", + "huks:libhukssdk", + "ipc:ipc_single", + "safwk:system_ability_fwk", + ] + + deps = [ + ":kvdb_src_file", + "../../../libs/distributeddb/:distributeddb", + ] + + public_external_deps = [ + "googletest:gmock_main", + "googletest:gtest_main", + ] +} + ############################################################################### group("unittest") { testonly = true diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/test/mock/include/accesstoken_kit_mock.h b/kv_store/frameworks/innerkitsimpl/kvdb/test/mock/include/accesstoken_kit_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..0a837247769508eedab31f98405e03f122e3589b --- /dev/null +++ b/kv_store/frameworks/innerkitsimpl/kvdb/test/mock/include/accesstoken_kit_mock.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 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_SECURITY_ACCESSTOKEN_ACCESSTOKENKIT_MOCK_H +#define OHOS_SECURITY_ACCESSTOKEN_ACCESSTOKENKIT_MOCK_H + +#include "accesstoken_kit.h" +#include "access_token.h" +#include + +namespace OHOS { +namespace Security { +namespace AccessToken { +class BAccessTokenKit { +public: + virtual ATokenTypeEnum GetTokenTypeFlag(AccessTokenID) = 0; + BAccessTokenKit() = default; + virtual ~BAccessTokenKit() = default; +public: + static inline std::shared_ptr accessTokenKit = nullptr; +}; + +class AccessTokenKitMock : public BAccessTokenKit { +public: + MOCK_METHOD(ATokenTypeEnum, GetTokenTypeFlag, (AccessTokenID)); +}; +} // namespace AccessToken +} // namespace Security +} // namespace OHOS +#endif // OHOS_SECURITY_ACCESSTOKEN_ACCESSTOKENKIT_MOCK_H \ No newline at end of file diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/test/mock/include/convertor_mock.h b/kv_store/frameworks/innerkitsimpl/kvdb/test/mock/include/convertor_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..842914464ae6fbb33697b2488487436807f4fc0d --- /dev/null +++ b/kv_store/frameworks/innerkitsimpl/kvdb/test/mock/include/convertor_mock.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 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_FRAMEWORKS_CONVERTOR_MOCK_H +#define OHOS_DISTRIBUTED_DATA_FRAMEWORKS_CONVERTOR_MOCK_H +#include "convertor.h" +#include +#include + +namespace OHOS::DistributedKv { +using Key = OHOS::DistributedKv::Blob; +using DBKey = DistributedDB::Key; +using DBQuery = DistributedDB::Query; + +class BConvertor { +public: + virtual std::vector ToLocalDBKey(const Key&) const = 0; + virtual std::vector ToWholeDBKey(const Key&) const = 0; + virtual Key ToKey(DBKey &&key, std::string&) const = 0; + virtual std::vector GetPrefix(const Key&) const = 0; + virtual std::vector GetPrefix(const DataQuery&) const = 0; + virtual std::string GetRealKey(const std::string&, const DataQuery&) const = 0; + virtual DBQuery GetDBQuery(const DataQuery&) const = 0; + virtual std::vector TrimKey(const Key&) const = 0; + BConvertor() = default; + virtual ~BConvertor() = default; +public: + static inline std::shared_ptr convertor = nullptr; +}; + +class ConvertorMock : public BConvertor { +public: + MOCK_METHOD(std::vector, ToLocalDBKey, (const Key&), (const)); + MOCK_METHOD(std::vector, ToWholeDBKey, (const Key&), (const)); + MOCK_METHOD(Key, ToKey, (DBKey&&, std::string&), (const)); + MOCK_METHOD(std::vector, GetPrefix, (const Key&), (const)); + MOCK_METHOD(std::vector, GetPrefix, (const DataQuery&), (const)); + MOCK_METHOD(std::string, GetRealKey, (const std::string&, const DataQuery&), (const)); + MOCK_METHOD(DBQuery, GetDBQuery, (const DataQuery&), (const)); + MOCK_METHOD(std::vector, TrimKey, (const Key&), (const)); +}; +} // namespace OHOS::DistributedKv +#endif // OHOS_DISTRIBUTED_DATA_FRAMEWORKS_CONVERTOR_MOCK_H \ No newline at end of file diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/test/mock/src/accesstoken_kit_mock.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/test/mock/src/accesstoken_kit_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..605d93013a8b369630517727f37f9799ae5c2128 --- /dev/null +++ b/kv_store/frameworks/innerkitsimpl/kvdb/test/mock/src/accesstoken_kit_mock.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 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/accesstoken_kit_mock.h" + +namespace OHOS { +namespace Security { +namespace AccessToken { +ATokenTypeEnum AccessTokenKit::GetTokenTypeFlag(AccessTokenID tokenID) +{ + if (BAccessTokenKit::accessTokenKit == nullptr) { + return TOKEN_INVALID; + } + return BAccessTokenKit::accessTokenKit->GetTokenTypeFlag(tokenID); +} +} // namespace AccessToken +} // namespace Security +} // namespace OHOS \ No newline at end of file diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/test/mock/src/convertor_mock.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/test/mock/src/convertor_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37e336150feaeec437d8a65e56cbb1a533f23b4e --- /dev/null +++ b/kv_store/frameworks/innerkitsimpl/kvdb/test/mock/src/convertor_mock.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2024 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/convertor_mock.h" + +namespace OHOS::DistributedKv { +std::vector Convertor::ToLocalDBKey(const Key &key) const +{ + if (BConvertor::convertor == nullptr) { + std::vector vec; + return vec; + } + return BConvertor::convertor->ToLocalDBKey(key); +} + +std::vector Convertor::ToWholeDBKey(const Key &key) const +{ + if (BConvertor::convertor == nullptr) { + std::vector vc; + return vc; + } + return BConvertor::convertor->ToWholeDBKey(key); +} + +Key Convertor::ToKey(DBKey &&key, std::string &deviceId) const +{ + return std::move(key); +} + +std::vector Convertor::GetPrefix(const Key &prefix) const +{ + if (BConvertor::convertor == nullptr) { + std::vector dbKey; + return dbKey; + } + return BConvertor::convertor->GetPrefix(prefix); +} + +std::vector Convertor::GetPrefix(const DataQuery &query) const +{ + if (BConvertor::convertor == nullptr) { + std::vector vec; + return vec; + } + return BConvertor::convertor->GetPrefix(query); +} + +Convertor::DBQuery Convertor::GetDBQuery(const DataQuery &query) const +{ + if (BConvertor::convertor == nullptr) { + DBQuery dbQuery = *(query.query_); + return dbQuery; + } + return BConvertor::convertor->GetDBQuery(query); +} + +std::string Convertor::GetRealKey(const std::string &key, const DataQuery &query) const +{ + if (BConvertor::convertor == nullptr) { + return ""; + } + return BConvertor::convertor->GetRealKey(key, query); +} + +std::vector Convertor::TrimKey(const Key &prefix) const +{ + if (BConvertor::convertor == nullptr) { + std::vector vc; + return vc; + } + return BConvertor::convertor->TrimKey(prefix); +} +} // namespace OHOS::DistributedKv \ No newline at end of file diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/test/mock/src/kvdb_service_client_mock.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/test/mock/src/kvdb_service_client_mock.cpp index 3b83820cf27de11b9e61e0389f21c16d50592cea..52e3877c6413d50ecc2b7f617f5748f820012a1d 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/test/mock/src/kvdb_service_client_mock.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/test/mock/src/kvdb_service_client_mock.cpp @@ -136,7 +136,7 @@ Status KVDBServiceClient::Unsubscribe(const AppId &appId, const StoreId &storeId } Status KVDBServiceClient::GetBackupPassword( - const AppId &appId, const StoreId &storeId, std::vector &password, int32_t passwordType) + const AppId &appId, const StoreId &storeId, std::vector> &password, int32_t passwordType) { return KVDBServiceClientMock::status; } diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/test/single_store_impl_mock_test.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/test/single_store_impl_mock_test.cpp deleted file mode 100644 index 354614f9ef2e0898cfdd6a720f506f3334499ecc..0000000000000000000000000000000000000000 --- a/kv_store/frameworks/innerkitsimpl/kvdb/test/single_store_impl_mock_test.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (c) 2024 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 - -#include -#include - -#include "convertor.h" -#include "include/dev_manager_mock.h" -#include "include/kvdb_notifier_client_mock.h" -#include "include/kvdb_service_client_mock.h" -#include "include/observer_bridge_mock.h" -#include "include/task_executor_mock.h" -#include "kvstore_observer.h" -#include "single_store_impl.h" -#include "store_factory.h" -#include "store_manager.h" - -namespace OHOS::DistributedKv { -using namespace std; -using namespace testing; -using namespace DistributedDB; - -static StoreId storeId = { "single_test" }; -static AppId appId = { "rekey" }; - -class SingleStoreImplMockTest : public testing::Test { -public: - static void SetUpTestCase(void); - static void TearDownTestCase(); - void SetUp() override; - void TearDown() override; - -public: - using DBStatus = DistributedDB::DBStatus; - using DBStore = DistributedDB::KvStoreNbDelegate; - using Observer = DistributedKv::KvStoreObserver; - static inline shared_ptr devManagerMock = nullptr; - static inline shared_ptr kVDBServiceClientMock = nullptr; - static inline shared_ptr kVDBNotifierClientMock = nullptr; - static inline shared_ptr observerBridgeMock = nullptr; - static inline shared_ptr taskExecutorMock = nullptr; - std::shared_ptr CreateKVStore(bool autosync = false); -}; - -void SingleStoreImplMockTest::SetUp() { } - -void SingleStoreImplMockTest::TearDown() { } - -void SingleStoreImplMockTest::SetUpTestCase() -{ - GTEST_LOG_(INFO) << "SetUpTestCase enter"; - std::string baseDir = "/data/service/el1/public/database/SingleStoreImplTest"; - mkdir(baseDir.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); - devManagerMock = make_shared(); - BDevManager::devManager = devManagerMock; - kVDBServiceClientMock = make_shared(); - BKVDBServiceClient::kVDBServiceClient = kVDBServiceClientMock; - kVDBNotifierClientMock = make_shared(); - BKVDBNotifierClient::kVDBNotifierClient = kVDBNotifierClientMock; - observerBridgeMock = make_shared(); - BObserverBridge::observerBridge = observerBridgeMock; - taskExecutorMock = make_shared(); - BTaskExecutor::taskExecutor = taskExecutorMock; -} - -void SingleStoreImplMockTest::TearDownTestCase() -{ - GTEST_LOG_(INFO) << "TearDownTestCase enter"; - BDevManager::devManager = nullptr; - devManagerMock = nullptr; - BKVDBServiceClient::kVDBServiceClient = nullptr; - kVDBServiceClientMock = nullptr; - BKVDBNotifierClient::kVDBNotifierClient = nullptr; - kVDBNotifierClientMock = nullptr; - BObserverBridge::observerBridge = nullptr; - observerBridgeMock = nullptr; - BTaskExecutor::taskExecutor = nullptr; - taskExecutorMock = nullptr; - std::string baseDir = "/data/service/el1/public/database/SingleStoreImplTest"; - (void)remove("/data/service/el1/public/database/SingleStoreImplTest"); -} - -std::shared_ptr SingleStoreImplMockTest::CreateKVStore(bool autosync) -{ - AppId appId = { "SingleStoreImplTest" }; - StoreId storeId = { "DestructorTest" }; - std::shared_ptr kvStore; - Options options; - options.kvStoreType = SINGLE_VERSION; - options.securityLevel = S2; - options.area = EL1; - options.autoSync = autosync; - options.baseDir = "/data/service/el1/public/database/SingleStoreImplTest"; - StoreFactory storeFactory; - auto dbManager = storeFactory.GetDBManager(options.baseDir, appId); - auto dbPassword = SecurityManager::GetInstance().GetDBPassword(storeId.storeId, options.baseDir, options.encrypt); - DBStatus dbStatus = DBStatus::DB_ERROR; - dbManager->GetKvStore(storeId, storeFactory.GetDBOption(options, dbPassword), - [&dbManager, &kvStore, &appId, &dbStatus, &options, &storeFactory](auto status, auto *store) { - dbStatus = status; - if (store == nullptr) { - return; - } - auto release = [dbManager](auto *store) { - dbManager->CloseKvStore(store); - }; - auto dbStore = std::shared_ptr(store, release); - storeFactory.SetDbConfig(dbStore); - const Convertor &convertor = *(storeFactory.convertors_[options.kvStoreType]); - kvStore = std::make_shared(dbStore, appId, options, convertor); - }); - return kvStore; -} - -/** - * @tc.name: IsRemoteChanged - * @tc.desc: is remote changed. - * @tc.type: FUNC - * @tc.require: - * @tc.author: cao zhijun - */ -HWTEST_F(SingleStoreImplMockTest, IsRemoteChanged, testing::ext::TestSize.Level1) -{ - GTEST_LOG_(INFO) << "SingleStoreImplMockTest-begin IsRemoteChanged"; - try { - EXPECT_CALL(*taskExecutorMock, Schedule(_, _, _, _)).Times(1); - std::shared_ptr kvStore; - kvStore = CreateKVStore(); - ASSERT_NE(kvStore, nullptr); - std::shared_ptr client = make_shared(nullptr); - ASSERT_NE(client, nullptr); - EXPECT_CALL(*devManagerMock, ToUUID(_)).WillOnce(Return("")); - bool ret = kvStore->IsRemoteChanged("123456789"); - EXPECT_TRUE(ret); - - EXPECT_CALL(*devManagerMock, ToUUID(_)).WillOnce(Return("123456789")); - EXPECT_CALL(*kVDBServiceClientMock, GetInstance()).WillOnce(Return(nullptr)); - ret = kvStore->IsRemoteChanged("123456789"); - EXPECT_TRUE(ret); - - EXPECT_CALL(*devManagerMock, ToUUID(_)).WillOnce(Return("123456789")); - EXPECT_CALL(*kVDBServiceClientMock, GetInstance()).WillOnce(Return(client)); - EXPECT_CALL(*kVDBServiceClientMock, GetServiceAgent(_)).WillOnce(Return(nullptr)); - ret = kvStore->IsRemoteChanged("123456789"); - EXPECT_TRUE(ret); - - sptr testAgent = new (std::nothrow) KVDBNotifierClient(); - ASSERT_NE(testAgent, nullptr); - EXPECT_CALL(*devManagerMock, ToUUID(_)).WillOnce(Return("123456789")); - EXPECT_CALL(*kVDBServiceClientMock, GetInstance()).WillOnce(Return(client)); - EXPECT_CALL(*kVDBServiceClientMock, GetServiceAgent(_)).WillOnce(Return(testAgent)); - EXPECT_CALL(*kVDBNotifierClientMock, IsChanged(_, _)).WillOnce(Return(true)); - ret = kvStore->IsRemoteChanged("123456789"); - EXPECT_TRUE(ret); - } catch (...) { - EXPECT_TRUE(false); - GTEST_LOG_(INFO) << "SingleStoreImplMockTest-an exception occurred by IsRemoteChanged."; - } - GTEST_LOG_(INFO) << "SingleStoreImplMockTest-end IsRemoteChanged"; -} - -/** - * @tc.name: OnRemoteDied - * @tc.desc: remote died. - * @tc.type: FUNC - * @tc.require: - * @tc.author: cao zhijun - */ -HWTEST_F(SingleStoreImplMockTest, OnRemoteDied, testing::ext::TestSize.Level1) -{ - GTEST_LOG_(INFO) << "SingleStoreImplMockTest-begin OnRemoteDied"; - try { - EXPECT_CALL(*taskExecutorMock, Schedule(_, _, _, _)).Times(1); - std::shared_ptr kvStore; - kvStore = CreateKVStore(); - ASSERT_NE(kvStore, nullptr); - kvStore->taskId_ = 1; - kvStore->OnRemoteDied(); - - kvStore->taskId_ = 0; - shared_ptr observer = make_shared(); - shared_ptr observer1 = make_shared(); - Convertor cvt; - Convertor cvt1; - shared_ptr obsBridge = make_shared(appId, storeId, observer, cvt); - shared_ptr obsBridge1 = make_shared(appId, storeId, observer1, cvt1); - - uint32_t firs = 0; - firs |= SUBSCRIBE_TYPE_REMOTE; - pair> one(0, obsBridge); - pair> two(firs, obsBridge1); - - kvStore->observers_.Insert(uintptr_t(observer.get()), one); - kvStore->observers_.Insert(uintptr_t(observer1.get()), two); - EXPECT_CALL(*observerBridgeMock, OnServiceDeath()).Times(1); - EXPECT_CALL(*taskExecutorMock, Schedule(_, _, _, _)).WillOnce(Return(1)); - kvStore->OnRemoteDied(); - kvStore->observers_.Erase(uintptr_t(observer.get())); - kvStore->observers_.Erase(uintptr_t(observer1.get())); - EXPECT_TRUE(kvStore->taskId_ == 1); - } catch (...) { - EXPECT_TRUE(false); - GTEST_LOG_(INFO) << "SingleStoreImplMockTest-an exception occurred by OnRemoteDied."; - } - GTEST_LOG_(INFO) << "SingleStoreImplMockTest-end OnRemoteDied"; -} - -/** - * @tc.name: Register - * @tc.desc: register. - * @tc.type: FUNC - * @tc.require: - * @tc.author: cao zhijun - */ -HWTEST_F(SingleStoreImplMockTest, Register, testing::ext::TestSize.Level1) -{ - GTEST_LOG_(INFO) << "SingleStoreImplMockTest-begin Register"; - try { - EXPECT_CALL(*taskExecutorMock, Schedule(_, _, _, _)).Times(1); - std::shared_ptr kvStore; - kvStore = CreateKVStore(); - ASSERT_NE(kvStore, nullptr); - - shared_ptr observer = make_shared(); - shared_ptr observer1 = make_shared(); - Convertor cvt; - Convertor cvt1; - shared_ptr obsBridge = make_shared(appId, storeId, observer, cvt); - shared_ptr obsBridge1 = make_shared(appId, storeId, observer1, cvt1); - - uint32_t firs = 0; - firs |= SUBSCRIBE_TYPE_CLOUD; - pair> one(0, obsBridge); - pair> two(firs, obsBridge1); - - kvStore->observers_.Insert(uintptr_t(observer.get()), one); - kvStore->observers_.Insert(uintptr_t(observer1.get()), two); - EXPECT_CALL(*observerBridgeMock, RegisterRemoteObserver(_)).WillOnce(Return(ERROR)); - EXPECT_CALL(*taskExecutorMock, Schedule(_, _, _, _)).WillOnce(Return(1)); - kvStore->Register(); - EXPECT_TRUE(kvStore->taskId_ == 1); - - EXPECT_CALL(*observerBridgeMock, RegisterRemoteObserver(_)).WillOnce(Return(SUCCESS)); - kvStore->Register(); - kvStore->observers_.Erase(uintptr_t(observer.get())); - kvStore->observers_.Erase(uintptr_t(observer1.get())); - EXPECT_TRUE(kvStore->taskId_ == 0); - } catch (...) { - EXPECT_TRUE(false); - GTEST_LOG_(INFO) << "SingleStoreImplMockTest-an exception occurred by Register."; - } - GTEST_LOG_(INFO) << "SingleStoreImplMockTest-end Register"; -} -} // namespace OHOS::DistributedKv \ No newline at end of file diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/test/single_store_impl_test.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/test/single_store_impl_test.cpp index b4f9567bd6b3e75d670b4b740fb6fbadcb5a7ad2..36e46397088c2526834cba8ea15504399ad076de 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/test/single_store_impl_test.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/test/single_store_impl_test.cpp @@ -214,8 +214,8 @@ HWTEST_F(SingleStoreImplTest, Put_Invalid_Key, TestSize.Level0) kvStore = CreateKVStore(storeId.storeId, DEVICE_COLLABORATION, false, true); ASSERT_NE(kvStore, nullptr); - size_t MAX_DEV_KEY_LEN = 897; - std::string str(MAX_DEV_KEY_LEN, 'a'); + size_t maxDevKeyLen = 897; + std::string str(maxDevKeyLen, 'a'); Blob key(str); Blob value("test_value"); Status status = kvStore->Put(key, value); @@ -233,8 +233,8 @@ HWTEST_F(SingleStoreImplTest, Put_Invalid_Key, TestSize.Level0) status = StoreManager::GetInstance().Delete(appId, storeId, baseDir); ASSERT_EQ(status, SUCCESS); - size_t MAX_SINGLE_KEY_LEN = 1025; - std::string str1(MAX_SINGLE_KEY_LEN, 'b'); + size_t maxSingleKeyLen = 1025; + std::string str1(maxSingleKeyLen, 'b'); Blob key2(str1); Blob value2("test_value2"); status = kvStore_->Put(key2, value2); @@ -630,11 +630,11 @@ HWTEST_F(SingleStoreImplTest, GetEntries_Greater_Prefix, TestSize.Level0) kvStore = CreateKVStore(storeId.storeId, DEVICE_COLLABORATION, false, true); ASSERT_NE(kvStore, nullptr); - size_t KEY_LEN = sizeof(uint32_t); + size_t keyLen = sizeof(uint32_t); std::vector input; for (int i = 1; i < 10; ++i) { Entry entry; - std::string str(KEY_LEN, i + '0'); + std::string str(keyLen, i + '0'); entry.key = str; entry.value = std::to_string(i).append("_v"); input.push_back(entry); @@ -642,7 +642,7 @@ HWTEST_F(SingleStoreImplTest, GetEntries_Greater_Prefix, TestSize.Level0) auto status = kvStore->PutBatch(input); ASSERT_EQ(status, SUCCESS); std::vector output; - std::string str1(KEY_LEN, '1'); + std::string str1(keyLen, '1'); status = kvStore->GetEntries(str1, output); ASSERT_NE(output.empty(), true); ASSERT_EQ(status, SUCCESS); @@ -2060,7 +2060,7 @@ HWTEST_F(SingleStoreImplTest, ReportDBCorruptedFault, TestSize.Level0) kvStore = CreateKVStore(); ASSERT_NE(kvStore, nullptr); Status status = DATA_CORRUPTED; - kvStore->ReportDBCorruptedFault(status); +// kvStore->ReportDBCorruptedFault(status); EXPECT_TRUE(status == DATA_CORRUPTED); } } // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/frameworks/jskitsimpl/distributeddata/include/js_schema.h b/kv_store/frameworks/jskitsimpl/distributeddata/include/js_schema.h index 615b43cb98b63a7255b3e8067a66c91c21d26922..a42b63318a318bc54d5037a7c06135f4d2303c20 100644 --- a/kv_store/frameworks/jskitsimpl/distributeddata/include/js_schema.h +++ b/kv_store/frameworks/jskitsimpl/distributeddata/include/js_schema.h @@ -29,7 +29,7 @@ public: static napi_value Constructor(napi_env env); static napi_value New(napi_env env, napi_callback_info info); - + static napi_status ToJson(napi_env env, napi_value inner, JsSchema*& out); std::string Dump(); private: diff --git a/kv_store/frameworks/jskitsimpl/distributeddata/src/entry_point.cpp b/kv_store/frameworks/jskitsimpl/distributeddata/src/entry_point.cpp index d3f105d41207b0240099f4f9ae08b5960c9e7f1d..25c12dd601f1126d22162e72cf64425bf3abdc51 100644 --- a/kv_store/frameworks/jskitsimpl/distributeddata/src/entry_point.cpp +++ b/kv_store/frameworks/jskitsimpl/distributeddata/src/entry_point.cpp @@ -29,19 +29,19 @@ static napi_value Init(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("createKVManager", JsKVManager::CreateKVManager) }; napi_status status = napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); - ZLOGI("init createKVManager %{public}d", status); + ZLOGI("Init createKVManager %{public}d", status); status = napi_set_named_property(env, exports, "FieldNode", JsFieldNode::Constructor(env)); - ZLOGI("init FieldNode %{public}d", status); + ZLOGI("Init FieldNode %{public}d", status); status = napi_set_named_property(env, exports, "Schema", JsSchema::Constructor(env)); - ZLOGI("init Schema %{public}d", status); + ZLOGI("Init Schema %{public}d", status); status = napi_set_named_property(env, exports, "Query", JsQuery::Constructor(env)); - ZLOGI("init Query %{public}d", status); + ZLOGI("Init Query %{public}d", status); status = InitConstProperties(env, exports); - ZLOGI("init Enumerate Constants %{public}d", status); + ZLOGI("Init Enumerate Constants %{public}d", status); return exports; } @@ -55,5 +55,5 @@ static __attribute__((constructor)) void RegisterModule() .nm_priv = ((void*)0), .reserved = { 0 } }; napi_module_register(&module); - ZLOGI("module register data.distributedData"); + ZLOGI("Module register data.distributedData"); } diff --git a/kv_store/frameworks/jskitsimpl/distributeddata/src/js_device_kv_store.cpp b/kv_store/frameworks/jskitsimpl/distributeddata/src/js_device_kv_store.cpp index 5f4748ca74b606aa1073f66a79645737e9891534..be343c507ff1ee58fe985f0449393a6f7979db5b 100644 --- a/kv_store/frameworks/jskitsimpl/distributeddata/src/js_device_kv_store.cpp +++ b/kv_store/frameworks/jskitsimpl/distributeddata/src/js_device_kv_store.cpp @@ -100,7 +100,7 @@ napi_value JsDeviceKVStore::Get(napi_env env, napi_callback_info info) OHOS::DistributedKv::Value value; auto& kvStore = reinterpret_cast(ctxt->native)->GetNative(); if (kvStore == nullptr) { - ZLOGE("kvStore is nullptr"); + ZLOGE("This kvStore is nullptr"); return; } bool isSchemaStore = reinterpret_cast(ctxt->native)->IsSchemaStore(); @@ -392,7 +392,7 @@ napi_value JsDeviceKVStore::RemoveDeviceData(napi_env env, napi_callback_info in CHECK_ARGS_RETURN_VOID(ctxt, argc == 1, "invalid arguments!"); ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->deviceId); if (ctxt->deviceId.empty()) { - ZLOGE("deviceId is empty"); + ZLOGE("This deviceId is empty"); ctxt->status = napi_generic_failure; return; } diff --git a/kv_store/frameworks/jskitsimpl/distributeddata/src/napi_queue.cpp b/kv_store/frameworks/jskitsimpl/distributeddata/src/napi_queue.cpp index de35ddcaef49494769d9d7c632ded9adf1679d79..975e4a0164673febfc6a14006107579f369d281e 100644 --- a/kv_store/frameworks/jskitsimpl/distributeddata/src/napi_queue.cpp +++ b/kv_store/frameworks/jskitsimpl/distributeddata/src/napi_queue.cpp @@ -20,7 +20,7 @@ using namespace OHOS::DistributedKv; namespace OHOS::DistributedData { ContextBase::~ContextBase() { - ZLOGD("no memory leak after callback or promise[resolved/rejected]"); + ZLOGD("No memory leak after callback or promise[resolved/rejected]"); if (env != nullptr) { if (callbackRef != nullptr) { auto status = napi_delete_reference(env, callbackRef); @@ -58,9 +58,9 @@ void ContextBase::GetCbInfo(napi_env envi, napi_callback_info info, NapiCbInfoPa status = napi_create_reference(env, argv[index], 1, &callbackRef); CHECK_STATUS_RETURN_VOID(this, "ref callback failed!"); argc = index; - ZLOGD("async callback, no promise"); + ZLOGD("Async callback, no promise"); } else { - ZLOGD("no callback, async pormose"); + ZLOGD("No callback, async pormose"); } } @@ -84,7 +84,7 @@ napi_value NapiQueue::AsyncWork(napi_env env, std::shared_ptr ctxt, if (aCtx->ctx->callbackRef == nullptr) { auto ret = napi_create_promise(env, &aCtx->deferred, &promise); CHECK_RETURN(ret == napi_ok, "napi_create_promise fail", nullptr); - ZLOGD("create deferred promise"); + ZLOGD("Create deferred promise"); } else { napi_get_undefined(env, &promise); } @@ -151,7 +151,7 @@ void NapiQueue::GenerateOutput(AsyncContext &ctx, napi_value output) napi_value callback = nullptr; napi_get_reference_value(ctx.env, ctx.ctx->callbackRef, &callback); napi_value callbackResult = nullptr; - ZLOGD("call callback function"); + ZLOGD("Call callback function"); napi_call_function(ctx.env, nullptr, callback, RESULT_ALL, result, &callbackResult); } } diff --git a/kv_store/frameworks/jskitsimpl/distributeddata/src/uv_queue.cpp b/kv_store/frameworks/jskitsimpl/distributeddata/src/uv_queue.cpp index 3344b4618d1eafcd9c6b97c3aa76b18287275d86..0c5d17ee6c65bc44b865c70b34ea2e643ab13671 100644 --- a/kv_store/frameworks/jskitsimpl/distributeddata/src/uv_queue.cpp +++ b/kv_store/frameworks/jskitsimpl/distributeddata/src/uv_queue.cpp @@ -29,25 +29,25 @@ UvQueue::UvQueue(napi_env env) UvQueue::~UvQueue() { - ZLOGD("no memory leak for queue-callback"); + ZLOGD("No memory leak for queue-callback"); env_ = nullptr; } void UvQueue::AsyncCall(NapiCallbackGetter getter, NapiArgsGenerator genArgs) { if (loop_ == nullptr || !getter) { - ZLOGE("loop_ or callback is nullptr"); + ZLOGE("This loop_ or callback is nullptr"); return; } uv_work_t* work = new (std::nothrow) uv_work_t; if (work == nullptr) { - ZLOGE("no memory for uv_work_t"); + ZLOGE("No memory for uv_work_t"); return; } work->data = new UvEntry{ env_, getter, std::move(genArgs) }; if (work->data == nullptr) { - ZLOGE("no memory for UvEntry"); + ZLOGE("No memory for UvEntry"); delete work; work = nullptr; return; @@ -74,7 +74,7 @@ void UvQueue::Work(uv_work_t* work, int uvStatus) napi_open_handle_scope(entry->env, &scope); napi_value method = entry->callback(entry->env); if (method == nullptr) { - ZLOGE("the callback is invalid, maybe is cleared!"); + ZLOGE("The callback is invalid, maybe is cleared!"); if (scope != nullptr) { napi_close_handle_scope(entry->env, scope); } @@ -92,7 +92,7 @@ void UvQueue::Work(uv_work_t* work, int uvStatus) napi_value result; napi_status status = napi_call_function(entry->env, global, method, argc, argv, &result); if (status != napi_ok) { - ZLOGE("notify data change failed status:%{public}d.", status); + ZLOGE("Notify data change failed status:%{public}d.", status); } if (scope != nullptr) { napi_close_handle_scope(entry->env, scope); diff --git a/kv_store/frameworks/jskitsimpl/distributedkvstore/include/js_kv_manager.h b/kv_store/frameworks/jskitsimpl/distributedkvstore/include/js_kv_manager.h index b5d4b7b8076219b13180c56b2f0cc7479a2334b9..8b8b00d5d6b196a3189dfc538a142f0355d40726 100644 --- a/kv_store/frameworks/jskitsimpl/distributedkvstore/include/js_kv_manager.h +++ b/kv_store/frameworks/jskitsimpl/distributedkvstore/include/js_kv_manager.h @@ -63,7 +63,7 @@ private: std::shared_ptr uvQueue_; std::shared_ptr param_; static constexpr int MAX_APP_ID_LEN = 256; - static constexpr int API_14_VERSION = 14; + static constexpr int API_16_VERSION = 16; }; } // namespace OHOS::DistributedKVStore #endif // OHOS_KV_MANAGER_H diff --git a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/entry_point.cpp b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/entry_point.cpp index a5e537c9d8bbe60b3e15f4cf2efabdade4a48bc3..9d9be5a4f447f34a54a94322e469c843e8d73341 100644 --- a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/entry_point.cpp +++ b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/entry_point.cpp @@ -29,19 +29,19 @@ static napi_value Init(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("createKVManager", JsKVManager::CreateKVManager) }; napi_status status = napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); - ZLOGI("init createKVManager %{public}d", status); + ZLOGI("Init createKVManager %{public}d", status); status = napi_set_named_property(env, exports, "FieldNode", JsFieldNode::Constructor(env)); - ZLOGI("init FieldNode %{public}d", status); + ZLOGI("Init FieldNode %{public}d", status); status = napi_set_named_property(env, exports, "Schema", JsSchema::Constructor(env)); - ZLOGI("init Schema %{public}d", status); + ZLOGI("Init Schema %{public}d", status); status = napi_set_named_property(env, exports, "Query", JsQuery::Constructor(env)); - ZLOGI("init Query %{public}d", status); + ZLOGI("Init Query %{public}d", status); status = InitConstProperties(env, exports); - ZLOGI("init Enumerate Constants %{public}d", status); + ZLOGI("Init Enumerate Constants %{public}d", status); return exports; } @@ -55,5 +55,5 @@ static __attribute__((constructor)) void RegisterModule() .nm_priv = ((void*)0), .reserved = { 0 } }; napi_module_register(&module); - ZLOGI("module register data.distributedKvstore"); + ZLOGI("Module register data.distributedKvstore"); } diff --git a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_kv_manager.cpp b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_kv_manager.cpp index f5bccd2000845eab4c1eb558a669ee5b8453c1bb..823948ff4bb48014b0d3f838e34ac0b422869861 100644 --- a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_kv_manager.cpp +++ b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_kv_manager.cpp @@ -152,7 +152,7 @@ napi_value JsKVManager::GetKVStore(napi_env env, napi_callback_info info) status = kvm->kvDataManager_.GetSingleKvStore(ctxt->options, appId, storeId, kvStore); ZLOGE("Data has corrupted, rebuild db"); } - if (status == CRYPT_ERROR && kvm->param_->apiVersion < API_14_VERSION) { + if (status == CRYPT_ERROR && kvm->param_->apiVersion < API_16_VERSION) { status = DATA_CORRUPTED; } ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ? diff --git a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/napi_queue.cpp b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/napi_queue.cpp index e94124571a0aedaa2182361fd5c92b2d6f475302..5c75659c055f2762edebdd0f362f4a2881378288 100644 --- a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/napi_queue.cpp +++ b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/napi_queue.cpp @@ -20,7 +20,7 @@ using namespace OHOS::DistributedKv; namespace OHOS::DistributedKVStore { ContextBase::~ContextBase() { - ZLOGD("no memory leak after callback or promise[resolved/rejected]"); + ZLOGD("No memory leak after callback or promise[resolved/rejected]"); if (env != nullptr) { if (callbackRef != nullptr) { auto status = napi_delete_reference(env, callbackRef); @@ -58,9 +58,9 @@ void ContextBase::GetCbInfo(napi_env envi, napi_callback_info info, NapiCbInfoPa status = napi_create_reference(env, argv[index], 1, &callbackRef); ASSERT_STATUS(this, "ref callback failed!"); argc = index; - ZLOGD("async callback, no promise"); + ZLOGD("Async callback, no promise"); } else { - ZLOGD("no callback, async pormose"); + ZLOGD("No callback, async pormose"); } } @@ -84,7 +84,7 @@ napi_value NapiQueue::AsyncWork(napi_env env, std::shared_ptr ctxt, if (aCtx->ctx->callbackRef == nullptr) { auto ret = napi_create_promise(env, &aCtx->deferred, &promise); ASSERT(ret == napi_ok, "napi_create_promise fail", nullptr); - ZLOGD("create deferred promise"); + ZLOGD("Create deferred promise"); } else { napi_get_undefined(env, &promise); } @@ -159,7 +159,7 @@ void NapiQueue::GenerateOutput(AsyncContext &ctx, napi_value output) napi_value callback = nullptr; napi_get_reference_value(ctx.env, ctx.ctx->callbackRef, &callback); napi_value callbackResult = nullptr; - ZLOGD("call callback function"); + ZLOGD("Call callback function"); napi_call_function(ctx.env, nullptr, callback, RESULT_ALL, result, &callbackResult); } } diff --git a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/uv_queue.cpp b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/uv_queue.cpp index 2aaf40e3f415f05e9d0534c2fb8ad546bbcbfb91..3bf0d286e9e02c1645efec221eb351bcf703bef9 100644 --- a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/uv_queue.cpp +++ b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/uv_queue.cpp @@ -29,7 +29,7 @@ UvQueue::UvQueue(napi_env env) UvQueue::~UvQueue() { - ZLOGD("no memory leak for queue-callback"); + ZLOGD("No memory leak for queue-callback"); env_ = nullptr; } @@ -42,12 +42,12 @@ void UvQueue::AsyncCall(NapiCallbackGetter getter, NapiArgsGenerator genArgs) uv_work_t* work = new (std::nothrow) uv_work_t; if (work == nullptr) { - ZLOGE("no memory for uv_work_t"); + ZLOGE("No memory for uv_work_t"); return; } work->data = new UvEntry{ env_, getter, std::move(genArgs) }; if (work->data == nullptr) { - ZLOGE("no memory for UvEntry"); + ZLOGE("No memory for UvEntry"); delete work; work = nullptr; return; @@ -74,7 +74,7 @@ void UvQueue::Work(uv_work_t* work, int uvStatus) napi_open_handle_scope(entry->env, &scope); napi_value method = entry->callback(entry->env); if (method == nullptr) { - ZLOGE("the callback is invalid, maybe is cleared!"); + ZLOGE("The callback is invalid, maybe is cleared!"); if (scope != nullptr) { napi_close_handle_scope(entry->env, scope); } @@ -92,7 +92,7 @@ void UvQueue::Work(uv_work_t* work, int uvStatus) napi_value result; napi_status status = napi_call_function(entry->env, global, method, argc, argv, &result); if (status != napi_ok) { - ZLOGE("notify data change failed status:%{public}d.", status); + ZLOGE("Notify data change failed status:%{public}d.", status); } if (scope != nullptr) { napi_close_handle_scope(entry->env, scope); diff --git a/kv_store/frameworks/libs/distributeddb/BUILD.gn b/kv_store/frameworks/libs/distributeddb/BUILD.gn index 80f2fba30ae6e4969771c43282cad7476f08de21..da27de4597d115c8d308a46ef0e31a85dd1a784b 100644 --- a/kv_store/frameworks/libs/distributeddb/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/BUILD.gn @@ -44,7 +44,6 @@ config("distrdb_config") { "syncer/src/device", "syncer/src/device/multiver", "syncer/src/device/singlever", - "//third_party/openssl/include/", ] defines = [ @@ -70,6 +69,9 @@ config("distrdb_config") { if (is_ohos) { defines += [ "USE_FFRT" ] } + if (kv_store_cloud) { + defines += [ "USE_DISTRIBUTEDDB_CLOUD" ] + } } config("distrdb_public_config") { @@ -86,7 +88,10 @@ config("distrdb_public_config") { } group("build_module") { - deps = [ ":distributeddb" ] + deps = [ + ":customtokenizer", + ":distributeddb", + ] } ohos_shared_library("distributeddb") { @@ -99,11 +104,17 @@ ohos_shared_library("distributeddb") { debug = false } sources = distributeddb_src + if (kv_store_cloud) { + sources += distributeddb_cloud_src + } configs = [ ":distrdb_config" ] public_configs = [ ":distrdb_public_config" ] - cflags_cc = [ "-fvisibility=hidden" ] + cflags_cc = [ + "-fvisibility=hidden", + "-Os", + ] deps = [ "gaussdb_rd:gaussdb_rd" ] external_deps = [ @@ -125,3 +136,54 @@ ohos_shared_library("distributeddb") { innerapi_tags = [ "platformsdk_indirect" ] part_name = "kv_store" } + +tokenizer_path = "." + +config("tokenizer_config") { + visibility = [ ":*" ] + include_dirs = [ + "$tokenizer_path/sqlite_adapter/include", + "$tokenizer_path/sqlite_adapter/src", + ] + defines = [ "HARMONY_OS" ] +} + +config("tokenizer_public_config") { + visibility = [ ":*" ] + include_dirs = [ "$tokenizer_path/sqlite_adapter/include" ] +} + +ohos_shared_library("customtokenizer") { + branch_protector_ret = "pac_ret" + sanitize = { + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + sources = [ + "$tokenizer_path/sqlite_adapter/src/tokenizer_api.cpp", + "$tokenizer_path/sqlite_adapter/src/tokenizer_api_mgr.cpp", + "$tokenizer_path/sqlite_adapter/src/tokenizer_sqlite.cpp", + ] + + configs = [ ":tokenizer_config" ] + public_configs = [ ":tokenizer_public_config" ] + + cflags_cc = [ + "-fvisibility=hidden", + "-Os", + ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + ] + + public_external_deps = [ "sqlite:sqlite" ] + + subsystem_name = "distributeddatamgr" + innerapi_tags = [ "platformsdk_indirect" ] + part_name = "kv_store" +} diff --git a/kv_store/frameworks/libs/distributeddb/common/include/auto_launch.h b/kv_store/frameworks/libs/distributeddb/common/include/auto_launch.h index c73853386c426c8307882bc63b7b52c78c15c77f..87b043047277e661d0f542b66f3b09198a5b57f8 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/auto_launch.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/auto_launch.h @@ -118,6 +118,9 @@ protected: int EnableKvStoreAutoLaunchParmCheck(AutoLaunchItem &autoLaunchItem, const std::string &normalIdentifier, const std::string &dualTupleIdentifier, bool isDualTupleMode); + void GetKVConnectionInEnableInner(const AutoLaunchItem &autoLaunchItem, const std::string &identifier, + const std::string &userId); + int GetKVConnectionInEnable(AutoLaunchItem &autoLaunchItem, const std::string &identifier); // before ReleaseDatabaseConnection, if errCode != E_OK, we not return, we try close more diff --git a/kv_store/frameworks/libs/distributeddb/common/include/cloud/asset_operation_utils.h b/kv_store/frameworks/libs/distributeddb/common/include/cloud/asset_operation_utils.h index 72268adf0f5de6bad01f40b59ef591b20ced19ab..aadbb89b36190cf0c8cb5fb2f1082476388162c8 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/cloud/asset_operation_utils.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/cloud/asset_operation_utils.h @@ -41,6 +41,9 @@ public: static uint32_t EraseBitMask(uint32_t status); static void UpdateAssetsFlag(std::vector &from, std::vector &target); static void FilterDeleteAsset(VBucket &record); + static std::map FilterNeedDownloadAsset(VBucket &record); + static bool IsAssetNeedDownload(const Asset &asset); + static bool IsAssetsNeedDownload(const Assets &assets); private: static void Init(); static AssetOperationUtils::AssetOpType DefaultOperation(const Asset &, const Assets &); @@ -53,6 +56,9 @@ private: static Assets GetAssets(const std::string &colName, const VBucket &rowData); static void MergeAssetFlag(const Assets &from, Asset &target); static void MergeAssetsFlag(const Assets &from, Type &target); + static void FillDownloadAssetIfNeed(const std::string &field, const Asset &asset, + std::map &beFilledAssets); + static bool IsFirstDownloadAsset(const Asset &asset); static constexpr uint32_t BIT_MASK_COUNT = 16; }; } diff --git a/kv_store/frameworks/libs/distributeddb/common/include/cloud/assets_download_manager.h b/kv_store/frameworks/libs/distributeddb/common/include/cloud/assets_download_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..3712226543e1a71b05284970cf76cde50211073f --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/common/include/cloud/assets_download_manager.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024 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 ASSETS_DOWNLOAD_MANAGER_H +#define ASSETS_DOWNLOAD_MANAGER_H + +#include "cloud/cloud_store_types.h" +#include "notification_chain.h" +#include "store_types.h" + +namespace DistributedDB { +class AssetsDownloadManager { +public: + AssetsDownloadManager(); + ~AssetsDownloadManager(); + + int SetAsyncDownloadAssetsConfig(const AsyncDownloadAssetsConfig &config); + + using FinishAction = std::function; + using FinalizeAction = std::function; + // try to add download count, add finish listener when out of limit + std::pair BeginDownloadWithListener(const FinishAction &finishAction, + const FinalizeAction &finalizeAction = nullptr); + + void FinishDownload(); + + uint32_t GetCurrentDownloadCount(); + + uint32_t GetMaxDownloadAssetsCount() const; + + bool CanStartNewTask() const; +private: + int InitNotificationChain(); + + static constexpr const int DOWNLOAD_FINISH_EVENT = 1; + mutable std::mutex notifyMutex_; + NotificationChain *notificationChain_; + + mutable std::mutex dataMutex_; + uint32_t currentDownloadCount_; + AsyncDownloadAssetsConfig config_; +}; +} +#endif // ASSETS_DOWNLOAD_MANAGER_H \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/common/include/cloud/cloud_db_constant.h b/kv_store/frameworks/libs/distributeddb/common/include/cloud/cloud_db_constant.h index 9ee39239948eb4f2204b28f813a2fbda1c4706fa..1b1a815c2218f297a0b2a1e3025a12565558677c 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/cloud/cloud_db_constant.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/cloud/cloud_db_constant.h @@ -88,6 +88,19 @@ public: static constexpr const int32_t MAX_UPLOAD_SIZE = 128 * 1024 * 1024; // 128M static constexpr const int32_t MIN_UPLOAD_SIZE = 1024; // 1024Bytes static constexpr const int32_t MIN_RETRY_CONFLICT_COUNTS = -1; // unlimited + + static constexpr const int32_t MAX_ASYNC_DOWNLOAD_TASK = 12; // max async download task in process + static constexpr const int32_t MIN_ASYNC_DOWNLOAD_TASK = 1; + static constexpr const int32_t MAX_ASYNC_DOWNLOAD_ASSETS = 2000; // max async download assets count in one batch + static constexpr const int32_t MIN_ASYNC_DOWNLOAD_ASSETS = 1; + + static constexpr const int32_t COMMON_TASK_PRIORITY_LEVEL = -1; + static constexpr const int32_t PRIORITY_TASK_DEFALUT_LEVEL = 0; + static constexpr const int32_t PRIORITY_TASK_MAX_LEVEL = 2; + static constexpr const int32_t MAX_CONDITIONS_SIZE = 100; + + static constexpr const uint32_t ON_CHANGE_TRACKER = 0x1; + static constexpr const uint32_t ON_CHANGE_P2P = 0x2; }; } // namespace DistributedDB #endif // CLOUD_DB_CONSTANT_H \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/common/include/db_common.h b/kv_store/frameworks/libs/distributeddb/common/include/db_common.h index 4158ab9ca27114fd399313dd6271580737345dd7..ce92782f7cf8835b026d84150db0396088745dbe 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/db_common.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/db_common.h @@ -156,6 +156,9 @@ public: static bool ConvertToUInt64(const std::string &str, uint64_t &value); static void RemoveDuplicateAssetsData(std::vector &assets); + + static std::set TransformToCaseInsensitive( + const std::vector &origin); private: static void InsertNodesByScore(const std::map> &graph, const std::vector &generateNodes, const std::map &scoreGraph, diff --git a/kv_store/frameworks/libs/distributeddb/common/include/db_constant.h b/kv_store/frameworks/libs/distributeddb/common/include/db_constant.h index b0576bf5ca80f309aa3a1ac5e27ae5ccf2576a55..a3f03e08389b87562f96de2977f4464c72273581 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/db_constant.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/db_constant.h @@ -22,7 +22,8 @@ namespace DistributedDB { class DBConstant { public: static constexpr const size_t MAX_KEY_SIZE = 1024; - static constexpr const size_t MAX_VALUE_SIZE = 4194304; + static constexpr const size_t MAX_VALUE_SIZE = 4 * 1024 * 1024; // 4M + static constexpr const size_t MAX_SET_VALUE_SIZE = 64 * 1024 * 1024; // 64M static constexpr const size_t MAX_BATCH_SIZE = 128; static constexpr const size_t MAX_DEV_LENGTH = 128; static constexpr const size_t MAX_TRANSACTION_KEY_VALUE_LENS = 512 * 1024 * 1024; // 512M @@ -47,7 +48,7 @@ public: static constexpr const uint32_t MAX_COLUMN = 32767; - static constexpr const int MAX_REMOTEDATA_SIZE = 4194304; // 4M. + static constexpr const int MAX_REMOTEDATA_SIZE = 4 * 1024 * 1024; // 4M. static constexpr const int DEFAULT_ITER_TIMES = 5000; @@ -166,7 +167,8 @@ public: static constexpr const char *LOG_TABLE_VERSION_5_5 = "5.05"; // add status field static constexpr const char *LOG_TABLE_VERSION_5_8 = "5.08"; // migrate cursor to meta table static constexpr const char *LOG_TABLE_VERSION_5_9 = "5.09"; // insert retains the old version - static constexpr const char *LOG_TABLE_VERSION_CURRENT = LOG_TABLE_VERSION_5_9; + static constexpr const char *LOG_TABLE_VERSION_5_10 = "5.10"; // retain downloading asset in update trigger + static constexpr const char *LOG_TABLE_VERSION_CURRENT = LOG_TABLE_VERSION_5_10; static const std::string LOG_TABLE_VERSION_KEY; @@ -180,7 +182,7 @@ public: static constexpr const int HASH_KEY_SIZE = 32; // size of SHA256_DIGEST_LENGTH - static constexpr const char *TABLE_IS_DROPPED = "table_is_dropped_"; + static constexpr const char *TABLE_WAS_DROPPED = "table_was_dropped_"; static constexpr const char *SQLITE_INNER_ROWID = "_rowid_"; static constexpr const int32_t DEFAULT_ROW_ID = -1; diff --git a/kv_store/frameworks/libs/distributeddb/common/include/db_errno.h b/kv_store/frameworks/libs/distributeddb/common/include/db_errno.h index 805da445d9d2f1826ece986229b8b8950148b7d9..c5a5cf2d406f09efd4e53463eee478f1006458fc 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/db_errno.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/db_errno.h @@ -151,6 +151,8 @@ constexpr const int E_WITH_INVENTORY_DATA = (E_BASE + 126); // inventory data ex constexpr const int E_WAIT_COMPENSATED_SYNC = (E_BASE + 127); // need to do compensated sync constexpr const int E_CLOUD_SYNC_TASK_MERGED = (E_BASE + 128); // sync task is merged constexpr const int E_SQLITE_CANT_OPEN = (E_BASE + 129); // the sqlite cannot open. +constexpr const int E_LOCAL_ASSET_NOT_FOUND = (E_BASE + 130); // local asset not found. +constexpr const int E_ASSET_NOT_FOUND_FOR_DOWN_ONLY = (E_BASE + 131); // asset not found for download asset only. // Num 150+ is reserved for schema related errno, since it may be added regularly constexpr const int E_JSON_PARSE_FAIL = (E_BASE + 150); // Parse json fail in grammatical level constexpr const int E_JSON_INSERT_PATH_EXIST = (E_BASE + 151); // Path already exist before insert @@ -185,6 +187,8 @@ constexpr const int E_FEEDBACK_COMMUNICATOR_NOT_FOUND = (E_BASE + 201); constexpr const int E_DISTRIBUTED_SCHEMA_NOT_FOUND = (E_BASE + 202); constexpr const int E_DISTRIBUTED_SCHEMA_CHANGED = (E_BASE + 203); // Schema has change when do sync constexpr const int E_TABLE_REFERENCE_CHANGED = (E_BASE + 204); // table reference is changed +constexpr const int E_CLOUD_DISABLED = (E_BASE + 205); // The cloud switch has been turned off +constexpr const int E_DISTRIBUTED_FIELD_DECREASE = (E_BASE + 206); // Sync fewer specified columns than last time } // namespace DistributedDB #endif // DISTRIBUTEDDB_ERRNO_H diff --git a/kv_store/frameworks/libs/distributeddb/common/include/db_types.h b/kv_store/frameworks/libs/distributeddb/common/include/db_types.h index e9f240d851eeb3c401912ed12df6c1f2f6c2ecf6..c6194dc628045e20ac306144212f49c0fd92f111 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/db_types.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/db_types.h @@ -158,12 +158,6 @@ enum class StorageType : int32_t { STORAGE_TYPE_BLOB }; -// Table mode of device data for relational store -enum DistributedTableMode : int { - COLLABORATION = 0, // Save all devices data in user table - SPLIT_BY_DEVICE // Save device data in each table split by device -}; - struct CaseInsensitiveComparator { bool operator() (const std::string& first, const std::string& second) const { diff --git a/kv_store/frameworks/libs/distributeddb/common/include/param_check_utils.h b/kv_store/frameworks/libs/distributeddb/common/include/param_check_utils.h index e217f55e1773d610850072acd464f6fc5f208ac2..2f2f324b1080dcff83cc3f33f67bcf0507763f93 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/param_check_utils.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/param_check_utils.h @@ -61,6 +61,8 @@ public: static bool CheckSharedTableName(const DataBaseSchema &schema); static void TransferSchemaToLower(DataBaseSchema &schema); + + static bool IsSchemaTablesEmpty(const DistributedSchema &schema); }; } // namespace DistributedDB #endif // PARAM_CHECK_UTILS_H diff --git a/kv_store/frameworks/libs/distributeddb/common/include/parcel.h b/kv_store/frameworks/libs/distributeddb/common/include/parcel.h index fb42ce19bb8be2a50974f78f6aa7bd4ee346f4b3..5e73b3ebbb967b5b9fa61ebd8b8640b8206e7112 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/parcel.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/parcel.h @@ -77,7 +77,8 @@ public: uint32_t len = data.size(); uint64_t stepLen = static_cast(data.size()) * sizeof(T) + sizeof(uint32_t); len = HostToNet(len); - if (bufPtr_ == nullptr || stepLen > INT32_MAX || parcelLen_ + BYTE_8_ALIGN(stepLen) > totalLen_) { + if (bufPtr_ == nullptr || stepLen > INT32_MAX || parcelLen_ + BYTE_8_ALIGN(stepLen) > totalLen_ || + parcelLen_ + sizeof(uint32_t) > totalLen_) { LOGE("[WriteVector] bufPtr:%d, stepLen:%llu, totalLen:%llu, parcelLen:%llu", bufPtr_ != nullptr, ULL(stepLen), ULL(totalLen_), ULL(parcelLen_)); isError_ = true; diff --git a/kv_store/frameworks/libs/distributeddb/common/include/relational/relational_schema_object.h b/kv_store/frameworks/libs/distributeddb/common/include/relational/relational_schema_object.h index 0014ffdbd556b6ac20d1a915c37e5bcc91aaae93..b47ffa2ddb6d0a4cd89e850a9d4d0c6eec6f1a5f 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/relational/relational_schema_object.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/relational/relational_schema_object.h @@ -66,6 +66,17 @@ public: std::set CompareReferenceProperty(const std::vector &others) const; std::map> GetReachableRef(); std::map GetTableWeight(); + + bool CheckDistributedSchemaChange(const DistributedSchema &schema); + void SetDistributedSchema(const DistributedSchema &schema); + DistributedSchema GetDistributedSchema() const; + + bool IsNeedSkipSyncField(const FieldInfo &fieldInfo, const std::string &tableName, + bool ignoreTableNonExist = true) const; + + std::vector GetSyncFieldInfo(const std::string &tableName, bool ignoreTableNonExist = true) const; + + DistributedTable GetDistributedTable(const std::string &table) const; private: int CompareAgainstSchemaObject(const std::string &inSchemaString, std::map &cmpRst) const; @@ -94,6 +105,9 @@ private: int ParseCheckReferenceColumns(const JsonObject &inJsonObject, TableReferenceProperty &tableReferenceProperty); // parse one reference column pair int ParseCheckReferenceColumn(const JsonObject &inJsonObject, TableReferenceProperty &tableReferenceProperty); + int ParseDistributedSchema(const JsonObject &inJsonObject); // parse distributed schema if need + int ParseDistributedTables(const JsonObject &inJsonObject); // parse distributed tables if need + int ParseDistributedTable(const JsonObject &inJsonObject); // parse distributed table if need void GenerateSchemaString(); void GenerateTrackerSchemaString(); @@ -110,6 +124,13 @@ private: void RefreshReachableRef(const TableReferenceProperty &referenceProperty); void CalculateTableWeight(const std::set &startNodes, const std::map> &nextNodes); + std::string GetDistributedSchemaString(); + + static bool CheckDistributedFieldChange(const std::vector &source, + const std::vector &target); + static std::string GetOneDistributedTableString(const DistributedTable &table); + static int ParseDistributedFields(const JsonObject &inJsonObject, std::vector &fields); + static int ParseDistributedField(const JsonObject &inJsonObject, DistributedField &field); bool isValid_ = false; // set to true after parse success from string or add at least one relational table SchemaType schemaType_ = SchemaType::RELATIVE; // Default RELATIVE @@ -120,6 +141,7 @@ private: std::vector referenceProperty_; std::map> reachableReference_; std::map tableWeight_; + DistributedSchema dbSchema_; DistributedTableMode tableMode_ = DistributedTableMode::SPLIT_BY_DEVICE; }; diff --git a/kv_store/frameworks/libs/distributeddb/common/include/relational/table_info.h b/kv_store/frameworks/libs/distributeddb/common/include/relational/table_info.h index 633243ab1216be080659e076aa445caf9a3e33a9..4b914602d735f16f06b432741f5effd16026a65e 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/relational/table_info.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/relational/table_info.h @@ -83,6 +83,7 @@ public: const FieldInfoMap &GetFields() const; // const IndexInfoMap &GetIndexDefine() const; const std::map &GetPrimaryKey() const; + bool IsPrimaryKey(const FieldName &fieldName) const; const std::vector &GetUniqueDefine() const; void SetTableName(const std::string &tableName); @@ -127,6 +128,13 @@ public: bool IsNoPkTable() const; + bool IsFieldExist(const std::string &fieldName) const; + + void SetDistributedTable(const DistributedTable &distributedTable); + + std::vector GetSyncField() const; + + std::vector GetSyncDistributedPk() const; private: void AddFieldDefineString(std::string &attrStr) const; void AddIndexDefineString(std::string &attrStr) const; @@ -154,6 +162,7 @@ private: std::vector uniqueDefines_; int id_ = -1; TrackerTable trackerTable_; + DistributedTable distributedTable_; // a // b c // d e f ,table_info[a] = {b,c} [b] = {d, e} [c] = {f} diff --git a/kv_store/frameworks/libs/distributeddb/common/include/runtime_context.h b/kv_store/frameworks/libs/distributeddb/common/include/runtime_context.h index e0a9851421a391efac29abf89d76263a21034034..0d1846681546d16e85a3f4b120ded4954437d2f9 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/runtime_context.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/runtime_context.h @@ -22,6 +22,7 @@ #include "auto_launch.h" #include "auto_launch_export.h" +#include "cloud/assets_download_manager.h" #include "cloud/icloud_data_translate.h" #include "db_info_handle.h" #include "icommunicator_aggregator.h" @@ -86,6 +87,8 @@ public: virtual int SetPermissionCheckCallback(const PermissionCheckCallbackV3 &callback) = 0; + virtual int SetPermissionCheckCallback(const PermissionCheckCallbackV4 &callback) = 0; + virtual int RunPermissionCheck(const PermissionCheckParam ¶m, uint8_t flag) const = 0; virtual int EnableKvStoreAutoLaunch(const KvDBProperties &properties, AutoLaunchNotifier notifier, @@ -119,8 +122,9 @@ public: virtual void SetStoreStatusNotifier(const StoreStatusNotifier ¬ifier) = 0; - virtual void NotifyDatabaseStatusChange(const std::string &userId, const std::string &appId, - const std::string &storeId, const std::string &deviceId, bool onlineStatus) = 0; + virtual void SetStoreStatusNotifier(const StoreStatusNotifierV2 ¬ifier) = 0; + + virtual void NotifyDatabaseStatusChange(const StoreStatusNotifierParam ¶m, bool onlineStatus) = 0; virtual int SetSyncActivationCheckCallback(const SyncActivationCheckCallback &callback) = 0; @@ -202,6 +206,8 @@ public: virtual bool IsBatchDownloadAssets() const = 0; virtual void SetBatchDownloadAssets(bool isBatchDownload) = 0; + + virtual std::shared_ptr GetAssetsDownloadManager() = 0; protected: RuntimeContext() = default; virtual ~RuntimeContext() {} diff --git a/kv_store/frameworks/libs/distributeddb/common/include/schema_constant.h b/kv_store/frameworks/libs/distributeddb/common/include/schema_constant.h index b71b96006a328fdc3d7c1fa918815baefc1931de..479a67fe113c5c67796b49c8d7fbd419201e18ee 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/schema_constant.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/schema_constant.h @@ -64,6 +64,14 @@ public: static constexpr const char *COLUMNS = "COLUMNS"; static constexpr const char *SOURCE_COL = "SOURCE_COL"; static constexpr const char *TARGET_COL = "TARGET_COL"; + static constexpr const char *KEYWORD_DISTRIBUTED_SCHEMA = "DISTRIBUTED_SCHEMA"; + static constexpr const char *KEYWORD_DISTRIBUTED_VERSION = "VERSION"; + static constexpr const char *KEYWORD_DISTRIBUTED_TABLE = "DISTRIBUTED_TABLE"; + static constexpr const char *KEYWORD_DISTRIBUTED_TABLE_NAME = "TABLE_NAME"; + static constexpr const char *KEYWORD_DISTRIBUTED_FIELD = "DISTRIBUTED_FIELD"; + static constexpr const char *KEYWORD_DISTRIBUTED_COL_NAME = "COL_NAME"; + static constexpr const char *KEYWORD_DISTRIBUTED_IS_P2P_SYNC = "IS_P2P_SYNC"; + static constexpr const char *KEYWORD_DISTRIBUTED_IS_SPECIFIED = "IS_SPECIFIED"; static const uint32_t SCHEMA_META_FEILD_COUNT_MAX; static const uint32_t SCHEMA_META_FEILD_COUNT_MIN; diff --git a/kv_store/frameworks/libs/distributeddb/common/include/schema_utils.h b/kv_store/frameworks/libs/distributeddb/common/include/schema_utils.h index dd6eb4a24272c3158d47e65a102d35d04a860d74..e1aec19db49141c9f0fe37b0ccee2bca502e0bd1 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/schema_utils.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/schema_utils.h @@ -53,6 +53,11 @@ public: static void TransTrackerSchemaToLower(const TrackerSchema &srcSchema, TrackerSchema &destSchema); + static int ExtractJsonObj(const JsonObject &inJsonObject, const std::string &field, JsonObject &out); + + static int ExtractJsonObjArray(const JsonObject &inJsonObject, const std::string &field, + std::vector &out); + SchemaUtils() = delete; ~SchemaUtils() = delete; diff --git a/kv_store/frameworks/libs/distributeddb/common/include/version.h b/kv_store/frameworks/libs/distributeddb/common/include/version.h index df8f0a016898fd2bcb47ec11a4e8652a873e9f92..ca9d5d1b10618cffd4f81826f109b58f0a7ecb15 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/version.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/version.h @@ -48,8 +48,10 @@ constexpr const uint32_t SOFTWARE_VERSION_RELEASE_8_0 = SOFTWARE_VERSION_BASE + constexpr const uint32_t SOFTWARE_VERSION_RELEASE_9_0 = SOFTWARE_VERSION_BASE + 9; // 9 for ninth released version // 110 version add totalDataCount field in DataRequestPkt constexpr const uint32_t SOFTWARE_VERSION_RELEASE_10_0 = SOFTWARE_VERSION_BASE + 10; // 10 for tenth released version +// 111 version record remote version and rdb sync with config column +constexpr const uint32_t SOFTWARE_VERSION_RELEASE_11_0 = SOFTWARE_VERSION_BASE + 11; // 11 for tenth released version constexpr const uint32_t SOFTWARE_VERSION_EARLIEST = SOFTWARE_VERSION_RELEASE_1_0; -constexpr const uint32_t SOFTWARE_VERSION_CURRENT = SOFTWARE_VERSION_RELEASE_10_0; +constexpr const uint32_t SOFTWARE_VERSION_CURRENT = SOFTWARE_VERSION_RELEASE_11_0; constexpr const int VERSION_INVALID = INT32_MAX; // Storage Related Version diff --git a/kv_store/frameworks/libs/distributeddb/common/src/auto_launch.cpp b/kv_store/frameworks/libs/distributeddb/common/src/auto_launch.cpp index 141d71dd3a9475ae0f5241cd765215a79a8fb7cf..27721a640a8757b67514926f2cd35af713664f5b 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/auto_launch.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/auto_launch.cpp @@ -193,11 +193,24 @@ int AutoLaunch::EnableKvStoreAutoLaunch(const KvDBProperties &properties, AutoLa return errCode; } +void AutoLaunch::GetKVConnectionInEnableInner(const AutoLaunchItem &autoLaunchItem, const std::string &identifier, + const std::string &userId) +{ + std::lock_guard autoLock(dataLock_); + autoLaunchItemMap_[identifier][userId].state = AutoLaunchItemState::IDLE; + autoLaunchItemMap_[identifier][userId].conn = autoLaunchItem.conn; + autoLaunchItemMap_[identifier][userId].observerHandle = autoLaunchItem.observerHandle; +} + int AutoLaunch::GetKVConnectionInEnable(AutoLaunchItem &autoLaunchItem, const std::string &identifier) { LOGI("[AutoLaunch] GetKVConnectionInEnable"); int errCode; std::shared_ptr properties = std::static_pointer_cast(autoLaunchItem.propertiesPtr); + if (properties == nullptr) { + LOGE("[AutoLaunch] GetKVConnectionInEnable properties is nullptr"); + return -E_INTERNAL_ERROR; + } std::string userId = properties->GetStringProp(KvDBProperties::USER_ID, ""); autoLaunchItem.conn = KvDBManager::GetDatabaseConnection(*properties, errCode, false); if (errCode == -E_ALREADY_OPENED) { @@ -230,10 +243,7 @@ int AutoLaunch::GetKVConnectionInEnable(AutoLaunchItem &autoLaunchItem, const st } errCode = RegisterObserverAndLifeCycleCallback(autoLaunchItem, identifier, false); if (errCode == E_OK) { - std::lock_guard autoLock(dataLock_); - autoLaunchItemMap_[identifier][userId].state = AutoLaunchItemState::IDLE; - autoLaunchItemMap_[identifier][userId].conn = autoLaunchItem.conn; - autoLaunchItemMap_[identifier][userId].observerHandle = autoLaunchItem.observerHandle; + GetKVConnectionInEnableInner(autoLaunchItem, identifier, userId); } else { LOGE("[AutoLaunch] GetKVConnectionInEnable RegisterObserverAndLifeCycleCallback err, do CloseConnection"); TryCloseConnection(autoLaunchItem); // do nothing if failed @@ -1037,7 +1047,7 @@ int AutoLaunch::GetAutoLaunchKVProperties(const AutoLaunchParam ¶m, propertiesPtr->SetBoolProp(KvDBProperties::SYNC_DUAL_TUPLE_MODE, param.option.syncDualTupleMode); propertiesPtr->SetBoolProp(KvDBProperties::READ_ONLY_MODE, false); propertiesPtr->SetBoolProp(KvDBProperties::SHARED_MODE, false); - DbIdParam dbIdParam = { param.appId, param.userId, param.storeId }; + DbIdParam dbIdParam = { param.appId, param.userId, param.storeId, param.subUser }; DBCommon::SetDatabaseIds(*propertiesPtr, dbIdParam); return E_OK; } @@ -1045,13 +1055,15 @@ int AutoLaunch::GetAutoLaunchKVProperties(const AutoLaunchParam ¶m, int AutoLaunch::GetAutoLaunchRelationProperties(const AutoLaunchParam ¶m, const std::shared_ptr &propertiesPtr) { - if (!ParamCheckUtils::CheckStoreParameter({param.storeId, param.appId, param.userId}, false, "", true)) { + if (!ParamCheckUtils::CheckStoreParameter({param.userId, param.appId, param.storeId}, + false, param.subUser, true)) { LOGE("[AutoLaunch] CheckStoreParameter is invalid."); return -E_INVALID_ARGS; } propertiesPtr->SetStringProp(RelationalDBProperties::DATA_DIR, param.path); - propertiesPtr->SetIdentifier(param.userId, param.appId, param.storeId); + propertiesPtr->SetIdentifier(param.userId, param.appId, param.storeId, param.subUser); propertiesPtr->SetBoolProp(RelationalDBProperties::SYNC_DUAL_TUPLE_MODE, param.option.syncDualTupleMode); + propertiesPtr->SetIntProp(RelationalDBProperties::DISTRIBUTED_TABLE_MODE, static_cast(param.option.tableMode)); if (param.option.isEncryptedDb) { if (!ParamCheckUtils::CheckEncryptedParameter(param.option.cipher, param.option.passwd) || param.option.iterateTimes == 0) { @@ -1298,11 +1310,10 @@ int AutoLaunch::RegisterRelationalObserver(AutoLaunchItem &autoLaunchItem, const } RelationalStoreConnection *conn = static_cast(autoLaunchItem.conn); (void)conn->RegisterObserverAction(autoLaunchItem.storeObserver, [this, autoLaunchItem, identifier]( - const std::string &changedDevice, ChangedData &&changedData, bool isChangedData) { + const std::string &changedDevice, ChangedData &&changedData, bool isChangedData, Origin origin) { if (isChangedData && autoLaunchItem.storeObserver) { LOGD("begin to observer on changed data"); - autoLaunchItem.storeObserver->OnChange( - Origin::ORIGIN_CLOUD, changedDevice, std::move(changedData)); + autoLaunchItem.storeObserver->OnChange(origin, changedDevice, std::move(changedData)); return; } std::string userId; diff --git a/kv_store/frameworks/libs/distributeddb/common/src/cloud/asset_operation_utils.cpp b/kv_store/frameworks/libs/distributeddb/common/src/cloud/asset_operation_utils.cpp index 97f26ffa95d6ffcc0de50e407eaed4a2d8406e58..e6407cb23e8d71f7369ad4fa7a87ccf290540d18 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/cloud/asset_operation_utils.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/cloud/asset_operation_utils.cpp @@ -255,4 +255,63 @@ void AssetOperationUtils::MergeAssetsFlag(const Assets &from, Type &target) } } } + +std::map AssetOperationUtils::FilterNeedDownloadAsset(VBucket &record) +{ + std::map res; + for (const auto &[field, value] : record) { + if (value.index() != TYPE_INDEX && value.index() != TYPE_INDEX) { + continue; + } + if (value.index() == TYPE_INDEX) { + Assets assets = std::get(value); + for (const auto &asset : assets) { + FillDownloadAssetIfNeed(field, asset, res); + } + } else { + Asset asset = std::get(value); + FillDownloadAssetIfNeed(field, asset, res); + } + } + return res; +} + +void AssetOperationUtils::FillDownloadAssetIfNeed(const std::string &field, const Asset &asset, + std::map &beFilledAssets) +{ + if (!IsAssetNeedDownload(asset)) { + return; + } + Asset tempAsset = asset; + if (IsFirstDownloadAsset(asset)) { + tempAsset.flag = static_cast(DistributedDB::AssetOpType::INSERT); + tempAsset.status = static_cast(DistributedDB::AssetStatus::INSERT); + } else { + tempAsset.flag = static_cast(DistributedDB::AssetOpType::UPDATE); + tempAsset.status = static_cast(DistributedDB::AssetStatus::UPDATE); + } + beFilledAssets[field].push_back(tempAsset); +} + +bool AssetOperationUtils::IsAssetNeedDownload(const Asset &asset) +{ + auto rawStatus = AssetOperationUtils::EraseBitMask(asset.status); + return rawStatus == static_cast(AssetStatus::ABNORMAL) || + rawStatus == static_cast(AssetStatus::DOWNLOADING); +} + +bool AssetOperationUtils::IsAssetsNeedDownload(const Assets &assets) +{ + for (const Asset &asset: assets) { + if (AssetOperationUtils::IsAssetNeedDownload(asset)) { + return true; + } + } + return false; +} + +bool AssetOperationUtils::IsFirstDownloadAsset(const Asset &asset) +{ + return (asset.status & static_cast(AssetStatus::DOWNLOAD_WITH_NULL)) != 0; +} } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/common/src/cloud/assets_download_manager.cpp b/kv_store/frameworks/libs/distributeddb/common/src/cloud/assets_download_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1f3ad794474f417d5e6f4337f68716ea8679c706 --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/common/src/cloud/assets_download_manager.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2024 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 "cloud/assets_download_manager.h" + +#include "cloud/cloud_db_constant.h" +#include "db_errno.h" +#include "log_print.h" +namespace DistributedDB { +AssetsDownloadManager::AssetsDownloadManager() + : notificationChain_(nullptr), currentDownloadCount_(0) +{ +} + +AssetsDownloadManager::~AssetsDownloadManager() +{ + NotificationChain *notificationChain = nullptr; + { + std::lock_guard autoLock(notifyMutex_); + if (notificationChain_ == nullptr) { + return; + } + notificationChain = notificationChain_; + notificationChain_ = nullptr; + } + RefObject::KillAndDecObjRef(notificationChain); +} + +int AssetsDownloadManager::SetAsyncDownloadAssetsConfig(const AsyncDownloadAssetsConfig &config) +{ + if (config.maxDownloadTask < CloudDbConstant::MIN_ASYNC_DOWNLOAD_TASK || + config.maxDownloadTask > CloudDbConstant::MAX_ASYNC_DOWNLOAD_TASK) { + LOGE("[AssetsDownloadManager] Invalid max download task %" PRIu32, config.maxDownloadTask); + return -E_INVALID_ARGS; + } + if (config.maxDownloadAssetsCount < CloudDbConstant::MIN_ASYNC_DOWNLOAD_ASSETS || + config.maxDownloadAssetsCount > CloudDbConstant::MAX_ASYNC_DOWNLOAD_ASSETS) { + LOGE("[AssetsDownloadManager] Invalid max download asset count %" PRIu32, config.maxDownloadAssetsCount); + return -E_INVALID_ARGS; + } + std::lock_guard autoLock(dataMutex_); + config_ = config; + LOGI("[AssetsDownloadManager] Config max task %" PRIu32 " max count %" PRIu32, + config.maxDownloadTask, config.maxDownloadAssetsCount); + return E_OK; +} + +std::pair AssetsDownloadManager::BeginDownloadWithListener( + const FinishAction &finishAction, const FinalizeAction &finalizeAction) +{ + std::lock_guard autoLock(dataMutex_); + if (currentDownloadCount_ < config_.maxDownloadTask) { + currentDownloadCount_++; + LOGI("[AssetsDownloadManager] Begin download task now %" PRIu32, currentDownloadCount_); + return {E_OK, nullptr}; + } + LOGW("[AssetsDownloadManager] Too muck download task now %" PRIu32, currentDownloadCount_); + NotificationChain *notificationChain = nullptr; + int errCode = E_OK; + { + std::lock_guard notifyLock(notifyMutex_); + errCode = InitNotificationChain(); + if (errCode != E_OK) { + return {errCode, nullptr}; + } + notificationChain = notificationChain_; + RefObject::IncObjRef(notificationChain); + } + NotificationChain::Listener *listener = + notificationChain->RegisterListener(DOWNLOAD_FINISH_EVENT, finishAction, finalizeAction, errCode); + RefObject::DecObjRef(notificationChain); + if (errCode != E_OK) { + LOGW("[AssetsDownloadManager] Register listener failed %d", errCode); + } else { + errCode = -E_MAX_LIMITS; + } + return {errCode, listener}; +} + +void AssetsDownloadManager::FinishDownload() +{ + NotificationChain *notificationChain = nullptr; + { + std::lock_guard autoLock(notifyMutex_); + notificationChain = notificationChain_; + RefObject::IncObjRef(notificationChain); + } + { + std::lock_guard autoLock(dataMutex_); + currentDownloadCount_--; + } + if (notificationChain != nullptr) { + notificationChain->NotifyEvent(DOWNLOAD_FINISH_EVENT, nullptr); + } + RefObject::DecObjRef(notificationChain); + LOGI("[AssetsDownloadManager] NotifyDownloadFinish currentDownloadCount %" PRIu32, currentDownloadCount_); +} + +uint32_t AssetsDownloadManager::GetCurrentDownloadCount() +{ + std::lock_guard autoLock(dataMutex_); + return currentDownloadCount_; +} + +uint32_t AssetsDownloadManager::GetMaxDownloadAssetsCount() const +{ + std::lock_guard autoLock(dataMutex_); + return config_.maxDownloadAssetsCount; +} + +bool AssetsDownloadManager::CanStartNewTask() const +{ + std::lock_guard autoLock(dataMutex_); + return config_.maxDownloadTask > currentDownloadCount_; +} + +int AssetsDownloadManager::InitNotificationChain() +{ + if (notificationChain_ != nullptr) { + return E_OK; + } + notificationChain_ = new(std::nothrow) NotificationChain(); + if (notificationChain_ == nullptr) { + LOGE("[AssetsDownloadManager] create notification chain failed %d", errno); + return -E_OUT_OF_MEMORY; + } + int errCode = notificationChain_->RegisterEventType(DOWNLOAD_FINISH_EVENT); + if (errCode != E_OK) { + LOGE("[AssetsDownloadManager] register even type failed %d", errCode); + RefObject::KillAndDecObjRef(notificationChain_); + notificationChain_ = nullptr; + } + return errCode; +} +} \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/common/src/data_value.cpp b/kv_store/frameworks/libs/distributeddb/common/src/data_value.cpp index bc2861218ea40c29678f91f0338630bdb8acf985..df78c44763fa354c09c0efe2688948779c848614 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/data_value.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/data_value.cpp @@ -303,6 +303,9 @@ int DataValue::GetText(std::string &outValue) const if (type_ != StorageType::STORAGE_TYPE_TEXT) { return -E_NOT_SUPPORT; } + if (value_.blobPtr == nullptr) { + return -E_OUT_OF_MEMORY; + } const uint8_t *data = value_.blobPtr->GetData(); uint32_t len = value_.blobPtr->GetSize(); if (len == 0) { diff --git a/kv_store/frameworks/libs/distributeddb/common/src/db_common.cpp b/kv_store/frameworks/libs/distributeddb/common/src/db_common.cpp index 5caa2b80fea2f4811599b28aea24b90d66b71621..4f5c51f5336691b430865919be6753bf0159ac38 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/db_common.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/db_common.cpp @@ -875,4 +875,14 @@ void DBCommon::RemoveDuplicateAssetsData(std::vector &assets) arrIndex++; } } + +std::set DBCommon::TransformToCaseInsensitive( + const std::vector &origin) +{ + std::set res; + for (const auto &item : origin) { + res.insert(item); + } + return res; +} } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/common/src/evloop/src/event_impl.cpp b/kv_store/frameworks/libs/distributeddb/common/src/evloop/src/event_impl.cpp index 3fddc42b6514bb87e90096c099e7167b9a42f061..e17b3bc239c4e4c03a4733d2c5b065ade5479d78 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/evloop/src/event_impl.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/evloop/src/event_impl.cpp @@ -76,7 +76,7 @@ EventImpl::EventImpl(const EventFd &fd, EventsMask events, EventTime timeout) EventImpl::~EventImpl() { if (loop_ != nullptr) { - loop_->DecObjRef(loop_); + RefObject::DecObjRef(loop_); loop_ = nullptr; } if (fd_.IsValid()) { @@ -118,11 +118,11 @@ int EventImpl::AddEvents(EventsMask events) return E_OK; } loop = loop_; - loop->IncObjRef(loop); + RefObject::IncObjRef(loop); } int errCode = loop->Modify(this, true, events); - loop->DecObjRef(loop); + RefObject::DecObjRef(loop); if (errCode != E_OK) { LOGE("ev add events failed, err: '%d'.", errCode); } @@ -149,11 +149,11 @@ int EventImpl::RemoveEvents(EventsMask events) return E_OK; } loop = loop_; - loop->IncObjRef(loop); + RefObject::IncObjRef(loop); } int errCode = loop->Modify(this, false, events); - loop->DecObjRef(loop); + RefObject::DecObjRef(loop); if (errCode != E_OK) { LOGE("ev remove events failed, err: '%d'.", errCode); } @@ -174,11 +174,11 @@ int EventImpl::SetTimeout(EventTime timeout) return E_OK; } loop = loop_; - loop->IncObjRef(loop); + RefObject::IncObjRef(loop); } int errCode = loop->Modify(this, timeout); - loop->DecObjRef(loop); + RefObject::DecObjRef(loop); if (errCode != E_OK) { LOGE("ev set timeout failed, err: '%d'.", errCode); } @@ -194,7 +194,7 @@ int EventImpl::Detach(bool wait) return E_OK; } loop = loop_; - loop->IncObjRef(loop); + RefObject::IncObjRef(loop); } int errCode = loop->Remove(this); @@ -207,11 +207,11 @@ int EventImpl::Detach(bool wait) if (!loop->IsInLoopThread(started)) { Wait(); } - loop->DecObjRef(loop); + RefObject::DecObjRef(loop); return E_OK; } - loop->DecObjRef(loop); + RefObject::DecObjRef(loop); return errCode; } @@ -257,14 +257,14 @@ bool EventImpl::SetLoop(EventLoopImpl *loop) RefObject::AutoLock lockGuard(this); if (loop == nullptr) { if (loop_ != nullptr) { - loop_->DecObjRef(loop_); + RefObject::DecObjRef(loop_); loop_ = nullptr; } detached_.notify_one(); return true; } if (loop_ == nullptr) { - loop->IncObjRef(loop); + RefObject::IncObjRef(loop); loop_ = loop; return true; } diff --git a/kv_store/frameworks/libs/distributeddb/common/src/evloop/src/event_loop_impl.cpp b/kv_store/frameworks/libs/distributeddb/common/src/evloop/src/event_loop_impl.cpp index e8c8fa8baa526516470c076c09f4566dd6e2249f..4e4c4145d189d5b349507953b06b6e1c0f92b143 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/evloop/src/event_loop_impl.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/evloop/src/event_loop_impl.cpp @@ -39,7 +39,7 @@ public: timeout_(0) { if (event != nullptr) { - event->IncObjRef(event); + RefObject::IncObjRef(event); } } @@ -50,14 +50,14 @@ public: timeout_(timeout) { if (event != nullptr) { - event->IncObjRef(event); + RefObject::IncObjRef(event); } } ~EventRequest() { if (event_ != nullptr) { - event_->DecObjRef(event_); + RefObject::DecObjRef(event_); event_ = nullptr; } } @@ -351,7 +351,7 @@ int EventLoopImpl::AddEventObject(EventImpl *event, EventTime now) polling_.insert(event); event->SetStartTime(now); event->SetRevents(0); - event->IncObjRef(event); + RefObject::IncObjRef(event); pollingSetChanged_ = true; } else { LOGE("Add event failed. err: '%d'.", errCode); @@ -376,7 +376,7 @@ int EventLoopImpl::RemoveEventObject(EventImpl *event) if (errCode == E_OK) { polling_.erase(event); event->SetLoop(nullptr); - event->DecObjRef(event); + RefObject::DecObjRef(event); pollingSetChanged_ = true; } else { LOGE("Remove event failed. err: '%d'.", errCode); @@ -534,7 +534,7 @@ int EventLoopImpl::DispatchAll() continue; } - event->IncObjRef(event); + RefObject::IncObjRef(event); event->UpdateElapsedTime(now); int errCode = event->Dispatch(); if (errCode != E_OK) { @@ -542,7 +542,7 @@ int EventLoopImpl::DispatchAll() } else { event->SetRevents(0); } - event->DecObjRef(event); + RefObject::DecObjRef(event); if (pollingSetChanged_) { break; diff --git a/kv_store/frameworks/libs/distributeddb/common/src/json_object.cpp b/kv_store/frameworks/libs/distributeddb/common/src/json_object.cpp index 252459f76d3bfd3a6828dedc8a95c933e2e52ad4..49c9616c6e0d89223332a4781d9915406eae8193 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/json_object.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/json_object.cpp @@ -46,7 +46,11 @@ uint32_t JsonObject::SetMaxNestDepth(uint32_t nestDepth) uint32_t JsonObject::CalculateNestDepth(const std::string &inString, int &errCode) { - auto begin = reinterpret_cast(inString.c_str()); + std::vector bytes; + for (auto it = inString.begin(); it != inString.end(); ++it) { + bytes.push_back(static_cast(*it)); + } + const uint8_t *begin = bytes.data(); auto end = begin + inString.size(); return CalculateNestDepth(begin, end, errCode); } @@ -421,7 +425,7 @@ int JsonObject::GetArrayContentOfStringOrStringArray(const FieldPath &inPath, LOGE("[Json][GetArrayContent] Not an array."); return -E_NOT_SUPPORT; } - if (valueNode.size() > DBConstant::MAX_VALUE_SIZE) { + if (valueNode.size() > DBConstant::MAX_SET_VALUE_SIZE) { LOGE("[Json][GetArrayContent] Exceeds max value size."); return -E_NOT_SUPPORT; } @@ -605,7 +609,7 @@ int JsonObject::GetStringArrayContentByJsonValue(const Json::Value &value, LOGE("[Json][GetStringArrayByValue] Not an array."); return -E_NOT_SUPPORT; } - if (value.size() > DBConstant::MAX_VALUE_SIZE) { + if (value.size() > DBConstant::MAX_SET_VALUE_SIZE) { LOGE("[Json][GetStringArrayByValue] Exceeds max value size."); return -E_NOT_SUPPORT; } @@ -686,6 +690,10 @@ const Json::Value &JsonObject::GetJsonValueByFieldPath(const FieldPath &inPath, return value_; } const Json::Value *valueNode = &value_; + if (valueNode == nullptr) { + errCode = -E_INVALID_PATH; + return value_; + } for (const auto &eachPathSegment : inPath) { if ((valueNode->type() != Json::ValueType::objectValue) || (!valueNode->isMember(eachPathSegment))) { // Current JsonValue is not an object, or no such member field @@ -746,7 +754,7 @@ int JsonObject::GetObjectArrayByFieldPath(const FieldPath &inPath, std::vector DBConstant::MAX_VALUE_SIZE) { + if (valueNode.size() > DBConstant::MAX_SET_VALUE_SIZE) { LOGE("[Json][GetValue] Exceeds max value size."); return -E_NOT_PERMIT; } diff --git a/kv_store/frameworks/libs/distributeddb/common/src/notification_chain.cpp b/kv_store/frameworks/libs/distributeddb/common/src/notification_chain.cpp index c9d9870bcb55f46a5797e12f890d488aacd411bb..153dd58116d40b77cc370ce8e2657d10959841e7 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/notification_chain.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/notification_chain.cpp @@ -43,7 +43,7 @@ NotificationChain::Listener *NotificationChain::RegisterListener( NotificationChain::Listener *listener = new (std::nothrow) NotificationChain::Listener(onEvent, onFinalize); if (listener == nullptr) { - listenerChain->DecObjRef(listenerChain); + RefObject::DecObjRef(listenerChain); listenerChain = nullptr; errCode = -E_OUT_OF_MEMORY; return nullptr; @@ -52,14 +52,14 @@ NotificationChain::Listener *NotificationChain::RegisterListener( errCode = listenerChain->RegisterListener(listener); if (errCode != E_OK) { LOGE("[NotificationChain] Register listener failed, event type %u has been unregistered!", type); - listener->DecObjRef(listener); + RefObject::DecObjRef(listener); listener = nullptr; - listenerChain->DecObjRef(listenerChain); + RefObject::DecObjRef(listenerChain); listenerChain = nullptr; return nullptr; } - listenerChain->DecObjRef(listenerChain); + RefObject::DecObjRef(listenerChain); listenerChain = nullptr; return listener; } @@ -118,7 +118,7 @@ void NotificationChain::NotifyEvent(EventType type, void *arg) return; } listenerChain->NotifyListeners(arg); - listenerChain->DecObjRef(listenerChain); + RefObject::DecObjRef(listenerChain); listenerChain = nullptr; } @@ -144,7 +144,7 @@ NotificationChain::ListenerChain *NotificationChain::FindAndGetListenerChainLock if (listenerChain == nullptr) { return nullptr; } - listenerChain->IncObjRef(listenerChain); + RefObject::IncObjRef(listenerChain); return listenerChain; } @@ -217,7 +217,7 @@ void NotificationChain::ListenerChain::NotifyListeners(void *arg) for (auto listener : tmpSet) { if (listener != nullptr) { listener->NotifyListener(arg); - listener->DecObjRef(listener); + RefObject::DecObjRef(listener); listener = nullptr; } } @@ -308,11 +308,11 @@ void NotificationChain::Listener::KillWait() void NotificationChain::Listener::SetOwner(ListenerChain *listenerChain) { if (listenerChain_ != nullptr) { - listenerChain_->DecObjRef(listenerChain_); + RefObject::DecObjRef(listenerChain_); } listenerChain_ = listenerChain; if (listenerChain_ != nullptr) { - listenerChain_->IncObjRef(listenerChain_); + RefObject::IncObjRef(listenerChain_); } } diff --git a/kv_store/frameworks/libs/distributeddb/common/src/param_check_utils.cpp b/kv_store/frameworks/libs/distributeddb/common/src/param_check_utils.cpp index f4e73096108716789b81928c3e1b47ae00436b62..5fdf237a6473752a137c6151ccd77bc62fc78bb3 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/param_check_utils.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/param_check_utils.cpp @@ -314,4 +314,17 @@ void ParamCheckUtils::TransferSchemaToLower(DataBaseSchema &schema) } } } + +bool ParamCheckUtils::IsSchemaTablesEmpty(const DistributedSchema &schema) +{ + if (schema.tables.empty()) { + return true; + } + for (auto &tableSchema : schema.tables) { + if (tableSchema.fields.empty()) { + return true; + } + } + return false; +} } // namespace DistributedDB \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/common/src/parcel.cpp b/kv_store/frameworks/libs/distributeddb/common/src/parcel.cpp index 844d7253ca1d97c90676ba6fe7cbb47263d5073d..a54047d7d963cd94c24d90fa5d26eb942819f358 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/parcel.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/parcel.cpp @@ -168,6 +168,9 @@ int Parcel::WriteString(const std::string &inVal) isError_ = true; return -E_PARSE_FAIL; } + if (bufPtr_ == nullptr) { + return -E_PARSE_FAIL; + } errno_t errCode = memcpy_s(bufPtr_, totalLen_ - parcelLen_, &len, sizeof(uint32_t)); if (errCode != EOK) { LOGE("[WriteString] bufPtr:%d, totalLen:%" PRIu64 ", parcelLen:%" PRIu64, bufPtr_ != nullptr, totalLen_, @@ -471,11 +474,13 @@ uint32_t Parcel::GetVectorCharLen(const std::vector &data) uint32_t Parcel::GetStringLen(const std::string &data) { if (data.size() > INT32_MAX) { + LOGE("GetStringLen data size is too large"); return 0; } uint64_t len = sizeof(uint32_t) + static_cast(data.size()); len = BYTE_8_ALIGN(len); if (len > INT32_MAX) { + LOGE("GetStringLen byte 8 align len is too large"); return 0; } return static_cast(len); diff --git a/kv_store/frameworks/libs/distributeddb/common/src/query.cpp b/kv_store/frameworks/libs/distributeddb/common/src/query.cpp index 9333c61e281616cede257c4f4bd5b074772c5b3c..c7aa6711e8662fde0e1a871ffae25e63867ab14b 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/query.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/query.cpp @@ -73,6 +73,12 @@ Query &Query::Range(const std::vector &keyBegin, const std::vector &keyBegin, cons endKey_ = keyEnd; } +void QueryExpression::QueryAssetsOnly(const AssetsMap &assets) +{ + isAssetsOnly_ = true; + if (useFromTable_) { + expressions_[fromTable_].QueryAssetsOnly(assets); + validStatusForAssetsOnly_ = expressions_[fromTable_].GetExpressionStatusForAssetsOnly(); + return; + } + if (queryInfo_.empty()) { + LOGE("[QueryExpression] the QueryAssetsOnly option must be connected with And."); + validStatusForAssetsOnly_ = -E_INVALID_ARGS; + return; + } else if (queryInfo_.back().operFlag != QueryObjType::AND) { + LOGE("[QueryExpression] the QueryAssetsOnly option must be connected with And."); + validStatusForAssetsOnly_ = -E_INVALID_ARGS; + return; + } else { + queryInfo_.pop_back(); + } + if (assetsGroupMap_.find(groupNum_) != assetsGroupMap_.end()) { + LOGE("[QueryExpression]assets only already set!"); + validStatusForAssetsOnly_ = -E_INVALID_ARGS; + return; + } + if (assets.empty()) { + LOGE("[QueryExpression]assets map can not be empty!"); + validStatusForAssetsOnly_ = -E_INVALID_ARGS; + return; + } + for (const auto &item : assets) { + if (item.second.empty() && item.first.empty()) { + LOGE("[QueryExpression]assets filed or asset name can not be empty!"); + validStatusForAssetsOnly_ = -E_INVALID_ARGS; + return; + } + } + assetsGroupMap_[groupNum_] = assets; + for (uint32_t i = 0; i <= groupNum_; i++) { + if (assetsGroupMap_.find(i) == assetsGroupMap_.end()) { + LOGE("[QueryExpression]asset group " PRIu32 " not found, may be AssetsOnly interface use in wrong way.", i); + validStatusForAssetsOnly_ = -E_INVALID_ARGS; + return; + } + } +} + void QueryExpression::QueryBySuggestIndex(const std::string &indexName) { if (useFromTable_) { @@ -303,6 +349,12 @@ void QueryExpression::BeginGroup() expressions_[fromTable_].BeginGroup(); return; } + if (isAssetsOnly_) { + auto iter = queryInfo_.rbegin(); + if (iter != queryInfo_.rend() && (*iter).operFlag != QueryObjType::OR) { + validStatusForAssetsOnly_ = -E_INVALID_ARGS; + } + } SetNotSupportIfFromTables(); queryInfo_.emplace_back(QueryObjNode{QueryObjType::BEGIN_GROUP, std::string(), QueryValueType::VALUE_TYPE_NULL, std::vector()}); @@ -315,6 +367,7 @@ void QueryExpression::EndGroup() return; } SetNotSupportIfFromTables(); + groupNum_++; queryInfo_.emplace_back(QueryObjNode{QueryObjType::END_GROUP, std::string(), QueryValueType::VALUE_TYPE_NULL, std::vector()}); } @@ -404,6 +457,11 @@ int QueryExpression::GetExpressionStatus() const return validStatus_; } +int QueryExpression::GetExpressionStatusForAssetsOnly() const +{ + return validStatusForAssetsOnly_; +} + std::vector QueryExpression::GetQueryExpressions() const { if (!useFromTable_) { @@ -474,4 +532,19 @@ int QueryExpression::RangeParamCheck() const } return E_OK; } + +bool QueryExpression::IsAssetsOnly() const +{ + return isAssetsOnly_; +} + +AssetsGroupMap QueryExpression::GetAssetsOnlyGroupMap() const +{ + return assetsGroupMap_; +} + +uint32_t QueryExpression::GetGroupNum() const +{ + return groupNum_; +} } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/common/src/relational/relational_schema_object.cpp b/kv_store/frameworks/libs/distributeddb/common/src/relational/relational_schema_object.cpp index fb3100c07e581f83f3224b22f29158e38bc7a7f5..ac64289070f163f63a3304f7390b301da0630474 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/relational/relational_schema_object.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/relational/relational_schema_object.cpp @@ -89,6 +89,7 @@ void RelationalSchemaObject::GenerateSchemaString() } schemaString_ += R"(])"; schemaString_ += GetReferencePropertyString(); + schemaString_ += GetDistributedSchemaString(); schemaString_ += "}"; } @@ -471,11 +472,12 @@ int RelationalSchemaObject::ParseCheckTrackerExtendName(const JsonObject &inJson if (errCode == E_OK) { // LCOV_EXCL_BR_LINE if (!DBCommon::CheckIsAlnumOrUnderscore(fieldValue.stringValue)) { // LCOV_EXCL_BR_LINE LOGE("[RelationalSchema][Parse] Invalid characters in extend name, err=%d.", errCode); - } else { + return -E_SCHEMA_PARSE_FAIL; + } else if (!fieldValue.stringValue.empty()) { resultTable.SetExtendName(fieldValue.stringValue); resultTable.SetExtendNames({fieldValue.stringValue}); - return E_OK; } + return E_OK; } LOGE("[RelationalSchema][Parse] Get extend col names fieldType failed: %d.", errCode); return -E_SCHEMA_PARSE_FAIL; @@ -556,7 +558,11 @@ int RelationalSchemaObject::ParseRelationalSchema(const JsonObject &inJsonObject if (errCode != E_OK) { return errCode; } - return ParseCheckReferenceProperty(inJsonObject); + errCode = ParseCheckReferenceProperty(inJsonObject); + if (errCode != E_OK) { + return errCode; + } + return ParseDistributedSchema(inJsonObject); } namespace { @@ -631,7 +637,7 @@ int RelationalSchemaObject::ParseCheckTableMode(const JsonObject &inJsonObject) } tableMode_ = SchemaUtils::Strip(fieldValue.stringValue) == SchemaConstant::KEYWORD_TABLE_SPLIT_DEVICE ? - DistributedDB::SPLIT_BY_DEVICE : DistributedTableMode::COLLABORATION; + DistributedTableMode::SPLIT_BY_DEVICE : DistributedTableMode::COLLABORATION; return E_OK; } @@ -1166,5 +1172,316 @@ int RelationalSchemaObject::ParseCheckTrackerAction(const JsonObject &inJsonObje } return errCode; } + +bool RelationalSchemaObject::CheckDistributedSchemaChange(const DistributedSchema &schema) +{ + if (schema.version != dbSchema_.version) { + return true; + } + std::map, CaseInsensitiveComparator> tableSchema; + for (const auto &table : dbSchema_.tables) { + tableSchema[table.tableName] = table.fields; + } + if (tableSchema.size() != schema.tables.size()) { + return true; + } + for (const auto &table : schema.tables) { + if (tableSchema.find(table.tableName) == tableSchema.end()) { + return true; + } + if (CheckDistributedFieldChange(tableSchema[table.tableName], table.fields)) { + return true; + } + } + return false; +} + +bool RelationalSchemaObject::CheckDistributedFieldChange(const std::vector &source, + const std::vector &target) +{ + std::map fields; + for (const auto &field : source) { + fields[field.colName] = field; + } + if (fields.size() != target.size()) { + return true; + } + for (const auto &field : target) { + if (fields.find(field.colName) == fields.end()) { + return true; + } + if (fields[field.colName].isP2pSync != field.isP2pSync) { + return true; + } + } + return false; +} + +void RelationalSchemaObject::SetDistributedSchema(const DistributedSchema &schema) +{ + dbSchema_ = schema; + for (const auto &table : schema.tables) { + if (tables_.find(table.tableName) == tables_.end()) { + continue; + } + tables_.at(table.tableName).SetDistributedTable(table); + } + GenerateSchemaString(); +} + +DistributedSchema RelationalSchemaObject::GetDistributedSchema() const +{ + return dbSchema_; +} + +std::string RelationalSchemaObject::GetDistributedSchemaString() +{ + std::string res; + res += R"(,")"; + res += SchemaConstant::KEYWORD_DISTRIBUTED_SCHEMA; + res += R"(":{)"; + res += R"(")"; + res += SchemaConstant::KEYWORD_DISTRIBUTED_VERSION; + res += R"(":)"; + res += std::to_string(dbSchema_.version); + res += R"(,")"; + res += SchemaConstant::KEYWORD_DISTRIBUTED_TABLE; + res += R"(":[)"; + for (const auto &table : dbSchema_.tables) { + res += GetOneDistributedTableString(table) + ","; + } + if (!dbSchema_.tables.empty()) { + res.pop_back(); + } + res += R"(]})"; + return res; +} + +std::string RelationalSchemaObject::GetOneDistributedTableString(const DistributedTable &table) +{ + std::string res; + res += R"({")"; + res += SchemaConstant::KEYWORD_DISTRIBUTED_TABLE_NAME; + res += R"(":")"; + res += table.tableName; + res += R"(", ")"; + res += SchemaConstant::KEYWORD_DISTRIBUTED_FIELD; + res += R"(":[)"; + for (const auto &field : table.fields) { + res += R"({")"; + res += SchemaConstant::KEYWORD_DISTRIBUTED_COL_NAME; + res += R"(":")"; + res += field.colName; + res += R"(", ")"; + res += SchemaConstant::KEYWORD_DISTRIBUTED_IS_P2P_SYNC; + res += R"(":)"; + if (field.isP2pSync) { + res += "true"; + } else { + res += "false"; + } + res += R"(, ")"; + res += SchemaConstant::KEYWORD_DISTRIBUTED_IS_SPECIFIED; + res += R"(":)"; + if (field.isSpecified) { + res += "true"; + } else { + res += "false"; + } + res += R"(},)"; + } + if (!table.fields.empty()) { + res.pop_back(); + } + res += R"(]})"; + return res; +} + +int RelationalSchemaObject::ParseDistributedSchema(const JsonObject &inJsonObject) +{ + if (!inJsonObject.IsFieldPathExist(FieldPath {SchemaConstant::KEYWORD_DISTRIBUTED_SCHEMA})) { + return E_OK; + } + + JsonObject schemaObj; + int errCode = SchemaUtils::ExtractJsonObj(inJsonObject, SchemaConstant::KEYWORD_DISTRIBUTED_SCHEMA, schemaObj); + if (errCode != E_OK) { + return errCode; + } + + FieldValue fieldValue; + errCode = GetMemberFromJsonObject(schemaObj, SchemaConstant::KEYWORD_DISTRIBUTED_VERSION, + FieldType::LEAF_FIELD_INTEGER, true, fieldValue); + if (errCode != E_OK) { + return errCode; + } + dbSchema_.version = static_cast(fieldValue.integerValue); + return ParseDistributedTables(schemaObj); +} + +int RelationalSchemaObject::ParseDistributedTables(const JsonObject &inJsonObject) +{ + if (!inJsonObject.IsFieldPathExist(FieldPath {SchemaConstant::KEYWORD_DISTRIBUTED_TABLE})) { + return E_OK; + } + + std::vector tablesObj; + int errCode = SchemaUtils::ExtractJsonObjArray(inJsonObject, SchemaConstant::KEYWORD_DISTRIBUTED_TABLE, tablesObj); + if (errCode != E_OK) { + return errCode; + } + + for (const auto &tableObj : tablesObj) { + errCode = ParseDistributedTable(tableObj); + if (errCode != E_OK) { + return errCode; + } + } + return E_OK; +} + +int RelationalSchemaObject::ParseDistributedTable(const JsonObject &inJsonObject) +{ + if (!inJsonObject.IsFieldPathExist(FieldPath {SchemaConstant::KEYWORD_DISTRIBUTED_TABLE_NAME})) { + return E_OK; + } + + FieldValue fieldValue; + int errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::KEYWORD_DISTRIBUTED_TABLE_NAME, + FieldType::LEAF_FIELD_STRING, true, fieldValue); + if (errCode != E_OK) { + return errCode; + } + DistributedTable table; + table.tableName = fieldValue.stringValue; + errCode = ParseDistributedFields(inJsonObject, table.fields); + if (errCode != E_OK) { + return errCode; + } + dbSchema_.tables.push_back(std::move(table)); + return E_OK; +} + +int RelationalSchemaObject::ParseDistributedFields(const JsonObject &inJsonObject, + std::vector &fields) +{ + if (!inJsonObject.IsFieldPathExist(FieldPath {SchemaConstant::KEYWORD_DISTRIBUTED_FIELD})) { + return E_OK; + } + + std::vector fieldsObj; + int errCode = SchemaUtils::ExtractJsonObjArray(inJsonObject, SchemaConstant::KEYWORD_DISTRIBUTED_FIELD, fieldsObj); + if (errCode != E_OK) { + return errCode; + } + + for (const auto &fieldObj : fieldsObj) { + DistributedField field; + errCode = ParseDistributedField(fieldObj, field); + if (errCode != E_OK) { + return errCode; + } + fields.push_back(std::move(field)); + } + return E_OK; +} + +int RelationalSchemaObject::ParseDistributedField(const JsonObject &inJsonObject, DistributedField &field) +{ + FieldValue fieldValue; + int errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::KEYWORD_DISTRIBUTED_COL_NAME, + FieldType::LEAF_FIELD_STRING, true, fieldValue); + if (errCode != E_OK) { + return errCode; + } + field.colName = fieldValue.stringValue; + errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::KEYWORD_DISTRIBUTED_IS_P2P_SYNC, + FieldType::LEAF_FIELD_BOOL, true, fieldValue); + if (errCode != E_OK) { + return errCode; + } + field.isP2pSync = fieldValue.boolValue; + errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::KEYWORD_DISTRIBUTED_IS_SPECIFIED, + FieldType::LEAF_FIELD_BOOL, true, fieldValue); + if (errCode != E_OK) { + return errCode; + } + field.isSpecified = fieldValue.boolValue; + return E_OK; +} + +bool RelationalSchemaObject::IsNeedSkipSyncField(const FieldInfo &fieldInfo, const std::string &tableName, + bool ignoreTableNonExist) const +{ + bool splitByDevice = tableMode_ == DistributedTableMode::SPLIT_BY_DEVICE; + if (splitByDevice) { + return false; + } + auto it = tables_.find(tableName); + if (it == tables_.end()) { + LOGW("[RelationalSchemaObject][IsNeedSkipSyncField] Unknown table %s size %zu", + DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + return false; + } + auto match = std::find_if(dbSchema_.tables.begin(), dbSchema_.tables.end(), + [&tableName](const DistributedTable &distributedTable) { + return DBCommon::CaseInsensitiveCompare(distributedTable.tableName, tableName); + }); + if (match == dbSchema_.tables.end()) { + return !ignoreTableNonExist; + } + bool existDistributedPk = false; + for (const auto &item : match->fields) { + if (item.isSpecified && item.isP2pSync) { + existDistributedPk = true; + break; + } + } + if (!existDistributedPk) { + auto pks = it->second.GetPrimaryKey(); + for (const auto &pk : pks) { + if (DBCommon::CaseInsensitiveCompare(fieldInfo.GetFieldName(), pk.second)) { + return false; + } + } + } + auto matchField = std::find_if(match->fields.begin(), match->fields.end(), + [&fieldInfo](const DistributedField &distributedField) { + return distributedField.isP2pSync && + DBCommon::CaseInsensitiveCompare(distributedField.colName, fieldInfo.GetFieldName()); + }); + return matchField == match->fields.end(); +} + +std::vector RelationalSchemaObject::GetSyncFieldInfo(const std::string &tableName, + bool ignoreTableNonExist) const +{ + std::vector res; + auto it = tables_.find(tableName); + if (it == tables_.end()) { + LOGW("[RelationalSchemaObject][GetSyncFieldInfo] Unknown table %s size %zu", + DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + return res; + } + for (const auto &fieldInfo : it->second.GetFieldInfos()) { + if (IsNeedSkipSyncField(fieldInfo, tableName, ignoreTableNonExist)) { + continue; + } + res.push_back(fieldInfo); + } + return res; +} + +DistributedTable RelationalSchemaObject::GetDistributedTable(const std::string &table) const +{ + auto match = std::find_if(dbSchema_.tables.begin(), dbSchema_.tables.end(), + [&table](const DistributedTable &distributedTable) { + return DBCommon::CaseInsensitiveCompare(distributedTable.tableName, table); + }); + if (match == dbSchema_.tables.end()) { + return {}; + } + return *match; +} } #endif \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/common/src/relational/table_info.cpp b/kv_store/frameworks/libs/distributeddb/common/src/relational/table_info.cpp index 0796a5f802d998b0c29316d5269a840779d0a71a..e1091c33822111239327a651efe192f1722a05c2 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/relational/table_info.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/relational/table_info.cpp @@ -350,6 +350,16 @@ const std::map &TableInfo::GetPrimaryKey() const return primaryKey_; } +bool TableInfo::IsPrimaryKey(const std::string &colName) const +{ + for (const auto &item : primaryKey_) { + if (colName == item.second) { + return true; + } + } + return false; +} + CompositeFields TableInfo::GetIdentifyKey() const { if (primaryKey_.size() == 1 && primaryKey_.at(0) == ROW_ID) { @@ -748,36 +758,30 @@ int TableInfo::CheckTrackerTable() LOGE("the table name in schema is different from tracker table."); return -E_NOT_FOUND; } - if (trackerTable_.GetTrackerColNames().empty()) { - return E_OK; - } - const char *tableName = DBCommon::StringMiddleMasking(tableName_).c_str(); + const std::string tableName = DBCommon::StringMiddleMasking(tableName_); size_t nameLength = tableName_.size(); for (const auto &colName: trackerTable_.GetTrackerColNames()) { if (colName.empty()) { - LOGE("[%s [%zu]] tracker col cannot be empty.", tableName, nameLength); + LOGE("[%s [%zu]] tracker col cannot be empty.", tableName.c_str(), nameLength); return -E_INVALID_ARGS; } if (GetFields().find(colName) == GetFields().end()) { - LOGE("[%s [%zu]] unable to match the tracker col from table schema.", tableName, nameLength); + LOGE("[%s [%zu]] unable to match the tracker col from table schema.", tableName.c_str(), nameLength); return -E_SCHEMA_MISMATCH; } } - if (trackerTable_.GetExtendNames().empty()) { - return E_OK; - } for (const auto &colName : trackerTable_.GetExtendNames()) { if (colName.empty()) { - LOGE("[%s [%zu]] extend col cannot be empty.", tableName, nameLength); + LOGE("[%s [%zu]] extend col cannot be empty.", tableName.c_str(), nameLength); return -E_INVALID_ARGS; } auto iter = GetFields().find(colName); if (iter == GetFields().end()) { - LOGE("[%s [%zu]] unable to match the extend col from table schema.", tableName, nameLength); + LOGE("[%s [%zu]] unable to match the extend col from table schema.", tableName.c_str(), nameLength); return -E_SCHEMA_MISMATCH; } else { if (iter->second.IsAssetType() || iter->second.IsAssetsType()) { - LOGE("[%s [%zu]] extend col is not allowed to be set as an asset field.", tableName, nameLength); + LOGE("[%s [%zu]] extend col is not allowed to be set as asset field.", tableName.c_str(), nameLength); return -E_INVALID_ARGS; } } @@ -812,4 +816,42 @@ bool TableInfo::IsNoPkTable() const } return false; } + +bool TableInfo::IsFieldExist(const std::string &fieldName) const +{ + if (fields_.find(fieldName) != fields_.end()) { + return true; + } + LOGE("[TableInfo][IsFieldExist] table %s table len %zu not exist field %s", + DBCommon::StringMiddleMasking(tableName_).c_str(), tableName_.size(), + DBCommon::StringMiddleMasking(fieldName).c_str()); + return false; +} + +void TableInfo::SetDistributedTable(const DistributedTable &distributedTable) +{ + distributedTable_ = distributedTable; +} + +std::vector TableInfo::GetSyncField() const +{ + std::vector res; + for (const auto &item : distributedTable_.fields) { + if (item.isP2pSync) { + res.push_back(item.colName); + } + } + return res; +} + +std::vector TableInfo::GetSyncDistributedPk() const +{ + std::vector res; + for (const auto &item : distributedTable_.fields) { + if (item.isP2pSync && item.isSpecified) { + res.push_back(item.colName); + } + } + return res; +} } // namespace DistributeDB \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/common/src/runtime_context_impl.cpp b/kv_store/frameworks/libs/distributeddb/common/src/runtime_context_impl.cpp index 113caa4271465ecc095ebd4708c55952ec4b79ca..d768614baaf587f9f6e5784637a37558595fbb97 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/runtime_context_impl.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/runtime_context_impl.cpp @@ -181,16 +181,16 @@ int RuntimeContextImpl::SetTimer(int milliSeconds, const TimerAction &action, IEvent *evTimer = IEvent::CreateEvent(milliSeconds, errCode); if (evTimer == nullptr) { - loop->DecObjRef(loop); + RefObject::DecObjRef(loop); loop = nullptr; return errCode; } errCode = AllocTimerId(evTimer, timerId); if (errCode != E_OK) { - evTimer->DecObjRef(evTimer); + RefObject::DecObjRef(evTimer); evTimer = nullptr; - loop->DecObjRef(loop); + RefObject::DecObjRef(loop); loop = nullptr; return errCode; } @@ -211,7 +211,7 @@ int RuntimeContextImpl::SetTimer(int milliSeconds, const TimerAction &action, timerId = 0; } - loop->DecObjRef(loop); + RefObject::DecObjRef(loop); loop = nullptr; return errCode; } @@ -256,7 +256,7 @@ void RuntimeContextImpl::RemoveTimer(TimerId timerId, bool wait) if (evTimer != nullptr) { evTimer->Detach(wait); - evTimer->DecObjRef(evTimer); + RefObject::DecObjRef(evTimer); evTimer = nullptr; } } @@ -322,7 +322,7 @@ NotificationChain::Listener *RuntimeContextImpl::RegisterTimeChangedLister(const { std::lock_guard autoLock(timeTickMonitorLock_); if (timeTickMonitor_ == nullptr) { - timeTickMonitor_ = std::make_unique(); + timeTickMonitor_ = std::make_shared(); errCode = timeTickMonitor_->StartTimeTickMonitor(); if (errCode != E_OK) { LOGE("TimeTickMonitor start failed!"); @@ -339,7 +339,7 @@ int RuntimeContextImpl::PrepareLoop(IEventLoop *&loop) std::lock_guard autoLock(loopLock_); if (mainLoop_ != nullptr) { loop = mainLoop_; - loop->IncObjRef(loop); // ref 1 returned to caller. + RefObject::IncObjRef(loop); // ref 1 returned to caller. return E_OK; } @@ -349,15 +349,15 @@ int RuntimeContextImpl::PrepareLoop(IEventLoop *&loop) return errCode; } - loop->IncObjRef(loop); // ref 1 owned by thread. + RefObject::IncObjRef(loop); // ref 1 owned by thread. std::thread loopThread([loop]() { loop->Run(); - loop->DecObjRef(loop); // ref 1 dropped by thread. + RefObject::DecObjRef(loop); // ref 1 dropped by thread. }); loopThread.detach(); mainLoop_ = loop; - loop->IncObjRef(loop); // ref 1 returned to caller. + RefObject::IncObjRef(loop); // ref 1 returned to caller. return E_OK; } @@ -424,11 +424,27 @@ int RuntimeContextImpl::SetPermissionCheckCallback(const PermissionCheckCallback return E_OK; } +int RuntimeContextImpl::SetPermissionCheckCallback(const PermissionCheckCallbackV4 &callback) +{ + std::unique_lock writeLock(permissionCheckCallbackMutex_); + permissionCheckCallbackV4_ = callback; + LOGI("SetPermissionCheckCallback V4 ok"); + return E_OK; +} + int RuntimeContextImpl::RunPermissionCheck(const PermissionCheckParam ¶m, uint8_t flag) const { bool checkResult = false; std::shared_lock autoLock(permissionCheckCallbackMutex_); - if (permissionCheckCallbackV3_) { + if (permissionCheckCallbackV4_) { + PermissionCheckParamV4 paramV4; + paramV4.appId = param.appId; + paramV4.userId = param.userId; + paramV4.storeId = param.storeId; + paramV4.deviceId = param.deviceId; + paramV4.subUserId = param.subUserId; + checkResult = permissionCheckCallbackV4_(paramV4, flag); + } else if (permissionCheckCallbackV3_) { checkResult = permissionCheckCallbackV3_(param, flag); } else if (permissionCheckCallbackV2_) { checkResult = permissionCheckCallbackV2_(param.userId, param.appId, param.storeId, param.deviceId, flag); @@ -618,12 +634,16 @@ bool RuntimeContextImpl::IsProcessSystemApiAdapterValid() const void RuntimeContextImpl::NotifyTimestampChanged(TimeOffset offset) const { - std::lock_guard autoLock(timeTickMonitorLock_); - if (timeTickMonitor_ == nullptr) { - LOGD("NotifyTimestampChanged fail, timeTickMonitor_ is null."); - return; + std::shared_ptr timeTickMonitor = nullptr; + { + std::lock_guard autoLock(timeTickMonitorLock_); + if (timeTickMonitor_ == nullptr) { + LOGD("NotifyTimestampChanged fail, timeTickMonitor_ is null."); + return; + } + timeTickMonitor = timeTickMonitor_; } - timeTickMonitor_->NotifyTimeChange(offset); + timeTickMonitor->NotifyTimeChange(offset); } bool RuntimeContextImpl::IsCommunicatorAggregatorValid() const @@ -642,14 +662,24 @@ void RuntimeContextImpl::SetStoreStatusNotifier(const StoreStatusNotifier ¬if LOGI("SetStoreStatusNotifier ok"); } -void RuntimeContextImpl::NotifyDatabaseStatusChange(const std::string &userId, const std::string &appId, - const std::string &storeId, const std::string &deviceId, bool onlineStatus) +void RuntimeContextImpl::SetStoreStatusNotifier(const StoreStatusNotifierV2 ¬ifier) { - ScheduleTask([this, userId, appId, storeId, deviceId, onlineStatus] { + std::unique_lock writeLock(databaseStatusCallbackMutex_); + databaseStatusNotifyCallbackV2_ = notifier; + LOGI("SetStoreStatusNotifier ok"); +} + +void RuntimeContextImpl::NotifyDatabaseStatusChange(const StoreStatusNotifierParam ¶m, bool onlineStatus) +{ + ScheduleTask([this, param, onlineStatus] { std::shared_lock autoLock(databaseStatusCallbackMutex_); + if (databaseStatusNotifyCallbackV2_) { + LOGI("start notify database status:%d", onlineStatus); + databaseStatusNotifyCallbackV2_(param, onlineStatus); + } if (databaseStatusNotifyCallback_) { LOGI("start notify database status:%d", onlineStatus); - databaseStatusNotifyCallback_(userId, appId, storeId, deviceId, onlineStatus); + databaseStatusNotifyCallback_(param.userId, param.appId, param.storeId, param.deviceId, onlineStatus); } }); } @@ -676,6 +706,7 @@ bool RuntimeContextImpl::IsSyncerNeedActive(const DBProperties &properties) cons properties.GetStringProp(DBProperties::USER_ID, ""), properties.GetStringProp(DBProperties::APP_ID, ""), properties.GetStringProp(DBProperties::STORE_ID, ""), + properties.GetStringProp(DBProperties::SUB_USER, ""), properties.GetIntProp(DBProperties::INSTANCE_ID, 0) }; std::shared_lock autoLock(syncActivationCheckCallbackMutex_); @@ -754,6 +785,7 @@ std::map RuntimeContextImpl::GetPermissionCheckParam(c properties.GetStringProp(DBProperties::USER_ID, ""), properties.GetStringProp(DBProperties::APP_ID, ""), properties.GetStringProp(DBProperties::STORE_ID, ""), + properties.GetStringProp(DBProperties::SUB_USER, ""), properties.GetIntProp(DBProperties::INSTANCE_ID, 0) }; std::shared_lock autoLock(permissionConditionLock_); @@ -1215,7 +1247,7 @@ void RuntimeContextImpl::SetTimeChanged(bool timeChange) { std::lock_guard autoLock(timeTickMonitorLock_); if (timeTickMonitor_ == nullptr) { - timeTickMonitor_ = std::make_unique(); + timeTickMonitor_ = std::make_shared(); (void)timeTickMonitor_->StartTimeTickMonitor(); LOGD("[RuntimeContext] TimeTickMonitor start success"); } @@ -1231,4 +1263,14 @@ void RuntimeContextImpl::SetBatchDownloadAssets(bool isBatchDownload) { isBatchDownloadAssets_ = isBatchDownload; } + +std::shared_ptr RuntimeContextImpl::GetAssetsDownloadManager() +{ + std::lock_guard autoLock(assetsDownloadManagerLock_); + if (assetsDownloadManager_ != nullptr) { + return assetsDownloadManager_; + } + assetsDownloadManager_ = std::make_shared(); + return assetsDownloadManager_; +} } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/common/src/runtime_context_impl.h b/kv_store/frameworks/libs/distributeddb/common/src/runtime_context_impl.h index 2d78683974905ee6c3597d5dea7bee8d751cbe12..99cb7e51573759f976ecfa9d72db1cffe2afbfae 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/runtime_context_impl.h +++ b/kv_store/frameworks/libs/distributeddb/common/src/runtime_context_impl.h @@ -71,6 +71,8 @@ public: int SetPermissionCheckCallback(const PermissionCheckCallbackV3 &callback) override; + int SetPermissionCheckCallback(const PermissionCheckCallbackV4 &callback) override; + int RunPermissionCheck(const PermissionCheckParam ¶m, uint8_t flag) const override; int EnableKvStoreAutoLaunch(const KvDBProperties &properties, AutoLaunchNotifier notifier, @@ -104,8 +106,9 @@ public: void SetStoreStatusNotifier(const StoreStatusNotifier ¬ifier) override; - void NotifyDatabaseStatusChange(const std::string &userId, const std::string &appId, const std::string &storeId, - const std::string &deviceId, bool onlineStatus) override; + void SetStoreStatusNotifier(const StoreStatusNotifierV2 ¬ifier) override; + + void NotifyDatabaseStatusChange(const StoreStatusNotifierParam ¶m, bool onlineStatus) override; int SetSyncActivationCheckCallback(const SyncActivationCheckCallback &callback) override; @@ -185,6 +188,8 @@ public: bool IsBatchDownloadAssets() const override; void SetBatchDownloadAssets(bool isBatchDownload) override; + + std::shared_ptr GetAssetsDownloadManager() override; private: static constexpr int MAX_TP_THREADS = 10; // max threads of the task pool. static constexpr int MIN_TP_THREADS = 1; // min threads of the task pool. @@ -230,12 +235,13 @@ private: // TimeTick mutable std::mutex timeTickMonitorLock_; - std::unique_ptr timeTickMonitor_; + std::shared_ptr timeTickMonitor_; mutable std::shared_mutex permissionCheckCallbackMutex_ {}; PermissionCheckCallback permissionCheckCallback_; PermissionCheckCallbackV2 permissionCheckCallbackV2_; PermissionCheckCallbackV3 permissionCheckCallbackV3_; + PermissionCheckCallbackV4 permissionCheckCallbackV4_; AutoLaunch autoLaunch_; @@ -247,6 +253,7 @@ private: mutable std::shared_mutex databaseStatusCallbackMutex_ {}; StoreStatusNotifier databaseStatusNotifyCallback_; + StoreStatusNotifierV2 databaseStatusNotifyCallbackV2_; mutable std::shared_mutex syncActivationCheckCallbackMutex_ {}; SyncActivationCheckCallback syncActivationCheckCallback_; @@ -286,6 +293,9 @@ private: std::map, bool> dbTimeChange_; std::atomic isBatchDownloadAssets_; + + mutable std::mutex assetsDownloadManagerLock_; + std::shared_ptr assetsDownloadManager_; }; } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/common/src/schema_utils.cpp b/kv_store/frameworks/libs/distributeddb/common/src/schema_utils.cpp index 7908acc63c6b7a31702a128984632c39bf5284a5..f4814779bfd0e2ac6e09941f7a5b3117c9c298f8 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/schema_utils.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/schema_utils.cpp @@ -515,4 +515,50 @@ void SchemaUtils::TransTrackerSchemaToLower(const TrackerSchema &srcSchema, Trac destSchema.trackerColNames.insert(DBCommon::ToLowerCase(srcName)); } } + +int SchemaUtils::ExtractJsonObj(const JsonObject &inJsonObject, const std::string &field, + JsonObject &out) +{ + FieldType fieldType; + auto fieldPath = FieldPath {field}; + int errCode = inJsonObject.GetFieldTypeByFieldPath(fieldPath, fieldType); + if (errCode != E_OK) { + LOGE("[SchemaUtils][ExtractJsonObj] Get schema %s fieldType failed: %d.", field.c_str(), errCode); + return -E_SCHEMA_PARSE_FAIL; + } + if (FieldType::INTERNAL_FIELD_OBJECT != fieldType) { + LOGE("[SchemaUtils][ExtractJsonObj] Expect %s Object but %s.", field.c_str(), + SchemaUtils::FieldTypeString(fieldType).c_str()); + return -E_SCHEMA_PARSE_FAIL; + } + errCode = inJsonObject.GetObjectByFieldPath(fieldPath, out); + if (errCode != E_OK) { + LOGE("[SchemaUtils][ExtractJsonObj] Get schema %s value failed: %d.", field.c_str(), errCode); + return -E_SCHEMA_PARSE_FAIL; + } + return E_OK; +} + +int SchemaUtils::ExtractJsonObjArray(const JsonObject &inJsonObject, const std::string &field, + std::vector &out) +{ + FieldType fieldType; + auto fieldPath = FieldPath {field}; + int errCode = inJsonObject.GetFieldTypeByFieldPath(fieldPath, fieldType); + if (errCode != E_OK) { + LOGE("[SchemaUtils][ExtractJsonObj] Get schema %s fieldType failed: %d.", field.c_str(), errCode); + return -E_SCHEMA_PARSE_FAIL; + } + if (FieldType::LEAF_FIELD_ARRAY != fieldType) { + LOGE("[SchemaUtils][ExtractJsonObj] Expect %s Object but %s.", field.c_str(), + SchemaUtils::FieldTypeString(fieldType).c_str()); + return -E_SCHEMA_PARSE_FAIL; + } + errCode = inJsonObject.GetObjectArrayByFieldPath(fieldPath, out); + if (errCode != E_OK) { + LOGE("[SchemaUtils][ExtractJsonObj] Get schema %s value failed: %d.", field.c_str(), errCode); + return -E_SCHEMA_PARSE_FAIL; + } + return E_OK; +} } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/communicator/include/communicator_aggregator.h b/kv_store/frameworks/libs/distributeddb/communicator/include/communicator_aggregator.h index 8b43fae52b9ff10b12194d268ede2e070a4e5a39..a552ccb4a8377d3ec2ad1373c5217a4546ae6191 100644 --- a/kv_store/frameworks/libs/distributeddb/communicator/include/communicator_aggregator.h +++ b/kv_store/frameworks/libs/distributeddb/communicator/include/communicator_aggregator.h @@ -59,10 +59,11 @@ public: // Must not call any other functions if Finalize had been called. In fact, Finalize has no chance to be called. void Finalize() override; - ICommunicator *AllocCommunicator(uint64_t commLabel, int &outErrorNo) override; - ICommunicator *AllocCommunicator(const LabelType &commLabel, int &outErrorNo) override; + ICommunicator *AllocCommunicator(uint64_t commLabel, int &outErrorNo, const std::string &userId = "") override; + ICommunicator *AllocCommunicator(const LabelType &commLabel, int &outErrorNo, + const std::string &userId = "") override; - void ReleaseCommunicator(ICommunicator *inCommunicator) override; + void ReleaseCommunicator(ICommunicator *inCommunicator, const std::string &userId = "") override; int RegCommunicatorLackCallback(const CommunicatorLackCallback &onCommLack, const Finalizer &inOper) override; int RegOnConnectCallback(const OnConnectCallback &onConnect, const Finalizer &inOper) override; @@ -81,7 +82,7 @@ public: int GetRemoteCommunicatorVersion(const std::string &target, uint16_t &outVersion) const; // Called by communicator to make itself really in work - void ActivateCommunicator(const LabelType &commLabel); + void ActivateCommunicator(const LabelType &commLabel, const std::string &userId = ""); // SerialBuffer surely is heap memory, ScheduleSendTask responsible for lifecycle int ScheduleSendTask(const std::string &dstTarget, SerialBuffer *inBuff, FrameType inType, @@ -118,7 +119,7 @@ private: // Function with suffix NoMutex should be called with mutex in the caller int TryDeliverAppLayerFrameToCommunicatorNoMutex(const std::string &srcTarget, SerialBuffer *&inFrameBuffer, - const LabelType &toLabel); + const LabelType &toLabel, const std::string &userId = ""); // Auxiliary function for cutting short primary function int RegCallbackToAdapter(); @@ -171,7 +172,8 @@ private: // Handle related mutable std::mutex commMapMutex_; - std::map> commMap_; // bool true indicate communicator activated + // bool true indicate communicator activated + std::map>> commMap_; FrameCombiner combiner_; FrameRetainer retainer_; SendTaskScheduler scheduler_; diff --git a/kv_store/frameworks/libs/distributeddb/communicator/include/iadapter.h b/kv_store/frameworks/libs/distributeddb/communicator/include/iadapter.h index b3560e817604f87c8bbd1d1dc5ae6694c618e971..4ded51afb39fdde8332381ec3306ecec762f0d8a 100644 --- a/kv_store/frameworks/libs/distributeddb/communicator/include/iadapter.h +++ b/kv_store/frameworks/libs/distributeddb/communicator/include/iadapter.h @@ -28,7 +28,7 @@ namespace DistributedDB { using BytesReceiveCallback = std::function; using TargetChangeCallback = std::function; -using SendableCallback = std::function; +using SendableCallback = std::function; class IAdapter { public: diff --git a/kv_store/frameworks/libs/distributeddb/communicator/include/icommunicator.h b/kv_store/frameworks/libs/distributeddb/communicator/include/icommunicator.h index 0234c2dc8549c6976ed96885acaa83321ed31006..4b73ab3262ad8a2cdff11b76cefd71f2ec355e7a 100644 --- a/kv_store/frameworks/libs/distributeddb/communicator/include/icommunicator.h +++ b/kv_store/frameworks/libs/distributeddb/communicator/include/icommunicator.h @@ -47,6 +47,7 @@ inline void SetSendConfigParam(const DBProperties &dbProperty, const std::string sendConf.paramInfo.userId = dbProperty.GetStringProp(DBProperties::USER_ID, ""); sendConf.paramInfo.storeId = dbProperty.GetStringProp(DBProperties::STORE_ID, ""); sendConf.paramInfo.dstTarget = dstTarget; + sendConf.paramInfo.subUserId = dbProperty.GetStringProp(DBProperties::SUB_USER, ""); } class ICommunicator : public virtual RefObject { @@ -57,7 +58,7 @@ public: virtual int RegOnConnectCallback(const OnConnectCallback &onConnect, const Finalizer &inOper) = 0; virtual int RegOnSendableCallback(const std::function &onSendable, const Finalizer &inOper) = 0; - virtual void Activate() = 0; + virtual void Activate(const std::string &userId = "") = 0; // return optimal allowed data size(Some header is taken into account and subtract) virtual uint32_t GetCommunicatorMtuSize() const = 0; diff --git a/kv_store/frameworks/libs/distributeddb/communicator/include/icommunicator_aggregator.h b/kv_store/frameworks/libs/distributeddb/communicator/include/icommunicator_aggregator.h index 70ee63cf8f1b09bc74c00931df7a31a36c9f4145..656e165bced0c5aaf12a6abe40ce586e648ec42c 100644 --- a/kv_store/frameworks/libs/distributeddb/communicator/include/icommunicator_aggregator.h +++ b/kv_store/frameworks/libs/distributeddb/communicator/include/icommunicator_aggregator.h @@ -42,9 +42,10 @@ public: virtual void Finalize() = 0; // If not success, return nullptr and set outErrorNo - virtual ICommunicator *AllocCommunicator(uint64_t commLabel, int &outErrorNo) = 0; - virtual ICommunicator *AllocCommunicator(const LabelType &commLabel, int &outErrorNo) = 0; - virtual void ReleaseCommunicator(ICommunicator *inCommunicator) = 0; + virtual ICommunicator *AllocCommunicator(uint64_t commLabel, int &outErrorNo, const std::string &userId = "") = 0; + virtual ICommunicator *AllocCommunicator(const LabelType &commLabel, int &outErrorNo, + const std::string &userId = "") = 0; + virtual void ReleaseCommunicator(ICommunicator *inCommunicator, const std::string &userId = "") = 0; virtual int RegCommunicatorLackCallback(const CommunicatorLackCallback &onCommLack, const Finalizer &inOper) = 0; virtual int RegOnConnectCallback(const OnConnectCallback &onConnect, const Finalizer &inOper) = 0; virtual int GetLocalIdentity(std::string &outTarget) const = 0; diff --git a/kv_store/frameworks/libs/distributeddb/communicator/include/send_task_scheduler.h b/kv_store/frameworks/libs/distributeddb/communicator/include/send_task_scheduler.h index 94040f2371bb7799dac9ac52196b22572c09e36e..d5a7553a7db8fa17abbf870925fa9816036d826e 100644 --- a/kv_store/frameworks/libs/distributeddb/communicator/include/send_task_scheduler.h +++ b/kv_store/frameworks/libs/distributeddb/communicator/include/send_task_scheduler.h @@ -78,7 +78,7 @@ public: uint32_t GetNoDelayTaskCount() const; void InvalidSendTask(const std::string &target); - void SetSoftBusErrCode(const std::string &target, int softBusErrCode); + void SetDeviceCommErrCode(const std::string &target, int deviceCommErrCode); private: int ScheduleDelayTask(SendTask &outTask, SendTaskInfo &outTaskInfo); @@ -103,7 +103,7 @@ private: std::string lastScheduleTarget_; Priority lastSchedulePriority_ = Priority::LOW; - std::map softBusErrCodeMap_; + std::map deviceCommErrCodeMap_; }; } diff --git a/kv_store/frameworks/libs/distributeddb/communicator/src/communicator.cpp b/kv_store/frameworks/libs/distributeddb/communicator/src/communicator.cpp index d8e5efdd887f6d607c1dc93710a73ac6fb63990b..608adaf912dcdf682d6eacdb16d92f96e0775c3e 100644 --- a/kv_store/frameworks/libs/distributeddb/communicator/src/communicator.cpp +++ b/kv_store/frameworks/libs/distributeddb/communicator/src/communicator.cpp @@ -60,9 +60,9 @@ int Communicator::RegOnSendableCallback(const std::function &onSenda return RegCallBack(onSendable, onSendableHandle_, inOper, onSendableFinalizer_); } -void Communicator::Activate() +void Communicator::Activate(const std::string &userId) { - commAggrHandle_->ActivateCommunicator(commLabel_); + commAggrHandle_->ActivateCommunicator(commLabel_, userId); } uint32_t Communicator::GetCommunicatorMtuSize() const diff --git a/kv_store/frameworks/libs/distributeddb/communicator/src/communicator.h b/kv_store/frameworks/libs/distributeddb/communicator/src/communicator.h index fd9436ddfa66735c52262ada5bfd6d6382608d0f..976ce0ae9488ecf3f4a4b2b4c6f362592a7974f7 100644 --- a/kv_store/frameworks/libs/distributeddb/communicator/src/communicator.h +++ b/kv_store/frameworks/libs/distributeddb/communicator/src/communicator.h @@ -39,7 +39,7 @@ public: int RegOnConnectCallback(const OnConnectCallback &onConnect, const Finalizer &inOper) override; int RegOnSendableCallback(const std::function &onSendable, const Finalizer &inOper) override; - void Activate() override; + void Activate(const std::string &userId = "") override; uint32_t GetCommunicatorMtuSize() const override; uint32_t GetCommunicatorMtuSize(const std::string &target) const override; diff --git a/kv_store/frameworks/libs/distributeddb/communicator/src/communicator_aggregator.cpp b/kv_store/frameworks/libs/distributeddb/communicator/src/communicator_aggregator.cpp index ab137ca31703f5a54a320ac91fbb82b4f6c8b477..b825143b5e555a3cb73cd67c53a4ff102430611c 100644 --- a/kv_store/frameworks/libs/distributeddb/communicator/src/communicator_aggregator.cpp +++ b/kv_store/frameworks/libs/distributeddb/communicator/src/communicator_aggregator.cpp @@ -134,7 +134,7 @@ void CommunicatorAggregator::Finalize() dbStatusAdapter_ = nullptr; } -ICommunicator *CommunicatorAggregator::AllocCommunicator(uint64_t commLabel, int &outErrorNo) +ICommunicator *CommunicatorAggregator::AllocCommunicator(uint64_t commLabel, int &outErrorNo, const std::string &userId) { uint64_t netOrderLabel = HostToNet(commLabel); uint8_t *eachByte = reinterpret_cast(&netOrderLabel); @@ -142,10 +142,11 @@ ICommunicator *CommunicatorAggregator::AllocCommunicator(uint64_t commLabel, int for (int i = 0; i < static_cast(sizeof(uint64_t)); i++) { realLabel[i] = eachByte[i]; } - return AllocCommunicator(realLabel, outErrorNo); + return AllocCommunicator(realLabel, outErrorNo, userId); } -ICommunicator *CommunicatorAggregator::AllocCommunicator(const std::vector &commLabel, int &outErrorNo) +ICommunicator *CommunicatorAggregator::AllocCommunicator(const std::vector &commLabel, int &outErrorNo, + const std::string &userId) { std::lock_guard commMapLockGuard(commMapMutex_); LOGI("[CommAggr][Alloc] Label=%.3s.", VEC_TO_STR(commLabel)); @@ -154,21 +155,22 @@ ICommunicator *CommunicatorAggregator::AllocCommunicator(const std::vector commMapLockGuard(commMapMutex_); - if (commMap_.count(commLabel) == 0) { + if (commMap_.count(userId) == 0 || commMap_[userId].count(commLabel) == 0) { LOGE("[CommAggr][Release] Not Found."); return; } - commMap_.erase(commLabel); + commMap_[userId].erase(commLabel); + if (commMap_[userId].empty()) { + commMap_.erase(userId); + } RefObject::DecObjRef(commPtr); // Refcount of Communicator is 1 when created, here to unref Communicator int errCode = commLinker_->DecreaseLocalLabel(commLabel); @@ -243,18 +248,18 @@ int CommunicatorAggregator::GetLocalIdentity(std::string &outTarget) const return adapterHandle_->GetLocalIdentity(outTarget); } -void CommunicatorAggregator::ActivateCommunicator(const LabelType &commLabel) +void CommunicatorAggregator::ActivateCommunicator(const LabelType &commLabel, const std::string &userId) { std::lock_guard commMapLockGuard(commMapMutex_); LOGI("[CommAggr][Activate] Label=%.3s.", VEC_TO_STR(commLabel)); - if (commMap_.count(commLabel) == 0) { + if (commMap_[userId].count(commLabel) == 0) { LOGW("[CommAggr][Activate] Communicator of this label not allocated."); return; } - if (commMap_.at(commLabel).second) { + if (commMap_[userId].at(commLabel).second) { return; } - commMap_.at(commLabel).second = true; // Mark this communicator as activated + commMap_[userId].at(commLabel).second = true; // Mark this communicator as activated // IncreaseLocalLabel below and DecreaseLocalLabel in ReleaseCommunicator should all be protected by commMapMutex_ // To avoid disordering probably caused by concurrent call to ActivateCommunicator and ReleaseCommunicator @@ -266,12 +271,12 @@ void CommunicatorAggregator::ActivateCommunicator(const LabelType &commLabel) } for (auto &entry : onlineTargets) { LOGI("[CommAggr][Activate] Already Online Target=%s{private}.", entry.c_str()); - commMap_.at(commLabel).first->OnConnectChange(entry, true); + commMap_[userId].at(commLabel).first->OnConnectChange(entry, true); } // Do Redeliver, the communicator is responsible to deal with the frame std::list framesToRedeliver = retainer_.FetchFramesForSpecificCommunicator(commLabel); for (auto &entry : framesToRedeliver) { - commMap_.at(commLabel).first->OnBufferReceive(entry.srcTarget, entry.buffer); + commMap_[userId].at(commLabel).first->OnBufferReceive(entry.srcTarget, entry.buffer); } } @@ -468,10 +473,12 @@ void CommunicatorAggregator::TaskFinalizer(const SendTask &inTask, int result) void CommunicatorAggregator::NotifySendableToAllCommunicator() { std::lock_guard commMapLockGuard(commMapMutex_); - for (auto &entry : commMap_) { - // Ignore nonactivated communicator - if (entry.second.second) { - entry.second.first->OnSendAvailable(); + for (auto &userCommMap : commMap_) { + for (auto &entry : userCommMap.second) { + // Ignore nonactivated communicator + if (entry.second.second) { + entry.second.first->OnSendAvailable(); + } } } } @@ -543,10 +550,12 @@ void CommunicatorAggregator::OnTargetChange(const std::string &target, bool isCo } // All related communicator online or offline this target, no matter TargetOnline or TargetOffline fail or not std::lock_guard commMapLockGuard(commMapMutex_); - for (auto &entry : commMap_) { - // Ignore nonactivated communicator - if (entry.second.second && (!isConnect || (relatedLabels.count(entry.first) != 0))) { - entry.second.first->OnConnectChange(target, isConnect); + for (auto &userCommMap : commMap_) { + for (auto &entry: userCommMap.second) { + // Ignore nonactivated communicator + if (entry.second.second && (!isConnect || (relatedLabels.count(entry.first) != 0))) { + entry.second.first->OnConnectChange(target, isConnect); + } } } } @@ -667,7 +676,7 @@ int CommunicatorAggregator::OnAppLayerFrameReceive(const std::string &srcTarget, LabelType toLabel = inResult.GetCommLabel(); { std::lock_guard commMapLockGuard(commMapMutex_); - int errCode = TryDeliverAppLayerFrameToCommunicatorNoMutex(srcTarget, inFrameBuffer, toLabel); + int errCode = TryDeliverAppLayerFrameToCommunicatorNoMutex(srcTarget, inFrameBuffer, toLabel, userId); if (errCode == E_OK) { // Attention: Here is equal to E_OK return E_OK; } @@ -685,7 +694,7 @@ int CommunicatorAggregator::OnAppLayerFrameReceive(const std::string &srcTarget, } // Here we have to lock commMapMutex_ and search communicator again. std::lock_guard commMapLockGuard(commMapMutex_); - int errCodeAgain = TryDeliverAppLayerFrameToCommunicatorNoMutex(srcTarget, inFrameBuffer, toLabel); + int errCodeAgain = TryDeliverAppLayerFrameToCommunicatorNoMutex(srcTarget, inFrameBuffer, toLabel, userId); if (errCodeAgain == E_OK) { // Attention: Here is equal to E_OK. LOGI("[CommAggr][AppReceive] Communicator of %.3s found after try again(rare case).", VEC_TO_STR(toLabel)); return E_OK; @@ -704,15 +713,37 @@ int CommunicatorAggregator::OnAppLayerFrameReceive(const std::string &srcTarget, } int CommunicatorAggregator::TryDeliverAppLayerFrameToCommunicatorNoMutex(const std::string &srcTarget, - SerialBuffer *&inFrameBuffer, const LabelType &toLabel) + SerialBuffer *&inFrameBuffer, const LabelType &toLabel, const std::string &userId) { // Ignore nonactivated communicator, which is regarded as inexistent - if (commMap_.count(toLabel) != 0 && commMap_.at(toLabel).second) { - commMap_.at(toLabel).first->OnBufferReceive(srcTarget, inFrameBuffer); + if (commMap_[userId].count(toLabel) != 0 && commMap_[userId].at(toLabel).second) { + commMap_[userId].at(toLabel).first->OnBufferReceive(srcTarget, inFrameBuffer); // Frame handed over to communicator who is responsible to delete it. The frame is deleted here after return. inFrameBuffer = nullptr; return E_OK; } + Communicator *communicator = nullptr; + bool isEmpty = false; + for (auto &userCommMap : commMap_) { + for (auto &entry : userCommMap.second) { + if (entry.first == toLabel && entry.second.second) { + communicator = entry.second.first; + isEmpty = userCommMap.first.empty(); + LOGW("[CommAggr][TryDeliver] Found communicator of %s, but required user is %s", + userCommMap.first.c_str(), userId.c_str()); + break; + } + } + if (communicator != nullptr) { + break; + } + } + if (communicator != nullptr && (userId.empty() || isEmpty)) { + communicator->OnBufferReceive(srcTarget, inFrameBuffer); + inFrameBuffer = nullptr; + return E_OK; + } + LOGE("[CommAggr][TryDeliver] Communicator not found"); return -E_NOT_FOUND; } @@ -738,13 +769,13 @@ int CommunicatorAggregator::RegCallbackToAdapter() } RefObject::IncObjRef(this); // Reference to be hold by adapter - errCode = adapterHandle_->RegSendableCallback([this](const std::string &target, int softBusErrCode) { - LOGI("[CommAggr] Send able dev=%.3s, softBusErrCode=%d", target.c_str(), softBusErrCode); - if (softBusErrCode == E_OK) { + errCode = adapterHandle_->RegSendableCallback([this](const std::string &target, int deviceCommErrCode) { + LOGI("[CommAggr] Send able dev=%.3s, deviceCommErrCode=%d", target.c_str(), deviceCommErrCode); + if (deviceCommErrCode == E_OK) { (void)IncreaseSendSequenceId(target); OnSendable(target); } - scheduler_.SetSoftBusErrCode(target, softBusErrCode); + scheduler_.SetDeviceCommErrCode(target, deviceCommErrCode); }, [this]() { RefObject::DecObjRef(this); }); if (errCode != E_OK) { @@ -901,11 +932,13 @@ void CommunicatorAggregator::NotifyConnectChange(const std::string &srcTarget, // Do target change notify std::lock_guard commMapLockGuard(commMapMutex_); for (auto &entry : changedLabels) { - // Ignore nonactivated communicator - if (commMap_.count(entry.first) != 0 && commMap_.at(entry.first).second) { - LOGI("[CommAggr][NotifyConnectChange] label=%s, srcTarget=%s{private}, isOnline=%d.", - VEC_TO_STR(entry.first), srcTarget.c_str(), entry.second); - commMap_.at(entry.first).first->OnConnectChange(srcTarget, entry.second); + for (auto &userCommMap : commMap_) { + // Ignore nonactivated communicator + if (userCommMap.second.count(entry.first) != 0 && userCommMap.second.at(entry.first).second) { + LOGI("[CommAggr][NotifyConnectChange] label=%s, srcTarget=%s{private}, isOnline=%d.", + VEC_TO_STR(entry.first), srcTarget.c_str(), entry.second); + userCommMap.second.at(entry.first).first->OnConnectChange(srcTarget, entry.second); + } } } } @@ -950,6 +983,10 @@ void CommunicatorAggregator::SendOnceData() // std::vector, uint32_t>> piecePackets; uint32_t mtu = adapterHandle_->GetMtuSize(taskToSend.dstTarget); + if (taskToSend.buffer == nullptr) { + LOGE("[CommAggr] buffer of taskToSend is nullptr."); + return; + } errCode = ProtocolProto::SplitFrameIntoPacketsIfNeed(taskToSend.buffer, mtu, piecePackets); if (errCode != E_OK) { LOGE("[CommAggr] Split frame fail, errCode=%d.", errCode); diff --git a/kv_store/frameworks/libs/distributeddb/communicator/src/network_adapter.cpp b/kv_store/frameworks/libs/distributeddb/communicator/src/network_adapter.cpp index f1a7e35575d12d55660c34e63c9031e268945ab2..688ea39422a5df540b899c1fc1d8849ac55c9716 100644 --- a/kv_store/frameworks/libs/distributeddb/communicator/src/network_adapter.cpp +++ b/kv_store/frameworks/libs/distributeddb/communicator/src/network_adapter.cpp @@ -84,9 +84,9 @@ int NetworkAdapter::StartAdapter() LOGI("[NAdapt][Start] ROLLBACK: Stop errCode=%d.", static_cast(errCode)); return -E_PERIPHERAL_INTERFACE_FAIL; } - processCommunicator_->RegOnSendAble([this](const DeviceInfos &devInfo, int softBusErrCode) { + processCommunicator_->RegOnSendAble([this](const DeviceInfos &devInfo, int deviceCommErrCode) { if (onSendableHandle_ != nullptr) { - onSendableHandle_(devInfo.identifier, softBusErrCode); + onSendableHandle_(devInfo.identifier, deviceCommErrCode); } }); // These code is compensation for the probable defect of IProcessCommunicator implementation. diff --git a/kv_store/frameworks/libs/distributeddb/communicator/src/protocol_proto.cpp b/kv_store/frameworks/libs/distributeddb/communicator/src/protocol_proto.cpp index 3cf9bb19789fe379e49f7c8e39a4df0cac356261..d5339ebb0168435f9f59365dacdbb3d503dfcf96 100644 --- a/kv_store/frameworks/libs/distributeddb/communicator/src/protocol_proto.cpp +++ b/kv_store/frameworks/libs/distributeddb/communicator/src/protocol_proto.cpp @@ -36,7 +36,7 @@ const uint8_t PACKET_TYPE_FRAGMENTED = BITX(0); // Use bit 0 const uint8_t PACKET_TYPE_NOT_FRAGMENTED = 0; const uint8_t MAX_PADDING_LEN = 7; const uint32_t LENGTH_BEFORE_SUM_RANGE = sizeof(uint64_t) + sizeof(uint64_t); -const uint32_t MAX_FRAME_LEN = 32 * 1024 * 1024; // Max 32 MB, 1024 is scale +const uint32_t MAX_FRAME_LEN = 128 * 1024 * 1024; // Max 128 MB, 1024 is scale const uint16_t MIN_FRAGMENT_COUNT = 2; // At least a frame will be splited into 2 parts // LabelExchange(Ack) Frame Field Length const uint32_t LABEL_VER_LEN = sizeof(uint64_t); diff --git a/kv_store/frameworks/libs/distributeddb/communicator/src/send_task_scheduler.cpp b/kv_store/frameworks/libs/distributeddb/communicator/src/send_task_scheduler.cpp index db1b9d4e33f4575e564311f3558c9d7de9b61d93..d3df2bab48e250bf7d88ac6692e55735bbfeea51 100644 --- a/kv_store/frameworks/libs/distributeddb/communicator/src/send_task_scheduler.cpp +++ b/kv_store/frameworks/libs/distributeddb/communicator/src/send_task_scheduler.cpp @@ -300,23 +300,23 @@ void SendTaskScheduler::InvalidSendTask(const std::string &target) for (auto &sendTask : taskGroupByPrio_[priority][target]) { sendTask.isValid = false; LOGI("[Scheduler][InvalidSendTask] invalid frameId=%" PRIu32, sendTask.frameId); - if ((softBusErrCodeMap_.count(target) == 0) || (softBusErrCodeMap_[target] == E_OK)) { + if ((deviceCommErrCodeMap_.count(target) == 0) || (deviceCommErrCodeMap_[target] == E_OK)) { continue; } - LOGE("[Scheduler][InvalidSendTask] target=%.3s, errCode=%d", target.c_str(), softBusErrCodeMap_[target]); + LOGE("[Scheduler][InvalidSendTask] target=%.3s, errCode=%d", target.c_str(), deviceCommErrCodeMap_[target]); if (sendTask.onEnd) { LOGI("[Scheduler][InvalidSendTask] On Send End."); - sendTask.onEnd(softBusErrCodeMap_[target], false); + sendTask.onEnd(deviceCommErrCodeMap_[target], false); sendTask.onEnd = nullptr; } } } - softBusErrCodeMap_.erase(target); + deviceCommErrCodeMap_.erase(target); } -void SendTaskScheduler::SetSoftBusErrCode(const std::string &target, int softBusErrCode) +void SendTaskScheduler::SetDeviceCommErrCode(const std::string &target, int deviceCommErrCode) { std::lock_guard overallLockGuard(overallMutex_); - softBusErrCodeMap_[target] = softBusErrCode; + deviceCommErrCodeMap_[target] = deviceCommErrCode; } } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/distributeddb.gni b/kv_store/frameworks/libs/distributeddb/distributeddb.gni index 620289b4b697a85b4533d18e24467136c696f92e..def61407b0d06055329272bcdbdb3397fd97ddc8 100644 --- a/kv_store/frameworks/libs/distributeddb/distributeddb.gni +++ b/kv_store/frameworks/libs/distributeddb/distributeddb.gni @@ -14,9 +14,14 @@ distributeddb_path = "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb" +declare_args() { + kv_store_cloud = true +} + distributeddb_src = [ "${distributeddb_path}/common/src/auto_launch.cpp", "${distributeddb_path}/common/src/cloud/asset_operation_utils.cpp", + "${distributeddb_path}/common/src/cloud/assets_download_manager.cpp", "${distributeddb_path}/common/src/concurrent_adapter.cpp", "${distributeddb_path}/common/src/data_compression.cpp", "${distributeddb_path}/common/src/data_value.cpp", @@ -143,6 +148,7 @@ distributeddb_src = [ "${distributeddb_path}/storage/src/relational/relational_store_connection.cpp", "${distributeddb_path}/storage/src/relational/relational_store_instance.cpp", "${distributeddb_path}/storage/src/relational/relational_sync_able_storage.cpp", + "${distributeddb_path}/storage/src/relational/relational_sync_able_storage_extend.cpp", "${distributeddb_path}/storage/src/relational/relational_sync_data_inserter.cpp", "${distributeddb_path}/storage/src/relational/relationaldb_properties.cpp", "${distributeddb_path}/storage/src/result_entries_window.cpp", @@ -156,6 +162,7 @@ distributeddb_src = [ "${distributeddb_path}/storage/src/sqlite/query_sync_object.cpp", "${distributeddb_path}/storage/src/sqlite/relational/cloud_sync_log_table_manager.cpp", "${distributeddb_path}/storage/src/sqlite/relational/collaboration_log_table_manager.cpp", + "${distributeddb_path}/storage/src/sqlite/relational/device_tracker_log_table_manager.cpp", "${distributeddb_path}/storage/src/sqlite/relational/log_table_manager_factory.cpp", "${distributeddb_path}/storage/src/sqlite/relational/relational_remote_query_continue_token.cpp", "${distributeddb_path}/storage/src/sqlite/relational/simple_tracker_log_table_manager.cpp", @@ -202,20 +209,6 @@ distributeddb_src = [ "${distributeddb_path}/storage/src/sync_able_engine.cpp", "${distributeddb_path}/storage/src/upgrader/single_ver_database_upgrader.cpp", "${distributeddb_path}/storage/src/upgrader/single_ver_schema_database_upgrader.cpp", - "${distributeddb_path}/syncer/src/cloud/cloud_force_pull_strategy.cpp", - "${distributeddb_path}/syncer/src/cloud/cloud_force_push_strategy.cpp", - "${distributeddb_path}/syncer/src/cloud/cloud_merge_strategy.cpp", - "${distributeddb_path}/syncer/src/cloud/cloud_sync_strategy.cpp", - "${distributeddb_path}/syncer/src/cloud/cloud_db_proxy.cpp", - "${distributeddb_path}/syncer/src/cloud/cloud_locker.cpp", - "${distributeddb_path}/syncer/src/cloud/cloud_syncer.cpp", - "${distributeddb_path}/syncer/src/cloud/cloud_syncer_extend.cpp", - "${distributeddb_path}/syncer/src/cloud/cloud_sync_state_machine.cpp", - "${distributeddb_path}/syncer/src/cloud/cloud_sync_tag_assets.cpp", - "${distributeddb_path}/syncer/src/cloud/cloud_sync_utils.cpp", - "${distributeddb_path}/syncer/src/cloud/process_notifier.cpp", - "${distributeddb_path}/syncer/src/cloud/process_recorder.cpp", - "${distributeddb_path}/syncer/src/cloud/strategy_factory.cpp", "${distributeddb_path}/syncer/src/device/ability_sync.cpp", "${distributeddb_path}/syncer/src/device/commit_history_sync.cpp", "${distributeddb_path}/syncer/src/device/communicator_proxy.cpp", @@ -261,6 +254,23 @@ distributeddb_src = [ "${distributeddb_path}/syncer/src/time_helper.cpp", ] +distributeddb_cloud_src = [ + "${distributeddb_path}/syncer/src/cloud/cloud_force_pull_strategy.cpp", + "${distributeddb_path}/syncer/src/cloud/cloud_force_push_strategy.cpp", + "${distributeddb_path}/syncer/src/cloud/cloud_merge_strategy.cpp", + "${distributeddb_path}/syncer/src/cloud/cloud_sync_strategy.cpp", + "${distributeddb_path}/syncer/src/cloud/cloud_db_proxy.cpp", + "${distributeddb_path}/syncer/src/cloud/cloud_locker.cpp", + "${distributeddb_path}/syncer/src/cloud/cloud_syncer.cpp", + "${distributeddb_path}/syncer/src/cloud/cloud_syncer_extend.cpp", + "${distributeddb_path}/syncer/src/cloud/cloud_sync_state_machine.cpp", + "${distributeddb_path}/syncer/src/cloud/cloud_sync_tag_assets.cpp", + "${distributeddb_path}/syncer/src/cloud/cloud_sync_utils.cpp", + "${distributeddb_path}/syncer/src/cloud/process_notifier.cpp", + "${distributeddb_path}/syncer/src/cloud/process_recorder.cpp", + "${distributeddb_path}/syncer/src/cloud/strategy_factory.cpp", +] + distributeddb_src_rd = [ "${distributeddb_path}/gaussdb_rd/src/common/src/collection_option.cpp", "${distributeddb_path}/gaussdb_rd/src/common/src/db_config.cpp", diff --git a/kv_store/frameworks/libs/distributeddb/gaussdb_rd/src/interface/src/collection.cpp b/kv_store/frameworks/libs/distributeddb/gaussdb_rd/src/interface/src/collection.cpp index 89f76030fff7edee29ad0fd05b4c5adde2b29c11..b56650198722c656ec62707d3a88430f2e13543d 100644 --- a/kv_store/frameworks/libs/distributeddb/gaussdb_rd/src/interface/src/collection.cpp +++ b/kv_store/frameworks/libs/distributeddb/gaussdb_rd/src/interface/src/collection.cpp @@ -40,6 +40,9 @@ int Collection::InsertUntilSuccess(Key &key, const std::string &id, Value &valSe { DocKey docKey; key.assign(id.begin(), id.end()); + if (executor_ == nullptr) { + return -E_INNER_ERROR; + } int errCode = executor_->InsertData(name_, key, valSet); while (errCode == -E_DATA_CONFLICT) { // if id alreay exist, create new one. DocumentKey::GetOidDocKey(docKey); diff --git a/kv_store/frameworks/libs/distributeddb/gaussdb_rd/src/oh_adapter/src/rd_json_object.cpp b/kv_store/frameworks/libs/distributeddb/gaussdb_rd/src/oh_adapter/src/rd_json_object.cpp index 1b469f2c410f16a5d33424e90e15945b8de6742c..48c9103711f896d940190fb5e3bc602abc11c08e 100644 --- a/kv_store/frameworks/libs/distributeddb/gaussdb_rd/src/oh_adapter/src/rd_json_object.cpp +++ b/kv_store/frameworks/libs/distributeddb/gaussdb_rd/src/oh_adapter/src/rd_json_object.cpp @@ -40,7 +40,9 @@ ValueObject::ValueObject(double val) ValueObject::ValueObject(const char *val) { valueType = ValueType::VALUE_STRING; - stringValue = val; + if (val != nullptr) { + stringValue = val; + } } ValueObject::ValueType ValueObject::GetValueType() const diff --git a/kv_store/frameworks/libs/distributeddb/gaussdb_rd/test/unittest/api/documentdb_find_test.cpp b/kv_store/frameworks/libs/distributeddb/gaussdb_rd/test/unittest/api/documentdb_find_test.cpp index 44515ca6b43275908b51a46dbc5c38bbb0a41699..2b5c72a0824a90bafea1c26df8006e414ec8d82f 100644 --- a/kv_store/frameworks/libs/distributeddb/gaussdb_rd/test/unittest/api/documentdb_find_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/gaussdb_rd/test/unittest/api/documentdb_find_test.cpp @@ -1391,14 +1391,6 @@ HWTEST_F(DocumentDBFindTest, DocumentDBFindTest057, TestSize.Level1) */ EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); } -/** - * @tc.name: DocumentDBFindTest058 - * @tc.desc: Test findDoc with no _id. - * @tc.type: FUNC - * @tc.require: - * @tc.author: mazhao - */ -HWTEST_F(DocumentDBFindTest, DocumentDBFindTest058, TestSize.Level1) {} HWTEST_F(DocumentDBFindTest, DocumentDBFindTest059, TestSize.Level1) { diff --git a/kv_store/frameworks/libs/distributeddb/include/auto_launch_export.h b/kv_store/frameworks/libs/distributeddb/include/auto_launch_export.h index 485c395da208a5f181add61528df4af97a0f5789..5f5a83999610923138905fc5318b17e9ecf18667 100644 --- a/kv_store/frameworks/libs/distributeddb/include/auto_launch_export.h +++ b/kv_store/frameworks/libs/distributeddb/include/auto_launch_export.h @@ -43,6 +43,7 @@ struct AutoLaunchOption { bool syncDualTupleMode = false; // communicator label use dualTuple hash or not uint32_t iterateTimes = 0; int conflictResolvePolicy = LAST_WIN; + DistributedTableMode tableMode = DistributedTableMode::SPLIT_BY_DEVICE; }; struct AutoLaunchParam { @@ -52,6 +53,7 @@ struct AutoLaunchParam { AutoLaunchOption option; AutoLaunchNotifier notifier; std::string path; + std::string subUser = ""; }; using AutoLaunchRequestCallback = std::function; diff --git a/kv_store/frameworks/libs/distributeddb/include/query.h b/kv_store/frameworks/libs/distributeddb/include/query.h index 39957c94b8ef79e3b80c538ff3d5060662c36693..ded9c1a574df097f1cb3f9a31227fbc581978f5c 100644 --- a/kv_store/frameworks/libs/distributeddb/include/query.h +++ b/kv_store/frameworks/libs/distributeddb/include/query.h @@ -151,6 +151,8 @@ public: DB_API Query &Range(const std::vector &keyBegin, const std::vector &keyEnd); + DB_API Query &AssetsOnly(const AssetsMap &assets); + friend class GetQueryInfo; DB_API ~Query() = default; DB_API Query() = default; diff --git a/kv_store/frameworks/libs/distributeddb/include/query_expression.h b/kv_store/frameworks/libs/distributeddb/include/query_expression.h index f7c44dc85be8f9c1f034195749fbaeed0dbe2e37..e0763cc4d0b05b6d9d442e67d5661549d410166b 100644 --- a/kv_store/frameworks/libs/distributeddb/include/query_expression.h +++ b/kv_store/frameworks/libs/distributeddb/include/query_expression.h @@ -125,6 +125,8 @@ public: void QueryByKeyRange(const std::vector &keyBegin, const std::vector &keyEnd); + void QueryAssetsOnly(const AssetsMap &assets); + std::vector GetPreFixKey() const; std::vector GetBeginKey() const; @@ -155,6 +157,12 @@ public: int GetExpressionStatus() const; std::vector GetQueryExpressions() const; int RangeParamCheck() const; + + bool IsAssetsOnly() const; + AssetsGroupMap GetAssetsOnlyGroupMap() const; + uint32_t GetGroupNum() const; + int GetExpressionStatusForAssetsOnly() const; + private: void AssemblyQueryInfo(const QueryObjType queryOperType, const std::string &field, const QueryValueType type, const std::vector &value, bool isNeedFieldPath); @@ -182,6 +190,10 @@ private: std::list tableSequence_; std::map expressions_; int validStatus_ = 0; + uint32_t groupNum_ = 0; + bool isAssetsOnly_ = false; + AssetsGroupMap assetsGroupMap_; + int validStatusForAssetsOnly_ = 0; }; // specialize for double diff --git a/kv_store/frameworks/libs/distributeddb/include/types_export.h b/kv_store/frameworks/libs/distributeddb/include/types_export.h index 21158ebc6a0300d612850ccb1fe2316a8ab04f64..73abe2cd7d05fa58ba1a4d8ec688afadf26c0620 100644 --- a/kv_store/frameworks/libs/distributeddb/include/types_export.h +++ b/kv_store/frameworks/libs/distributeddb/include/types_export.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,9 @@ namespace DistributedDB { using Key = std::vector; using Value = std::vector; +using AssetsMap = std::map>; +using AssetsGroupMap = std::map; + struct Entry { Key key; Value value; @@ -119,14 +123,24 @@ struct PermissionCheckParam { std::string appId; std::string storeId; std::string deviceId; + std::string subUserId; int32_t instanceId = 0; std::map extraConditions; }; +struct PermissionCheckParamV4 { + std::string userId; + std::string appId; + std::string storeId; + std::string deviceId; + std::string subUserId; +}; + struct ActivationCheckParam { std::string userId; std::string appId; std::string storeId; + std::string subUserId; int32_t instanceId = 0; }; @@ -134,9 +148,18 @@ struct PermissionConditionParam { std::string userId; std::string appId; std::string storeId; + std::string subUserId; int32_t instanceId = 0; }; +struct StoreStatusNotifierParam { + std::string userId; + std::string appId; + std::string storeId; + std::string subUserId; + std::string deviceId; +}; + using PermissionCheckCallback = std::function; @@ -145,9 +168,14 @@ using PermissionCheckCallbackV2 = std::function; +using PermissionCheckCallbackV4 = std::function; + using StoreStatusNotifier = std::function; // status, 1: online, 0: offline +using StoreStatusNotifierV2 = std::function; // status, 1: online, 0: offline + using SyncActivationCheckCallback = std::function; diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/include/cloud/cloud_store_types.h b/kv_store/frameworks/libs/distributeddb/interfaces/include/cloud/cloud_store_types.h index 5e481e6c8375ad4ad60cbca3b18ba6aaa3e3ccc7..f9858e210a5986c207001cf6c99d241bbb9233c5 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/include/cloud/cloud_store_types.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/include/cloud/cloud_store_types.h @@ -151,12 +151,14 @@ struct CloudSyncOption { Query query; int64_t waitTime = 0; bool priorityTask = false; + int32_t priorityLevel = 0; // [0, 2] bool compensatedSyncOnly = false; std::vector users; bool merge = false; // default, upload insert need lock LockAction lockAction = LockAction::INSERT; std::string prepareTraceId; + bool asyncDownloadAssets = false; }; enum class QueryNodeType : uint32_t { @@ -199,5 +201,10 @@ struct CloudSyncConfig { int32_t maxUploadSize = 1024 * 512 * 3; // default max upload 1024 * 512 * 3 = 1.5m int32_t maxRetryConflictTimes = -1; // default max retry -1 is unlimited retry times }; + +struct AsyncDownloadAssetsConfig { + uint32_t maxDownloadTask = 1; // valid range in [1, 12] max async download task in process + uint32_t maxDownloadAssetsCount = 100; // valid range in [1, 2000] max async download assets count in one batch +}; } // namespace DistributedDB #endif // CLOUD_STORE_TYPE_H \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/include/cloud/iAssetLoader.h b/kv_store/frameworks/libs/distributeddb/interfaces/include/cloud/iAssetLoader.h index acd16cb7dbce03c05b9739f229ce264ed6f031fe..2d19e21d36ea561248291d6596a583a9f63f6047 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/include/cloud/iAssetLoader.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/include/cloud/iAssetLoader.h @@ -59,6 +59,11 @@ public: virtual void BatchRemoveLocalAssets(const std::string &tableName, std::vector &removeAssets) { } + + virtual DBStatus CancelDownload() + { + return OK; + } }; } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/include/iprocess_communicator.h b/kv_store/frameworks/libs/distributeddb/interfaces/include/iprocess_communicator.h index 5cc6d11b6f9aaaf9711b04c149dc479800f151e4..e1ac4b1751ff4a31619341b5dfc0edec59357a7f 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/include/iprocess_communicator.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/include/iprocess_communicator.h @@ -34,6 +34,7 @@ struct ExtendInfo { std::string storeId; std::string userId; std::string dstTarget; + std::string subUserId; }; class ExtendHeaderHandle { @@ -67,7 +68,7 @@ using OnDeviceChange = std::function; -using OnSendAble = std::function; +using OnSendAble = std::function; // For all functions with returnType DBStatus: // return DBStatus::OK if successful, otherwise DBStatus::DB_ERROR if anything wrong. diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/include/kv_store_delegate_manager.h b/kv_store/frameworks/libs/distributeddb/interfaces/include/kv_store_delegate_manager.h index fdc97a6ffca5d5edf8d14355f9bcbc2fd4b9a4ba..d09f6c65eda577f92154717f6e2c27385c54db62 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/include/kv_store_delegate_manager.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/include/kv_store_delegate_manager.h @@ -86,12 +86,19 @@ public: DB_API static DBStatus SetPermissionCheckCallback(const PermissionCheckCallbackV2 &callback); + DB_API static DBStatus SetPermissionCheckCallback(const PermissionCheckCallbackV4 &callback); + DB_API static DBStatus EnableKvStoreAutoLaunch(const std::string &userId, const std::string &appId, const std::string &storeId, const AutoLaunchOption &option, const AutoLaunchNotifier ¬ifier); + DB_API static DBStatus EnableKvStoreAutoLaunch(const AutoLaunchParam ¶m); + DB_API static DBStatus DisableKvStoreAutoLaunch(const std::string &userId, const std::string &appId, const std::string &storeId); + DB_API static DBStatus DisableKvStoreAutoLaunch(const std::string &userId, const std::string &subUser, + const std::string &appId, const std::string &storeId); + // deprecated DB_API static void SetAutoLaunchRequestCallback(const AutoLaunchRequestCallback &callback); @@ -105,6 +112,8 @@ public: DB_API static void SetStoreStatusNotifier(const StoreStatusNotifier ¬ifier); + DB_API static void SetStoreStatusNotifier(const StoreStatusNotifierV2 ¬ifier); + DB_API static DBStatus SetSyncActivationCheckCallback(const SyncActivationCheckCallback &callback); DB_API static DBStatus NotifyUserChanged(); diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/include/kv_store_nb_delegate.h b/kv_store/frameworks/libs/distributeddb/interfaces/include/kv_store_nb_delegate.h index 072a31d07e538b1d127d14fafd84672653385fdb..c70d32fcaa9f21f6efe257dd011dbaed40dd5baa 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/include/kv_store_nb_delegate.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/include/kv_store_nb_delegate.h @@ -251,13 +251,24 @@ public: DB_API virtual std::pair GetWatermarkInfo(const std::string &device) = 0; // sync with cloud - DB_API virtual DBStatus Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess) = 0; + DB_API virtual DBStatus Sync([[gnu::unused]] const CloudSyncOption &option, + [[gnu::unused]] const SyncProcessCallback &onProcess) + { + return OK; + } // set cloud db with user - DB_API virtual DBStatus SetCloudDB(const std::map> &cloudDBs) = 0; + DB_API virtual DBStatus SetCloudDB( + [[gnu::unused]] const std::map> &cloudDBs) + { + return OK; + } // set cloud schema - DB_API virtual DBStatus SetCloudDbSchema(const std::map &schema) = 0; + DB_API virtual DBStatus SetCloudDbSchema([[gnu::unused]] const std::map &schema) + { + return OK; + } // remove device data for cloud DB_API virtual DBStatus RemoveDeviceData(const std::string &device, ClearMode mode) = 0; @@ -269,18 +280,27 @@ public: DB_API virtual int32_t GetTaskCount() = 0; // set generate cloud version callback - DB_API virtual void SetGenCloudVersionCallback(const GenerateCloudVersionCallback &callback) = 0; + DB_API virtual void SetGenCloudVersionCallback([[gnu::unused]] const GenerateCloudVersionCallback &callback) + { + return; + } // get cloud version by device DB_API virtual std::pair> GetCloudVersion( - const std::string &device) = 0; + [[gnu::unused]] const std::string &device) + { + return {}; + } // This API is not recommended. Before using this API, you need to understand the API usage rules. // The interceptor works when receive data. DB_API virtual DBStatus SetReceiveDataInterceptor(const DataInterceptor &interceptor) = 0; // set the config for cloud sync task - DB_API virtual DBStatus SetCloudSyncConfig(const CloudSyncConfig &config) = 0; + DB_API virtual DBStatus SetCloudSyncConfig([[gnu::unused]] const CloudSyncConfig &config) + { + return OK; + } // Get Entries by the device(uuid) in sync_data. // If device is empty, it would return all the entries which was written by local device. diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_delegate.h b/kv_store/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_delegate.h index 829a409a36c47d8597f4926879e0ecf85fae5bd2..65720ca2c91696ce766b276bbd12bd527c62e312 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_delegate.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_delegate.h @@ -40,6 +40,7 @@ public: CipherType cipher = CipherType::DEFAULT; CipherPassword passwd; uint32_t iterateTimes = 0; + DistributedTableMode tableMode = DistributedTableMode::SPLIT_BY_DEVICE; }; DB_API DBStatus CreateDistributedTable(const std::string &tableName, TableSyncType type = DEVICE_COOPERATION) @@ -50,7 +51,10 @@ public: DB_API virtual DBStatus Sync(const std::vector &devices, SyncMode mode, const Query &query, const SyncStatusCallback &onComplete, bool wait) = 0; - DB_API virtual int32_t GetCloudSyncTaskCount() = 0; + DB_API virtual int32_t GetCloudSyncTaskCount() + { + return 0; + } DB_API DBStatus RemoveDeviceData(const std::string &device, ClearMode mode = DEFAULT) { @@ -66,13 +70,22 @@ public: // remove all device data DB_API virtual DBStatus RemoveDeviceData() = 0; - DB_API virtual DBStatus Sync(const std::vector &devices, SyncMode mode, - const Query &query, const SyncProcessCallback &onProcess, - int64_t waitTime) = 0; + DB_API virtual DBStatus Sync([[gnu::unused]] const std::vector &devices, + [[gnu::unused]] SyncMode mode, [[gnu::unused]] const Query &query, + [[gnu::unused]] const SyncProcessCallback &onProcess, [[gnu::unused]] int64_t waitTime) + { + return OK; + } - DB_API virtual DBStatus SetCloudDB(const std::shared_ptr &cloudDb) = 0; + DB_API virtual DBStatus SetCloudDB([[gnu::unused]] const std::shared_ptr &cloudDb) + { + return OK; + } - DB_API virtual DBStatus SetCloudDbSchema(const DataBaseSchema &schema) = 0; + DB_API virtual DBStatus SetCloudDbSchema([[gnu::unused]] const DataBaseSchema &schema) + { + return OK; + } // just support one observer exist at same time DB_API virtual DBStatus RegisterObserver(StoreObserver *observer) = 0; @@ -81,9 +94,16 @@ public: DB_API virtual DBStatus UnRegisterObserver(StoreObserver *observer) = 0; - DB_API virtual DBStatus SetIAssetLoader(const std::shared_ptr &loader) = 0; + DB_API virtual DBStatus SetIAssetLoader([[gnu::unused]] const std::shared_ptr &loader) + { + return OK; + } - DB_API virtual DBStatus Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess) = 0; + DB_API virtual DBStatus Sync([[gnu::unused]] const CloudSyncOption &option, + [[gnu::unused]] const SyncProcessCallback &onProcess) + { + return OK; + } DB_API virtual DBStatus SetTrackerTable(const TrackerSchema &schema) = 0; @@ -99,7 +119,10 @@ public: RecordStatus status = RecordStatus::WAIT_COMPENSATED_SYNC) = 0; // set the config for cloud sync task - DB_API virtual DBStatus SetCloudSyncConfig(const CloudSyncConfig &config) = 0; + DB_API virtual DBStatus SetCloudSyncConfig([[gnu::unused]] const CloudSyncConfig &config) + { + return OK; + } DB_API virtual DBStatus Sync([[gnu::unused]] const CloudSyncOption &option, [[gnu::unused]] const SyncProcessCallback &onProcess, @@ -112,6 +135,16 @@ public: { return {}; } + + DB_API virtual DBStatus SetDistributedSchema([[gnu::unused]] const DistributedSchema &schema) + { + return OK; + } + + DB_API virtual std::pair GetDownloadingAssetsCount() + { + return {OK, 0}; + } protected: virtual DBStatus RemoveDeviceDataInner(const std::string &device, ClearMode mode) = 0; virtual DBStatus CreateDistributedTableInner(const std::string &tableName, TableSyncType type) = 0; diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_manager.h b/kv_store/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_manager.h index 745f4dc71f21d9f63ded58ff1a88c9062a6e6e6b..2715b2274ccfcc61705e0d0a1601729a44b01b42 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_manager.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_manager.h @@ -56,6 +56,9 @@ public: DB_API static std::string GetRelationalStoreIdentifier(const std::string &userId, const std::string &appId, const std::string &storeId, bool syncDualTupleMode = false); + DB_API static std::string GetRelationalStoreIdentifier(const std::string &userId, const std::string &subUserId, + const std::string &appId, const std::string &storeId, bool syncDualTupleMode = false); + DB_API static std::vector ParserQueryNodes(const Bytes &queryBytes, DBStatus &status); private: bool PreCheckOpenStore(const std::string &path, const std::string &storeId, diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/include/runtime_config.h b/kv_store/frameworks/libs/distributeddb/interfaces/include/runtime_config.h index f98fe90247bc6da82438c2f5c3923b147c46c976..2e87ba34d0a53b05eada471aa5edfcdf1d0c6d69 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/include/runtime_config.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/include/runtime_config.h @@ -45,6 +45,8 @@ public: DB_API static DBStatus SetPermissionCheckCallback(const PermissionCheckCallbackV3 &callback); + DB_API static DBStatus SetPermissionCheckCallback(const PermissionCheckCallbackV4 &callback); + DB_API static DBStatus SetProcessSystemAPIAdapter(const std::shared_ptr &adapter); DB_API static void Dump(int fd, const std::vector &args); @@ -70,12 +72,20 @@ public: DB_API static std::string GetStoreIdentifier(const std::string &userId, const std::string &appId, const std::string &storeId, bool syncDualTupleMode = false); + DB_API static std::string GetStoreIdentifier(const std::string &userId, const std::string &subUserId, + const std::string &appId, const std::string &storeId, bool syncDualTupleMode = false); + DB_API static void ReleaseAutoLaunch(const std::string &userId, const std::string &appId, const std::string &storeId, DBType type); + DB_API static void ReleaseAutoLaunch(const std::string &userId, const std::string &subUserId, + const std::string &appId, const std::string &storeId, DBType type); + DB_API static void SetThreadPool(const std::shared_ptr &threadPool); DB_API static void SetCloudTranslate(const std::shared_ptr &dataTranslate); + + DB_API static DBStatus SetAsyncDownloadAssetsConfig(const AsyncDownloadAssetsConfig &config); private: static std::mutex communicatorMutex_; static std::mutex multiUserMutex_; diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/include/store_types.h b/kv_store/frameworks/libs/distributeddb/interfaces/include/store_types.h index 91f96be81635cf3d386f5c5426ddae2cf76e0c65..5fff893a1cdbea5cfec335f9474eb459e5136aaa 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/include/store_types.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/include/store_types.h @@ -90,6 +90,10 @@ enum DBStatus { CLOUD_RECORD_ALREADY_EXISTED, // this error happen in BatchInsert SQLITE_CANT_OPEN, // the sqlite cannot open LOCAL_ASSET_NOT_FOUND, // file manager miss local assets + ASSET_NOT_FOUND_FOR_DOWN_ONLY, // assets miss for asset only + CLOUD_DISABLED, // the cloud switch has been turned off + DISTRIBUTED_FIELD_DECREASE, // sync fewer specified columns than last time + SKIP_ASSET, // workaround status for contact app assets download failure, need to ignore these failures BUTT_STATUS = 27394048 // end of status }; @@ -117,6 +121,7 @@ enum PragmaCmd { SET_MAX_LOG_LIMIT, EXEC_CHECKPOINT, LOGIC_DELETE_SYNC_DATA, + SET_MAX_VALUE_SIZE, }; enum ResolutionPolicyType { @@ -252,6 +257,7 @@ static constexpr const char *GAUSSDB_RD = "gaussdb_rd"; static constexpr const char *SQLITE = "sqlite"; struct ChangeProperties { bool isTrackedDataChange = false; + bool isP2pSyncDataChange = false; }; enum IndexType : uint32_t { @@ -284,5 +290,28 @@ struct DbIdParam { std::string subUser = ""; int32_t instanceId = 0; }; + +struct DistributedField { + std::string colName; + bool isP2pSync = false; // device p2p sync with this column when it was true + // default generate by local table pk when none field was specified + bool isSpecified = false; // local log hashKey will generate by specified field and deal conflict with them +}; + +struct DistributedTable { + std::string tableName; + std::vector fields; +}; + +struct DistributedSchema { + uint32_t version = 0; + std::vector tables; +}; + +// Table mode of device data for relational store +enum class DistributedTableMode : int { + COLLABORATION = 0, // Save all devices data in user table + SPLIT_BY_DEVICE // Save device data in each table split by device +}; } // namespace DistributedDB #endif // KV_STORE_TYPE_H diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_delegate_manager.cpp b/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_delegate_manager.cpp index aa14598b5afd6152508e38ced44f185fcd9a7e77..f81b47919d1750184d2b69b95b4922cd98ec8060 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_delegate_manager.cpp +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_delegate_manager.cpp @@ -558,22 +558,31 @@ DBStatus KvStoreDelegateManager::SetPermissionCheckCallback(const PermissionChec return TransferDBErrno(errCode); } +DBStatus KvStoreDelegateManager::SetPermissionCheckCallback(const PermissionCheckCallbackV4 &callback) +{ + return TransferDBErrno(RuntimeContext::GetInstance()->SetPermissionCheckCallback(callback)); +} + DBStatus KvStoreDelegateManager::EnableKvStoreAutoLaunch(const std::string &userId, const std::string &appId, const std::string &storeId, const AutoLaunchOption &option, const AutoLaunchNotifier ¬ifier) +{ + AutoLaunchParam param{ userId, appId, storeId, option, notifier, {}, "" }; + return EnableKvStoreAutoLaunch(param); +} + +DBStatus KvStoreDelegateManager::EnableKvStoreAutoLaunch(const AutoLaunchParam ¶m) { if (RuntimeContext::GetInstance() == nullptr) { return DB_ERROR; } - AutoLaunchParam param{ userId, appId, storeId, option, notifier, {} }; std::shared_ptr ptr; int errCode = AutoLaunch::GetAutoLaunchProperties(param, DBTypeInner::DB_KV, true, ptr); if (errCode != E_OK) { LOGE("[KvStoreManager] Enable auto launch, get properties failed:%d", errCode); return TransferDBErrno(errCode); } - std::shared_ptr kvPtr = std::static_pointer_cast(ptr); - errCode = RuntimeContext::GetInstance()->EnableKvStoreAutoLaunch(*kvPtr, notifier, option); + errCode = RuntimeContext::GetInstance()->EnableKvStoreAutoLaunch(*kvPtr, param.notifier, param.option); if (errCode != E_OK) { LOGE("[KvStoreManager] Enable auto launch failed:%d", errCode); return TransferDBErrno(errCode, true); @@ -584,12 +593,18 @@ DBStatus KvStoreDelegateManager::EnableKvStoreAutoLaunch(const std::string &user DBStatus KvStoreDelegateManager::DisableKvStoreAutoLaunch( const std::string &userId, const std::string &appId, const std::string &storeId) +{ + return DisableKvStoreAutoLaunch(userId, "", appId, storeId); +} + +DBStatus KvStoreDelegateManager::DisableKvStoreAutoLaunch(const std::string &userId, const std::string &subUser, + const std::string &appId, const std::string &storeId) { if (RuntimeContext::GetInstance() == nullptr) { return DB_ERROR; } - std::string syncIdentifier = DBCommon::GenerateIdentifierId(storeId, appId, userId, "", 0); + std::string syncIdentifier = DBCommon::GenerateIdentifierId(storeId, appId, userId, subUser, 0); std::string hashIdentifier = DBCommon::TransferHashString(syncIdentifier); std::string dualIdentifier = DBCommon::TransferHashString(DBCommon::GenerateDualTupleIdentifierId(storeId, appId)); int errCode = RuntimeContext::GetInstance()->DisableKvStoreAutoLaunch(hashIdentifier, dualIdentifier, userId); @@ -622,6 +637,11 @@ void KvStoreDelegateManager::SetStoreStatusNotifier(const StoreStatusNotifier &n RuntimeContext::GetInstance()->SetStoreStatusNotifier(notifier); } +void KvStoreDelegateManager::SetStoreStatusNotifier(const StoreStatusNotifierV2 ¬ifier) +{ + RuntimeContext::GetInstance()->SetStoreStatusNotifier(notifier); +} + DBStatus KvStoreDelegateManager::SetSyncActivationCheckCallback(const SyncActivationCheckCallback &callback) { std::lock_guard lock(multiUserMutex_); diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_errno.cpp b/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_errno.cpp index b2d889cbdce2be5f1ac540c03fd0e2bd5c0b6b8e..259013693e8a3859ecb67aad737c6cc5e7762356 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_errno.cpp +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_errno.cpp @@ -83,6 +83,10 @@ namespace { { -E_WAIT_COMPENSATED_SYNC, WAIT_COMPENSATED_SYNC }, { -E_CLOUD_SYNC_TASK_MERGED, CLOUD_SYNC_TASK_MERGED }, { -E_SQLITE_CANT_OPEN, SQLITE_CANT_OPEN }, + { -E_LOCAL_ASSET_NOT_FOUND, LOCAL_ASSET_NOT_FOUND }, + { -E_ASSET_NOT_FOUND_FOR_DOWN_ONLY, ASSET_NOT_FOUND_FOR_DOWN_ONLY }, + { -E_CLOUD_DISABLED, CLOUD_DISABLED }, + { -E_DISTRIBUTED_FIELD_DECREASE, DISTRIBUTED_FIELD_DECREASE }, }; } diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_nb_delegate_impl.cpp b/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_nb_delegate_impl.cpp index 57e32c9706dfc058f767389d7853d544327f339a..8a6399c2d7fac32f387c36f8fc148a0c04a36a61 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_nb_delegate_impl.cpp +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_nb_delegate_impl.cpp @@ -60,6 +60,7 @@ namespace { {SET_SYNC_RETRY, PRAGMA_SET_SYNC_RETRY}, {SET_MAX_LOG_LIMIT, PRAGMA_SET_MAX_LOG_LIMIT}, {EXEC_CHECKPOINT, PRAGMA_EXEC_CHECKPOINT}, + {SET_MAX_VALUE_SIZE, PRAGMA_SET_MAX_VALUE_SIZE}, }; constexpr const char *INVALID_CONNECTION = "[KvStoreNbDelegate] Invalid connection for operation"; @@ -1178,37 +1179,6 @@ std::pair KvStoreNbDelegateImpl::GetWatermarkInfo(const return res; } -DBStatus KvStoreNbDelegateImpl::Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess) -{ - if (conn_ == nullptr) { - LOGE("%s", INVALID_CONNECTION); - return DB_ERROR; - } - return TransferDBErrno(conn_->Sync(option, onProcess)); -} - -DBStatus KvStoreNbDelegateImpl::SetCloudDB(const std::map> &cloudDBs) -{ - if (conn_ == nullptr) { - LOGE("%s", INVALID_CONNECTION); - return DB_ERROR; - } - if (cloudDBs.empty()) { - LOGE("[KvStoreNbDelegate] no cloud db"); - return INVALID_ARGS; - } - return TransferDBErrno(conn_->SetCloudDB(cloudDBs)); -} - -DBStatus KvStoreNbDelegateImpl::SetCloudDbSchema(const std::map &schema) -{ - if (conn_ == nullptr) { - LOGE("%s", INVALID_CONNECTION); - return DB_ERROR; - } - return TransferDBErrno(conn_->SetCloudDbSchema(schema)); -} - DBStatus KvStoreNbDelegateImpl::RemoveDeviceData(const std::string &device, ClearMode mode) { if (conn_ == nullptr) { @@ -1254,54 +1224,76 @@ int32_t KvStoreNbDelegateImpl::GetTaskCount() return conn_->GetTaskCount(); } -void KvStoreNbDelegateImpl::SetGenCloudVersionCallback(const GenerateCloudVersionCallback &callback) +DBStatus KvStoreNbDelegateImpl::SetReceiveDataInterceptor(const DataInterceptor &interceptor) { - if (conn_ == nullptr || callback == nullptr) { - LOGD("[KvStoreNbDelegate] Invalid connection or callback for operation"); - return; + if (conn_ == nullptr) { + LOGE("%s", INVALID_CONNECTION); + return DB_ERROR; } - conn_->SetGenCloudVersionCallback(callback); + int errCode = conn_->SetReceiveDataInterceptor(interceptor); + if (errCode != E_OK) { + LOGE("[KvStoreNbDelegate] Set receive data interceptor errCode:%d", errCode); + } + LOGI("[KvStoreNbDelegate] Set receive data interceptor"); + return TransferDBErrno(errCode); } -std::pair> KvStoreNbDelegateImpl::GetCloudVersion( - const std::string &device) +DBStatus KvStoreNbDelegateImpl::GetDeviceEntries(const std::string &device, std::vector &entries) const { - std::pair> res; - if (device.size() > DBConstant::MAX_DEV_LENGTH) { - LOGE("[KvStoreNbDelegate] device invalid length %zu", device.size()); - res.first = INVALID_ARGS; - return res; - } if (conn_ == nullptr) { LOGE("%s", INVALID_CONNECTION); - res.first = DB_ERROR; - return res; + return DB_ERROR; } - int errCode = conn_->GetCloudVersion(device, res.second); + int errCode = conn_->GetEntries(device, entries); if (errCode == E_OK) { - LOGI("[KvStoreNbDelegate] get cloudVersion success"); - } else { - LOGE("[KvStoreNbDelegate] get cloudVersion failed:%d", errCode); + return OK; } - if (errCode == E_OK && res.second.empty()) { - errCode = -E_NOT_FOUND; + LOGE("[KvStoreNbDelegate] Get the entries failed:%d", errCode); + return TransferDBErrno(errCode); +} + +KvStoreNbDelegate::DatabaseStatus KvStoreNbDelegateImpl::GetDatabaseStatus() const +{ + KvStoreNbDelegate::DatabaseStatus status; + if (conn_ == nullptr) { + LOGE("%s", INVALID_CONNECTION); + return status; } - res.first = TransferDBErrno(errCode); - return res; + status.isRebuild = conn_->IsRebuild(); + LOGI("[KvStoreNbDelegate] rebuild %d", static_cast(status.isRebuild)); + return status; } -DBStatus KvStoreNbDelegateImpl::SetReceiveDataInterceptor(const DataInterceptor &interceptor) +#ifdef USE_DISTRIBUTEDDB_CLOUD +DBStatus KvStoreNbDelegateImpl::Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess) { if (conn_ == nullptr) { LOGE("%s", INVALID_CONNECTION); return DB_ERROR; } - int errCode = conn_->SetReceiveDataInterceptor(interceptor); - if (errCode != E_OK) { - LOGE("[KvStoreNbDelegate] Set receive data interceptor errCode:%d", errCode); + return TransferDBErrno(conn_->Sync(option, onProcess)); +} + +DBStatus KvStoreNbDelegateImpl::SetCloudDB(const std::map> &cloudDBs) +{ + if (conn_ == nullptr) { + LOGE("%s", INVALID_CONNECTION); + return DB_ERROR; } - LOGI("[KvStoreNbDelegate] Set receive data interceptor"); - return TransferDBErrno(errCode); + if (cloudDBs.empty()) { + LOGE("[KvStoreNbDelegate] no cloud db"); + return INVALID_ARGS; + } + return TransferDBErrno(conn_->SetCloudDB(cloudDBs)); +} + +DBStatus KvStoreNbDelegateImpl::SetCloudDbSchema(const std::map &schema) +{ + if (conn_ == nullptr) { + LOGE("%s", INVALID_CONNECTION); + return DB_ERROR; + } + return TransferDBErrno(conn_->SetCloudDbSchema(schema)); } DBStatus KvStoreNbDelegateImpl::SetCloudSyncConfig(const CloudSyncConfig &config) @@ -1321,29 +1313,40 @@ DBStatus KvStoreNbDelegateImpl::SetCloudSyncConfig(const CloudSyncConfig &config return TransferDBErrno(errCode); } -DBStatus KvStoreNbDelegateImpl::GetDeviceEntries(const std::string &device, std::vector &entries) const +void KvStoreNbDelegateImpl::SetGenCloudVersionCallback(const GenerateCloudVersionCallback &callback) { - if (conn_ == nullptr) { - LOGE("%s", INVALID_CONNECTION); - return DB_ERROR; - } - int errCode = conn_->GetEntries(device, entries); - if (errCode == E_OK) { - return OK; + if (conn_ == nullptr || callback == nullptr) { + LOGD("[KvStoreNbDelegate] Invalid connection or callback for operation"); + return; } - LOGE("[KvStoreNbDelegate] Get the entries failed:%d", errCode); - return TransferDBErrno(errCode); + conn_->SetGenCloudVersionCallback(callback); } -KvStoreNbDelegate::DatabaseStatus KvStoreNbDelegateImpl::GetDatabaseStatus() const +std::pair> KvStoreNbDelegateImpl::GetCloudVersion( + const std::string &device) { - KvStoreNbDelegate::DatabaseStatus status; + std::pair> res; + if (device.size() > DBConstant::MAX_DEV_LENGTH) { + LOGE("[KvStoreNbDelegate] device invalid length %zu", device.size()); + res.first = INVALID_ARGS; + return res; + } if (conn_ == nullptr) { LOGE("%s", INVALID_CONNECTION); - return status; + res.first = DB_ERROR; + return res; } - status.isRebuild = conn_->IsRebuild(); - LOGI("[KvStoreNbDelegate] rebuild %d", static_cast(status.isRebuild)); - return status; + int errCode = conn_->GetCloudVersion(device, res.second); + if (errCode == E_OK) { + LOGI("[KvStoreNbDelegate] get cloudVersion success"); + } else { + LOGE("[KvStoreNbDelegate] get cloudVersion failed:%d", errCode); + } + if (errCode == E_OK && res.second.empty()) { + errCode = -E_NOT_FOUND; + } + res.first = TransferDBErrno(errCode); + return res; } +#endif } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_nb_delegate_impl.h b/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_nb_delegate_impl.h index 8f897ee9c0a4de20dbce1fe7c840581c6897c861..2a4c9b0d5a078677c7bda943131196b9bef7f002 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_nb_delegate_impl.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_nb_delegate_impl.h @@ -168,29 +168,31 @@ public: std::pair GetWatermarkInfo(const std::string &device) override; - DBStatus Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess) override; - - DBStatus SetCloudDB(const std::map> &cloudDBs) override; - - DBStatus SetCloudDbSchema(const std::map &schema) override; - DBStatus RemoveDeviceData(const std::string &device, ClearMode mode) override; DBStatus RemoveDeviceData(const std::string &device, const std::string &user, ClearMode mode) override; int32_t GetTaskCount() override; - void SetGenCloudVersionCallback(const GenerateCloudVersionCallback &callback) override; - - std::pair> GetCloudVersion(const std::string &device) override; - DBStatus SetReceiveDataInterceptor(const DataInterceptor &interceptor) override; - DBStatus SetCloudSyncConfig(const CloudSyncConfig &config) override; - DBStatus GetDeviceEntries(const std::string &device, std::vector &entries) const override; DatabaseStatus GetDatabaseStatus() const override; + +#ifdef USE_DISTRIBUTEDDB_CLOUD + DBStatus Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess) override; + + DBStatus SetCloudDB(const std::map> &cloudDBs) override; + + DBStatus SetCloudDbSchema(const std::map &schema) override; + + void SetGenCloudVersionCallback(const GenerateCloudVersionCallback &callback) override; + + DBStatus SetCloudSyncConfig(const CloudSyncConfig &config) override; + + std::pair> GetCloudVersion(const std::string &device) override; +#endif private: DBStatus GetInner(const IOption &option, const Key &key, Value &value) const; DBStatus PutInner(const IOption &option, const Key &key, const Value &value); diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.cpp b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.cpp index e592d8a167eae4dea76c8c3d48b95ce59ea278a6..99741c8baa039b5814ef22dcc5772c65498f5384 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.cpp +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.cpp @@ -55,27 +55,16 @@ DBStatus RelationalStoreDelegateImpl::RemoveDeviceDataInner(const std::string &d return DB_ERROR; } +#ifdef USE_DISTRIBUTEDDB_CLOUD int errCode = conn_->DoClean(mode); if (errCode != E_OK) { LOGE("[RelationalStore Delegate] remove device cloud data failed:%d", errCode); return TransferDBErrno(errCode); } +#endif return OK; } -int32_t RelationalStoreDelegateImpl::GetCloudSyncTaskCount() -{ - if (conn_ == nullptr) { - LOGE("[RelationalStore Delegate] Invalid connection for operation!"); - return -1; - } - int32_t count = conn_->GetCloudSyncTaskCount(); - if (count == -1) { - LOGE("[RelationalStore Delegate] Failed to get cloud sync task count."); - } - return count; -} - DBStatus RelationalStoreDelegateImpl::CreateDistributedTableInner(const std::string &tableName, TableSyncType type) { LOGI("[RelationalStore Delegate] Create distributed table for [%s length[%u]], type[%d]", @@ -227,43 +216,6 @@ DBStatus RelationalStoreDelegateImpl::RemoveDeviceData() return OK; } -DBStatus RelationalStoreDelegateImpl::Sync(const std::vector &devices, SyncMode mode, const Query &query, - const SyncProcessCallback &onProcess, int64_t waitTime) -{ - CloudSyncOption option; - option.devices = devices; - option.mode = mode; - option.query = query; - option.waitTime = waitTime; - return Sync(option, onProcess); -} - -DBStatus RelationalStoreDelegateImpl::SetCloudDB(const std::shared_ptr &cloudDb) -{ - if (conn_ == nullptr || conn_->SetCloudDB(cloudDb) != E_OK) { - return DB_ERROR; - } - return OK; -} - -DBStatus RelationalStoreDelegateImpl::SetCloudDbSchema(const DataBaseSchema &schema) -{ - DataBaseSchema cloudSchema = schema; - if (!ParamCheckUtils::CheckSharedTableName(cloudSchema)) { - LOGE("[RelationalStore Delegate] SharedTableName check failed!"); - return INVALID_ARGS; - } - if (conn_ == nullptr) { - return DB_ERROR; - } - // create shared table and set cloud db schema - int errorCode = conn_->PrepareAndSetCloudDbSchema(cloudSchema); - if (errorCode != E_OK) { - LOGE("[RelationalStore Delegate] set cloud schema failed!"); - } - return TransferDBErrno(errorCode); -} - DBStatus RelationalStoreDelegateImpl::RegisterObserver(StoreObserver *observer) { if (observer == nullptr) { @@ -280,9 +232,9 @@ DBStatus RelationalStoreDelegateImpl::RegisterObserver(StoreObserver *observer) return DB_ERROR; } errCode = conn_->RegisterObserverAction(observer, [observer, userId, appId, storeId]( - const std::string &changedDevice, ChangedData &&changedData, bool isChangedData) { + const std::string &changedDevice, ChangedData &&changedData, bool isChangedData, Origin origin) { if (isChangedData && observer != nullptr) { - observer->OnChange(Origin::ORIGIN_CLOUD, changedDevice, std::move(changedData)); + observer->OnChange(origin, changedDevice, std::move(changedData)); LOGD("begin to observer on changed data"); return; } @@ -296,6 +248,7 @@ DBStatus RelationalStoreDelegateImpl::RegisterObserver(StoreObserver *observer) return TransferDBErrno(errCode); } +#ifdef USE_DISTRIBUTEDDB_CLOUD DBStatus RelationalStoreDelegateImpl::SetIAssetLoader(const std::shared_ptr &loader) { if (conn_ == nullptr || conn_->SetIAssetLoader(loader) != E_OK) { @@ -303,6 +256,7 @@ DBStatus RelationalStoreDelegateImpl::SetIAssetLoader(const std::shared_ptrUnRegisterObserverAction(observer)); } -DBStatus RelationalStoreDelegateImpl::Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess) -{ - uint64_t taskId = 0; - return Sync(option, onProcess, taskId); -} - DBStatus RelationalStoreDelegateImpl::SetTrackerTable(const TrackerSchema &schema) { LOGI("[RelationalStore Delegate] create tracker table for [%s length[%u]]", @@ -443,6 +391,90 @@ DBStatus RelationalStoreDelegateImpl::UpsertData(const std::string &tableName, c return OK; } +DBStatus RelationalStoreDelegateImpl::SetDistributedSchema(const DistributedSchema &schema) +{ + if (conn_ == nullptr) { + LOGE("[RelationalStore Delegate] Invalid connection for setting db schema!"); + return DB_ERROR; + } + + if (ParamCheckUtils::IsSchemaTablesEmpty(schema)) { + LOGE("[RelationalStore Delegate] Schema tables are empty when setting db schema!"); + return SCHEMA_MISMATCH; + } + + std::string userId; + std::string appId; + std::string storeId; + int errCode = conn_->GetStoreInfo(userId, appId, storeId); + if (errCode != E_OK) { + LOGW("[RelationalStore Delegate] Get storeInfo failed %d", errCode); + return TransferDBErrno(errCode); + } + errCode = conn_->SetDistributedDbSchema(schema); + LOGI("[RelationalStore Delegate] %s %s SetDistributedSchema errCode:%d", + DBCommon::StringMiddleMasking(appId).c_str(), DBCommon::StringMiddleMasking(storeId).c_str(), errCode); + return TransferDBErrno(errCode); +} + +std::pair RelationalStoreDelegateImpl::GetDownloadingAssetsCount() +{ + if (conn_ == nullptr) { + LOGE("[RelationalStore Delegate] Invalid connection for sync!"); + return {DB_ERROR, 0}; + } + int32_t count = 0; + int errCode = conn_->GetDownloadingAssetsCount(count); + if (errCode != E_OK) { + LOGE("[RelationalStore Delegate] get downloading assets count failed:%d", errCode); + } + return {TransferDBErrno(errCode), count}; +} + +#ifdef USE_DISTRIBUTEDDB_CLOUD +DBStatus RelationalStoreDelegateImpl::Sync(const std::vector &devices, SyncMode mode, const Query &query, + const SyncProcessCallback &onProcess, int64_t waitTime) +{ + CloudSyncOption option; + option.devices = devices; + option.mode = mode; + option.query = query; + option.waitTime = waitTime; + return Sync(option, onProcess); +} + +DBStatus RelationalStoreDelegateImpl::SetCloudDB(const std::shared_ptr &cloudDb) +{ + if (conn_ == nullptr || conn_->SetCloudDB(cloudDb) != E_OK) { + return DB_ERROR; + } + return OK; +} + +DBStatus RelationalStoreDelegateImpl::SetCloudDbSchema(const DataBaseSchema &schema) +{ + DataBaseSchema cloudSchema = schema; + if (!ParamCheckUtils::CheckSharedTableName(cloudSchema)) { + LOGE("[RelationalStore Delegate] SharedTableName check failed!"); + return INVALID_ARGS; + } + if (conn_ == nullptr) { + return DB_ERROR; + } + // create shared table and set cloud db schema + int errorCode = conn_->PrepareAndSetCloudDbSchema(cloudSchema); + if (errorCode != E_OK) { + LOGE("[RelationalStore Delegate] set cloud schema failed!"); + } + return TransferDBErrno(errorCode); +} + +DBStatus RelationalStoreDelegateImpl::Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess) +{ + uint64_t taskId = 0; + return Sync(option, onProcess, taskId); +} + DBStatus RelationalStoreDelegateImpl::SetCloudSyncConfig(const CloudSyncConfig &config) { if (conn_ == nullptr) { @@ -486,5 +518,18 @@ SyncProcess RelationalStoreDelegateImpl::GetCloudTaskStatus(uint64_t taskId) } return conn_->GetCloudTaskStatus(taskId); } +int32_t RelationalStoreDelegateImpl::GetCloudSyncTaskCount() +{ + if (conn_ == nullptr) { + LOGE("[RelationalStore Delegate] Invalid connection for operation!"); + return -1; + } + int32_t count = conn_->GetCloudSyncTaskCount(); + if (count == -1) { + LOGE("[RelationalStore Delegate] Failed to get cloud sync task count."); + } + return count; +} +#endif } // namespace DistributedDB #endif \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.h b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.h index 00d648dfceaac9f886466110f047a17a9f588b8d..3ec59811712a6f3d6c33893345ac31266f0b9c53 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.h @@ -32,8 +32,6 @@ public: DBStatus Sync(const std::vector &devices, SyncMode mode, const Query &query, const SyncStatusCallback &onComplete, bool wait) override; - int32_t GetCloudSyncTaskCount() override; - DBStatus RemoveDeviceDataInner(const std::string &device, ClearMode mode) override; DBStatus CreateDistributedTableInner(const std::string &tableName, TableSyncType type) override; @@ -50,23 +48,12 @@ public: DBStatus RemoveDeviceData() override; - DBStatus Sync(const std::vector &devices, SyncMode mode, const Query &query, - const SyncProcessCallback &onProcess, int64_t waitTime) override; - - DBStatus SetCloudDB(const std::shared_ptr &cloudDb) override; - - DBStatus SetCloudDbSchema(const DataBaseSchema &schema) override; - DBStatus RegisterObserver(StoreObserver *observer) override; DBStatus UnRegisterObserver() override; DBStatus UnRegisterObserver(StoreObserver *observer) override; - DBStatus SetIAssetLoader(const std::shared_ptr &loader) override; - - DBStatus Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess) override; - DBStatus SetTrackerTable(const TrackerSchema &schema) override; DBStatus ExecuteSql(const SqlCondition &condition, std::vector &records) override; @@ -80,11 +67,30 @@ public: DBStatus UpsertData(const std::string &tableName, const std::vector &records, RecordStatus status) override; + DBStatus SetDistributedSchema(const DistributedSchema &schema) override; + + std::pair GetDownloadingAssetsCount() override; + +#ifdef USE_DISTRIBUTEDDB_CLOUD + int32_t GetCloudSyncTaskCount() override; + + DBStatus SetCloudDB(const std::shared_ptr &cloudDb) override; + + DBStatus SetCloudDbSchema(const DataBaseSchema &schema) override; + + DBStatus Sync(const std::vector &devices, SyncMode mode, const Query &query, + const SyncProcessCallback &onProcess, int64_t waitTime) override; + + DBStatus Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess) override; + DBStatus SetCloudSyncConfig(const CloudSyncConfig &config) override; DBStatus Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess, uint64_t taskId) override; SyncProcess GetCloudTaskStatus(uint64_t taskId) override; + + DBStatus SetIAssetLoader(const std::shared_ptr &loader) override; +#endif private: static void OnSyncComplete(const std::map> &devicesStatus, const SyncStatusCallback &onComplete); diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_manager.cpp b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_manager.cpp index 30703ce8ec0c498006c6409b3c6ddda4c8eceb3e..3ebb2e6295425c100a6129c62292635125c106cd 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_manager.cpp +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_manager.cpp @@ -99,6 +99,7 @@ DB_API DBStatus RelationalStoreManager::OpenStore(const std::string &path, const RelationalDBProperties properties; properties.SetStringProp(RelationalDBProperties::DATA_DIR, canonicalDir); + properties.SetIntProp(RelationalDBProperties::DISTRIBUTED_TABLE_MODE, static_cast(option.tableMode)); properties.SetIdentifier(userId_, appId_, storeId, subUser_, instanceId_); properties.SetBoolProp(RelationalDBProperties::SYNC_DUAL_TUPLE_MODE, option.syncDualTupleMode); if (option.isEncryptedDb) { @@ -240,6 +241,12 @@ std::string RelationalStoreManager::GetRelationalStoreIdentifier(const std::stri return RuntimeConfig::GetStoreIdentifier(userId, appId, storeId, syncDualTupleMode); } +std::string RelationalStoreManager::GetRelationalStoreIdentifier(const std::string &userId, + const std::string &subUserId, const std::string &appId, const std::string &storeId, bool syncDualTupleMode) +{ + return RuntimeConfig::GetStoreIdentifier(userId, subUserId, appId, storeId, syncDualTupleMode); +} + std::vector RelationalStoreManager::ParserQueryNodes(const Bytes &queryBytes, DBStatus &status) { diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_sqlite_ext.cpp b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_sqlite_ext.cpp index 96a1a628fd0650490434345a6b35d947aa02fb2d..e314e3e2e8632bb0516c63d8498940f18cc34200 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_sqlite_ext.cpp +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_sqlite_ext.cpp @@ -441,7 +441,7 @@ void StringToUpper(std::string &str) void CalcHashKey(sqlite3_context *ctx, int argc, sqlite3_value **argv) { // 1 means that the function only needs one parameter, namely key - if (ctx == nullptr || argc != 2 || argv == nullptr) { // 2 is params count + if (ctx == nullptr || argc != 2 || argv == nullptr || argv[0] == nullptr || argv[1] == nullptr) { // 2 params count return; } @@ -660,7 +660,9 @@ void CloudDataChangedObserver(sqlite3_context *ctx, int argc, sqlite3_value **ar } std::string tableName = static_cast(tableNameChar); - uint64_t isTrackerChange = static_cast(sqlite3_value_int(argv[3])); // 3 is param index + auto changeStatus = static_cast(sqlite3_value_int(argv[3])); // 3 is param index + bool isTrackerChange = (changeStatus & CloudDbConstant::ON_CHANGE_TRACKER) != 0; + bool isP2pChange = (changeStatus & CloudDbConstant::ON_CHANGE_P2P) != 0; bool isExistObserver = false; { std::lock_guard lock(g_clientObserverMutex); @@ -672,10 +674,13 @@ void CloudDataChangedObserver(sqlite3_context *ctx, int argc, sqlite3_value **ar if (isExistObserver) { auto itTable = g_clientChangedDataMap[hashFileName].tableData.find(tableName); if (itTable != g_clientChangedDataMap[hashFileName].tableData.end()) { - itTable->second.isTrackedDataChange = - (static_cast(itTable->second.isTrackedDataChange) | isTrackerChange) > 0; + itTable->second.isTrackedDataChange |= isTrackerChange; + itTable->second.isP2pSyncDataChange |= isP2pChange; } else { - DistributedDB::ChangeProperties properties = { .isTrackedDataChange = (isTrackerChange > 0) }; + DistributedDB::ChangeProperties properties = { + .isTrackedDataChange = isTrackerChange, + .isP2pSyncDataChange = isP2pChange + }; g_clientChangedDataMap[hashFileName].tableData.insert_or_assign(tableName, properties); } } @@ -1312,7 +1317,7 @@ int HandleDropLogicDeleteData(sqlite3 *db, const std::string &tableName, uint64_ int SaveDeleteFlagToDB(sqlite3 *db, const std::string &tableName) { - std::string keyStr = DBConstant::TABLE_IS_DROPPED + tableName; + std::string keyStr = DBConstant::TABLE_WAS_DROPPED + tableName; Key key; DBCommon::StringToVector(keyStr, key); Value value; diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_sync_able_storage.h b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_sync_able_storage.h index b7f13f5001036ff5605918270d5d87da40625e66..8dacecdf0df8cb10b48b4b5c0c626fd8f1c85a07 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_sync_able_storage.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_sync_able_storage.h @@ -31,7 +31,7 @@ namespace DistributedDB { using RelationalObserverAction = - std::function; + std::function; class RelationalSyncAbleStorage : public RelationalDBSyncInterface, public ICloudSyncStorageInterface, public virtual RefObject { public: @@ -130,7 +130,7 @@ public: int SaveRemoteDeviceSchema(const std::string &deviceId, const std::string &remoteSchema, uint8_t type) override; - int GetRemoteDeviceSchema(const std::string &deviceId, RelationalSchemaObject &schemaObj) override; + int GetRemoteDeviceSchema(const std::string &deviceId, RelationalSchemaObject &schemaObj) const override; void ReleaseRemoteQueryContinueToken(ContinueToken &token) const override; @@ -174,12 +174,19 @@ public: int PutCloudSyncData(const std::string &tableName, DownloadData &downloadData) override; + int UpdateAssetStatusForAssetOnly(const std::string &tableName, VBucket &asset) override; + int CleanCloudData(ClearMode mode, const std::vector &tableNameList, const RelationalSchemaObject &localSchema, std::vector &assets) override; int FillCloudAssetForDownload(const std::string &tableName, VBucket &asset, bool isDownloadSuccess) override; + int FillCloudAssetForAsyncDownload(const std::string &tableName, VBucket &asset, bool isDownloadSuccess) override; + int SetLogTriggerStatus(bool status) override; + + int SetLogTriggerStatusForAsyncDownload(bool status) override; + int SetCursorIncFlag(bool flag) override; int FillCloudLogAndAsset(OpType opType, const CloudSyncData &data, bool fillAsset, bool ignoreEmptyGid) override; @@ -206,19 +213,29 @@ public: std::pair GetAssetsByGidOrHashKey(const TableSchema &tableSchema, const std::string &gid, const Bytes &hashKey, VBucket &assets) override; + std::pair GetAssetsByGidOrHashKeyForAsyncDownload( + const TableSchema &tableSchema, const std::string &gid, const Bytes &hashKey, VBucket &assets) override; + int SetIAssetLoader(const std::shared_ptr &loader) override; int UpsertData(RecordStatus status, const std::string &tableName, const std::vector &records); int UpdateRecordFlag(const std::string &tableName, bool recordConflict, const LogInfo &logInfo) override; - int GetCompensatedSyncQuery(std::vector &syncQuery, std::vector &users) override; + int UpdateRecordFlagForAsyncDownload(const std::string &tableName, bool recordConflict, + const LogInfo &logInfo) override; + + int GetCompensatedSyncQuery(std::vector &syncQuery, std::vector &users, + bool isQueryDownloadRecords) override; int ClearUnLockingNoNeedCompensated() override; int MarkFlagAsConsistent(const std::string &tableName, const DownloadData &downloadData, const std::set &gidFilters) override; + int MarkFlagAsAssetAsyncDownload(const std::string &tableName, const DownloadData &downloadData, + const std::set &gidFilters) override; + CloudSyncConfig GetCloudSyncConfig() const override; void SetCloudSyncConfig(const CloudSyncConfig &config); @@ -234,6 +251,21 @@ public: bool IsCurrentLogicDelete() const override; int GetLocalDataCount(const std::string &tableName, int &dataCount, int &logicDeleteDataCount) override; + + std::pair> GetDownloadAssetTable() override; + + std::pair> GetDownloadAssetRecords(const std::string &tableName, + int64_t beginTime) override; + + int GetInfoByPrimaryKeyOrGid(const std::string &tableName, const VBucket &vBucket, bool useTransaction, + DataInfoWithLog &dataInfoWithLog, VBucket &assetInfo) override; + + void TriggerObserverAction(const std::string &deviceName, ChangedData &&changedData, bool isChangedData, + Origin origin); + + void PrintCursorChange(const std::string &tableName) override; + + int GetLockStatusByGid(const std::string &tableName, const std::string &gid, LockStatus &status) override; protected: int FillReferenceData(CloudSyncData &syncData); @@ -249,9 +281,6 @@ protected: int FillCloudLogAndAssetInner(SQLiteSingleVerRelationalStorageExecutor *handle, OpType opType, const CloudSyncData &data, bool fillAsset, bool ignoreEmptyGid); - int UpdateRecordFlagAfterUpload(SQLiteSingleVerRelationalStorageExecutor *handle, const std::string &tableName, - const CloudSyncBatch &updateData, const CloudWaterType &type, bool isLock = false); - static int FillReferenceDataIntoExtend(const std::vector &rowid, const std::map &referenceGid, std::vector &extend); @@ -267,7 +296,7 @@ private: // get int GetSyncDataForQuerySync(std::vector &dataItems, SQLiteSingleVerRelationalContinueToken *&token, - const DataSizeSpecInfo &dataSizeInfo) const; + const DataSizeSpecInfo &dataSizeInfo, RelationalSchemaObject &&filterSchema) const; int GetRemoteQueryData(const PreparedStmt &prepStmt, size_t packetSize, std::vector &colNames, std::vector &data) const; @@ -292,7 +321,7 @@ private: int GetCloudTableWithoutShared(std::vector &tables); int GetCompensatedSyncQueryInner(SQLiteSingleVerRelationalStorageExecutor *handle, - const std::vector &tables, std::vector &syncQuery); + const std::vector &tables, std::vector &syncQuery, bool isQueryDownloadRecords); int CreateTempSyncTriggerInner(SQLiteSingleVerRelationalStorageExecutor *handle, const std::string &tableName, bool flag = false); @@ -301,7 +330,10 @@ private: void ExecuteDataChangeCallback( const std::pair> &item, - const std::string &deviceName, const ChangedData &changedData, bool isChangedData, int &observerCnt); + const std::string &deviceName, const ChangedData &changedData, bool isChangedData, Origin origin); + + void SaveCursorChange(const std::string &tableName, uint64_t currCursor); + // data std::shared_ptr storageEngine_ = nullptr; std::function onSchemaChanged_; @@ -315,7 +347,7 @@ private: std::function heartBeatListener_; mutable std::mutex heartBeatMutex_; - LruMap remoteDeviceSchema_; + mutable LruMap remoteDeviceSchema_; StorageExecutor *reusedHandle_; mutable std::mutex reusedHandleMutex_; @@ -340,6 +372,8 @@ private: CloudSyncConfig cloudSyncConfig_; CloudUploadRecorder uploadRecorder_; + + std::map> cursorChangeMap_; }; } // namespace DistributedDB #endif diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/runtime_config.cpp b/kv_store/frameworks/libs/distributeddb/interfaces/src/runtime_config.cpp index 45d80fcd8edd4b87f24e05afc47c21e9c1fdd25f..5e5bf4c011d2631f53f04cd38de237cc061f6a7a 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/runtime_config.cpp +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/runtime_config.cpp @@ -88,6 +88,11 @@ DBStatus RuntimeConfig::SetPermissionCheckCallback(const PermissionCheckCallback return TransferDBErrno(RuntimeContext::GetInstance()->SetPermissionCheckCallback(callback)); } +DBStatus RuntimeConfig::SetPermissionCheckCallback(const PermissionCheckCallbackV4 &callback) +{ + return TransferDBErrno(RuntimeContext::GetInstance()->SetPermissionCheckCallback(callback)); +} + DBStatus RuntimeConfig::SetProcessSystemAPIAdapter(const std::shared_ptr &adapter) { return TransferDBErrno(RuntimeContext::GetInstance()->SetProcessSystemApiAdapter(adapter)); @@ -155,20 +160,35 @@ void RuntimeConfig::SetAutoLaunchRequestCallback(const AutoLaunchRequestCallback std::string RuntimeConfig::GetStoreIdentifier(const std::string &userId, const std::string &appId, const std::string &storeId, bool syncDualTupleMode) { - if (!ParamCheckUtils::CheckStoreParameter(storeId, appId, userId, syncDualTupleMode)) { + return GetStoreIdentifier(userId, "", appId, storeId, syncDualTupleMode); +} + +std::string RuntimeConfig::GetStoreIdentifier(const std::string &userId, const std::string &subUserId, + const std::string &appId, const std::string &storeId, bool syncDualTupleMode) +{ + if (!ParamCheckUtils::CheckStoreParameter(storeId, appId, userId, syncDualTupleMode, subUserId)) { return ""; } if (syncDualTupleMode) { return DBCommon::TransferHashString(appId + "-" + storeId); } - return DBCommon::TransferHashString(userId + "-" + appId + "-" + storeId); + if (subUserId.empty()) { + return DBCommon::TransferHashString(userId + "-" + appId + "-" + storeId); + } + return DBCommon::TransferHashString(userId + "-" + appId + "-" + storeId + "-" + subUserId); } void RuntimeConfig::ReleaseAutoLaunch(const std::string &userId, const std::string &appId, const std::string &storeId, DBType type) +{ + ReleaseAutoLaunch(userId, "", appId, storeId, type); +} + +void RuntimeConfig::ReleaseAutoLaunch(const std::string &userId, const std::string &subUserId, + const std::string &appId, const std::string &storeId, DBType type) { DBProperties properties; - properties.SetIdentifier(userId, appId, storeId); + properties.SetIdentifier(userId, appId, storeId, subUserId); DBTypeInner innerType = (type == DBType::DB_KV ? DBTypeInner::DB_KV : DBTypeInner::DB_RELATION); RuntimeContext::GetInstance()->CloseAutoLaunchConnection(innerType, properties); @@ -183,5 +203,11 @@ void RuntimeConfig::SetCloudTranslate(const std::shared_ptr { RuntimeContext::GetInstance()->SetCloudTranslate(dataTranslate); } + +DBStatus RuntimeConfig::SetAsyncDownloadAssetsConfig(const AsyncDownloadAssetsConfig &config) +{ + return TransferDBErrno(RuntimeContext::GetInstance()->GetAssetsDownloadManager() + ->SetAsyncDownloadAssetsConfig(config)); +} } // namespace DistributedDB -#endif \ No newline at end of file +#endif diff --git a/kv_store/frameworks/libs/distributeddb/sqlite_adapter/CMakeLists.txt b/kv_store/frameworks/libs/distributeddb/sqlite_adapter/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7e3ddb6bf48af19d1b6bafb8827a01f8aa78a2d0 --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/sqlite_adapter/CMakeLists.txt @@ -0,0 +1,47 @@ +cmake_minimum_required(VERSION 3.2) + +project(sqlite_adapter VERSION 1.0.0) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -std=c++17 -pthread") + +add_compile_options(-Werror=sign-compare) +add_compile_options(-Werror=unused-variable) +add_compile_options(-Wuninitialized) +add_compile_options(-Wformat) +add_compile_options(-Wno-deprecated-declarations) + + +set(BASE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) +#set(BASE_PATH ${PROJECT_SOURCE_DIR}) + + +message("build sqlite begin") + +# build sqlite +add_subdirectory(third_party/sqlite) +message("build sqlite end") + + +set(SQLITE_ADAPTER_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +include_directories( + ${SQLITE_ADAPTER_PATH}/include +) + +include_directories( + ${BASE_PATH}/third_party/sqlite + ${BASE_PATH}/third_party/sqlite/build/third_party/huawei_secure_c/include +) + + +set(SOURCE_FILES + ${SQLITE_ADAPTER_PATH}/src/tokenizer_api_mgr.cpp + ${SQLITE_ADAPTER_PATH}/src/tokenizer_api.cpp + ${SQLITE_ADAPTER_PATH}/src/tokenizer_sqlite.cpp +) + +add_library(customtokenizer SHARED ${SOURCE_FILES}) + +target_link_libraries(customtokenizer PUBLIC sqlite3 securec) + +target_include_directories(customtokenizer PUBLIC include) diff --git a/kv_store/frameworks/libs/distributeddb/sqlite_adapter/include/tokenizer_sqlite.h b/kv_store/frameworks/libs/distributeddb/sqlite_adapter/include/tokenizer_sqlite.h new file mode 100644 index 0000000000000000000000000000000000000000..975d4810ffcce10c7abad5540351a3e39e4c502f --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/sqlite_adapter/include/tokenizer_sqlite.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 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 GRD_TOKENIZER_SQLITE_H +#define GRD_TOKENIZER_SQLITE_H + +#ifndef GRD_API +#ifndef _WIN32 +#define GRD_API __attribute__((visibility("default"))) +#else +#define GRD_API +#endif // _WIN32 +#endif // GRD_API + +#include "sqlite3ext.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +typedef int (*XTokenFn)(void *, int, const char *, int, int, int); + +GRD_API int fts5_customtokenizer_xCreate(void *sqlite3, const char **azArg, int nArg, Fts5Tokenizer **ppOut); +GRD_API int fts5_customtokenizer_xTokenize(Fts5Tokenizer *tokenizer_ptr, void *pCtx, int flags, const char *pText, + int nText, XTokenFn xToken); +GRD_API void fts5_customtokenizer_xDelete(Fts5Tokenizer *tokenizer_ptr); + +GRD_API int sqlite3_customtokenizer_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // GRD_TOKENIZER_SQLITE_H diff --git a/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_api.cpp b/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_api.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bb93745f4036648a2fe6c5571c2fa38d8dbd79fc --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_api.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025 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 "tokenizer_api_mgr.h" +#include "tokenizer_api.h" + +namespace CNTokenizer { + +static GRD_CNTokenizerApiT g_tokenizerApi = {}; + +GRD_API int32_t GRD_TokenizerInit(const char *userDictPath, const char *userStopWordPath, GRD_TokenizerParamT param) +{ + if (g_tokenizerApi.tokenizerInit == nullptr) { + g_tokenizerApi = GetTokenizerApi(); + } + if (g_tokenizerApi.tokenizerInit == nullptr) { + return GRD_API_NOT_SUPPORT; + } + return g_tokenizerApi.tokenizerInit(userDictPath, userStopWordPath, param); +} + +GRD_API int32_t GRD_TokenizerCut(const char *sentence, GRD_CutOptionT option, GRD_WordEntryListT **entryList) +{ + if (g_tokenizerApi.tokenizerCut == nullptr) { + g_tokenizerApi = GetTokenizerApi(); + } + if (g_tokenizerApi.tokenizerCut == nullptr) { + return GRD_API_NOT_SUPPORT; + } + return g_tokenizerApi.tokenizerCut(sentence, option, entryList); +} + +GRD_API int32_t GRD_TokenizerExtract(const char *sentence, GRD_ExtractOptionT option, GRD_WordEntryListT **entryList) +{ + if (g_tokenizerApi.tokenizerExtract == nullptr) { + g_tokenizerApi = GetTokenizerApi(); + } + if (g_tokenizerApi.tokenizerExtract == nullptr) { + return GRD_API_NOT_SUPPORT; + } + return g_tokenizerApi.tokenizerExtract(sentence, option, entryList); +} + +GRD_API int32_t GRD_TokenizerNext(GRD_WordEntryListT *list, GRD_WordEntryT *entry) +{ + if (g_tokenizerApi.tokenizerNext == nullptr) { + g_tokenizerApi = GetTokenizerApi(); + } + if (g_tokenizerApi.tokenizerNext == nullptr) { + return GRD_API_NOT_SUPPORT; + } + return g_tokenizerApi.tokenizerNext(list, entry); +} + +GRD_API int32_t GRD_TokenizerFreeWordEntryList(GRD_WordEntryListT *list) +{ + if (g_tokenizerApi.tokenizerFreeWordEntryList == nullptr) { + g_tokenizerApi = GetTokenizerApi(); + } + if (g_tokenizerApi.tokenizerFreeWordEntryList == nullptr) { + return GRD_API_NOT_SUPPORT; + } + return g_tokenizerApi.tokenizerFreeWordEntryList(list); +} + +GRD_API int32_t GRD_TokenizerDestroy(void *ptr) +{ + (void)ptr; + if (g_tokenizerApi.tokenizerDestroy == nullptr) { + g_tokenizerApi = GetTokenizerApi(); + } + if (g_tokenizerApi.tokenizerDestroy == nullptr) { + return GRD_API_NOT_SUPPORT; + } + g_tokenizerApi.tokenizerDestroy(); + return GRD_OK; +} +} // namespace CNTokenizer diff --git a/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_api.h b/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_api.h new file mode 100644 index 0000000000000000000000000000000000000000..df04fa4e78b3e7c615feb36a08b238a4895e98c6 --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_api.h @@ -0,0 +1,36 @@ +/* + +Copyright (c) 2025 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 GRD_TOKENIZER_API_H +#define GRD_TOKENIZER_API_H + +#include +#include "tokenizer_export_type.h" + +namespace CNTokenizer { + +int32_t GRD_TokenizerInit(const char *userDictPath, const char *userStopWordPath, GRD_TokenizerParamT param); + +int32_t GRD_TokenizerCut(const char *sentence, GRD_CutOptionT option, GRD_WordEntryListT **entryList); + +int32_t GRD_TokenizerExtract(const char *sentence, GRD_ExtractOptionT option, GRD_WordEntryListT **entryList); + +int32_t GRD_TokenizerNext(GRD_WordEntryListT *list, GRD_WordEntryT *entry); + +int32_t GRD_TokenizerFreeWordEntryList(GRD_WordEntryListT *list); + +int32_t GRD_TokenizerDestroy(void *ptr); + +} + +#endif // GRD_TOKENIZER_API_H diff --git a/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_api_mgr.cpp b/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_api_mgr.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b89368078e1f1358886e4f14db240be803745a74 --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_api_mgr.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025 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 "tokenizer_api_mgr.h" +#include +#ifndef _WIN32 +#include +#endif + +#ifndef _WIN32 +static void *g_library = nullptr; +#endif + +namespace CNTokenizer { + +void LoadTokenizerApi(GRD_CNTokenizerApiT &tokenizerApi) +{ +#ifndef _WIN32 + tokenizerApi.tokenizerInit = (TokenizerInit)dlsym(g_library, "GRD_TokenizerInit"); + tokenizerApi.tokenizerCut = (TokenizerCut)dlsym(g_library, "GRD_TokenizerCut"); + tokenizerApi.tokenizerExtract = (TokenizerExtract)dlsym(g_library, "GRD_TokenizerExtract"); + tokenizerApi.tokenizerNext = (TokenizerNext)dlsym(g_library, "GRD_TokenizerNext"); + tokenizerApi.tokenizerFreeWordEntryList = + (TokenizerFreeWordEntryList)dlsym(g_library, "GRD_TokenizerFreeWordEntryList"); + tokenizerApi.tokenizerDestroy = (TokenizerDestroy)dlsym(g_library, "GRD_TokenizerDestroy"); +#endif +} + +GRD_CNTokenizerApiT GetTokenizerApi() +{ + GRD_CNTokenizerApiT tokenizerApi = {}; +#ifdef _WIN32 + return tokenizerApi; +#endif + std::string libPath = "libarkdata_tokenizer.z.so"; +#ifndef HARMONY_OS + libPath = "libgrd_store.so"; +#endif + g_library = dlopen(libPath.c_str(), RTLD_LAZY); + if (g_library) { + LoadTokenizerApi(tokenizerApi); + } + return tokenizerApi; +} +} // namespace CNTokenizer diff --git a/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_api_mgr.h b/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_api_mgr.h new file mode 100644 index 0000000000000000000000000000000000000000..3d2a1f4a5a8a45eb6e9afca451a8523850d920ff --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_api_mgr.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 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 TOKENIZER_API_MGR_H +#define TOKENIZER_API_MGR_H + +#include "tokenizer_export_type.h" + +namespace CNTokenizer { +typedef int32_t (*TokenizerInit)(const char *userDictPath, const char *userStopWordPath, GRD_TokenizerParamT param); + +typedef int32_t (*TokenizerCut)(const char *sentence, GRD_CutOptionT option, GRD_WordEntryListT **entryList); + +typedef int32_t (*TokenizerExtract)(const char *sentence, GRD_ExtractOptionT option, GRD_WordEntryListT **entryList); + +typedef int32_t (*TokenizerNext)(GRD_WordEntryListT *list, GRD_WordEntryT *entry); + +typedef int32_t (*TokenizerFreeWordEntryList)(GRD_WordEntryListT *list); + +typedef void (*TokenizerDestroy)(void); + +typedef struct GRD_CNTokenizerApi { + TokenizerCut tokenizerCut = nullptr; + TokenizerExtract tokenizerExtract = nullptr; + TokenizerNext tokenizerNext = nullptr; + TokenizerFreeWordEntryList tokenizerFreeWordEntryList = nullptr; + TokenizerInit tokenizerInit = nullptr; + TokenizerDestroy tokenizerDestroy = nullptr; +} GRD_CNTokenizerApiT; + +GRD_CNTokenizerApiT GetTokenizerApi(); + +void InitApiInfo(const char *configStr); +} // namespace CNTokenizer +#endif // TOKENIZER_API_MGR_H diff --git a/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_export_type.h b/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_export_type.h new file mode 100644 index 0000000000000000000000000000000000000000..366c75e36242336c2330f761e4b1ccfaaf90c6cc --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_export_type.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025 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 GRD_TOKENNIZER_TYPE_H +#define GRD_TOKENNIZER_TYPE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define GRD_OK 0 +#define GRD_API_NOT_SUPPORT (-8888) +#define GRD_NO_DATA (-11000) +#define GRD_FAILED_MEMORY_ALLOCATE (-13000) + +#ifndef GRD_API +#ifndef _WIN32 +#define GRD_API __attribute__((visibility("default"))) +#else +#define GRD_API +#endif +#endif // GRD_API + +typedef enum GRD_CutMode { + CUT_MMSEG = 0, + CUT_BUTT // INVALID TokenizeMode +} GRD_CutModeE; + +typedef enum GRD_ExtractMode { + EXTRACT_TF_IDF = 0, + EXTRACT_BUTT // INVALID ExtractMode +} GRD_ExtractModeE; + +typedef struct GRD_TokenizerParam { + GRD_CutModeE cutMode; + GRD_ExtractModeE extractMode; +} GRD_TokenizerParamT; + +typedef struct GRD_CutOption { + bool needPreProcess; +} GRD_CutOptionT; + +typedef struct GRD_ExtractOption { + uint32_t topN; // used for extract +} GRD_ExtractOptionT; + +typedef struct GRD_WordEntryList GRD_WordEntryListT; + +typedef struct GRD_WordEntry { + const char *word; + uint32_t length; +} GRD_WordEntryT; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // GRD_TOKENNIZER_TYPE_H diff --git a/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_sqlite.cpp b/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_sqlite.cpp new file mode 100644 index 0000000000000000000000000000000000000000..afaf739b9558a7a9fedb3ba55c4e4a0791e97928 --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/sqlite_adapter/src/tokenizer_sqlite.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2025 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 "tokenizer_sqlite.h" +#include "tokenizer_api.h" +#include "tokenizer_export_type.h" +#include "securec.h" + +#include + +SQLITE_EXTENSION_INIT1 + +using namespace CNTokenizer; + +static std::mutex g_mtx; +static uint32_t g_magicCode = 0x12345678; +static uint32_t g_refCount = 0; +constexpr int FTS5_MAX_VERSION = 2; + +int fts5_customtokenizer_xCreate(void *sqlite3, const char **azArg, int nArg, Fts5Tokenizer **ppOut) +{ + (void)sqlite3; + std::lock_guard lock(g_mtx); + g_refCount++; + if (g_refCount != 1) { + *ppOut = (Fts5Tokenizer *)&g_magicCode; + return SQLITE_OK; + } + + GRD_TokenizerParamT param = {CUT_MMSEG, EXTRACT_TF_IDF}; + int ret = GRD_TokenizerInit(NULL, NULL, param); + if (ret != GRD_OK) { + sqlite3_log(ret, "GRD_TokenizerInit wrong"); + return ret; + } + *ppOut = (Fts5Tokenizer *)&g_magicCode; + return SQLITE_OK; +} + +static char *CpyStr(const char *pText, int nText) +{ + if (nText < 0) { + return nullptr; + } + char *ptr = (char *)malloc(nText + 1); + if (ptr == nullptr) { + return nullptr; + } + errno_t err = memcpy_s(ptr, nText + 1, pText, nText); + if (err != EOK) { + return nullptr; + } + ptr[nText] = '\0'; + return ptr; +} + +int fts5_customtokenizer_xTokenize(Fts5Tokenizer *tokenizer_ptr, void *pCtx, int flags, const char *pText, int nText, + XTokenFn xToken) +{ + if (nText == 0) { + return SQLITE_OK; + } + char *ptr = CpyStr(pText, nText); + if (ptr == nullptr) { + sqlite3_log(GRD_FAILED_MEMORY_ALLOCATE, "CpyStr wrong"); + return GRD_FAILED_MEMORY_ALLOCATE; + } + GRD_CutOptionT option = {false}; + GRD_WordEntryListT *entryList = nullptr; + int ret = GRD_TokenizerCut(ptr, option, &entryList); + if (ret != GRD_OK) { + sqlite3_log(ret, "GRD_TokenizerCut wrong"); + return ret; + } + GRD_WordEntryT entry; + int start = 0; + int end = 0; + while ((ret = GRD_TokenizerNext(entryList, &entry)) == GRD_OK) { + start = entry.word - ptr; + end = start + entry.length; + ret = xToken(pCtx, 0, entry.word, entry.length, start, end); + if (ret != SQLITE_OK) { + sqlite3_log(ret, "xToken wrong"); + break; + } + } + GRD_TokenizerFreeWordEntryList(entryList); + free(ptr); + if (ret != GRD_OK && ret != GRD_NO_DATA) { + return ret; + } + return SQLITE_OK; +} + +void fts5_customtokenizer_xDelete(Fts5Tokenizer *tokenizer_ptr) +{ + std::lock_guard lock(g_mtx); + g_refCount--; + if (g_refCount != 0) { + return; + } + (void)GRD_TokenizerDestroy(tokenizer_ptr); +} + +/* +** Return a pointer to the fts5_api pointer for database connection db. +** If an error occurs, return NULL and leave an error in the database +** handle (accessible using sqlite3_errcode()/errmsg()). +*/ +static int fts5_api_from_db(sqlite3 *db, fts5_api **ppApi) +{ + sqlite3_stmt *pStmt = 0; + int rc; + + *ppApi = 0; + rc = sqlite3_prepare(db, "SELECT fts5(?1)", -1, &pStmt, 0); + if (rc == SQLITE_OK) { + sqlite3_bind_pointer(pStmt, 1, reinterpret_cast(ppApi), "fts5_api_ptr", 0); + (void)sqlite3_step(pStmt); + rc = sqlite3_finalize(pStmt); + } + + return rc; +} + +int sqlite3_customtokenizer_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) +{ + (void)pzErrMsg; + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi) + + fts5_tokenizer tokenizer = { + fts5_customtokenizer_xCreate, + fts5_customtokenizer_xDelete, + fts5_customtokenizer_xTokenize + }; + fts5_api *fts5api; + rc = fts5_api_from_db(db, &fts5api); + if (rc != SQLITE_OK) { + sqlite3_log(rc, "fts5_api_from_db wrong"); + return rc; + } + if (fts5api == 0 || fts5api->iVersion < FTS5_MAX_VERSION) { + sqlite3_log(SQLITE_ERROR, "sqlite3_customtokenizer_init wrong"); + return SQLITE_ERROR; + } + return fts5api->xCreateTokenizer(fts5api, "customtokenizer", reinterpret_cast(fts5api), &tokenizer, NULL); +} diff --git a/kv_store/frameworks/libs/distributeddb/storage/include/cloud/cloud_storage_utils.h b/kv_store/frameworks/libs/distributeddb/storage/include/cloud/cloud_storage_utils.h index e63e1579ac1fcd4d149b6df896286dc79660601b..58c219723ed812a48f61e320f5222bcd6a40c2e6 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/include/cloud/cloud_storage_utils.h +++ b/kv_store/frameworks/libs/distributeddb/storage/include/cloud/cloud_storage_utils.h @@ -20,6 +20,7 @@ #include "cloud/cloud_store_types.h" #include "cloud/cloud_upload_recorder.h" #include "icloud_sync_storage_interface.h" +#include "sqlite_single_ver_relational_storage_executor.h" #include "sqlite_utils.h" namespace DistributedDB { @@ -106,7 +107,7 @@ public: static std::string GetCursorIncSql(const std::string &tableName); static std::string GetCursorIncSqlWhenAllow(const std::string &tableName); static std::string GetCursorUpgradeSql(const std::string &tableName); - static std::string GetUpdateUploadFinishedSql(const std::string &tableName); + static std::string GetUpdateUploadFinishedSql(const std::string &tableName, bool isExistAssetsDownload); static bool IsSharedTable(const TableSchema &tableSchema); static bool ChkFillCloudAssetParam(const CloudSyncBatch &data, int errCode); @@ -115,8 +116,8 @@ public: static std::pair> GetHashValueWithPrimaryKeyMap(const VBucket &vBucket, const TableSchema &tableSchema, const TableInfo &localTable, const std::map &pkMap, bool allowEmpty); - static std::string GetUpdateRecordFlagSql(const std::string &tableName, bool recordConflict, - const LogInfo &logInfo, const VBucket &uploadExtend = {}, const CloudWaterType &type = CloudWaterType::BUTT); + static std::string GetUpdateRecordFlagSql(UpdateRecordFlagStruct updateRecordFlag, const LogInfo &logInfo, + const VBucket &uploadExtend = {}, const CloudWaterType &type = CloudWaterType::BUTT); static std::string GetUpdateRecordFlagSqlUpload(const std::string &tableName, bool recordConflict, const LogInfo &logInfo, const VBucket &uploadExtend = {}, const CloudWaterType &type = CloudWaterType::BUTT); static int BindStepConsistentFlagStmt(sqlite3_stmt *stmt, const VBucket &data, @@ -193,9 +194,30 @@ public: static bool IsSystemRecord(const Key &key); static int GetSyncQueryByPk(const std::string &tableName, const std::vector &data, bool isKv, - QuerySyncObject &querySyncObject); + std::vector &syncQuery); + + static bool IsAssetsContainDownloadRecord(const VBucket &dbAssets); + + struct CloudSyncParam { + std::string tableName; + CloudWaterType type; + TableSchema tableSchema; + }; + + static int UpdateRecordFlagAfterUpload(SQLiteSingleVerRelationalStorageExecutor *handle, + const CloudSyncParam ¶m, const CloudSyncBatch &updateData, CloudUploadRecorder &recorder, + bool isLock = false); + + static int FillCloudQueryToExtend(QuerySyncObject &obj, VBucket &extend); + private: static int IdentifyCloudTypeInner(CloudSyncData &cloudSyncData, VBucket &data, VBucket &log, VBucket &flags); + + static int FillQueryByPK(const std::string &tableName, bool isKv, std::map dataIndex, + std::vector>> syncPkVec, std::vector &syncQuery); + + static void PutSyncPkVec(const std::string &col, std::map> &syncPk, + std::vector>> &syncPkVec); }; } #endif // CLOUD_STORAGE_UTILS_H diff --git a/kv_store/frameworks/libs/distributeddb/storage/include/icloud_sync_storage_interface.h b/kv_store/frameworks/libs/distributeddb/storage/include/icloud_sync_storage_interface.h index b37840ec1564ff2e998964403b1d377576d100d5..738fbd8a1f2b0b0f64655ffd5c084c99b643536b 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/include/icloud_sync_storage_interface.h +++ b/kv_store/frameworks/libs/distributeddb/storage/include/icloud_sync_storage_interface.h @@ -81,9 +81,22 @@ public: uploadStartFunc_(); } } + + void SetBeforeUploadTransaction(const std::function &func) + { + beforeUploadTransaction_ = func; + } + + void DoBeforeUploadTransaction() + { + if (beforeUploadTransaction_) { + beforeUploadTransaction_(); + } + } protected: std::function syncFinishFunc_; std::function uploadStartFunc_; + std::function beforeUploadTransaction_; }; class ICloudSyncStorageInterface : public ICloudSyncStorageHook { @@ -130,6 +143,8 @@ public: virtual int PutCloudSyncData(const std::string &tableName, DownloadData &downloadData) = 0; + virtual int UpdateAssetStatusForAssetOnly(const std::string &tableName, VBucket &asset) = 0; + virtual int CleanCloudData(ClearMode mode, const std::vector &tableNameList, const RelationalSchemaObject &localSchema, std::vector &assets) { @@ -141,8 +156,13 @@ public: virtual int FillCloudAssetForDownload(const std::string &tableName, VBucket &asset, bool isDownloadSuccess) = 0; + virtual int FillCloudAssetForAsyncDownload(const std::string &tableName, VBucket &asset, + bool isDownloadSuccess) = 0; + virtual int SetLogTriggerStatus(bool status) = 0; + virtual int SetLogTriggerStatusForAsyncDownload(bool status) = 0; + virtual int SetCursorIncFlag(bool flag) { return E_OK; @@ -177,6 +197,12 @@ public: return { E_OK, static_cast(LockStatus::UNLOCK) }; } + virtual std::pair GetAssetsByGidOrHashKeyForAsyncDownload(const TableSchema &tableSchema, + const std::string &gid, const Bytes &hashKey, VBucket &assets) + { + return { E_OK, static_cast(LockStatus::UNLOCK) }; + } + virtual int SetIAssetLoader([[gnu::unused]] const std::shared_ptr &loader) { return E_OK; @@ -188,8 +214,14 @@ public: return E_OK; } + virtual int UpdateRecordFlagForAsyncDownload([[gnu::unused]] const std::string &tableName, + [[gnu::unused]] bool recordConflict, [[gnu::unused]] const LogInfo &logInfo) + { + return E_OK; + } + virtual int GetCompensatedSyncQuery([[gnu::unused]] std::vector &syncQuery, - [[gnu::unused]] std::vector &users) + [[gnu::unused]] std::vector &users, [[gnu::unused]] bool isQueryDownloadRecords) { return E_OK; } @@ -205,6 +237,12 @@ public: return E_OK; } + virtual int MarkFlagAsAssetAsyncDownload([[gnu::unused]] const std::string &tableName, + [[gnu::unused]] const DownloadData &downloadData, [[gnu::unused]] const std::set &gidFilters) + { + return E_OK; + } + virtual void SetUser([[gnu::unused]] const std::string &user) { } @@ -246,7 +284,7 @@ public: virtual int GetCursor(const std::string &tableName, uint64_t &cursor) { cursor = DBConstant::INVALID_CURSOR; - return E_NOT_SUPPORT; + return -E_NOT_SUPPORT; } virtual bool IsCurrentLogicDelete() const @@ -255,6 +293,24 @@ public: } virtual int GetLocalDataCount(const std::string &tableName, int &dataCount, int &logicDeleteDataCount) = 0; + + virtual std::pair> GetDownloadAssetTable() = 0; + + virtual std::pair> GetDownloadAssetRecords(const std::string &tableName, + int64_t beginTime) = 0; + + virtual int GetInfoByPrimaryKeyOrGid(const std::string &tableName, const VBucket &vBucket, + [[gnu::unused]] bool useTransaction, DataInfoWithLog &dataInfoWithLog, VBucket &assetInfo) + { + return GetInfoByPrimaryKeyOrGid(tableName, vBucket, dataInfoWithLog, assetInfo); + } + + virtual void PrintCursorChange([[gnu::unused]] const std::string &tableName) {} + + virtual int GetLockStatusByGid(const std::string &tableName, const std::string &gid, LockStatus &status) + { + return E_OK; + } }; } diff --git a/kv_store/frameworks/libs/distributeddb/storage/include/kvdb_pragma.h b/kv_store/frameworks/libs/distributeddb/storage/include/kvdb_pragma.h index 5114992397d5e33f143afbf54773a9e77bcef1e6..dd47e8fd53b9200d5ada8106f6f479d8917f9795 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/include/kvdb_pragma.h +++ b/kv_store/frameworks/libs/distributeddb/storage/include/kvdb_pragma.h @@ -52,6 +52,7 @@ enum : int { PRAGMA_SET_MAX_LOG_LIMIT, PRAGMA_EXEC_CHECKPOINT, PRAGMA_CANCEL_SYNC_DEVICES, + PRAGMA_SET_MAX_VALUE_SIZE, }; struct PragmaSync { diff --git a/kv_store/frameworks/libs/distributeddb/storage/include/relational_db_sync_interface.h b/kv_store/frameworks/libs/distributeddb/storage/include/relational_db_sync_interface.h index d135dbcb25d23bba7e21a3a87aa45239e0261483..21ec06f46e353516a3f5fe7642959d2b54a4dade 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/include/relational_db_sync_interface.h +++ b/kv_store/frameworks/libs/distributeddb/storage/include/relational_db_sync_interface.h @@ -53,7 +53,7 @@ public: virtual int GetSchemaFromDB(RelationalSchemaObject &schema) = 0; - virtual int GetRemoteDeviceSchema(const std::string &deviceId, RelationalSchemaObject &schemaObj) = 0; + virtual int GetRemoteDeviceSchema(const std::string &deviceId, RelationalSchemaObject &schemaObj) const = 0; virtual void ReleaseRemoteQueryContinueToken(ContinueToken &token) const = 0; }; diff --git a/kv_store/frameworks/libs/distributeddb/storage/include/relational_store_connection.h b/kv_store/frameworks/libs/distributeddb/storage/include/relational_store_connection.h index 2db86c10453603da407d171a730a56a16b051635..0de011966b000c2db628075162af72703931bf64 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/include/relational_store_connection.h +++ b/kv_store/frameworks/libs/distributeddb/storage/include/relational_store_connection.h @@ -28,7 +28,7 @@ namespace DistributedDB { class IRelationalStore; using RelationalObserverAction = - std::function; + std::function; class RelationalStoreConnection : public IConnection, public virtual RefObject { public: struct SyncInfo { @@ -50,7 +50,6 @@ public: // Close and release the connection. virtual int Close() = 0; virtual int SyncToDevice(SyncInfo &info) = 0; - virtual int32_t GetCloudSyncTaskCount() = 0; virtual std::string GetIdentifier() = 0; virtual int CreateDistributedTable(const std::string &tableName, TableSyncType syncType) = 0; virtual int RegisterLifeCycleCallback(const DatabaseLifeCycleNotifier ¬ifier) = 0; @@ -58,14 +57,10 @@ public: virtual int RemoveDeviceData() = 0; virtual int RemoveDeviceData(const std::string &device) = 0; virtual int RemoveDeviceData(const std::string &device, const std::string &tableName) = 0; - virtual int DoClean(ClearMode mode) = 0; virtual int RegisterObserverAction(const StoreObserver *observer, const RelationalObserverAction &action) = 0; virtual int UnRegisterObserverAction(const StoreObserver *observer) = 0; virtual int RemoteQuery(const std::string &device, const RemoteCondition &condition, uint64_t timeout, std::shared_ptr &result) = 0; - virtual int SetCloudDB(const std::shared_ptr &cloudDb) = 0; - virtual int PrepareAndSetCloudDbSchema(const DataBaseSchema &schema) = 0; - virtual int SetIAssetLoader(const std::shared_ptr &loader) = 0; virtual int GetStoreInfo(std::string &userId, std::string &appId, std::string &storeId) = 0; @@ -79,11 +74,27 @@ public: virtual int UpsertData(RecordStatus status, const std::string &tableName, const std::vector &records) = 0; + virtual int GetDownloadingAssetsCount(int32_t &count) = 0; + + virtual int SetDistributedDbSchema(const DistributedSchema &schema) = 0; + +#ifdef USE_DISTRIBUTEDDB_CLOUD + virtual int32_t GetCloudSyncTaskCount() = 0; + + virtual int DoClean(ClearMode mode) = 0; + + virtual int SetCloudDB(const std::shared_ptr &cloudDb) = 0; + + virtual int PrepareAndSetCloudDbSchema(const DataBaseSchema &schema) = 0; + + virtual int SetIAssetLoader(const std::shared_ptr &loader) = 0; + virtual int SetCloudSyncConfig(const CloudSyncConfig &config) = 0; virtual int Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess, uint64_t taskId) = 0; virtual SyncProcess GetCloudTaskStatus(uint64_t taskId) = 0; +#endif protected: // Get the stashed 'RelationalDB_ pointer' without ref. template diff --git a/kv_store/frameworks/libs/distributeddb/storage/include/relationaldb_properties.h b/kv_store/frameworks/libs/distributeddb/storage/include/relationaldb_properties.h index a9dc4660d285cabca6d4aa4fb88d9046fff06152..9ff2007457645889067c224553a8e8d39a4fcf1a 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/include/relationaldb_properties.h +++ b/kv_store/frameworks/libs/distributeddb/storage/include/relationaldb_properties.h @@ -41,6 +41,8 @@ public: const CipherPassword &GetPasswd() const; uint32_t GetIterTimes() const; + DistributedTableMode GetDistributedTableMode() const; + static const std::string DISTRIBUTED_TABLE_MODE; private: diff --git a/kv_store/frameworks/libs/distributeddb/storage/include/storage_proxy.h b/kv_store/frameworks/libs/distributeddb/storage/include/storage_proxy.h index 64fd735dfb4480369f63d0e6314402e4a428beec..36d2a991358b6661de76f8b1a70a21ec66349ce3 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/include/storage_proxy.h +++ b/kv_store/frameworks/libs/distributeddb/storage/include/storage_proxy.h @@ -77,11 +77,13 @@ public: int GetCloudGid(const QuerySyncObject &querySyncObject, bool isCloudForcePush, bool isCompensatedTask, std::vector &cloudGid); - int GetInfoByPrimaryKeyOrGid(const std::string &tableName, const VBucket &vBucket, + int GetInfoByPrimaryKeyOrGid(const std::string &tableName, const VBucket &vBucket, bool useTransaction, DataInfoWithLog &dataInfoWithLog, VBucket &assetInfo); int PutCloudSyncData(const std::string &tableName, DownloadData &downloadData); + int UpdateAssetStatusForAssetOnly(const std::string &tableName, VBucket &asset); + int CleanCloudData(ClearMode mode, const std::vector &tableNameList, const RelationalSchemaObject &localSchema, std::vector &assets); @@ -98,7 +100,9 @@ public: int FillCloudAssetForDownload(const std::string &tableName, VBucket &asset, bool isDownloadSuccess); - int SetLogTriggerStatus(bool status); + int FillCloudAssetForAsyncDownload(const std::string &tableName, VBucket &asset, bool isDownloadSuccess); + + int SetLogTriggerStatus(bool status, bool isAsyncDownload = false); int SetCursorIncFlag(bool flag); @@ -120,20 +124,25 @@ public: void FillCloudGidIfSuccess(const OpType opType, const CloudSyncData &data); - std::pair GetAssetsByGidOrHashKey(const std::string &tableName, const std::string &gid, - const Bytes &hashKey, VBucket &assets); + std::pair GetAssetsByGidOrHashKey(const std::string &tableName, bool isAsyncDownload, + const std::string &gid, const Bytes &hashKey, VBucket &assets); int SetIAssetLoader(const std::shared_ptr &loader); - int UpdateRecordFlag(const std::string &tableName, bool recordConflict, const LogInfo &logInfo); + int UpdateRecordFlag(const std::string &tableName, bool isAsyncDownload, bool recordConflict, + const LogInfo &logInfo); - int GetCompensatedSyncQuery(std::vector &syncQuery, std::vector &users); + int GetCompensatedSyncQuery(std::vector &syncQuery, std::vector &users, + bool isQueryDownloadRecords); int ClearUnLockingNoNeedCompensated(); int MarkFlagAsConsistent(const std::string &tableName, const DownloadData &downloadData, const std::set &gidFilters); + int MarkFlagAsAssetAsyncDownload(const std::string &tableName, const DownloadData &downloadData, + const std::set &gidFilters); + void SetUser(const std::string &user); void OnSyncFinish(); @@ -164,6 +173,19 @@ public: bool IsCurrentLogicDelete() const; int GetLocalDataCount(const std::string &tableName, int &dataCount, int &logicDeleteDataCount); + + std::pair> GetDownloadAssetTable(); + + std::pair> GetDownloadAssetRecords(const std::string &tableName, + int64_t beginTime); + + void BeforeUploadTransaction(); + + void PrintCursorChange(const std::string &tableName); + + int GetLockStatusByGid(const std::string &tableName, const std::string &gid, LockStatus &status); + + bool IsContainAssetsTable(); protected: void Init(); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/cloud/cloud_storage_utils.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/cloud/cloud_storage_utils.cpp index 3625b9aba426508c33d1c176cea0294fe436f75f..899e4ca1bbb249498f9f83d240246abc2ac91568 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/cloud/cloud_storage_utils.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/cloud/cloud_storage_utils.cpp @@ -447,7 +447,6 @@ Type CloudStorageUtils::GetAssetFromAssets(Type &value) int CloudStorageUtils::FillAssetBeforeDownload(Asset &asset) { AssetOpType flag = static_cast(asset.flag); - AssetStatus status = static_cast(asset.status); uint32_t lowStatus = AssetOperationUtils::EraseBitMask(asset.status); switch (flag) { case AssetOpType::DELETE: { @@ -459,13 +458,6 @@ int CloudStorageUtils::FillAssetBeforeDownload(Asset &asset) } break; } - case AssetOpType::INSERT: - case AssetOpType::UPDATE: { - if (status != AssetStatus::NORMAL) { - asset.hash = std::string(""); - } - break; - } default: break; } @@ -943,19 +935,7 @@ int CloudStorageUtils::FillAssetAfterDownloadFail(Asset &asset, Asset &dbAsset, if (status != AssetStatus::ABNORMAL) { return FillAssetAfterDownload(asset, dbAsset, assetOpType); } - AssetOpType flag = static_cast(asset.flag); dbAsset = asset; - switch (flag) { - case AssetOpType::INSERT: - case AssetOpType::DELETE: - case AssetOpType::UPDATE: { - dbAsset.hash = std::string(""); - break; - } - default: - // other flag type do not need to clear hash - break; - } return E_OK; } @@ -1122,19 +1102,25 @@ int CloudStorageUtils::BindUpdateLogStmtFromVBucket(const VBucket &vBucket, cons return E_OK; } -std::string CloudStorageUtils::GetUpdateRecordFlagSql(const std::string &tableName, bool recordConflict, - const LogInfo &logInfo, const VBucket &uploadExtend, const CloudWaterType &type) +std::string CloudStorageUtils::GetUpdateRecordFlagSql(UpdateRecordFlagStruct updateRecordFlag, const LogInfo &logInfo, + const VBucket &uploadExtend, const CloudWaterType &type) { std::string compensatedBit = std::to_string(static_cast(LogInfoFlag::FLAG_WAIT_COMPENSATED_SYNC)); std::string inconsistencyBit = std::to_string(static_cast(LogInfoFlag::FLAG_DEVICE_CLOUD_INCONSISTENCY)); bool gidEmpty = logInfo.cloudGid.empty(); bool isDeleted = logInfo.dataKey == DBConstant::DEFAULT_ROW_ID; - std::string sql = "UPDATE " + DBCommon::GetLogTableName(tableName) + " SET flag = (CASE WHEN timestamp = ? THEN "; - bool isNeedCompensated = recordConflict || DBCommon::IsNeedCompensatedForUpload(uploadExtend, type); + std::string sql = "UPDATE " + DBCommon::GetLogTableName(updateRecordFlag.tableName) + + " SET flag = (CASE WHEN timestamp = ? THEN "; + bool isNeedCompensated = + updateRecordFlag.isRecordConflict || DBCommon::IsNeedCompensatedForUpload(uploadExtend, type); if (isNeedCompensated && !(isDeleted && gidEmpty)) { sql += "flag | " + compensatedBit + " ELSE flag | " + compensatedBit; } else { - sql += "flag & ~" + compensatedBit + " & ~" + inconsistencyBit + " ELSE flag & ~" + compensatedBit; + if (updateRecordFlag.isInconsistency) { + sql += "flag & ~" + compensatedBit + " |" + inconsistencyBit + " ELSE flag & ~" + compensatedBit; + } else { + sql += "flag & ~" + compensatedBit + " & ~" + inconsistencyBit + " ELSE flag & ~" + compensatedBit; + } } sql += " END), status = (CASE WHEN status == 2 THEN 3 WHEN (status == 1 AND timestamp = ?) THEN 0 ELSE status END)"; if (DBCommon::IsCloudRecordNotFound(uploadExtend) && @@ -1196,13 +1182,20 @@ std::string CloudStorageUtils::GetUpdateRecordFlagSqlUpload(const std::string &t return sql; } -std::string CloudStorageUtils::GetUpdateUploadFinishedSql(const std::string &tableName) +std::string CloudStorageUtils::GetUpdateUploadFinishedSql(const std::string &tableName, bool isExistAssetsDownload) { std::string finishedBit = std::to_string(static_cast(LogInfoFlag::FLAG_UPLOAD_FINISHED)); std::string compensatedBit = std::to_string(static_cast(LogInfoFlag::FLAG_WAIT_COMPENSATED_SYNC)); // When the data flag is not in the compensation state and the local data does not change, the upload is finished. - return "UPDATE " + DBCommon::GetLogTableName(tableName) + " SET flag = (CASE WHEN timestamp = ? AND flag & " + - compensatedBit + " != " + compensatedBit + " THEN flag | " + finishedBit + " ELSE flag END) WHERE hash_key=?"; + if (isExistAssetsDownload) { + return "UPDATE " + DBCommon::GetLogTableName(tableName) + " SET flag = (CASE WHEN timestamp = ? AND flag & " + + compensatedBit + " != " + compensatedBit + " THEN flag | " + finishedBit + + " ELSE flag END) WHERE hash_key=?"; + } + // Clear IsWaitAssetDownload flag when no asset is to be downloaded + return "UPDATE " + DBCommon::GetLogTableName(tableName) + " SET flag = ((CASE WHEN timestamp = ? AND flag & " + + compensatedBit + " != " + compensatedBit + " THEN flag | " + finishedBit + + " ELSE flag END) & ~0x1000) WHERE hash_key=?"; } int CloudStorageUtils::BindStepConsistentFlagStmt(sqlite3_stmt *stmt, const VBucket &data, @@ -1498,10 +1491,41 @@ std::string CloudStorageUtils::GetCursorUpgradeSql(const std::string &tableName) " NULL THEN 0 ELSE MAX(cursor) END FROM " + DBCommon::GetLogTableName(tableName) + "));"; } +int CloudStorageUtils::FillQueryByPK(const std::string &tableName, bool isKv, std::map dataIndex, + std::vector>> syncPkVec, std::vector &syncQuery) +{ + for (const auto syncPk : syncPkVec) { + Query query = Query::Select().From(tableName); + if (isKv) { + QueryUtils::FillQueryInKeys(syncPk, dataIndex, query); + } else { + for (const auto &[col, pkList] : syncPk) { + QueryUtils::FillQueryIn(col, pkList, dataIndex[col], query); + } + } + auto objectList = QuerySyncObject::GetQuerySyncObject(query); + if (objectList.size() != 1u) { // only support one QueryExpression + return -E_INTERNAL_ERROR; + } + syncQuery.push_back(objectList[0]); + } + return E_OK; +} + +void CloudStorageUtils::PutSyncPkVec(const std::string &col, std::map> &syncPk, + std::vector>> &syncPkVec) +{ + if (syncPk[col].size() >= CloudDbConstant::MAX_CONDITIONS_SIZE) { + syncPkVec.push_back(syncPk); + syncPk[col].clear(); + } +} + int CloudStorageUtils::GetSyncQueryByPk(const std::string &tableName, const std::vector &data, bool isKv, - QuerySyncObject &querySyncObject) + std::vector &syncQuery) { std::map dataIndex; + std::vector>> syncPkVec; std::map> syncPk; int ignoreCount = 0; for (const auto &oneRow : data) { @@ -1519,6 +1543,7 @@ int CloudStorageUtils::GetSyncQueryByPk(const std::string &tableName, const std: if (!isFind && value.index() != TYPE_INDEX) { dataIndex[col] = value.index(); syncPk[col].push_back(value); + PutSyncPkVec(col, syncPk, syncPkVec); continue; } if (isFind && dataIndex[col] != value.index()) { @@ -1526,22 +1551,96 @@ int CloudStorageUtils::GetSyncQueryByPk(const std::string &tableName, const std: continue; } syncPk[col].push_back(value); + PutSyncPkVec(col, syncPk, syncPkVec); } } + syncPkVec.push_back(syncPk); LOGI("match %zu data for compensated sync, ignore %d", data.size(), ignoreCount); - Query query = Query::Select().From(tableName); - if (isKv) { - QueryUtils::FillQueryInKeys(syncPk, dataIndex, query); - } else { - for (const auto &[col, pkList] : syncPk) { - QueryUtils::FillQueryIn(col, pkList, dataIndex[col], query); + return FillQueryByPK(tableName, isKv, dataIndex, syncPkVec, syncQuery); +} + +bool CloudStorageUtils::IsAssetsContainDownloadRecord(const VBucket &dbAssets) +{ + for (const auto &item: dbAssets) { + if (IsAsset(item.second)) { + const auto &asset = std::get(item.second); + if (AssetOperationUtils::IsAssetNeedDownload(asset)) { + return true; + } + } else if (IsAssets(item.second)) { + const auto &assets = std::get(item.second); + if (AssetOperationUtils::IsAssetsNeedDownload(assets)) { + return true; + } + } + } + return false; +} + +int CloudStorageUtils::UpdateRecordFlagAfterUpload(SQLiteSingleVerRelationalStorageExecutor *handle, + const CloudSyncParam ¶m, const CloudSyncBatch &updateData, CloudUploadRecorder &recorder, bool isLock) +{ + if (updateData.timestamp.size() != updateData.extend.size()) { + LOGE("the num of extend:%zu and timestamp:%zu is not equal.", + updateData.extend.size(), updateData.timestamp.size()); + return -E_INVALID_ARGS; + } + for (size_t i = 0; i < updateData.extend.size(); ++i) { + const auto &record = updateData.extend[i]; + if (DBCommon::IsRecordError(record) || DBCommon::IsRecordAssetsMissing(record) || + DBCommon::IsRecordVersionConflict(record) || isLock) { + if (DBCommon::IsRecordAssetsMissing(record)) { + LOGI("[CloudStorageUtils][UpdateRecordFlagAfterUpload] Record assets missing, skip update."); + } + int errCode = handle->UpdateRecordStatus(param.tableName, CloudDbConstant::TO_LOCAL_CHANGE, + updateData.hashKey[i]); + if (errCode != E_OK) { + LOGE("[CloudStorageUtils] Update record status failed in index %zu", i); + return errCode; + } + continue; + } + const auto &rowId = updateData.rowid[i]; + std::string cloudGid; + (void)CloudStorageUtils::GetValueFromVBucket(CloudDbConstant::GID_FIELD, record, cloudGid); + LogInfo logInfo; + logInfo.cloudGid = cloudGid; + logInfo.timestamp = updateData.timestamp[i]; + logInfo.dataKey = rowId; + logInfo.hashKey = updateData.hashKey[i]; + std::string sql = CloudStorageUtils::GetUpdateRecordFlagSqlUpload( + param.tableName, DBCommon::IsRecordIgnored(record), logInfo, record, param.type); + int errCode = handle->UpdateRecordFlag(param.tableName, sql, logInfo); + if (errCode != E_OK) { + LOGE("[CloudStorageUtils] Update record flag failed in index %zu", i); + return errCode; + } + + std::vector assets; + errCode = handle->GetDownloadAssetRecordsByGid(param.tableSchema, logInfo.cloudGid, assets); + if (errCode != E_OK) { + LOGE("[RDBExecutor]Get downloading assets records by gid failed: %d", errCode); + return errCode; } + handle->MarkFlagAsUploadFinished(param.tableName, updateData.hashKey[i], updateData.timestamp[i], + !assets.empty()); + recorder.RecordUploadRecord(param.tableName, logInfo.hashKey, param.type, updateData.timestamp[i]); } - auto objectList = QuerySyncObject::GetQuerySyncObject(query); - if (objectList.size() != 1u) { // only support one QueryExpression - return -E_INTERNAL_ERROR; + return E_OK; +} + +int CloudStorageUtils::FillCloudQueryToExtend(QuerySyncObject &obj, VBucket &extend) +{ + Bytes bytes; + bytes.resize(obj.CalculateParcelLen(SOFTWARE_VERSION_CURRENT)); + Parcel parcel(bytes.data(), bytes.size()); + int errCode = obj.SerializeData(parcel, SOFTWARE_VERSION_CURRENT); + if (errCode != E_OK) { + LOGE("[CloudStorageUtils] Query serialize failed %d", errCode); + return errCode; } - querySyncObject = objectList[0]; + extend[CloudDbConstant::TYPE_FIELD] = static_cast(CloudQueryType::QUERY_FIELD); + extend[CloudDbConstant::QUERY_FIELD] = bytes; return E_OK; } } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/data_transformer.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/data_transformer.cpp index a6f5fcfc68318d0bfc44d3391e4712d55af34523..e923f2e9fabcb1d619d92b433fba6b36f5e3fe47 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/data_transformer.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/data_transformer.cpp @@ -198,7 +198,7 @@ int DeSerializeBlobByType(DataValue &dataValue, Parcel &parcel, StorageType type { uint32_t blobLength = 0; (void)parcel.ReadUInt32(blobLength); - if (blobLength >= DBConstant::MAX_VALUE_SIZE || parcel.IsError()) { // One blob cannot be over one value size. + if (blobLength > DBConstant::MAX_SET_VALUE_SIZE || parcel.IsError()) { // One blob cannot be over one value size. return -E_PARSE_FAIL; } char *array = nullptr; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/data_transformer.h b/kv_store/frameworks/libs/distributeddb/storage/src/data_transformer.h index 9e338e520f69477d49eaa5887d7e2efb2468d502..c77d4cc7b82a6ab44dbdb2a9b0c0895c0cedcea3 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/data_transformer.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/data_transformer.h @@ -57,6 +57,8 @@ enum class LogInfoFlag : uint32_t { FLAG_SYSTEM_RECORD = 0x200, FLAG_UPLOAD_FINISHED = 0x400, FLAG_LOGIC_DELETE_FOR_LOGOUT = 0x800, + FLAG_ASSET_DOWNLOADING_FOR_ASYNC = 0x1000, + FLAG_LOGIN_USER = 0x2000, // same hash key, login user's data }; struct RowDataWithLog { @@ -85,6 +87,12 @@ struct DataInfoWithLog { VBucket primaryKeys; }; +struct UpdateRecordFlagStruct { + std::string tableName; + bool isRecordConflict; + bool isInconsistency; +}; + class DataTransformer { public: static int TransformTableData(const TableDataWithLog &tableDataWithLog, diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/gaussdb_rd/rd_single_ver_natural_store_connection.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/gaussdb_rd/rd_single_ver_natural_store_connection.cpp index b3b3615d924bcfe27c2c8f5d436b3ab588ac8f3f..4faa13d985b8426ca10a10a6ec3bc3ecc2d21e27 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/gaussdb_rd/rd_single_ver_natural_store_connection.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/gaussdb_rd/rd_single_ver_natural_store_connection.cpp @@ -622,7 +622,7 @@ void RdSingleVerNaturalStoreConnection::ReleaseExecutor(RdSingleVerStorageExecut void RdSingleVerNaturalStoreConnection::ReleaseCommitData(SingleVerNaturalStoreCommitNotifyData *&committedData) { if (committedData != nullptr) { - committedData->DecObjRef(committedData); + RefObject::DecObjRef(committedData); committedData = nullptr; } } @@ -742,6 +742,7 @@ int RdSingleVerNaturalStoreConnection::GetWatermarkInfo(const std::string &devic return -E_NOT_SUPPORT; } +#ifdef USE_DISTRIBUTEDDB_CLOUD int RdSingleVerNaturalStoreConnection::Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess) { return -E_NOT_SUPPORT; @@ -755,5 +756,6 @@ int RdSingleVerNaturalStoreConnection::SetCloudDB(const std::map> &cloudDBs) override; void SetGenCloudVersionCallback(const GenerateCloudVersionCallback &callback) override; - +#endif private: int CheckRdMonoStatus(OperatePerm perm); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/kv/generic_kvdb.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/kv/generic_kvdb.cpp index 8003b0deeb7e602db27797a1b04c2e00109d30da..03c826eac66f75befa89ce88b941573c9e5a1e2c 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/kv/generic_kvdb.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/kv/generic_kvdb.cpp @@ -125,12 +125,12 @@ void GenericKvDB::CommitNotify(int notifyEvent, KvDBCommitNotifyFilterAbleData * notificationChain_->NotifyEvent(static_cast(notifyEvent), nullptr); } else { data->SetMyDb(this, eventNotifyCounter_); - data->IncObjRef(data); + RefObject::IncObjRef(data); int errCode = RuntimeContext::GetInstance()->ScheduleQueuedTask(GetStoreId(), [this, notifyEvent, data] { CommitNotifyAsync(notifyEvent, data); }); if (errCode != E_OK) { LOGE("Failed to do commit notify, schedule task err:%d.", errCode); - data->DecObjRef(data); + RefObject::DecObjRef(data); data = nullptr; } } @@ -291,7 +291,7 @@ void GenericKvDB::SetCorruptHandler(const DatabaseCorruptHandler &handler) void GenericKvDB::CommitNotifyAsync(int notifyEvent, KvDBCommitNotifyFilterAbleData *data) { notificationChain_->NotifyEvent(static_cast(notifyEvent), data); - data->DecObjRef(data); + RefObject::DecObjRef(data); data = nullptr; } @@ -349,10 +349,14 @@ int GenericKvDB::TransConflictTypeToRegisterFunctionType(int conflictType, Regis return -E_NOT_SUPPORT; } -int GenericKvDB::CheckDataStatus(const Key &key, const Value &value, bool isDeleted) const +uint32_t GenericKvDB::GetMaxValueSize() const { - if (key.empty() || key.size() > DBConstant::MAX_KEY_SIZE || - value.size() > DBConstant::MAX_VALUE_SIZE) { + return DBConstant::MAX_VALUE_SIZE; +} + +int GenericKvDB::CheckDataStatus(const Key &key, const Value &value, [[gnu::unused]] bool isDeleted) const +{ + if (key.empty() || key.size() > DBConstant::MAX_KEY_SIZE || value.size() > GetMaxValueSize()) { return -E_INVALID_ARGS; } return E_OK; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/kv/generic_kvdb.h b/kv_store/frameworks/libs/distributeddb/storage/src/kv/generic_kvdb.h index a34873e53bcbadbd5ca4fa5a7989365aa1b42d62..042e4bbd600bf13ef5cf4db5f5786d5d068123eb 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/kv/generic_kvdb.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/kv/generic_kvdb.h @@ -115,6 +115,8 @@ public: virtual int TransConflictTypeToRegisterFunctionType(int conflictType, RegisterFuncType &type) const; + virtual uint32_t GetMaxValueSize() const; + virtual int CheckDataStatus(const Key &key, const Value &value, bool isDeleted) const; virtual bool CheckWritePermission() const; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/kv/kvdb_commit_notify_filterable_data.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/kv/kvdb_commit_notify_filterable_data.cpp index dad5896dfe4b985c8214511d992a20aea9e9b520..a0b955eec639ce98844261616626ec25914ed8d8 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/kv/kvdb_commit_notify_filterable_data.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/kv/kvdb_commit_notify_filterable_data.cpp @@ -25,7 +25,7 @@ KvDBCommitNotifyFilterAbleData::KvDBCommitNotifyFilterAbleData() KvDBCommitNotifyFilterAbleData::~KvDBCommitNotifyFilterAbleData() { if (genericKvDB_ != nullptr) { - genericKvDB_->DecObjRef(genericKvDB_); + RefObject::DecObjRef(genericKvDB_); genericKvDB_ = nullptr; } } @@ -85,11 +85,11 @@ void KvDBCommitNotifyFilterAbleData::SetMyDb(GenericKvDB *db, uint64_t notifyID) return; } if (genericKvDB_ != nullptr) { - genericKvDB_->DecObjRef(genericKvDB_); + RefObject::DecObjRef(genericKvDB_); } genericKvDB_ = db; if (genericKvDB_ != nullptr) { - genericKvDB_->IncObjRef(genericKvDB_); + RefObject::IncObjRef(genericKvDB_); } notifyID_ = notifyID; } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/kv/kvdb_manager.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/kv/kvdb_manager.cpp index 33254e3875895c73ea8cc75a819aec0d3c2450c1..68d23e5041b2e301942a0245ca1cfe8a62978d9e 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/kv/kvdb_manager.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/kv/kvdb_manager.cpp @@ -705,14 +705,14 @@ IKvDB *KvDBManager::SaveKvDBToCache(IKvDB *kvDB) if (databaseType == KvDBProperties::LOCAL_TYPE_SQLITE) { IKvDB *kvDBTmp = FindKvDBFromCache(properties, localKvDBs_, true, errCode); if (kvDBTmp != nullptr) { - kvDBTmp->IncObjRef(kvDBTmp); + RefObject::IncObjRef(kvDBTmp); return kvDBTmp; } localKvDBs_.insert(std::pair(identifier, kvDB)); } else if (databaseType == KvDBProperties::MULTI_VER_TYPE_SQLITE) { IKvDB *kvDBTmp = FindKvDBFromCache(properties, multiVerNaturalStores_, true, errCode); if (kvDBTmp != nullptr) { - kvDBTmp->IncObjRef(kvDBTmp); + RefObject::IncObjRef(kvDBTmp); return kvDBTmp; } kvDB->WakeUpSyncer(); @@ -720,7 +720,7 @@ IKvDB *KvDBManager::SaveKvDBToCache(IKvDB *kvDB) } else { IKvDB *kvDBTmp = FindKvDBFromCache(properties, singleVerNaturalStores_, true, errCode); if (kvDBTmp != nullptr) { - kvDBTmp->IncObjRef(kvDBTmp); + RefObject::IncObjRef(kvDBTmp); return kvDBTmp; } kvDB->WakeUpSyncer(); @@ -759,7 +759,7 @@ IKvDB *KvDBManager::FindAndGetKvDBFromCache(const KvDBProperties &properties, in IKvDB *kvDB = FindKvDBFromCache(properties, localKvDBs_, true, errCode); if (kvDB != nullptr) { - kvDB->IncObjRef(kvDB); + RefObject::IncObjRef(kvDB); return kvDB; } if (errCode != -E_NOT_FOUND) { @@ -768,7 +768,7 @@ IKvDB *KvDBManager::FindAndGetKvDBFromCache(const KvDBProperties &properties, in kvDB = FindKvDBFromCache(properties, multiVerNaturalStores_, true, errCode); if (kvDB != nullptr) { - kvDB->IncObjRef(kvDB); + RefObject::IncObjRef(kvDB); return kvDB; } if (errCode != -E_NOT_FOUND) { @@ -777,7 +777,7 @@ IKvDB *KvDBManager::FindAndGetKvDBFromCache(const KvDBProperties &properties, in kvDB = FindKvDBFromCache(properties, singleVerNaturalStores_, true, errCode); if (kvDB != nullptr) { - kvDB->IncObjRef(kvDB); + RefObject::IncObjRef(kvDB); return kvDB; } return nullptr; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/kv/sync_able_kvdb.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/kv/sync_able_kvdb.cpp index fdc54ecd2de6223339b6d35c6db3bc4714a7f80f..ae6511bb828ccc5f5772eee76a87a94486a655af 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/kv/sync_able_kvdb.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/kv/sync_able_kvdb.cpp @@ -37,15 +37,24 @@ SyncAbleKvDB::SyncAbleKvDB() SyncAbleKvDB::~SyncAbleKvDB() { - if (notifyChain_ != nullptr) { - (void)notifyChain_->UnRegisterEventType(REMOTE_PUSH_FINISHED); - KillAndDecObjRef(notifyChain_); - notifyChain_ = nullptr; + { + std::unique_lock lock(notifyChainLock_); + if (notifyChain_ != nullptr) { + (void)notifyChain_->UnRegisterEventType(REMOTE_PUSH_FINISHED); + KillAndDecObjRef(notifyChain_); + notifyChain_ = nullptr; + } } - if (userChangeListener_ != nullptr) { - userChangeListener_->Drop(true); + NotificationChain::Listener *userChangeListener = nullptr; + { + std::unique_lock lock(syncerOperateLock_); + userChangeListener = userChangeListener_; userChangeListener_ = nullptr; } + if (userChangeListener != nullptr) { + userChangeListener->Drop(true); + userChangeListener = nullptr; + } std::lock_guard autoLock(cloudSyncerLock_); KillAndDecObjRef(cloudSyncer_); cloudSyncer_ = nullptr; @@ -211,6 +220,7 @@ int SyncAbleKvDB::StartSyncerWithNoLock(bool isCheckSyncActive, bool isNeedActiv // Stop syncer void SyncAbleKvDB::StopSyncer(bool isClosedOperation, bool isStopTaskOnly) { +#ifdef USE_DISTRIBUTEDDB_CLOUD { std::unique_lock lock(cloudSyncerLock_); if (cloudSyncer_ != nullptr) { @@ -223,6 +233,7 @@ void SyncAbleKvDB::StopSyncer(bool isClosedOperation, bool isStopTaskOnly) } } } +#endif NotificationChain::Listener *userChangeListener = nullptr; { std::unique_lock lock(syncerOperateLock_); @@ -238,12 +249,14 @@ void SyncAbleKvDB::StopSyncer(bool isClosedOperation, bool isStopTaskOnly) void SyncAbleKvDB::StopSyncerWithNoLock(bool isClosedOperation) { +#ifdef USE_DISTRIBUTEDDB_CLOUD if (!isClosedOperation && userChangeListener_ != nullptr) { std::unique_lock lock(cloudSyncerLock_); if (cloudSyncer_ != nullptr) { cloudSyncer_->StopAllTasks(); } } +#endif ReSetSyncModuleActive(); syncer_.Close(isClosedOperation); if (started_) { @@ -516,13 +529,16 @@ void SyncAbleKvDB::ResetSyncStatus() syncer_.ResetSyncStatus(); } +#ifdef USE_DISTRIBUTEDDB_CLOUD ICloudSyncStorageInterface *SyncAbleKvDB::GetICloudSyncInterface() const { return nullptr; } +#endif void SyncAbleKvDB::StartCloudSyncer() { +#ifdef USE_DISTRIBUTEDDB_CLOUD auto cloudStorage = GetICloudSyncInterface(); if (cloudStorage == nullptr) { return; @@ -540,6 +556,7 @@ void SyncAbleKvDB::StartCloudSyncer() LOGW("[SyncAbleKvDB][StartCloudSyncer] start cloud syncer and cloud syncer was not initialized"); } } +#endif } TimeOffset SyncAbleKvDB::GetLocalTimeOffset() @@ -550,6 +567,39 @@ TimeOffset SyncAbleKvDB::GetLocalTimeOffset() return syncer_.GetLocalTimeOffset(); } +std::map SyncAbleKvDB::GetDataBaseSchemas() +{ + return {}; +} + +int32_t SyncAbleKvDB::GetTaskCount() +{ + int32_t taskCount = 0; +#ifdef USE_DISTRIBUTEDDB_CLOUD + auto cloudSyncer = GetAndIncCloudSyncer(); + if (cloudSyncer != nullptr) { + taskCount += cloudSyncer->GetCloudSyncTaskCount(); + RefObject::DecObjRef(cloudSyncer); + } + if (NeedStartSyncer()) { + return taskCount; + } +#endif + taskCount += syncer_.GetTaskCount(); + return taskCount; +} + +CloudSyncer *SyncAbleKvDB::GetAndIncCloudSyncer() +{ + std::lock_guard autoLock(cloudSyncerLock_); + if (cloudSyncer_ == nullptr) { + return nullptr; + } + RefObject::IncObjRef(cloudSyncer_); + return cloudSyncer_; +} + +#ifdef USE_DISTRIBUTEDDB_CLOUD void SyncAbleKvDB::FillSyncInfo(const CloudSyncOption &option, const SyncProcessCallback &onProcess, CloudSyncer::CloudTaskInfo &info) { @@ -647,31 +697,6 @@ int SyncAbleKvDB::CleanAllWaterMark() return E_OK; } -int32_t SyncAbleKvDB::GetTaskCount() -{ - int32_t taskCount = 0; - auto cloudSyncer = GetAndIncCloudSyncer(); - if (cloudSyncer != nullptr) { - taskCount += cloudSyncer->GetCloudSyncTaskCount(); - RefObject::DecObjRef(cloudSyncer); - } - if (NeedStartSyncer()) { - return taskCount; - } - taskCount += syncer_.GetTaskCount(); - return taskCount; -} - -CloudSyncer *SyncAbleKvDB::GetAndIncCloudSyncer() -{ - std::lock_guard autoLock(cloudSyncerLock_); - if (cloudSyncer_ == nullptr) { - return nullptr; - } - RefObject::IncObjRef(cloudSyncer_); - return cloudSyncer_; -} - void SyncAbleKvDB::SetGenCloudVersionCallback(const GenerateCloudVersionCallback &callback) { auto cloudSyncer = GetAndIncCloudSyncer(); @@ -683,13 +708,9 @@ void SyncAbleKvDB::SetGenCloudVersionCallback(const GenerateCloudVersionCallback RefObject::DecObjRef(cloudSyncer); } -std::map SyncAbleKvDB::GetDataBaseSchemas() -{ - return {}; -} - bool SyncAbleKvDB::CheckSchemaSupportForCloudSync() const { return true; // default is valid } +#endif } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/kv/sync_able_kvdb.h b/kv_store/frameworks/libs/distributeddb/storage/src/kv/sync_able_kvdb.h index 968f82a6c46df31c6b6016a10b220345b3b4cd4c..8167cb6d40d208872d9cd08bc0019a0674edd4a2 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/kv/sync_able_kvdb.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/kv/sync_able_kvdb.h @@ -105,15 +105,17 @@ public: TimeOffset GetLocalTimeOffset(); + virtual void SetReceiveDataInterceptor(const DataInterceptor &interceptor) = 0; + + int32_t GetTaskCount(); + +#ifdef USE_DISTRIBUTEDDB_CLOUD int Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess); int SetCloudDB(const std::map> &cloudDBs); - int32_t GetTaskCount(); - void SetGenCloudVersionCallback(const GenerateCloudVersionCallback &callback); - - virtual void SetReceiveDataInterceptor(const DataInterceptor &interceptor) = 0; +#endif protected: virtual IKvDBSyncInterface *GetSyncInterface() = 0; @@ -143,15 +145,19 @@ protected: void TriggerSync(int notifyEvent); + CloudSyncer *GetAndIncCloudSyncer(); + +#ifdef USE_DISTRIBUTEDDB_CLOUD virtual ICloudSyncStorageInterface *GetICloudSyncInterface() const; int CleanAllWaterMark(); - - CloudSyncer *GetAndIncCloudSyncer(); +#endif protected: virtual std::map GetDataBaseSchemas(); +#ifdef USE_DISTRIBUTEDDB_CLOUD virtual bool CheckSchemaSupportForCloudSync() const; +#endif private: int RegisterEventType(EventType type); @@ -159,10 +165,12 @@ private: void StartCloudSyncer(); +#ifdef USE_DISTRIBUTEDDB_CLOUD void FillSyncInfo(const CloudSyncOption &option, const SyncProcessCallback &onProcess, CloudSyncer::CloudTaskInfo &info); int CheckSyncOption(const CloudSyncOption &option, const CloudSyncer &syncer); +#endif SyncerProxy syncer_; std::atomic started_; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/kv/sync_able_kvdb_connection.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/kv/sync_able_kvdb_connection.cpp index 37d7c2d4be4e09fa18ebee46d37b3bd800d5d1af..7468acdabef1f51914db14f50d7f51ebbc04bf4f 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/kv/sync_able_kvdb_connection.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/kv/sync_able_kvdb_connection.cpp @@ -397,6 +397,17 @@ int SyncAbleKvDBConnection::GetWatermarkInfo(const std::string &device, Watermar return kvDB->GetWatermarkInfo(device, info); } +int32_t SyncAbleKvDBConnection::GetTaskCount() +{ + SyncAbleKvDB *kvDB = GetDB(); + if (kvDB == nullptr) { + LOGW("[SyncAbleKvDBConnection] Get task count with null db"); + return -1; + } + return kvDB->GetTaskCount(); +} + +#ifdef USE_DISTRIBUTEDDB_CLOUD int SyncAbleKvDBConnection::Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess) { SyncAbleKvDB *kvDB = GetDB(); @@ -423,16 +434,6 @@ int SyncAbleKvDBConnection::SetCloudDB(const std::mapSetCloudDB(cloudDBs); } -int32_t SyncAbleKvDBConnection::GetTaskCount() -{ - SyncAbleKvDB *kvDB = GetDB(); - if (kvDB == nullptr) { - LOGW("[SyncAbleKvDBConnection] Get task count with null db"); - return -1; - } - return kvDB->GetTaskCount(); -} - void SyncAbleKvDBConnection::SetGenCloudVersionCallback(const GenerateCloudVersionCallback &callback) { auto *kvDB = GetDB(); @@ -442,6 +443,7 @@ void SyncAbleKvDBConnection::SetGenCloudVersionCallback(const GenerateCloudVersi } kvDB->SetGenCloudVersionCallback(callback); } +#endif int SyncAbleKvDBConnection::SetReceiveDataInterceptor(const DataInterceptor &interceptor) { diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/kv/sync_able_kvdb_connection.h b/kv_store/frameworks/libs/distributeddb/storage/src/kv/sync_able_kvdb_connection.h index fac8ef0e89e7f5629afc474da8e2dc7bf8229ccb..4594b3dd9b4caaa021e6ad496fd88eca7c9c99d3 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/kv/sync_able_kvdb_connection.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/kv/sync_able_kvdb_connection.h @@ -39,15 +39,17 @@ public: int GetWatermarkInfo(const std::string &device, WatermarkInfo &info) override; + int32_t GetTaskCount() override; + + int SetReceiveDataInterceptor(const DataInterceptor &interceptor) override; + +#ifdef USE_DISTRIBUTEDDB_CLOUD int Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess) override; int SetCloudDB(const std::map> &cloudDBs) override; - int32_t GetTaskCount() override; - void SetGenCloudVersionCallback(const GenerateCloudVersionCallback &callback) override; - - int SetReceiveDataInterceptor(const DataInterceptor &interceptor) override; +#endif protected: int DisableManualSync(); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/multiver/ikvdb_multi_ver_data_storage.h b/kv_store/frameworks/libs/distributeddb/storage/src/multiver/ikvdb_multi_ver_data_storage.h index 49e5f598ab5116d07228b9d2874e1e7619fff557..a845fe932c20f516717abe02acd2d94064b60d00 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/multiver/ikvdb_multi_ver_data_storage.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/multiver/ikvdb_multi_ver_data_storage.h @@ -32,7 +32,7 @@ enum class KvDataType { }; struct UpdateVerTimestamp { - uint64_t timestamp = 0ull; + uint64_t timestamp = 0uLL; bool isNeedUpdate = false; }; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/multiver/multi_ver_storage_executor.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/multiver/multi_ver_storage_executor.cpp index 639a260f8b63ea0ea4e0bc66d463c02cdaa2ddcb..17fb36aa6511ba6eb92297c2fcaea6d6358fa56d 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/multiver/multi_ver_storage_executor.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/multiver/multi_ver_storage_executor.cpp @@ -1133,7 +1133,7 @@ void MultiVerStorageExecutor::CommitNotifiedData(const CommitID &commitId) if (committedData != nullptr) { static_cast(kvDB_)->AddVersionConstraintToList(currentVersion - 1); static_cast(kvDB_)->CommitNotify(NATURAL_STORE_COMMIT_EVENT, committedData); - committedData->DecObjRef(committedData); + RefObject::DecObjRef(committedData); committedData = nullptr; } else { LOGE("Failed to do commit notify because of OOM."); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/operation/database_oper.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/operation/database_oper.cpp index 43983472c82c2f7831abd46200f6f8614565ea81..89164443051e7df1de85f8680f1b668c9c44bfee 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/operation/database_oper.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/operation/database_oper.cpp @@ -152,6 +152,10 @@ int DatabaseOper::RekeyRecover(const KvDBProperties &property) int DatabaseOper::CheckSecurityOption(const std::string &filePath, const KvDBProperties &property) const { + SecurityOption dbSecOpt; + dbSecOpt.securityFlag = property.GetSecFlag(); + dbSecOpt.securityLabel = property.GetSecLabel(); + RuntimeContext::GetInstance()->SetSecurityOption(filePath, dbSecOpt); SecurityOption secOption; int errCode = RuntimeContext::GetInstance()->GetSecurityOption(filePath, secOption); if (errCode != E_OK && errCode != -E_NOT_SUPPORT) { @@ -159,10 +163,6 @@ int DatabaseOper::CheckSecurityOption(const std::string &filePath, const KvDBPro return errCode; } - SecurityOption dbSecOpt; - dbSecOpt.securityFlag = property.GetSecFlag(); - dbSecOpt.securityLabel = property.GetSecLabel(); - if (dbSecOpt == secOption || secOption.securityLabel == SecurityLabel::NOT_SET) { return E_OK; } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_store_instance.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_store_instance.cpp index 5359c192ab2882b18637346c7d69c907c740a89d..5a7007608d6bf936ff7a9c6b865f508185c4f454 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_store_instance.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_store_instance.cpp @@ -81,7 +81,7 @@ static IRelationalStore *GetFromCache(const RelationalDBProperties &properties, errCode = -E_INTERNAL_ERROR; return nullptr; } - db->IncObjRef(db); + RefObject::IncObjRef(db); return db; } @@ -165,8 +165,7 @@ int CheckCompatibility(const RelationalDBProperties &prop, const RelationalDBPro LOGE("Failed to check store path, the input path does not match with cached store."); return -E_INVALID_ARGS; } - if (prop.GetIntProp(RelationalDBProperties::DISTRIBUTED_TABLE_MODE, DistributedTableMode::SPLIT_BY_DEVICE) != - existedProp.GetIntProp(RelationalDBProperties::DISTRIBUTED_TABLE_MODE, DistributedTableMode::SPLIT_BY_DEVICE)) { + if (prop.GetDistributedTableMode() != existedProp.GetDistributedTableMode()) { LOGE("Failed to check table mode."); return -E_INVALID_ARGS; } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_sync_able_storage.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_sync_able_storage.cpp index e6c2bdceb8cbcb956952a574aac3a8d6ccec8082..6b24e765bd71a95ef029da22b6a0779fcf2bbf99 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_sync_able_storage.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_sync_able_storage.cpp @@ -401,7 +401,8 @@ static void ProcessContinueTokenForQuerySync(const std::vector &dataIt * If error happened, token will be deleted here. */ int RelationalSyncAbleStorage::GetSyncDataForQuerySync(std::vector &dataItems, - SQLiteSingleVerRelationalContinueToken *&token, const DataSizeSpecInfo &dataSizeInfo) const + SQLiteSingleVerRelationalContinueToken *&token, const DataSizeSpecInfo &dataSizeInfo, + RelationalSchemaObject &&filterSchema) const { if (storageEngine_ == nullptr) { return -E_INVALID_DB; @@ -413,7 +414,7 @@ int RelationalSyncAbleStorage::GetSyncDataForQuerySync(std::vector &da if (handle == nullptr) { goto ERROR; } - + handle->SetLocalSchema(filterSchema); do { errCode = handle->GetSyncDataByQuery(dataItems, Parcel::GetAppendedLen(), @@ -460,10 +461,23 @@ int RelationalSyncAbleStorage::GetSyncDataNext(std::vector & ContinueToken &continueStmtToken, const DataSizeSpecInfo &dataSizeInfo) const { auto token = static_cast(continueStmtToken); + if (token == nullptr) { + LOGE("[SingleVerNStore] Allocate continue stmt token failed."); + return -E_OUT_OF_MEMORY; + } if (!token->CheckValid()) { return -E_INVALID_ARGS; } RelationalSchemaObject schema = storageEngine_->GetSchema(); + RelationalSchemaObject filterSchema; + if (token->IsUseLocalSchema()) { + filterSchema = schema; + } else { + int errCode = GetRemoteDeviceSchema(token->GetRemoteDev(), filterSchema); + if (errCode != E_OK) { + return errCode; + } + } const auto fieldInfos = schema.GetTable(token->GetQuery().GetTableName()).GetFieldInfos(); std::vector fieldNames; fieldNames.reserve(fieldInfos.size()); @@ -473,7 +487,7 @@ int RelationalSyncAbleStorage::GetSyncDataNext(std::vector & token->SetFieldNames(fieldNames); std::vector dataItems; - int errCode = GetSyncDataForQuerySync(dataItems, token, dataSizeInfo); + int errCode = GetSyncDataForQuerySync(dataItems, token, dataSizeInfo, std::move(filterSchema)); if (errCode != E_OK && errCode != -E_UNFINISHED) { // The code need be sent to outside except new error happened. continueStmtToken = static_cast(token); return errCode; @@ -518,37 +532,31 @@ int RelationalSyncAbleStorage::PutSyncDataWithQuery(const QueryObject &object, return PutSyncData(object, dataItems, deviceName); } -namespace { -inline DistributedTableMode GetCollaborationMode(const std::shared_ptr &engine) -{ - return static_cast(engine->GetProperties().GetIntProp( - RelationalDBProperties::DISTRIBUTED_TABLE_MODE, DistributedTableMode::SPLIT_BY_DEVICE)); -} - -inline bool IsCollaborationMode(const std::shared_ptr &engine) -{ - return GetCollaborationMode(engine) == DistributedTableMode::COLLABORATION; -} -} - int RelationalSyncAbleStorage::SaveSyncDataItems(const QueryObject &object, std::vector &dataItems, const std::string &deviceName) { int errCode = E_OK; LOGD("[RelationalSyncAbleStorage::SaveSyncDataItems] Get write handle."); QueryObject query = object; - query.SetSchema(storageEngine_->GetSchema()); + auto localSchema = storageEngine_->GetSchema(); + query.SetSchema(localSchema); - RelationalSchemaObject remoteSchema; - errCode = GetRemoteDeviceSchema(deviceName, remoteSchema); + RelationalSchemaObject filterSchema; + errCode = GetRemoteDeviceSchema(deviceName, filterSchema); if (errCode != E_OK) { LOGE("Find remote schema failed. err=%d", errCode); return errCode; } + if (query.IsUseLocalSchema()) { + // remote send always with its table col sort + filterSchema.SetDistributedSchema(localSchema.GetDistributedSchema()); + } StoreInfo info = GetStoreInfo(); auto inserter = RelationalSyncDataInserter::CreateInserter(deviceName, query, storageEngine_->GetSchema(), - remoteSchema.GetTable(query.GetTableName()).GetFieldInfos(), info); + filterSchema.GetSyncFieldInfo(query.GetTableName()), info); + ChangedData data; + data.properties.isP2pSyncDataChange = !dataItems.empty(); inserter.SetEntries(dataItems); auto *handle = GetHandle(true, errCode, OperatePerm::NORMAL_PERM); @@ -560,10 +568,12 @@ int RelationalSyncAbleStorage::SaveSyncDataItems(const QueryObject &object, std: // check if the table exists before each synchronization. // If the table does not exist, create it. // Because it is a fallback scenario, if the table creation fails, no failure will be returned - errCode = handle->CreateDistributedDeviceTable(deviceName, - storageEngine_->GetSchema().GetTable(query.GetTableName()), info); - if (errCode != E_OK) { - LOGW("[RelationalSyncAbleStorage::SaveSyncDataItems] Create distributed device table fail %d", errCode); + if (localSchema.GetTableMode() == DistributedTableMode::SPLIT_BY_DEVICE) { + errCode = handle->CreateDistributedDeviceTable(deviceName, + storageEngine_->GetSchema().GetTable(query.GetTableName()), info); + if (errCode != E_OK) { + LOGW("[RelationalSyncAbleStorage::SaveSyncDataItems] Create distributed device table fail %d", errCode); + } } DBDfxAdapter::StartTracing(); @@ -574,8 +584,11 @@ int RelationalSyncAbleStorage::SaveSyncDataItems(const QueryObject &object, std: // dataItems size > 0 now because already check before // all dataItems will write into db now, so need to observer notify here // if some dataItems will not write into db in the future, observer notify here need change - ChangedData data; - TriggerObserverAction(deviceName, std::move(data), false); + data.tableName = query.GetTableName(); + // SPLIT_BY_DEVICE trigger observer with device, userId, appId and storeId, so trigger with isChangeData false + // COLLABORATION trigger observer with changeData, so trigger with isChangeData true + TriggerObserverAction(deviceName, std::move(data), + GetDbProperties().GetDistributedTableMode() == DistributedTableMode::COLLABORATION, Origin::ORIGIN_REMOTE); } ReleaseHandle(handle); @@ -663,8 +676,7 @@ int RelationalSyncAbleStorage::InterceptData(std::vector &en int RelationalSyncAbleStorage::CreateDistributedDeviceTable(const std::string &device, const RelationalSyncStrategy &syncStrategy) { - auto mode = storageEngine_->GetProperties().GetIntProp(RelationalDBProperties::DISTRIBUTED_TABLE_MODE, - DistributedTableMode::SPLIT_BY_DEVICE); + auto mode = storageEngine_->GetProperties().GetDistributedTableMode(); if (mode != DistributedTableMode::SPLIT_BY_DEVICE) { LOGD("No need create device table in COLLABORATION mode."); return E_OK; @@ -790,35 +802,38 @@ int RelationalSyncAbleStorage::UnRegisterObserverAction(uint64_t connectionId, c void RelationalSyncAbleStorage::ExecuteDataChangeCallback( const std::pair> &item, - const std::string &deviceName, const ChangedData &changedData, bool isChangedData, int &observerCnt) + const std::string &deviceName, const ChangedData &changedData, bool isChangedData, Origin origin) { for (auto &action : item.second) { if (action.second == nullptr) { continue; } - observerCnt++; ChangedData observerChangeData = changedData; if (action.first != nullptr) { FilterChangeDataByDetailsType(observerChangeData, action.first->GetCallbackDetailsType()); } - action.second(deviceName, std::move(observerChangeData), isChangedData); + action.second(deviceName, std::move(observerChangeData), isChangedData, origin); } } void RelationalSyncAbleStorage::TriggerObserverAction(const std::string &deviceName, ChangedData &&changedData, bool isChangedData) +{ + TriggerObserverAction(deviceName, std::move(changedData), isChangedData, Origin::ORIGIN_CLOUD); +} + +void RelationalSyncAbleStorage::TriggerObserverAction(const std::string &deviceName, ChangedData &&changedData, + bool isChangedData, Origin origin) { IncObjRef(this); int taskErrCode = - ConcurrentAdapter::ScheduleTask([this, deviceName, changedData, isChangedData] () mutable { + ConcurrentAdapter::ScheduleTask([this, deviceName, changedData, isChangedData, origin] () mutable { LOGD("begin to trigger relational observer."); - int observerCnt = 0; ConcurrentAdapter::AdapterAutoLock(dataChangeDeviceMutex_); ResFinalizer finalizer([this]() { ConcurrentAdapter::AdapterAutoUnLock(dataChangeDeviceMutex_); }); for (const auto &item : dataChangeCallbackMap_) { - ExecuteDataChangeCallback(item, deviceName, changedData, isChangedData, observerCnt); + ExecuteDataChangeCallback(item, deviceName, changedData, isChangedData, origin); } - LOGD("relational observer size = %d", observerCnt); DecObjRef(this); }, &dataChangeCallbackMap_); if (taskErrCode != E_OK) { @@ -872,7 +887,7 @@ bool RelationalSyncAbleStorage::CheckCompatible(const std::string &schema, uint8 int RelationalSyncAbleStorage::GetRemoteQueryData(const PreparedStmt &prepStmt, size_t packetSize, std::vector &colNames, std::vector &data) const { - if (IsCollaborationMode(storageEngine_) || !storageEngine_->GetSchema().IsSchemaValid()) { + if (!storageEngine_->GetSchema().IsSchemaValid()) { return -E_NOT_SUPPORT; } if (prepStmt.GetOpCode() != PreparedStmt::ExecutorOperation::QUERY || !prepStmt.IsValid()) { @@ -964,9 +979,11 @@ int RelationalSyncAbleStorage::SaveRemoteDeviceSchema(const std::string &deviceI return remoteDeviceSchema_.Put(deviceId, remoteSchema); } -int RelationalSyncAbleStorage::GetRemoteDeviceSchema(const std::string &deviceId, RelationalSchemaObject &schemaObj) +int RelationalSyncAbleStorage::GetRemoteDeviceSchema(const std::string &deviceId, + RelationalSchemaObject &schemaObj) const { if (schemaObj.IsSchemaValid()) { + LOGE("schema is already valid"); return -E_INVALID_ARGS; } @@ -1254,12 +1271,7 @@ int RelationalSyncAbleStorage::SetCloudDbSchema(const DataBaseSchema &schema) int RelationalSyncAbleStorage::GetInfoByPrimaryKeyOrGid(const std::string &tableName, const VBucket &vBucket, DataInfoWithLog &dataInfoWithLog, VBucket &assetInfo) { - if (transactionHandle_ == nullptr) { - LOGE(" the transaction has not been started"); - return -E_INVALID_DB; - } - - return GetInfoByPrimaryKeyOrGidInner(transactionHandle_, tableName, vBucket, dataInfoWithLog, assetInfo); + return GetInfoByPrimaryKeyOrGid(tableName, vBucket, true, dataInfoWithLog, assetInfo); } int RelationalSyncAbleStorage::GetInfoByPrimaryKeyOrGidInner(SQLiteSingleVerRelationalStorageExecutor *handle, @@ -1366,7 +1378,8 @@ int RelationalSyncAbleStorage::FillCloudAssetForDownload(const std::string &tabl LOGE("Get cloud schema failed when fill cloud asset, %d", errCode); return errCode; } - errCode = transactionHandle_->FillCloudAssetForDownload(tableSchema, asset, isDownloadSuccess); + uint64_t currCursor = DBConstant::INVALID_CURSOR; + errCode = transactionHandle_->FillCloudAssetForDownload(tableSchema, asset, isDownloadSuccess, currCursor); if (errCode != E_OK) { LOGE("fill cloud asset for download failed.%d", errCode); } @@ -1861,7 +1874,22 @@ int RelationalSyncAbleStorage::UpdateRecordFlag(const std::string &tableName, bo LOGE("[RelationalSyncAbleStorage] the transaction has not been started"); return -E_INVALID_DB; } - std::string sql = CloudStorageUtils::GetUpdateRecordFlagSql(tableName, recordConflict, logInfo); + TableSchema tableSchema; + GetCloudTableSchema(tableName, tableSchema); + std::vector assets; + int errCode = transactionHandle_->GetDownloadAssetRecordsByGid(tableSchema, logInfo.cloudGid, assets); + if (errCode != E_OK) { + LOGE("[RelationalSyncAbleStorage] get download asset by gid %s failed %d", + DBCommon::StringMiddleMasking(logInfo.cloudGid).c_str(), errCode); + return errCode; + } + bool isInconsistency = !assets.empty(); + UpdateRecordFlagStruct updateRecordFlag = { + .tableName = tableName, + .isRecordConflict = recordConflict, + .isInconsistency = isInconsistency + }; + std::string sql = CloudStorageUtils::GetUpdateRecordFlagSql(updateRecordFlag, logInfo); return transactionHandle_->UpdateRecordFlag(tableName, sql, logInfo); } @@ -1879,63 +1907,23 @@ int RelationalSyncAbleStorage::FillCloudLogAndAssetInner(SQLiteSingleVerRelation return errCode; } if (opType == OpType::INSERT) { - errCode = UpdateRecordFlagAfterUpload(handle, data.tableName, data.insData, CloudWaterType::INSERT); + errCode = CloudStorageUtils::UpdateRecordFlagAfterUpload( + handle, {data.tableName, CloudWaterType::INSERT, tableSchema}, data.insData, uploadRecorder_); } else if (opType == OpType::UPDATE) { - errCode = UpdateRecordFlagAfterUpload(handle, data.tableName, data.updData, CloudWaterType::UPDATE); + errCode = CloudStorageUtils::UpdateRecordFlagAfterUpload( + handle, {data.tableName, CloudWaterType::UPDATE, tableSchema}, data.updData, uploadRecorder_); } else if (opType == OpType::DELETE) { - errCode = UpdateRecordFlagAfterUpload(handle, data.tableName, data.delData, CloudWaterType::DELETE); + errCode = CloudStorageUtils::UpdateRecordFlagAfterUpload( + handle, {data.tableName, CloudWaterType::DELETE, tableSchema}, data.delData, uploadRecorder_); } else if (opType == OpType::LOCKED_NOT_HANDLE) { - errCode = UpdateRecordFlagAfterUpload(handle, data.tableName, data.lockData, CloudWaterType::BUTT, true); + errCode = CloudStorageUtils::UpdateRecordFlagAfterUpload( + handle, {data.tableName, CloudWaterType::BUTT, tableSchema}, data.lockData, uploadRecorder_, true); } return errCode; } -int RelationalSyncAbleStorage::UpdateRecordFlagAfterUpload(SQLiteSingleVerRelationalStorageExecutor *handle, - const std::string &tableName, const CloudSyncBatch &updateData, const CloudWaterType &type, bool isLock) -{ - if (updateData.timestamp.size() != updateData.extend.size()) { - LOGE("the num of extend:%zu and timestamp:%zu is not equal.", - updateData.extend.size(), updateData.timestamp.size()); - return -E_INVALID_ARGS; - } - for (size_t i = 0; i < updateData.extend.size(); ++i) { - const auto &record = updateData.extend[i]; - if (DBCommon::IsRecordError(record) || DBCommon::IsRecordAssetsMissing(record) || - DBCommon::IsRecordVersionConflict(record) || isLock) { - if (DBCommon::IsRecordAssetsMissing(record)) { - LOGI("[RDBStorage][UpdateRecordFlagAfterUpload] Record assets missing, skip update."); - } - int errCode = handle->UpdateRecordStatus(tableName, CloudDbConstant::TO_LOCAL_CHANGE, - updateData.hashKey[i]); - if (errCode != E_OK) { - LOGE("[RDBStorage] Update record status failed in index %zu", i); - return errCode; - } - continue; - } - const auto &rowId = updateData.rowid[i]; - std::string cloudGid; - (void)CloudStorageUtils::GetValueFromVBucket(CloudDbConstant::GID_FIELD, record, cloudGid); - LogInfo logInfo; - logInfo.cloudGid = cloudGid; - logInfo.timestamp = updateData.timestamp[i]; - logInfo.dataKey = rowId; - logInfo.hashKey = updateData.hashKey[i]; - std::string sql = CloudStorageUtils::GetUpdateRecordFlagSqlUpload(tableName, DBCommon::IsRecordIgnored(record), - logInfo, record, type); - int errCode = handle->UpdateRecordFlag(tableName, sql, logInfo); - if (errCode != E_OK) { - LOGE("[RDBStorage] Update record flag failed in index %zu", i); - return errCode; - } - handle->MarkFlagAsUploadFinished(tableName, updateData.hashKey[i], updateData.timestamp[i]); - uploadRecorder_.RecordUploadRecord(tableName, logInfo.hashKey, type, updateData.timestamp[i]); - } - return E_OK; -} - int RelationalSyncAbleStorage::GetCompensatedSyncQuery(std::vector &syncQuery, - std::vector &users) + std::vector &users, bool isQueryDownloadRecords) { std::vector tables; int errCode = GetCloudTableWithoutShared(tables); @@ -1950,7 +1938,7 @@ int RelationalSyncAbleStorage::GetCompensatedSyncQuery(std::vector &tables, std::vector &syncQuery) + const std::vector &tables, std::vector &syncQuery, bool isQueryDownloadRecords) { int errCode = E_OK; errCode = handle->StartTransaction(TransactType::IMMEDIATE); @@ -2024,7 +2012,7 @@ int RelationalSyncAbleStorage::GetCompensatedSyncQueryInner(SQLiteSingleVerRelat } std::vector syncDataPk; - errCode = handle->GetWaitCompensatedSyncDataPk(table, syncDataPk); + errCode = handle->GetWaitCompensatedSyncDataPk(table, syncDataPk, isQueryDownloadRecords); if (errCode != E_OK) { LOGW("[RDBStorageEngine] Get wait compensated sync data failed, continue! errCode=%d", errCode); errCode = E_OK; @@ -2034,14 +2022,12 @@ int RelationalSyncAbleStorage::GetCompensatedSyncQueryInner(SQLiteSingleVerRelat // no data need to compensated sync continue; } - QuerySyncObject syncObject; - errCode = CloudStorageUtils::GetSyncQueryByPk(table.name, syncDataPk, false, syncObject); + errCode = CloudStorageUtils::GetSyncQueryByPk(table.name, syncDataPk, false, syncQuery); if (errCode != E_OK) { LOGW("[RDBStorageEngine] Get compensated sync query happen error, ignore it! errCode = %d", errCode); errCode = E_OK; continue; } - syncQuery.push_back(syncObject); } if (errCode == E_OK) { errCode = handle->Commit(); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_sync_able_storage_extend.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_sync_able_storage_extend.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2284aa7962eda7edd217a133a93c9a97055188a8 --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_sync_able_storage_extend.cpp @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2024 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. + */ +#ifdef RELATIONAL_STORE +#include "relational_sync_able_storage.h" + +#include + +#include "cloud/cloud_db_constant.h" +#include "cloud/cloud_storage_utils.h" +#include "concurrent_adapter.h" +#include "data_compression.h" +#include "db_common.h" +#include "db_dfx_adapter.h" +#include "generic_single_ver_kv_entry.h" +#include "platform_specific.h" +#include "query_utils.h" +#include "relational_remote_query_continue_token.h" +#include "relational_sync_data_inserter.h" +#include "res_finalizer.h" +#include "runtime_context.h" +#include "time_helper.h" + +namespace DistributedDB { +int RelationalSyncAbleStorage::MarkFlagAsAssetAsyncDownload(const std::string &tableName, + const DownloadData &downloadData, const std::set &gidFilters) +{ + if (transactionHandle_ == nullptr) { + LOGE("[RelationalSyncAbleStorage] the transaction has not been started, tableName:%s, length:%zu", + DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + return -E_INVALID_DB; + } + int errCode = transactionHandle_->MarkFlagAsAssetAsyncDownload(tableName, downloadData, gidFilters); + if (errCode != E_OK) { + LOGE("[RelationalSyncAbleStorage] mark flag as asset async download failed.%d, tableName:%s, length:%zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + } + return errCode; +} + +std::pair> RelationalSyncAbleStorage::GetDownloadAssetTable() +{ + int errCode = E_OK; + auto *handle = GetHandle(false, errCode); + if (handle == nullptr || errCode != E_OK) { + LOGE("[RelationalSyncAbleStorage] Get handle failed when get downloading asset table: %d", errCode); + return {errCode, {}}; + } + std::vector tableNames; + auto allTableNames = storageEngine_->GetSchema().GetTableNames(); + for (const auto &it : allTableNames) { + int32_t count = 0; + errCode = handle->GetDownloadingCount(it, count); + if (errCode != E_OK) { + LOGE("[RelationalSyncAbleStorage] Get downloading asset count failed: %d", errCode); + ReleaseHandle(handle); + return {errCode, tableNames}; + } + if (count > 0) { + tableNames.push_back(it); + } + } + ReleaseHandle(handle); + return {errCode, tableNames}; +} + +std::pair> RelationalSyncAbleStorage::GetDownloadAssetRecords( + const std::string &tableName, int64_t beginTime) +{ + TableSchema schema; + int errCode = GetCloudTableSchema(tableName, schema); + if (errCode != E_OK) { + LOGE("[RelationalSyncAbleStorage] Get schema when get asset records failed:%d, tableName:%s, length:%zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + return {errCode, {}}; + } + auto *handle = GetHandle(false, errCode); + if (handle == nullptr || errCode != E_OK) { + LOGE("[RelationalSyncAbleStorage] Get handle when get asset records failed:%d, tableName:%s, length:%zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + return {errCode, {}}; + } + std::vector gids; + errCode = handle->GetDownloadAssetRecordsInner(schema, beginTime, gids); + if (errCode != E_OK) { + LOGE("[RelationalSyncAbleStorage] Get downloading asset records failed:%d, tableName:%s, length:%zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + } + ReleaseHandle(handle); + return {errCode, gids}; +} + +int RelationalSyncAbleStorage::GetInfoByPrimaryKeyOrGid(const std::string &tableName, const VBucket &vBucket, + bool useTransaction, DataInfoWithLog &dataInfoWithLog, VBucket &assetInfo) +{ + if (useTransaction && transactionHandle_ == nullptr) { + LOGE(" the transaction has not been started"); + return -E_INVALID_DB; + } + SQLiteSingleVerRelationalStorageExecutor *handle; + int errCode = E_OK; + if (useTransaction) { + handle = transactionHandle_; + } else { + errCode = E_OK; + handle = GetHandle(false, errCode); + if (errCode != E_OK) { + return errCode; + } + } + errCode = GetInfoByPrimaryKeyOrGidInner(handle, tableName, vBucket, dataInfoWithLog, assetInfo); + if (!useTransaction) { + ReleaseHandle(handle); + } + return errCode; +} + +int RelationalSyncAbleStorage::UpdateAssetStatusForAssetOnly(const std::string &tableName, VBucket &asset) +{ + if (transactionHandle_ == nullptr) { + LOGE("the transaction has not been started"); + return -E_INVALID_DB; + } + + TableSchema tableSchema; + int errCode = GetCloudTableSchema(tableName, tableSchema); + if (errCode != E_OK) { + LOGE("Get cloud schema failed when save cloud data, %d", errCode); + return errCode; + } + RelationalSchemaObject localSchema = GetSchemaInfo(); + transactionHandle_->SetLocalSchema(localSchema); + transactionHandle_->SetLogicDelete(IsCurrentLogicDelete()); + errCode = transactionHandle_->UpdateAssetStatusForAssetOnly(tableSchema, asset); + transactionHandle_->SetLogicDelete(false); + return errCode; +} + +void RelationalSyncAbleStorage::PrintCursorChange(const std::string &tableName) +{ + auto iter = cursorChangeMap_.find(tableName); + if (iter == cursorChangeMap_.end()) { + return; + } + LOGI("[RelationalSyncAbleStorage] Upgrade cursor from %d to %d when asset download success.", + cursorChangeMap_[tableName].first, cursorChangeMap_[tableName].second); + cursorChangeMap_.erase(tableName); +} + +void RelationalSyncAbleStorage::SaveCursorChange(const std::string &tableName, uint64_t currCursor) +{ + auto iter = cursorChangeMap_.find(tableName); + if (iter == cursorChangeMap_.end()) { + std::pair initCursors = {currCursor, currCursor}; + cursorChangeMap_.insert(std::pair>(tableName, initCursors)); + return; + } + std::pair minMaxCursors = iter->second; + uint64_t minCursor = std::min(minMaxCursors.first, currCursor); + uint64_t maxCursor = std::max(minMaxCursors.second, currCursor); + cursorChangeMap_[tableName] = {minCursor, maxCursor}; +} + +int RelationalSyncAbleStorage::FillCloudAssetForAsyncDownload(const std::string &tableName, VBucket &asset, + bool isDownloadSuccess) +{ + if (storageEngine_ == nullptr) { + LOGE("[RelationalSyncAbleStorage]storage is null when fill asset for async download"); + return -E_INVALID_DB; + } + int errCode = E_OK; + auto *handle = GetHandle(true, errCode); + if (handle == nullptr) { + LOGE("executor is null when fill asset for async download."); + return errCode; + } + TableSchema tableSchema; + errCode = GetCloudTableSchema(tableName, tableSchema); + if (errCode != E_OK) { + ReleaseHandle(handle); + LOGE("Get cloud schema failed when fill cloud asset, %d, tableName:%s, length:%zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + return errCode; + } + uint64_t currCursor = DBConstant::INVALID_CURSOR; + errCode = handle->FillCloudAssetForDownload(tableSchema, asset, isDownloadSuccess, currCursor); + if (errCode != E_OK) { + LOGE("fill cloud asset for download failed:%d, tableName:%s, length:%zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + } + SaveCursorChange(tableName, currCursor); + ReleaseHandle(handle); + return errCode; +} + +int RelationalSyncAbleStorage::UpdateRecordFlagForAsyncDownload(const std::string &tableName, bool recordConflict, + const LogInfo &logInfo) +{ + int errCode = E_OK; + auto *handle = GetHandle(true, errCode); + if (handle == nullptr) { + LOGE("executor is null when update flag for async download."); + return errCode; + } + UpdateRecordFlagStruct updateRecordFlag = { + .tableName = tableName, + .isRecordConflict = recordConflict, + .isInconsistency = false + }; + std::string sql = CloudStorageUtils::GetUpdateRecordFlagSql(updateRecordFlag, logInfo); + errCode = handle->UpdateRecordFlag(tableName, sql, logInfo); + if (errCode != E_OK) { + LOGE("update flag for async download failed:%d, tableName:%s, length:%zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + } + ReleaseHandle(handle); + return errCode; +} + +int RelationalSyncAbleStorage::SetLogTriggerStatusForAsyncDownload(bool status) +{ + int errCode = E_OK; + auto *handle = GetHandle(false, errCode); + if (handle == nullptr) { + LOGE("executor is null when set trigger status for async download."); + return errCode; + } + errCode = handle->SetLogTriggerStatus(status); + if (errCode != E_OK) { + LOGE("set trigger status for async download failed:%d"); + } + ReleaseHandle(handle); + return errCode; +} + +std::pair RelationalSyncAbleStorage::GetAssetsByGidOrHashKeyForAsyncDownload( + const TableSchema &tableSchema, const std::string &gid, const Bytes &hashKey, VBucket &assets) +{ + if (gid.empty() && hashKey.empty()) { + LOGE("both gid and hashKey are empty."); + return { -E_INVALID_ARGS, static_cast(LockStatus::UNLOCK) }; + } + int errCode = E_OK; + auto *handle = GetHandle(false, errCode); + if (handle == nullptr) { + LOGE("executor is null when get assets by gid or hash for async download."); + return {errCode, static_cast(LockStatus::UNLOCK)}; + } + auto [ret, status] = handle->GetAssetsByGidOrHashKey(tableSchema, gid, hashKey, assets); + if (ret != E_OK && ret != -E_NOT_FOUND && ret != -E_CLOUD_GID_MISMATCH) { + LOGE("get assets by gid or hashKey failed for async download. %d", ret); + } + ReleaseHandle(handle); + return {ret, status}; +} + +int RelationalSyncAbleStorage::GetLockStatusByGid(const std::string &tableName, const std::string &gid, + LockStatus &status) +{ + if (tableName.empty() || gid.empty()) { + LOGE("[RelationalSyncAbleStorage] invalid table name or gid."); + return -E_INVALID_ARGS; + } + int errCode = E_OK; + auto *handle = GetHandle(false, errCode); + if (handle == nullptr) { + LOGE("[RelationalSyncAbleStorage] handle is null when get lock status by gid."); + return errCode; + } + errCode = handle->GetLockStatusByGid(tableName, gid, status); + ReleaseHandle(handle); + return errCode; +} +} +#endif \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_sync_data_inserter.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_sync_data_inserter.cpp index 0edb9c65c65bca32a42949f420c2cd2718d2b71f..699701a3f183d6105a30295af8937ad2151f9ec6 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_sync_data_inserter.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_sync_data_inserter.cpp @@ -14,16 +14,21 @@ */ #include "relational_sync_data_inserter.h" +#include "cloud/cloud_storage_utils.h" #include "data_transformer.h" #include "db_common.h" +#include "sqlite_relational_utils.h" #include "sqlite_utils.h" namespace DistributedDB { int SaveSyncDataStmt::ResetStatements(bool isNeedFinalize) { int errCode = E_OK; - if (saveDataStmt != nullptr) { - SQLiteUtils::ResetStatement(saveDataStmt, isNeedFinalize, errCode); + if (insertDataStmt != nullptr) { + SQLiteUtils::ResetStatement(insertDataStmt, isNeedFinalize, errCode); + } + if (updateDataStmt != nullptr) { + SQLiteUtils::ResetStatement(updateDataStmt, isNeedFinalize, errCode); } if (saveLogStmt != nullptr) { SQLiteUtils::ResetStatement(saveLogStmt, isNeedFinalize, errCode); @@ -40,14 +45,6 @@ int SaveSyncDataStmt::ResetStatements(bool isNeedFinalize) return errCode; } -RelationalSyncDataInserter::RelationalSyncDataInserter() -{ -} - -RelationalSyncDataInserter::~RelationalSyncDataInserter() -{ -} - RelationalSyncDataInserter RelationalSyncDataInserter::CreateInserter(const std::string &deviceName, const QueryObject &query, const RelationalSchemaObject &localSchema, const std::vector &remoteFields, const StoreInfo &info) @@ -126,21 +123,47 @@ int RelationalSyncDataInserter::GetInsertStatement(sqlite3 *db, sqlite3_stmt *&s colName.pop_back(); dataFormat.pop_back(); - const std::string sql = "INSERT OR REPLACE INTO '" + insertTableName_ + "'" + - " (" + colName + ") VALUES (" + dataFormat + ");"; + std::string sql = "INSERT OR REPLACE INTO '" + insertTableName_ + "'" + + "(" + colName + ") VALUES(" + dataFormat + ");"; int errCode = SQLiteUtils::GetStatement(db, sql, stmt); if (errCode != E_OK) { - LOGE("Get saving data statement fail! errCode:%d", errCode); + LOGE("Get insert data statement fail! errCode:%d", errCode); } return errCode; } -int RelationalSyncDataInserter::BindInsertStatement(sqlite3_stmt *stmt, const DataItem &dataItem) +int RelationalSyncDataInserter::SaveData(bool isUpdate, const DataItem &dataItem, + SaveSyncDataStmt &saveSyncDataStmt) { + sqlite3_stmt *&stmt = isUpdate ? saveSyncDataStmt.updateDataStmt : saveSyncDataStmt.insertDataStmt; + std::set filterSet; + if (isUpdate) { + for (const auto &primaryKey : localTable_.GetIdentifyKey()) { + filterSet.insert(primaryKey); + } + } if (stmt == nullptr) { - return -E_INVALID_ARGS; + LOGW("skip save data %s", DBCommon::StringMiddleMasking(DBCommon::VectorToHexString(dataItem.hashKey)).c_str()); + return E_OK; } + int errCode = BindSaveDataStatement(isUpdate, dataItem, filterSet, stmt); + if (errCode != E_OK) { + LOGE("Bind data failed, errCode=%d.", errCode); + int ret = E_OK; + SQLiteUtils::ResetStatement(stmt, false, ret); + return errCode; + } + + errCode = SQLiteUtils::StepWithRetry(stmt, false); + int ret = E_OK; + SQLiteUtils::ResetStatement(stmt, false, ret); + return errCode; +} + +int RelationalSyncDataInserter::BindSaveDataStatement(bool isExist, const DataItem &dataItem, + const std::set &filterSet, sqlite3_stmt *stmt) +{ OptRowDataWithLog data; // deserialize by remote field info int errCode = DataTransformer::DeSerializeDataItem(dataItem, data, remoteFields_); @@ -154,13 +177,18 @@ int RelationalSyncDataInserter::BindInsertStatement(sqlite3_stmt *stmt, const Da const auto &localTableFields = localTable_.GetFields(); for (const auto &it : remoteFields_) { if (localTableFields.find(it.GetFieldName()) == localTableFields.end()) { - LOGD("field %s not found in local schema.", it.GetFieldName().c_str()); + LOGD("field %s[%zu] not found in local schema.", DBCommon::StringMiddleMasking(it.GetFieldName()).c_str(), + it.GetFieldName().size()); dataIdx++; continue; // skip fields which is orphaned in remote } + if (filterSet.find(it.GetFieldName()) != filterSet.end()) { + dataIdx++; + continue; // skip fields when update + } if (dataIdx >= data.optionalData.size()) { LOGD("field over size. cnt:%d, data size:%d", dataIdx, data.optionalData.size()); - break; // cnt should less then optionalData size. + break; // cnt should less than optionalData size. } errCode = SQLiteUtils::BindDataValueByType(stmt, data.optionalData[dataIdx], bindIdx++); if (errCode != E_OK) { @@ -169,8 +197,7 @@ int RelationalSyncDataInserter::BindInsertStatement(sqlite3_stmt *stmt, const Da } dataIdx++; } - - return E_OK; + return isExist ? BindHashKeyAndDev(dataItem, stmt, bindIdx) : E_OK; } int RelationalSyncDataInserter::GetDeleteLogStmt(sqlite3 *db, sqlite3_stmt *&stmt) @@ -208,22 +235,30 @@ int RelationalSyncDataInserter::GetDeleteSyncDataStmt(sqlite3 *db, sqlite3_stmt int RelationalSyncDataInserter::GetSaveLogStatement(sqlite3 *db, sqlite3_stmt *&logStmt, sqlite3_stmt *&queryStmt) { + std::string conflictPk; + std::string selCondition; + if (mode_ == DistributedTableMode::COLLABORATION) { + conflictPk = "ON CONFLICT(hash_key)"; + selCondition = " WHERE hash_key = ?;"; + } else { + conflictPk = "ON CONFLICT(hash_key, device)"; + selCondition = " WHERE hash_key = ? AND device = ?;"; + } const std::string tableName = DBConstant::RELATIONAL_PREFIX + query_.GetTableName() + "_log"; std::string dataFormat = "?, '" + hashDevId_ + "', ?, ?, ?, ?, ?"; std::string columnList = "data_key, device, ori_device, timestamp, wtimestamp, flag, hash_key"; - std::string sql = "INSERT OR REPLACE INTO " + tableName + - " (" + columnList + ") VALUES (" + dataFormat + ");"; + std::string sql = "INSERT INTO " + tableName + + " (" + columnList + ", cursor) VALUES (" + dataFormat + "," + + CloudStorageUtils::GetSelectIncCursorSql(query_.GetTableName()) +") " + conflictPk + + " DO UPDATE SET data_key = excluded.data_key, device = excluded.device," + " ori_device = excluded.ori_device, timestamp = excluded.timestamp, wtimestamp = excluded.wtimestamp," + " flag = excluded.flag, cursor = excluded.cursor;"; int errCode = SQLiteUtils::GetStatement(db, sql, logStmt); if (errCode != E_OK) { LOGE("[info statement] Get log statement fail! errCode:%d", errCode); return errCode; } - std::string selectSql = "select " + columnList + " from " + tableName; - if (mode_ == DistributedTableMode::COLLABORATION) { - selectSql += " where hash_key = ?;"; - } else { - selectSql += " where hash_key = ? and device = ?;"; - } + std::string selectSql = "SELECT " + columnList + " FROM " + tableName + selCondition; errCode = SQLiteUtils::GetStatement(db, selectSql, queryStmt); if (errCode != E_OK) { SQLiteUtils::ResetStatement(logStmt, true, errCode); @@ -239,9 +274,14 @@ int RelationalSyncDataInserter::PrepareStatement(sqlite3 *db, SaveSyncDataStmt & LOGE("Get save log statement failed. err=%d", errCode); return errCode; } - errCode = GetInsertStatement(db, stmt.saveDataStmt); + errCode = GetInsertStatement(db, stmt.insertDataStmt); if (errCode != E_OK) { LOGE("Get insert statement failed. err=%d", errCode); + return errCode; + } + errCode = GetUpdateStatement(db, stmt.updateDataStmt); + if (errCode != E_OK) { + LOGE("Get update statement failed. err=%d", errCode); } return errCode; } @@ -259,4 +299,102 @@ int RelationalSyncDataInserter::Iterate(const std::function &s } return errCode; } + +int RelationalSyncDataInserter::GetUpdateStatement(sqlite3 *db, sqlite3_stmt *&stmt) +{ + if (stmt != nullptr) { + return -E_INVALID_ARGS; + } + + std::set identifyKeySet; + for (const auto &primaryKey : localTable_.GetIdentifyKey()) { + identifyKeySet.insert(primaryKey); + } + std::string updateValue; + const auto &localTableFields = localTable_.GetFields(); + for (const auto &it : remoteFields_) { + if (localTableFields.find(it.GetFieldName()) == localTableFields.end()) { + continue; // skip fields which is orphaned in remote + } + if (identifyKeySet.find(it.GetFieldName()) == identifyKeySet.end()) { + if (updateValue.empty()) { + updateValue.append(" SET "); + } else { + updateValue.append(", "); + } + updateValue.append("'").append(it.GetFieldName()).append("'=?"); + } + } + if (updateValue.empty()) { + // only sync pk no need update + return E_OK; + } + std::string sql = "UPDATE '" + insertTableName_ + "'" + updateValue + " WHERE " + + std::string(DBConstant::SQLITE_INNER_ROWID) + " IN (SELECT data_key FROM " + + DBConstant::RELATIONAL_PREFIX + localTable_.GetTableName() + "_log "; + if (mode_ == DistributedTableMode::COLLABORATION) { + sql += "WHERE hash_key=?);"; + } else { + sql += "WHERE hash_key=? AND device=? AND flag&0x01=0);"; + } + int errCode = SQLiteUtils::GetStatement(db, sql, stmt); + if (errCode != E_OK) { + LOGE("Get update data statement fail! errCode:%d", errCode); + } + return errCode; +} + +int RelationalSyncDataInserter::BindHashKeyAndDev(const DataItem &dataItem, sqlite3_stmt *stmt, + int beginIndex) +{ + int errCode = SQLiteUtils::BindBlobToStatement(stmt, beginIndex++, dataItem.hashKey); + if (errCode != E_OK) { + LOGE("[RelationalSyncDataInserter] bind hash key failed %d", errCode); + return errCode; + } + if (mode_ != DistributedTableMode::COLLABORATION) { + errCode = SQLiteUtils::BindTextToStatement(stmt, beginIndex, dataItem.dev); + if (errCode != E_OK) { + LOGE("[RelationalSyncDataInserter] bind dev failed %d", errCode); + } + } + return errCode; +} + +int RelationalSyncDataInserter::SaveSyncLog(sqlite3 *db, sqlite3_stmt *statement, sqlite3_stmt *queryStmt, + const DataItem &dataItem, int64_t rowid) +{ + LogInfo logInfoGet; + int errCode = SQLiteRelationalUtils::GetLogInfoPre(queryStmt, mode_, dataItem, logInfoGet); + LogInfo logInfoBind; + logInfoBind.hashKey = dataItem.hashKey; + logInfoBind.device = dataItem.dev; + logInfoBind.timestamp = dataItem.timestamp; + logInfoBind.flag = dataItem.flag; + + if (errCode == -E_NOT_FOUND) { // insert + logInfoBind.wTimestamp = dataItem.writeTimestamp; + logInfoBind.originDev = dataItem.dev; + } else if (errCode == E_OK) { // update + logInfoBind.wTimestamp = logInfoGet.wTimestamp; + logInfoBind.originDev = logInfoGet.originDev; + } else { + LOGE("[RelationalSyncDataInserter] get log info failed %d", errCode); + return errCode; + } + + // bind + SQLiteUtils::BindInt64ToStatement(statement, 1, rowid); // 1 means dataKey index + std::vector originDev(logInfoBind.originDev.begin(), logInfoBind.originDev.end()); + SQLiteUtils::BindBlobToStatement(statement, 2, originDev); // 2 means ori_dev index + SQLiteUtils::BindInt64ToStatement(statement, 3, logInfoBind.timestamp); // 3 means timestamp index + SQLiteUtils::BindInt64ToStatement(statement, 4, logInfoBind.wTimestamp); // 4 means w_timestamp index + SQLiteUtils::BindInt64ToStatement(statement, 5, logInfoBind.flag); // 5 means flag index + SQLiteUtils::BindBlobToStatement(statement, 6, logInfoBind.hashKey); // 6 means hashKey index + errCode = SQLiteUtils::StepWithRetry(statement, false); + if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + return E_OK; + } + return errCode; +} } // namespace DistributedDB \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_sync_data_inserter.h b/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_sync_data_inserter.h index 7120c28a3a734bae7d433b50e79d3761d7f9fce7..48173d93f28618fa1f76b6d2ced79ec525bc72d4 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_sync_data_inserter.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/relational/relational_sync_data_inserter.h @@ -24,7 +24,8 @@ namespace DistributedDB { struct SaveSyncDataStmt { - sqlite3_stmt *saveDataStmt = nullptr; + sqlite3_stmt *insertDataStmt = nullptr; + sqlite3_stmt *updateDataStmt = nullptr; sqlite3_stmt *saveLogStmt = nullptr; sqlite3_stmt *queryStmt = nullptr; sqlite3_stmt *rmDataStmt = nullptr; @@ -40,8 +41,8 @@ struct SaveSyncDataStmt { class RelationalSyncDataInserter { public: - RelationalSyncDataInserter(); - ~RelationalSyncDataInserter(); + RelationalSyncDataInserter() = default; + ~RelationalSyncDataInserter() = default; static RelationalSyncDataInserter CreateInserter(const std::string &deviceName, const QueryObject &query, const RelationalSchemaObject &localSchema, const std::vector &remoteFields, @@ -61,18 +62,27 @@ public: void SetTableMode(DistributedTableMode mode); int Iterate(const std::function &); - int BindInsertStatement(sqlite3_stmt *stmt, const DataItem &dataItem); + + int SaveData(bool isUpdate, const DataItem &dataItem, SaveSyncDataStmt &saveSyncDataStmt); + int BindSaveDataStatement(bool isExist, const DataItem &dataItem, const std::set &filterSet, + sqlite3_stmt *stmt); int PrepareStatement(sqlite3 *db, SaveSyncDataStmt &stmt); int GetDeleteLogStmt(sqlite3 *db, sqlite3_stmt *&stmt); int GetDeleteSyncDataStmt(sqlite3 *db, sqlite3_stmt *&stmt); + int BindHashKeyAndDev(const DataItem &dataItem, sqlite3_stmt *stmt, int beginIndex); + + int SaveSyncLog(sqlite3 *db, sqlite3_stmt *statement, sqlite3_stmt *queryStmt, const DataItem &dataItem, + int64_t rowid); private: int GetInsertStatement(sqlite3 *db, sqlite3_stmt *&stmt); int GetSaveLogStatement(sqlite3 *db, sqlite3_stmt *&logStmt, sqlite3_stmt *&queryStmt); + int GetUpdateStatement(sqlite3 *db, sqlite3_stmt *&stmt); + std::string hashDevId_; std::vector remoteFields_; std::vector entries_; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/relational/relationaldb_properties.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/relational/relationaldb_properties.cpp index ee0333bd53abca8d8db12c06fa4cf7e18398d6f9..65332e6c51e8010a19ffe04c63992e12a1f7f236 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/relational/relationaldb_properties.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/relational/relationaldb_properties.cpp @@ -66,5 +66,11 @@ uint32_t RelationalDBProperties::GetIterTimes() const { return iterTimes_; } + +DistributedTableMode RelationalDBProperties::GetDistributedTableMode() const +{ + auto defaultMode = static_cast(DistributedTableMode::SPLIT_BY_DEVICE); + return static_cast(GetIntProp(RelationalDBProperties::DISTRIBUTED_TABLE_MODE, defaultMode)); +} } #endif \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/result_entries_window.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/result_entries_window.cpp index 07a09aed46325b223684a41e9f3fd2d4bc6e68f4..7d96a733b0a1988e5766e8326068e675321a96da 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/result_entries_window.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/result_entries_window.cpp @@ -171,7 +171,7 @@ int ResultEntriesWindow::LoadData(int begin, int target) const return errCode; } // filter the abnormal data. - if (next.key.size() > DBConstant::MAX_KEY_SIZE || next.value.size() > DBConstant::MAX_VALUE_SIZE) { + if (next.key.size() > DBConstant::MAX_KEY_SIZE || next.value.size() > DBConstant::MAX_SET_VALUE_SIZE) { continue; } bufferSize += next.key.size() + next.value.size(); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/single_ver_natural_store.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/single_ver_natural_store.cpp index 0f9028b3fc9e1727424f2b6a446abd4fce313eef..b19356bfd04d047aee58102ea8ecc9e11db5506a 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/single_ver_natural_store.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/single_ver_natural_store.cpp @@ -116,7 +116,7 @@ void SingleVerNaturalStore::CommitAndReleaseNotifyData(SingleVerNaturalStoreComm } if (committedData != nullptr) { - committedData->DecObjRef(committedData); + RefObject::DecObjRef(committedData); committedData = nullptr; } } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/single_ver_natural_store_connection.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/single_ver_natural_store_connection.cpp index 92bf09c3a3021670b411b80fa99a589609b6f385..9d50169dfd4a244adc4246428d55dd8015ff07c0 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/single_ver_natural_store_connection.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/single_ver_natural_store_connection.cpp @@ -83,7 +83,7 @@ bool SingleVerNaturalStoreConnection::CheckAndGetKeyLen(const std::vector & return true; } -int SingleVerNaturalStoreConnection::CheckSyncEntriesValid(const std::vector &entries) const +int SingleVerNaturalStoreConnection::CheckSyncEntriesValid([[gnu::unused]] const std::vector &entries) const { return E_OK; } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/query_object.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/query_object.cpp index 297fe24c7b907045226674f5d218b4c5ac354751..b482eb60bc8a230be1a71a05655d46abb28be1b5 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/query_object.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/query_object.cpp @@ -35,7 +35,8 @@ QueryObject::QueryObject() hasLimit_(false), hasPrefixKey_(false), hasInKeys_(false), - orderByCounts_(0) + orderByCounts_(0), + isUseLocalSchema_(true) { } @@ -72,7 +73,8 @@ QueryObject::QueryObject(const QueryExpression &queryExpression) hasLimit_(false), hasPrefixKey_(false), hasInKeys_(false), - orderByCounts_(0) + orderByCounts_(0), + isUseLocalSchema_(true) { QueryExpression queryExpressions = queryExpression; queryObjNodes_ = queryExpressions.GetQueryExpression(); @@ -86,6 +88,10 @@ QueryObject::QueryObject(const QueryExpression &queryExpression) sortType_ = static_cast(queryExpressions.GetSortType()); tables_ = queryExpressions.GetTables(); validStatus = queryExpressions.GetExpressionStatus(); + isAssetsOnly_ = queryExpressions.IsAssetsOnly(); + groupNum_ = queryExpressions.GetGroupNum(); + assetsGroupMap_ = queryExpressions.GetAssetsOnlyGroupMap(); + isValidForAssetsOnly_ = queryExpressions.GetExpressionStatusForAssetsOnly() == E_OK; } QueryObject::QueryObject(const std::list &queryObjNodes, const std::vector &prefixKey, @@ -101,7 +107,8 @@ QueryObject::QueryObject(const std::list &queryObjNodes, const std hasLimit_(false), hasPrefixKey_(false), hasInKeys_(false), - orderByCounts_(0) + orderByCounts_(0), + isUseLocalSchema_(true) { SetAttrWithQueryObjNodes(); } @@ -556,5 +563,46 @@ std::vector QueryObject::GetQueryExpressions(const Query &query { return GetQueryInfo::GetQueryExpression(query).GetQueryExpressions(); } + +bool QueryObject::IsAssetsOnly() const +{ + return isAssetsOnly_; +} + +uint32_t QueryObject::GetGroupNum() const +{ + return groupNum_ <= 1 ? 1 : groupNum_; +} + +AssetsGroupMap QueryObject::GetAssetsOnlyGroupMap() const +{ + return assetsGroupMap_; +} + +bool QueryObject::IsValidForAssetsOnly() const +{ + return isValidForAssetsOnly_; +} + +void QueryObject::SetUseLocalSchema(bool isUse) +{ + isUseLocalSchema_ = isUse; +} + +bool QueryObject::IsUseLocalSchema() const +{ + return isUseLocalSchema_; +} + +std::string QueryObject::GetRemoteDev() const +{ + return remoteDev_; +} + +void QueryObject::SetRemoteDev(const std::string &dev) +{ + remoteDev_ = dev; +} + } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/query_object.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/query_object.h index 47681cf042df2be45e90a0e887dc4a38b12d8167..33b0bfd2dcbb3e2e183e0e8a83804473aa61ecd4 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/query_object.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/query_object.h @@ -66,12 +66,26 @@ public: int CheckPrimaryKey(const std::map &primaryKeyMap) const; + bool IsAssetsOnly() const; + + uint32_t GetGroupNum() const; + + AssetsGroupMap GetAssetsOnlyGroupMap() const; + + bool IsValidForAssetsOnly() const; + #ifdef RELATIONAL_STORE int SetSchema(const RelationalSchemaObject &schemaObj); // The interface can only be used in relational query. #endif // For continue token, once sync may not get all sync data, use AddOffset to continue last query void SetLimit(int limit, int offset); + + void SetUseLocalSchema(bool isUse); + bool IsUseLocalSchema() const; + + void SetRemoteDev(const std::string &dev); + std::string GetRemoteDev() const; protected: explicit QueryObject(const QueryExpression &queryExpression); static std::vector GetQueryExpressions(const Query &query); @@ -87,6 +101,10 @@ protected: bool isTableNameSpecified_ = false; std::vector tables_; int validStatus = E_OK; + uint32_t groupNum_ = 0; + bool isAssetsOnly_ = false; + AssetsGroupMap assetsGroupMap_; + bool isValidForAssetsOnly_ = false; private: int Parse(); @@ -110,7 +128,9 @@ private: bool hasPrefixKey_; bool hasInKeys_; int orderByCounts_; + bool isUseLocalSchema_; SortType sortType_ = SortType::NONE; + std::string remoteDev_; }; } #endif diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/query_sync_object.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/query_sync_object.cpp index f08f648ad163ba770f16fadd94d573c44fb21321..314e9e073a1bf06c01b3332a72df2019cae44257 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/query_sync_object.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/query_sync_object.cpp @@ -247,10 +247,12 @@ void QuerySyncObject::SetCloudGid(const std::vector &cloudGid) { for (size_t i = 0; i < cloudGid.size(); i+= MAX_VALUE_SIZE) { size_t end = std::min(i + MAX_VALUE_SIZE, cloudGid.size()); - QueryObjNode operateNode; - operateNode.operFlag = QueryObjType::OR; - operateNode.type = QueryValueType::VALUE_TYPE_NULL; - queryObjNodes_.emplace_back(operateNode); + if (!queryObjNodes_.empty()) { + QueryObjNode operateNode; + operateNode.operFlag = QueryObjType::OR; + operateNode.type = QueryValueType::VALUE_TYPE_NULL; + queryObjNodes_.emplace_back(operateNode); + } QueryObjNode objNode; objNode.operFlag = QueryObjType::IN; @@ -520,4 +522,52 @@ int QuerySyncObject::TransformNodeType(const QueryObjNode &objNode, QueryNode &n } return errCode; } + +int QuerySyncObject::GetQuerySyncObjectFromGroup(int64_t groupId, QuerySyncObject &obj) +{ + obj = *this; + if (groupNum_ <= 1) { + return E_OK; + } + // find the begin group node + bool isFindBeginGroup = false; + int64_t beginGroupIndex = 0; + for (auto iter = obj.queryObjNodes_.begin(); iter != obj.queryObjNodes_.end();) { + if ((*iter).operFlag != QueryObjType::BEGIN_GROUP) { + // eraes the node which is before the begin group node + iter = obj.queryObjNodes_.erase(iter); + continue; + } else if (beginGroupIndex != groupId) { + // eraes the node which is before the begin group node + iter = obj.queryObjNodes_.erase(iter); + beginGroupIndex++; + continue; + } else { + isFindBeginGroup = true; + break; + } + } + if (!isFindBeginGroup) { + LOGE("can not find the begin group node, groupid %u", groupId); + return -E_INVALID_ARGS; + } + + // find the end group node + bool isFindEndGroup = false; + for (auto iter = obj.queryObjNodes_.begin(); iter != obj.queryObjNodes_.end();) { + if (isFindEndGroup) { + // eraes the node which is behind the end group node + iter = obj.queryObjNodes_.erase(iter); + continue; + } else if ((*iter).operFlag == QueryObjType::END_GROUP) { + isFindEndGroup = true; + } + ++iter; + } + if (!isFindEndGroup) { + LOGE("can not find the end group node, groupid %u", groupId); + return -E_INVALID_ARGS; + } + return E_OK; +} } // namespace DistributedDB \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/query_sync_object.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/query_sync_object.h index c0fb607fa262614b4b72cef172d910ed91f7834e..caaa598a488c6f23d182d3ac86920fd4c8a94a5f 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/query_sync_object.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/query_sync_object.h @@ -63,6 +63,9 @@ public: static std::vector GetQuerySyncObject(const Query &query); static int ParserQueryNodes(const Bytes &bytes, std::vector &queryNodes); + + int GetQuerySyncObjectFromGroup(int64_t groupId, QuerySyncObject &obj); + private: explicit QuerySyncObject(const QueryExpression &expression); uint32_t CalculateLen() const; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/cloud_sync_log_table_manager.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/cloud_sync_log_table_manager.cpp index 6e6d930e81240bd5b59bdb46d79e76aced4945bd..671c0dafa63cf137558a55bcd1191e417196bacf 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/cloud_sync_log_table_manager.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/cloud_sync_log_table_manager.cpp @@ -87,11 +87,20 @@ std::string CloudSyncLogTableManager::GetPrimaryKeySql(const TableInfo &table) return "PRIMARY KEY(hash_key)"; } +std::string CloudSyncLogTableManager::GetConflictPkSql(const TableInfo &table) +{ + auto primaryKey = table.GetPrimaryKey(); + if (primaryKey[0] == CloudDbConstant::ROW_ID_FIELD_NAME) { + return "ON CONFLICT(hash_key, cloud_gid)"; + } + return "ON CONFLICT(hash_key)"; +} + // The parameter "identity" is a hash string that identifies a device. The same for the next two functions. std::string CloudSyncLogTableManager::GetInsertTrigger(const TableInfo &table, const std::string &identity) { std::string logTblName = GetLogTableName(table); - std::string tableName = table.GetTableName(); + const std::string &tableName = table.GetTableName(); std::string insertTrigger = "CREATE TRIGGER IF NOT EXISTS "; insertTrigger += "naturalbase_rdb_" + tableName + "_ON_INSERT AFTER INSERT \n"; insertTrigger += "ON '" + tableName + "'\n"; @@ -126,7 +135,7 @@ std::string CloudSyncLogTableManager::GetUpdateTrigger(const TableInfo &table, c { (void)identity; std::string logTblName = GetLogTableName(table); - std::string tableName = table.GetTableName(); + const std::string &tableName = table.GetTableName(); std::string updateTrigger = "CREATE TRIGGER IF NOT EXISTS "; updateTrigger += "naturalbase_rdb_" + tableName + "_ON_UPDATE AFTER UPDATE \n"; updateTrigger += "ON '" + tableName + "'\n"; @@ -135,7 +144,7 @@ std::string CloudSyncLogTableManager::GetUpdateTrigger(const TableInfo &table, c updateTrigger += "BEGIN\n"; // if user change the primary key, we can still use gid to identify which one is updated updateTrigger += CloudStorageUtils::GetCursorIncSql(tableName) + "\n"; updateTrigger += "\t UPDATE " + logTblName; - updateTrigger += " SET timestamp=get_raw_sys_time(), device='', flag=0x02|0x20"; + updateTrigger += " SET timestamp=get_raw_sys_time(), device='', flag=(flag&0x1000)|0x02|0x20"; if (!table.GetTrackerTable().IsEmpty()) { updateTrigger += table.GetTrackerTable().GetExtendAssignValSql(); } @@ -155,7 +164,7 @@ std::string CloudSyncLogTableManager::GetUpdateTrigger(const TableInfo &table, c std::string CloudSyncLogTableManager::GetDeleteTrigger(const TableInfo &table, const std::string &identity) { (void)identity; - std::string tableName = table.GetTableName(); + const std::string &tableName = table.GetTableName(); std::string deleteTrigger = "CREATE TRIGGER IF NOT EXISTS "; deleteTrigger += "naturalbase_rdb_" + tableName + "_ON_DELETE BEFORE DELETE \n"; deleteTrigger += "ON '" + tableName + "'\n"; @@ -189,7 +198,7 @@ std::string CloudSyncLogTableManager::GetDeleteTrigger(const TableInfo &table, c std::vector CloudSyncLogTableManager::GetDropTriggers(const TableInfo &table) { std::vector dropTriggers; - std::string tableName = table.GetTableName(); + const std::string &tableName = table.GetTableName(); std::string insertTrigger = "DROP TRIGGER IF EXISTS naturalbase_rdb_" + tableName + "_ON_INSERT; "; std::string updateTrigger = "DROP TRIGGER IF EXISTS naturalbase_rdb_" + tableName + "_ON_UPDATE; "; std::string deleteTrigger = "DROP TRIGGER IF EXISTS naturalbase_rdb_" + tableName + "_ON_DELETE; "; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/cloud_sync_log_table_manager.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/cloud_sync_log_table_manager.h index 6a8e837ccef45a909da774e64adeda6255ac6ef3..44e0b4f5f6807bf2cacf804289aa8f253f91d2f7 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/cloud_sync_log_table_manager.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/cloud_sync_log_table_manager.h @@ -27,6 +27,7 @@ public: // The parameter "references" is "", "NEW." or "OLD.". "identity" is a hash string that identifies a device. std::string CalcPrimaryKeyHash(const std::string &references, const TableInfo &table, const std::string &identity) override; + std::string GetConflictPkSql(const TableInfo &table) override; private: void GetIndexSql(const TableInfo &table, std::vector &schema) override; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/collaboration_log_table_manager.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/collaboration_log_table_manager.cpp index 501a50b6f87b6010f84c34d12e41562bdb1b9168..84a2bee6ec32600134420e9b84ee5e23d5188e10 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/collaboration_log_table_manager.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/collaboration_log_table_manager.cpp @@ -14,7 +14,7 @@ */ #include "collaboration_log_table_manager.h" - +#include "cloud/cloud_storage_utils.h" namespace DistributedDB { bool CollaborationLogTableManager::IsCollaborationWithoutKey(const TableInfo &table) { @@ -26,21 +26,14 @@ std::string CollaborationLogTableManager::CalcPrimaryKeyHash(const std::string & const std::string &identity) { std::string sql; - if (IsCollaborationWithoutKey(table)) { + auto distributedPk = table.GetSyncDistributedPk(); + if (!distributedPk.empty()) { + sql = CalcPkHash(references, distributedPk); + } else if (IsCollaborationWithoutKey(table)) { sql = "calc_hash('" + identity + "'||calc_hash(" + references + std::string(DBConstant::SQLITE_INNER_ROWID) + ", 0), 0)"; } else { - if (table.GetIdentifyKey().size() == 1u) { - sql = "calc_hash(" + references + "'" + table.GetIdentifyKey().at(0) + "', 0)"; - } else { - sql = "calc_hash("; - for (const auto &it : table.GetIdentifyKey()) { - sql += "calc_hash(" + references + "'" + it + "', 0)||"; - } - sql.pop_back(); - sql.pop_back(); - sql += ", 0)"; - } + sql = CalcPkHash(references, table.GetIdentifyKey()); } return sql; } @@ -54,13 +47,17 @@ std::string CollaborationLogTableManager::GetInsertTrigger(const TableInfo &tabl insertTrigger += "WHEN (SELECT count(*) from " + std::string(DBConstant::RELATIONAL_PREFIX) + "metadata "; insertTrigger += "WHERE key = 'log_trigger_switch' AND value = 'true')\n"; insertTrigger += "BEGIN\n"; + insertTrigger += CloudStorageUtils::GetCursorIncSql(table.GetTableName()) + "\n"; insertTrigger += "\t INSERT OR REPLACE INTO " + logTblName; - insertTrigger += " (data_key, device, ori_device, timestamp, wtimestamp, flag, hash_key)"; + insertTrigger += " (data_key, device, ori_device, timestamp, wtimestamp, flag, hash_key, cursor)"; insertTrigger += " VALUES (new." + std::string(DBConstant::SQLITE_INNER_ROWID) + ", '', '',"; insertTrigger += " get_sys_time(0), get_last_time(),"; insertTrigger += " CASE WHEN (SELECT count(*)<>0 FROM " + logTblName + " WHERE hash_key=" + CalcPrimaryKeyHash("NEW.", table, identity) + " AND flag&0x02=0x02) THEN 0x22 ELSE 0x02 END,"; - insertTrigger += CalcPrimaryKeyHash("NEW.", table, identity) + ");\n"; + insertTrigger += CalcPrimaryKeyHash("NEW.", table, identity) + ","; + insertTrigger += CloudStorageUtils::GetSelectIncCursorSql(table.GetTableName()) + ");\n"; + insertTrigger += "SELECT client_observer('" + table.GetTableName() + "', NEW."; + insertTrigger += std::string(DBConstant::SQLITE_INNER_ROWID) + ", 0, 2);\n"; // 0 is insert, 2 is p2p change insertTrigger += "END;"; return insertTrigger; } @@ -74,25 +71,31 @@ std::string CollaborationLogTableManager::GetUpdateTrigger(const TableInfo &tabl updateTrigger += "WHEN (SELECT count(*) from " + std::string(DBConstant::RELATIONAL_PREFIX) + "metadata "; updateTrigger += "WHERE key = 'log_trigger_switch' AND value = 'true')\n"; updateTrigger += "BEGIN\n"; + updateTrigger += CloudStorageUtils::GetCursorIncSql(table.GetTableName()) + "\n"; if (table.GetIdentifyKey().size() == 1u && table.GetIdentifyKey().at(0) == "rowid") { // primary key is rowid, it can't be changed updateTrigger += "\t UPDATE " + std::string(DBConstant::RELATIONAL_PREFIX) + table.GetTableName() + "_log"; - updateTrigger += " SET timestamp=get_sys_time(0), device='', flag=0x22"; + updateTrigger += " SET timestamp=" + GetUpdateTimestamp(table, false) + ", device='', flag=0x22, "; + updateTrigger += "cursor=" + CloudStorageUtils::GetSelectIncCursorSql(table.GetTableName()); updateTrigger += " WHERE data_key = OLD." + std::string(DBConstant::SQLITE_INNER_ROWID) + ";"; } else { - // primary key may be changed, so we need to set the old log record deleted, then insert or replace a new + // insert or replace a new // log record(if primary key not change, insert or replace will modify the log record we set deleted in previous // step) - updateTrigger += "\t UPDATE " + logTblName; - updateTrigger += " SET data_key=-1, timestamp=get_sys_time(0), device='', flag=0x03"; - updateTrigger += " WHERE data_key = OLD." + std::string(DBConstant::SQLITE_INNER_ROWID)+ ";\n"; - updateTrigger += "\t INSERT OR REPLACE INTO " + logTblName + " VALUES (NEW." + + updateTrigger += "\t INSERT INTO " + logTblName + " VALUES (NEW." + std::string(DBConstant::SQLITE_INNER_ROWID) + ", '', '', get_sys_time(0), " "get_last_time(), CASE WHEN (" + CalcPrimaryKeyHash("NEW.", table, identity) + " != " + CalcPrimaryKeyHash("NEW.", table, identity) + ") THEN 0x02 ELSE 0x22 END, " + // status not used, default value 0 is UNLOCK. - CalcPrimaryKeyHash("NEW.", table, identity) + ", '', '', '', '', '', 0);\n"; + CalcPrimaryKeyHash("NEW.", table, identity) + ", '', '', " + + CloudStorageUtils::GetSelectIncCursorSql(table.GetTableName()) + ", '', '', 0) " + + "ON CONFLICT(hash_key) DO UPDATE SET timestamp=" + GetUpdateTimestamp(table, false) + + ", device='', flag=0x22, cursor=" + CloudStorageUtils::GetSelectIncCursorSql(table.GetTableName()) + + ";\n"; } + updateTrigger += "SELECT client_observer('" + table.GetTableName() + "', OLD."; + updateTrigger += std::string(DBConstant::SQLITE_INNER_ROWID); + updateTrigger += ", 1, " + GetChangeDataStatus(table) + ");\n"; // 1 is updated updateTrigger += "END;"; return updateTrigger; } @@ -106,9 +109,13 @@ std::string CollaborationLogTableManager::GetDeleteTrigger(const TableInfo &tabl deleteTrigger += "WHEN (SELECT count(*) from " + std::string(DBConstant::RELATIONAL_PREFIX) + "metadata "; deleteTrigger += "WHERE key = 'log_trigger_switch' AND VALUE = 'true')\n"; deleteTrigger += "BEGIN\n"; + deleteTrigger += CloudStorageUtils::GetCursorIncSql(table.GetTableName()) + "\n"; deleteTrigger += "\t UPDATE " + std::string(DBConstant::RELATIONAL_PREFIX) + table.GetTableName() + "_log"; - deleteTrigger += " SET data_key=-1,flag=0x03,timestamp=get_sys_time(0)"; - deleteTrigger += " WHERE data_key = OLD." + std::string(DBConstant::SQLITE_INNER_ROWID) + ";"; + deleteTrigger += " SET data_key=-1,flag=0x03,timestamp=get_sys_time(0),"; + deleteTrigger += "cursor=" + CloudStorageUtils::GetSelectIncCursorSql(table.GetTableName()); + deleteTrigger += " WHERE data_key = OLD." + std::string(DBConstant::SQLITE_INNER_ROWID) + ";\n"; + // first 2 is deleted, second 2 is p2p change + deleteTrigger += "SELECT client_observer('" + table.GetTableName() + "', -1, 2, 2);\n"; deleteTrigger += "END;"; return deleteTrigger; } @@ -129,13 +136,44 @@ void CollaborationLogTableManager::GetIndexSql(const TableInfo &table, std::vect std::vector CollaborationLogTableManager::GetDropTriggers(const TableInfo &table) { std::vector dropTriggers; - std::string tableName = table.GetTableName(); + const std::string &tableName = table.GetTableName(); std::string insertTrigger = "DROP TRIGGER IF EXISTS naturalbase_rdb_" + tableName + "_ON_INSERT; "; std::string updateTrigger = "DROP TRIGGER IF EXISTS naturalbase_rdb_" + tableName + "_ON_UPDATE; "; std::string deleteTrigger = "DROP TRIGGER IF EXISTS naturalbase_rdb_" + tableName + "_ON_DELETE; "; + std::string updatePkTrigger = "DROP TRIGGER IF EXISTS naturalbase_rdb_" + tableName + "_ON_UPDATE_PK; "; dropTriggers.emplace_back(insertTrigger); dropTriggers.emplace_back(updateTrigger); dropTriggers.emplace_back(deleteTrigger); + dropTriggers.emplace_back(updatePkTrigger); return dropTriggers; } + +std::string CollaborationLogTableManager::GetUpdatePkTrigger(const TableInfo &table, const std::string &identity) +{ + if (table.GetIdentifyKey().size() == 1u && table.GetIdentifyKey().at(0) == "rowid") { + return ""; + } + std::string logTblName = DBConstant::RELATIONAL_PREFIX + table.GetTableName() + "_log"; + std::string updatePkTrigger = "CREATE TRIGGER IF NOT EXISTS "; + updatePkTrigger += "naturalbase_rdb_" + table.GetTableName() + "_ON_UPDATE_PK AFTER UPDATE \n"; + updatePkTrigger += "ON '" + table.GetTableName() + "'\n"; + updatePkTrigger += "WHEN (SELECT count(*) from " + std::string(DBConstant::RELATIONAL_PREFIX) + "metadata "; + updatePkTrigger += "WHERE key = 'log_trigger_switch' AND value = 'true' AND "; + updatePkTrigger += CalcPrimaryKeyHash("NEW.", table, identity) + " != " + + CalcPrimaryKeyHash("OLD.", table, identity); + updatePkTrigger += ")\n"; + updatePkTrigger += "BEGIN\n"; + // primary key was changed, so we need to set the old log record deleted, + updatePkTrigger += "\t UPDATE " + logTblName; + updatePkTrigger += " SET data_key=-1, timestamp=get_sys_time(0), device='', flag=0x03"; + updatePkTrigger += " WHERE data_key = OLD." + std::string(DBConstant::SQLITE_INNER_ROWID)+ ";\n"; + updatePkTrigger += "END;"; + return updatePkTrigger; +} + +std::string CollaborationLogTableManager::GetChangeDataStatus(const TableInfo &table) +{ + // first 2 is p2p change when sync field empty, second 2 is p2p change when sync field update + return GetUpdateWithAssignSql(table, "2", "2", "0"); +} } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/collaboration_log_table_manager.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/collaboration_log_table_manager.h index 4893e359b721f6822676c3166d01b9af90f788a2..b2a38b1bbfc6ebb1f11bcfaf444fe3edf5cbe35b 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/collaboration_log_table_manager.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/collaboration_log_table_manager.h @@ -26,7 +26,8 @@ public: std::string CalcPrimaryKeyHash(const std::string &references, const TableInfo &table, const std::string &identity) override; - +protected: + std::string GetUpdatePkTrigger(const TableInfo &table, const std::string &identity) override; private: bool IsCollaborationWithoutKey(const TableInfo &table); @@ -37,6 +38,8 @@ private: std::string GetUpdateTrigger(const TableInfo &table, const std::string &identity) override; std::string GetDeleteTrigger(const TableInfo &table, const std::string &identity) override; std::vector GetDropTriggers(const TableInfo &table) override; + + static std::string GetChangeDataStatus(const TableInfo &table); }; } #endif // COLLABORATION_LOG_TABLE_MANAGER_H \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/device_tracker_log_table_manager.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/device_tracker_log_table_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8dce09062c42f24a7918c821d08b98c6059574df --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/device_tracker_log_table_manager.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2024 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 "cloud/cloud_storage_utils.h" +#include "device_tracker_log_table_manager.h" + +namespace DistributedDB { + +std::string DeviceTrackerLogTableManager::CalcPrimaryKeyHash(const std::string &references, const TableInfo &table, + const std::string &identity) +{ + (void)identity; + std::string sql; + auto distributedPk = table.GetSyncDistributedPk(); + if (!distributedPk.empty()) { + sql = CalcPkHash(references, distributedPk); + } else { + sql = CalcPkHash(references, table.GetIdentifyKey()); + } + return sql; +} + +void DeviceTrackerLogTableManager::GetIndexSql(const TableInfo &table, std::vector &schema) +{ + const std::string tableName = GetLogTableName(table); + + std::string indexCursor = "CREATE INDEX IF NOT EXISTS " + tableName + + "_cursor_index ON " + tableName + "(cursor);"; + std::string indexDataKey = "CREATE INDEX IF NOT EXISTS " + tableName + + "_data_key_index ON " + tableName + "(data_key);"; + schema.emplace_back(indexCursor); + schema.emplace_back(indexDataKey); +} + +std::string DeviceTrackerLogTableManager::GetPrimaryKeySql(const TableInfo &table) +{ + return "PRIMARY KEY(hash_key)"; +} + +// The parameter "identity" is a hash string that identifies a device. The same for the next two functions. +std::string DeviceTrackerLogTableManager::GetInsertTrigger(const TableInfo &table, const std::string &identity) +{ + if (table.GetTrackerTable().IsEmpty()) { + return ""; + } + std::string logTblName = GetLogTableName(table); + std::string tableName = table.GetTableName(); + std::string insertTrigger = "CREATE TRIGGER IF NOT EXISTS "; + insertTrigger += "naturalbase_rdb_" + tableName + "_ON_INSERT AFTER INSERT \n"; + insertTrigger += "ON '" + tableName + "'\n"; + insertTrigger += "WHEN (SELECT count(*) from " + std::string(DBConstant::RELATIONAL_PREFIX) + "metadata "; + insertTrigger += "WHERE key = 'log_trigger_switch' AND value = 'true')\n"; + insertTrigger += "BEGIN\n"; + insertTrigger += CloudStorageUtils::GetCursorIncSql(tableName) + "\n"; + insertTrigger += "\t INSERT OR REPLACE INTO " + logTblName; + insertTrigger += " (data_key, device, ori_device, timestamp, wtimestamp, flag, hash_key, cloud_gid"; + insertTrigger += ", extend_field, cursor, version, sharing_resource, status)"; + insertTrigger += " VALUES (new." + std::string(DBConstant::SQLITE_INNER_ROWID) + ", '', '',"; + insertTrigger += " get_sys_time(0), get_last_time(),"; + insertTrigger += " CASE WHEN (SELECT count(*)<>0 FROM " + logTblName + " WHERE hash_key=" + + CalcPrimaryKeyHash("NEW.", table, identity) + " AND flag&0x02=0x02) THEN 0x22 ELSE 0x02 END,"; + insertTrigger += CalcPrimaryKeyHash("NEW.", table, identity) + ", '', "; + insertTrigger += table.GetTrackerTable().GetAssignValSql(); + insertTrigger += ", " + CloudStorageUtils::GetSelectIncCursorSql(tableName) + ", '', '', 0);\n"; + insertTrigger += "SELECT client_observer('" + tableName + "', NEW._rowid_, 0, 3"; + insertTrigger += ");\n"; + insertTrigger += "END;"; + return insertTrigger; +} + +std::string DeviceTrackerLogTableManager::GetUpdateTrigger(const TableInfo &table, const std::string &identity) +{ + if (table.GetTrackerTable().IsEmpty()) { + return ""; + } + (void)identity; + std::string logTblName = GetLogTableName(table); + std::string tableName = table.GetTableName(); + std::string updateTrigger = "CREATE TRIGGER IF NOT EXISTS "; + updateTrigger += "naturalbase_rdb_" + tableName + "_ON_UPDATE AFTER UPDATE \n"; + updateTrigger += "ON '" + tableName + "'\n"; + updateTrigger += "WHEN (SELECT count(*) from " + std::string(DBConstant::RELATIONAL_PREFIX) + "metadata "; + updateTrigger += "WHERE key = 'log_trigger_switch' AND value = 'true')\n"; + updateTrigger += "BEGIN\n"; + updateTrigger += CloudStorageUtils::GetCursorIncSql(tableName); + updateTrigger.pop_back(); + updateTrigger += ";"; + updateTrigger += "\t UPDATE " + logTblName; + updateTrigger += " SET timestamp=" + GetUpdateTimestamp(table, false) + ", device='', flag=0x22"; + updateTrigger += table.GetTrackerTable().GetExtendAssignValSql(); + updateTrigger += table.GetTrackerTable().GetDiffIncCursorSql(tableName); + updateTrigger += " WHERE data_key = OLD." + std::string(DBConstant::SQLITE_INNER_ROWID) + ";\n"; + updateTrigger += "SELECT client_observer('" + tableName + "', OLD." + std::string(DBConstant::SQLITE_INNER_ROWID); + updateTrigger += ", 1, ("; + updateTrigger += table.GetTrackerTable().GetDiffTrackerValSql(); + updateTrigger += ") | ("; + updateTrigger += GetChangeDataStatus(table); + updateTrigger += "));"; + updateTrigger += "END;"; + return updateTrigger; +} + +std::string DeviceTrackerLogTableManager::GetDeleteTrigger(const TableInfo &table, const std::string &identity) +{ + if (table.GetTrackerTable().IsEmpty()) { + return ""; + } + (void)identity; + std::string tableName = table.GetTableName(); + std::string deleteTrigger = "CREATE TRIGGER IF NOT EXISTS "; + deleteTrigger += "naturalbase_rdb_" + tableName + "_ON_DELETE BEFORE DELETE \n"; + deleteTrigger += "ON '" + tableName + "'\n"; + deleteTrigger += "WHEN (SELECT count(*) from " + std::string(DBConstant::RELATIONAL_PREFIX) + "metadata "; + deleteTrigger += "WHERE key = 'log_trigger_switch' AND VALUE = 'true')\n"; + deleteTrigger += "BEGIN\n"; + deleteTrigger += CloudStorageUtils::GetCursorIncSql(tableName) + "\n"; + deleteTrigger += "\t UPDATE " + GetLogTableName(table); + deleteTrigger += " SET data_key=-1,flag=0x03,timestamp=get_sys_time(0)"; + deleteTrigger += table.GetTrackerTable().GetExtendAssignValSql(true); + deleteTrigger += ", cursor=" + CloudStorageUtils::GetSelectIncCursorSql(tableName) + ""; + deleteTrigger += " WHERE data_key = OLD." + std::string(DBConstant::SQLITE_INNER_ROWID) + ";"; + deleteTrigger += "SELECT client_observer('" + tableName + "', -1, 2, "; + deleteTrigger += table.GetTrackerTable().IsEmpty() ? "2" : "3"; + deleteTrigger += ");\n"; + deleteTrigger += "END;"; + return deleteTrigger; +} + +std::vector DeviceTrackerLogTableManager::GetDropTriggers(const TableInfo &table) +{ + std::vector dropTriggers; + std::string tableName = table.GetTableName(); + std::string insertTrigger = "DROP TRIGGER IF EXISTS naturalbase_rdb_" + tableName + "_ON_INSERT; "; + std::string updateTrigger = "DROP TRIGGER IF EXISTS naturalbase_rdb_" + tableName + "_ON_UPDATE; "; + std::string deleteTrigger = "DROP TRIGGER IF EXISTS naturalbase_rdb_" + tableName + "_ON_DELETE; "; + dropTriggers.emplace_back(insertTrigger); + dropTriggers.emplace_back(updateTrigger); + dropTriggers.emplace_back(deleteTrigger); + if (table.GetTrackerTable().IsEmpty()) { + std::string deleteLogTable = "DROP TABLE IF EXISTS " + GetLogTableName(table) + ";"; + dropTriggers.emplace_back(deleteLogTable); + } + return dropTriggers; +} + +std::string DeviceTrackerLogTableManager::GetChangeDataStatus(const TableInfo &table) +{ + // first 2 is p2p change when sync field empty, second 2 is p2p change when sync field update + return GetUpdateWithAssignSql(table, "2", "2", "0"); +} +} diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/device_tracker_log_table_manager.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/device_tracker_log_table_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..7b237da9574e74fe3ab063a3c665666e6874a8ee --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/device_tracker_log_table_manager.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 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 DEVICE_TRACKER_LOG_TABLE_MANAGER_H +#define DEVICE_TRACKER_LOG_TABLE_MANAGER_H + +#include "sqlite_log_table_manager.h" + +namespace DistributedDB { +class DeviceTrackerLogTableManager : public SqliteLogTableManager { +public: + DeviceTrackerLogTableManager() = default; + ~DeviceTrackerLogTableManager() override = default; + + // The parameter "references" is "", "NEW." or "OLD.". "identity" is a hash string that identifies a device. + std::string CalcPrimaryKeyHash(const std::string &references, const TableInfo &table, + const std::string &identity) override; + +private: + void GetIndexSql(const TableInfo &table, std::vector &schema) override; + std::string GetPrimaryKeySql(const TableInfo &table) override; + + // The parameter "identity" is a hash string that identifies a device. The same for the next two functions. + std::string GetInsertTrigger(const TableInfo &table, const std::string &identity) override; + std::string GetUpdateTrigger(const TableInfo &table, const std::string &identity) override; + std::string GetDeleteTrigger(const TableInfo &table, const std::string &identity) override; + std::vector GetDropTriggers(const TableInfo &table) override; + static std::string GetChangeDataStatus(const TableInfo &table); +}; + +} // DistributedDB + +#endif // DEVICE_TRACKER_LOG_TABLE_MANAGER_H diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/split_device_log_table_manager.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/split_device_log_table_manager.cpp index db6145dd97d1443f641afd60e9a0437aef00cbf8..f35962cb84f140fc76ded2e1a77d207763a1b303 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/split_device_log_table_manager.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/split_device_log_table_manager.cpp @@ -102,6 +102,11 @@ std::string SplitDeviceLogTableManager::GetPrimaryKeySql(const TableInfo &table) return "PRIMARY KEY(device, hash_key)"; } +std::string SplitDeviceLogTableManager::GetConflictPkSql(const TableInfo &table) +{ + return "ON CONFLICT(device, hash_key)"; +} + std::vector SplitDeviceLogTableManager::GetDropTriggers(const TableInfo &table) { std::vector dropTriggers; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/split_device_log_table_manager.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/split_device_log_table_manager.h index eef03c17f02ba988f65ca93052ca62d33ddfbbe2..49eda3af5532c51ae33085350a94de77a39fefa2 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/split_device_log_table_manager.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/split_device_log_table_manager.h @@ -27,6 +27,7 @@ public: // The parameter "references" is "", "NEW." or "OLD.". "identity" is a hash string that identifies a device. std::string CalcPrimaryKeyHash(const std::string &references, const TableInfo &table, const std::string &identity) override; + std::string GetConflictPkSql(const TableInfo &table) override; private: std::string GetPrimaryKeySql(const TableInfo &table) override; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_database_upgrader.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_database_upgrader.cpp index a62a9f64b9ed0cae339b44af9930c07486108dfa..9c25c59b2ad67485bfafb258109a39d6fbb254c9 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_database_upgrader.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_database_upgrader.cpp @@ -127,6 +127,7 @@ int SqliteRelationalDatabaseUpgrader::UpgradeTrigger(const std::string &logTable } TableInfo tableInfo = table.second; tableInfo.SetTrackerTable(trackerSchemaObj.GetTrackerTable(table.first)); + tableInfo.SetDistributedTable(schemaObj.GetDistributedTable(table.first)); auto manager = LogTableManagerFactory::GetTableManager(mode, tableInfo.GetTableSyncType()); errCode = manager->AddRelationalLogTableTrigger(db_, tableInfo, ""); if (errCode != E_OK) { diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.cpp index 4b29ee62ba0f1399bbc5386b98d76cea244de19d..b1e7aa986db12729e60bd1a3e79a1271f5554a18 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.cpp @@ -90,11 +90,13 @@ void SQLiteRelationalStore::ReleaseResources() sqliteStorageEngine_->ClearEnginePasswd(); sqliteStorageEngine_ = nullptr; } +#ifdef USE_DISTRIBUTEDDB_CLOUD if (cloudSyncer_ != nullptr) { cloudSyncer_->Close(); RefObject::KillAndDecObjRef(cloudSyncer_); cloudSyncer_ = nullptr; } +#endif RefObject::DecObjRef(storageEngine_); } @@ -158,7 +160,7 @@ int SQLiteRelationalStore::CheckTableModeFromMeta(DistributedTableMode mode, boo return E_OK; // First set table mode. } - if (orgMode != mode) { + if (orgMode == DistributedTableMode::COLLABORATION && orgMode != mode) { LOGE("Check distributed table mode mismatch, orgMode=%d, openMode=%d", orgMode, mode); return -E_INVALID_ARGS; } @@ -183,8 +185,7 @@ int SQLiteRelationalStore::CheckProperties(RelationalDBProperties properties) // Empty schema means no distributed table has been used, we may set DB to any table mode // If there is a schema but no table mode, it is the 'SPLIT_BY_DEVICE' mode of old version bool isSchemaEmpty = (errCode == -E_NOT_FOUND); - auto mode = static_cast( - properties.GetIntProp(RelationalDBProperties::DISTRIBUTED_TABLE_MODE, DistributedTableMode::SPLIT_BY_DEVICE)); + auto mode = properties.GetDistributedTableMode(); errCode = CheckTableModeFromMeta(mode, isSchemaEmpty); if (errCode != E_OK) { LOGE("Get distributed table mode from meta failed. errcode=%d", errCode); @@ -207,7 +208,7 @@ int SQLiteRelationalStore::SaveTableModeToMeta(DistributedTableMode mode) { const Key modeKey(DISTRIBUTED_TABLE_MODE, DISTRIBUTED_TABLE_MODE + strlen(DISTRIBUTED_TABLE_MODE)); Value modeVal; - DBCommon::StringToVector(std::to_string(mode), modeVal); + DBCommon::StringToVector(std::to_string(static_cast(mode)), modeVal); int errCode = storageEngine_->PutMetaData(modeKey, modeVal); if (errCode != E_OK) { LOGE("Save relational schema to meta table failed. %d", errCode); @@ -289,8 +290,9 @@ int SQLiteRelationalStore::Open(const RelationalDBProperties &properties) // to guarantee the life cycle of sync module and syncAbleEngine_ are the same, then the sync module will not // be destructed when close store storageEngine_->SetSyncAbleEngine(syncAbleEngine_); +#ifdef USE_DISTRIBUTEDDB_CLOUD cloudSyncer_ = new (std::nothrow) CloudSyncer(StorageProxy::GetCloudDb(storageEngine_), false); - +#endif errCode = CheckDBMode(); if (errCode != E_OK) { break; @@ -384,11 +386,13 @@ void SQLiteRelationalStore::DecreaseConnectionCounter(uint64_t connectionId) // Sync Close syncAbleEngine_->Close(); +#ifdef USE_DISTRIBUTEDDB_CLOUD if (cloudSyncer_ != nullptr) { cloudSyncer_->Close(); RefObject::KillAndDecObjRef(cloudSyncer_); cloudSyncer_ = nullptr; } +#endif if (sqliteStorageEngine_ != nullptr) { sqliteStorageEngine_ = nullptr; @@ -439,20 +443,8 @@ int SQLiteRelationalStore::CreateDistributedTable(const std::string &tableName, } } - auto mode = static_cast(sqliteStorageEngine_->GetProperties().GetIntProp( - RelationalDBProperties::DISTRIBUTED_TABLE_MODE, DistributedTableMode::SPLIT_BY_DEVICE)); - - std::string localIdentity; // collaboration mode need local identify - if (mode == DistributedTableMode::COLLABORATION) { - int errCode = syncAbleEngine_->GetLocalIdentity(localIdentity); - if (errCode != E_OK || localIdentity.empty()) { - LOGD("Get local identity failed, can not create."); - return -E_NOT_SUPPORT; - } - } - bool schemaChanged = false; - int errCode = sqliteStorageEngine_->CreateDistributedTable(tableName, DBCommon::TransferStringToHex(localIdentity), + int errCode = sqliteStorageEngine_->CreateDistributedTable(tableName, DBCommon::TransferStringToHex(""), schemaChanged, syncType, trackerSchemaChanged); if (errCode != E_OK) { LOGE("Create distributed table failed. %d", errCode); @@ -464,6 +456,7 @@ int SQLiteRelationalStore::CreateDistributedTable(const std::string &tableName, return errCode; } +#ifdef USE_DISTRIBUTEDDB_CLOUD int32_t SQLiteRelationalStore::GetCloudSyncTaskCount() { if (cloudSyncer_ == nullptr) { @@ -475,12 +468,6 @@ int32_t SQLiteRelationalStore::GetCloudSyncTaskCount() int SQLiteRelationalStore::CleanCloudData(ClearMode mode) { - auto tableMode = static_cast(sqliteStorageEngine_->GetProperties().GetIntProp( - RelationalDBProperties::DISTRIBUTED_TABLE_MODE, DistributedTableMode::SPLIT_BY_DEVICE)); - if (tableMode == DistributedTableMode::COLLABORATION) { - LOGE("Not support remove device data in collaboration mode."); - return -E_NOT_SUPPORT; - } RelationalSchemaObject localSchema = sqliteStorageEngine_->GetSchema(); TableInfoMap tables = localSchema.GetTables(); std::vector cloudTableNameList; @@ -508,16 +495,10 @@ int SQLiteRelationalStore::CleanCloudData(ClearMode mode) return errCode; } +#endif int SQLiteRelationalStore::RemoveDeviceData() { - auto mode = static_cast(sqliteStorageEngine_->GetProperties().GetIntProp( - RelationalDBProperties::DISTRIBUTED_TABLE_MODE, DistributedTableMode::SPLIT_BY_DEVICE)); - if (mode == DistributedTableMode::COLLABORATION) { - LOGE("Not support remove device data in collaboration mode."); - return -E_NOT_SUPPORT; - } - std::vector tableNameList = GetAllDistributedTableName(); if (tableNameList.empty()) { return E_OK; @@ -562,13 +543,6 @@ int SQLiteRelationalStore::RemoveDeviceData() int SQLiteRelationalStore::RemoveDeviceData(const std::string &device, const std::string &tableName) { - auto mode = static_cast(sqliteStorageEngine_->GetProperties().GetIntProp( - RelationalDBProperties::DISTRIBUTED_TABLE_MODE, DistributedTableMode::SPLIT_BY_DEVICE)); - if (mode == DistributedTableMode::COLLABORATION) { - LOGE("Not support remove device data in collaboration mode."); - return -E_NOT_SUPPORT; - } - TableInfoMap tables = sqliteStorageEngine_->GetSchema().GetTables(); // TableInfoMap auto iter = tables.find(tableName); if (tables.empty() || (!tableName.empty() && iter == tables.end())) { @@ -776,13 +750,6 @@ int SQLiteRelationalStore::RemoteQuery(const std::string &device, const RemoteCo LOGW("not a distributed relational store."); return -E_NOT_SUPPORT; } - const auto &properties = sqliteStorageEngine_->GetProperties(); - int tableMode = - properties.GetIntProp(RelationalDBProperties::DISTRIBUTED_TABLE_MODE, DistributedTableMode::SPLIT_BY_DEVICE); - if (tableMode != DistributedTableMode::SPLIT_BY_DEVICE) { - LOGW("only support split mode."); - return -E_NOT_SUPPORT; - } // Check whether to be able to operate the db. int errCode = E_OK; @@ -919,12 +886,12 @@ int SQLiteRelationalStore::GetExistDevices(std::set &hashDevices) c return errCode; } -std::vector SQLiteRelationalStore::GetAllDistributedTableName() +std::vector SQLiteRelationalStore::GetAllDistributedTableName(TableSyncType tableSyncType) { TableInfoMap tables = sqliteStorageEngine_->GetSchema().GetTables(); // TableInfoMap std::vector tableNames; for (const auto &table : tables) { - if (table.second.GetTableSyncType() == TableSyncType::CLOUD_COOPERATION) { + if (table.second.GetTableSyncType() != tableSyncType) { continue; } tableNames.push_back(table.second.GetTableName()); @@ -932,6 +899,7 @@ std::vector SQLiteRelationalStore::GetAllDistributedTableName() return tableNames; } +#ifdef USE_DISTRIBUTEDDB_CLOUD int SQLiteRelationalStore::SetCloudDB(const std::shared_ptr &cloudDb) { if (cloudSyncer_ == nullptr) { @@ -941,6 +909,7 @@ int SQLiteRelationalStore::SetCloudDB(const std::shared_ptr &cloudDb) cloudSyncer_->SetCloudDB(cloudDb); return E_OK; } +#endif void SQLiteRelationalStore::AddFields(const std::vector &newFields, const std::set &equalFields, std::vector &addFields) @@ -1042,6 +1011,7 @@ bool SQLiteRelationalStore::PrepareSharedTable(const DataBaseSchema &schema, std return true; } +#ifdef USE_DISTRIBUTEDDB_CLOUD int SQLiteRelationalStore::PrepareAndSetCloudDbSchema(const DataBaseSchema &schema) { if (storageEngine_ == nullptr) { @@ -1070,9 +1040,23 @@ int SQLiteRelationalStore::SetIAssetLoader(const std::shared_ptr & cloudSyncer_->SetIAssetLoader(loader); return E_OK; } +#endif int SQLiteRelationalStore::ChkSchema(const TableName &tableName) { + // check schema is ok + int errCode = E_OK; + auto *handle = GetHandle(false, errCode); + if (handle == nullptr) { + LOGE("[SQLiteRelationalStore][ChkSchema] handle is nullptr"); + return errCode; + } + errCode = handle->CompareSchemaTableColumns(tableName); + ReleaseHandle(handle); + if (errCode != E_OK) { + LOGE("[SQLiteRelationalStore][ChkSchema] local schema info incompatible %d.", errCode); + return errCode; + } if (storageEngine_ == nullptr) { LOGE("[RelationalStore][ChkSchema] storageEngine was not initialized"); return -E_INVALID_DB; @@ -1080,6 +1064,7 @@ int SQLiteRelationalStore::ChkSchema(const TableName &tableName) return storageEngine_->ChkSchema(tableName); } +#ifdef USE_DISTRIBUTEDDB_CLOUD int SQLiteRelationalStore::Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess, uint64_t taskId) { if (storageEngine_ == nullptr) { @@ -1121,6 +1106,14 @@ int SQLiteRelationalStore::CheckBeforeSync(const CloudSyncOption &option) if (option.waitTime > DBConstant::MAX_SYNC_TIMEOUT || option.waitTime < DBConstant::INFINITE_WAIT) { return -E_INVALID_ARGS; } + if (option.priorityLevel < CloudDbConstant::PRIORITY_TASK_DEFALUT_LEVEL || + option.priorityLevel > CloudDbConstant::PRIORITY_TASK_MAX_LEVEL) { + LOGE("[RelationalStore] priority level is invalid value:%d", option.priorityLevel); + return -E_INVALID_ARGS; + } + if (option.compensatedSyncOnly && option.asyncDownloadAssets) { + return -E_NOT_SUPPORT; + } int errCode = CheckQueryValid(option); if (errCode != E_OK) { return errCode; @@ -1163,6 +1156,22 @@ int SQLiteRelationalStore::CheckQueryValid(const CloudSyncOption &option) for (const auto &item : object) { std::string tableName = item.GetRelationTableName(); syncTableNames.emplace_back(tableName); + if (item.IsContainQueryNodes() && option.asyncDownloadAssets) { + LOGE("[RelationalStore] not support async download assets with query table %s length %zu", + DBCommon::StringMiddleMasking(tableName).c_str(), tableName.length()); + return -E_NOT_SUPPORT; + } + if (item.IsAssetsOnly()) { + if (option.mode != SyncMode::SYNC_MODE_CLOUD_FORCE_PULL) { + LOGE("[RelationalStore] not support mode %d when sync with assets only", option.mode); + return -E_NOT_SUPPORT; + } + if (option.priorityLevel != CloudDbConstant::PRIORITY_TASK_MAX_LEVEL) { + LOGE("[RelationalStore] priorityLevel must be 2 when sync with assets only, now is %d", + option.priorityLevel); + return -E_INVALID_ARGS; + } + } } errCode = CheckTableName(syncTableNames); if (errCode != E_OK) { @@ -1244,38 +1253,91 @@ void SQLiteRelationalStore::FillSyncInfo(const CloudSyncOption &option, const Sy info.timeout = option.waitTime; info.priorityTask = option.priorityTask; info.compensatedTask = option.compensatedSyncOnly; - info.users.push_back(""); + info.priorityLevel = option.priorityLevel; + info.users.emplace_back(""); info.lockAction = option.lockAction; info.merge = option.merge; info.storeId = sqliteStorageEngine_->GetProperties().GetStringProp(DBProperties::STORE_ID, ""); info.prepareTraceId = option.prepareTraceId; + info.asyncDownloadAssets = option.asyncDownloadAssets; } +#endif int SQLiteRelationalStore::SetTrackerTable(const TrackerSchema &trackerSchema) { - int errCode = sqliteStorageEngine_->UpdateExtendField(trackerSchema); + TableInfo tableInfo; + bool isFirstCreate = false; + bool isNoTableInSchema = false; + int errCode = CheckTrackerTable(trackerSchema, tableInfo, isNoTableInSchema, isFirstCreate); + if (errCode != E_OK) { + if (errCode != -E_IGNORE_DATA) { + return errCode; + } + auto *handle = GetHandle(true, errCode); + if (handle != nullptr) { + handle->CheckAndCreateTrigger(tableInfo); + ReleaseHandle(handle); + } + return E_OK; + } + errCode = sqliteStorageEngine_->UpdateExtendField(trackerSchema); if (errCode != E_OK) { LOGE("[RelationalStore] update [%s [%zu]] extend_field failed: %d", DBCommon::StringMiddleMasking(trackerSchema.tableName).c_str(), trackerSchema.tableName.size(), errCode); return errCode; } - RelationalSchemaObject localSchema = sqliteStorageEngine_->GetSchema(); - TableInfo tableInfo = localSchema.GetTable(trackerSchema.tableName); - if (tableInfo.Empty()) { - return sqliteStorageEngine_->SetTrackerTable(trackerSchema); - } - bool isFirstCreate = false; - errCode = sqliteStorageEngine_->CheckAndCacheTrackerSchema(trackerSchema, tableInfo, isFirstCreate); - if (errCode != E_OK) { - return errCode == -E_IGNORE_DATA ? E_OK : errCode; + if (isNoTableInSchema) { + return sqliteStorageEngine_->SetTrackerTable(trackerSchema, tableInfo, isFirstCreate); } + sqliteStorageEngine_->CacheTrackerSchema(trackerSchema); errCode = CreateDistributedTable(trackerSchema.tableName, tableInfo.GetTableSyncType(), true); if (errCode != E_OK) { + LOGE("[RelationalStore] create distributed table of [%s [%zu]] failed: %d", + DBCommon::StringMiddleMasking(trackerSchema.tableName).c_str(), trackerSchema.tableName.size(), errCode); return errCode; } return sqliteStorageEngine_->SaveTrackerSchema(trackerSchema.tableName, isFirstCreate); } +int SQLiteRelationalStore::CheckTrackerTable(const TrackerSchema &trackerSchema, TableInfo &table, + bool &isNoTableInSchema, bool &isFirstCreate) +{ + const RelationalSchemaObject &tracker = sqliteStorageEngine_->GetTrackerSchema(); + isFirstCreate = tracker.GetTrackerTable(trackerSchema.tableName).GetTableName().empty(); + RelationalSchemaObject localSchema = sqliteStorageEngine_->GetSchema(); + table = localSchema.GetTable(trackerSchema.tableName); + TrackerTable trackerTable; + trackerTable.Init(trackerSchema); + int errCode = E_OK; + if (table.Empty()) { + isNoTableInSchema = true; + table.SetTableSyncType(TableSyncType::CLOUD_COOPERATION); + auto *handle = GetHandle(true, errCode); + if (handle == nullptr) { + return errCode; + } + errCode = handle->AnalysisTrackerTable(trackerTable, table); + ReleaseHandle(handle); + if (errCode != E_OK) { + LOGE("[CheckTrackerTable] analysis table schema failed %d.", errCode); + return errCode; + } + } else { + table.SetTrackerTable(trackerTable); + errCode = table.CheckTrackerTable(); + if (errCode != E_OK) { + LOGE("[CheckTrackerTable] check tracker table schema failed. %d", errCode); + return errCode; + } + } + if (!trackerSchema.isForceUpgrade && !tracker.GetTrackerTable(trackerSchema.tableName).IsChanging(trackerSchema)) { + LOGW("[CheckTrackerTable] tracker schema is no change, table[%s [%zu]]", + DBCommon::StringMiddleMasking(trackerSchema.tableName).c_str(), trackerSchema.tableName.size()); + return -E_IGNORE_DATA; + } + return E_OK; +} + int SQLiteRelationalStore::ExecuteSql(const SqlCondition &condition, std::vector &records) { if (condition.sql.empty()) { @@ -1308,10 +1370,12 @@ int SQLiteRelationalStore::CleanWaterMark(SQLiteSingleVerRelationalStorageExecut return errCode; } } +#ifdef USE_DISTRIBUTEDDB_CLOUD errCode = cloudSyncer_->CleanWaterMarkInMemory(clearWaterMarkTable); if (errCode != E_OK) { LOGE("[SQLiteRelationalStore] CleanWaterMarkInMemory failed, errCode = %d", errCode); } +#endif return errCode; } @@ -1542,6 +1606,7 @@ int SQLiteRelationalStore::InitSQLiteStorageEngine(const RelationalDBProperties return E_OK; } +#ifdef USE_DISTRIBUTEDDB_CLOUD int SQLiteRelationalStore::CheckCloudSchema(const DataBaseSchema &schema) { if (storageEngine_ == nullptr) { @@ -1589,5 +1654,54 @@ SyncProcess SQLiteRelationalStore::GetCloudTaskStatus(uint64_t taskId) { return cloudSyncer_->GetCloudTaskStatus(taskId); } +#endif + +int SQLiteRelationalStore::SetDistributedSchema(const DistributedSchema &schema) +{ + if (sqliteStorageEngine_ == nullptr || storageEngine_ == nullptr) { + LOGE("[RelationalStore] engine was not initialized"); + return -E_INVALID_DB; + } + auto [errCode, isSchemaChange] = sqliteStorageEngine_->SetDistributedSchema(schema); + if (errCode != E_OK) { + return errCode; + } + if (isSchemaChange) { + LOGI("[RelationalStore] schema was changed by setting distributed schema"); + storageEngine_->NotifySchemaChanged(); + } + return E_OK; +} + +int SQLiteRelationalStore::GetDownloadingAssetsCount(int32_t &count) +{ + std::vector tableNameList = GetAllDistributedTableName(TableSyncType::CLOUD_COOPERATION); + if (tableNameList.empty()) { + return E_OK; + } + + int errCode = E_OK; + SQLiteSingleVerRelationalStorageExecutor *handle = GetHandle(false, errCode); + if (handle == nullptr) { + return errCode; + } + for (const auto &tableName : tableNameList) { + TableSchema tableSchema; + int errCode = storageEngine_->GetCloudTableSchema(tableName, tableSchema); + if (errCode != E_OK) { + LOGE("[RelationalStore] Get schema failed when get download assets count, %d, tableName: %s, length: %zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + break; + } + errCode = handle->GetDownloadingAssetsCount(tableSchema, count); + if (errCode != E_OK) { + LOGE("[RelationalStore] Get download assets count failed: %d, tableName: %s, length: %zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + break; + } + } + ReleaseHandle(handle); + return errCode; +} } // namespace DistributedDB #endif diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.h index 26aea5c5e43dd7e1dd0bf32ba8c7771c5687a653..1af8b4233669b042c532ea00b728df2e6b71ae4e 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.h @@ -30,7 +30,7 @@ namespace DistributedDB { using RelationalObserverAction = - std::function; + std::function; class SQLiteRelationalStore : public IRelationalStore { public: SQLiteRelationalStore() = default; @@ -48,16 +48,12 @@ public: int Sync(const ISyncer::SyncParma &syncParam, uint64_t connectionId); - int32_t GetCloudSyncTaskCount(); - - int CleanCloudData(ClearMode mode); - void ReleaseDBConnection(uint64_t connectionId, RelationalStoreConnection *connection); void WakeUpSyncer() override; // for test mock - const RelationalSyncAbleStorage *GetStorageEngine() + RelationalSyncAbleStorage *GetStorageEngine() { return storageEngine_; } @@ -83,16 +79,10 @@ public: int RemoteQuery(const std::string &device, const RemoteCondition &condition, uint64_t timeout, uint64_t connectionId, std::shared_ptr &result); - int SetCloudDB(const std::shared_ptr &cloudDb); - - int PrepareAndSetCloudDbSchema(const DataBaseSchema &schema); - int SetIAssetLoader(const std::shared_ptr &loader); int ChkSchema(const TableName &tableName); - int Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess, uint64_t taskId); - int SetTrackerTable(const TrackerSchema &trackerSchema); int ExecuteSql(const SqlCondition &condition, std::vector &records); @@ -105,9 +95,25 @@ public: int UpsertData(RecordStatus status, const std::string &tableName, const std::vector &records); + int SetDistributedSchema(const DistributedSchema &schema); + + int GetDownloadingAssetsCount(int32_t &count); + +#ifdef USE_DISTRIBUTEDDB_CLOUD + int PrepareAndSetCloudDbSchema(const DataBaseSchema &schema); + + int32_t GetCloudSyncTaskCount(); + + int CleanCloudData(ClearMode mode); + + int SetCloudDB(const std::shared_ptr &cloudDb); + + int Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess, uint64_t taskId); + int SetCloudSyncConfig(const CloudSyncConfig &config); SyncProcess GetCloudTaskStatus(uint64_t taskId); +#endif private: void ReleaseResources(); @@ -142,7 +148,7 @@ private: int GetExistDevices(std::set &hashDevices) const; - std::vector GetAllDistributedTableName(); + std::vector GetAllDistributedTableName(TableSyncType tableSyncType = DEVICE_COOPERATION); int CheckBeforeSync(const CloudSyncOption &option); @@ -152,9 +158,6 @@ private: int CheckTableName(const std::vector &tableNames); - void FillSyncInfo(const CloudSyncOption &option, const SyncProcessCallback &onProcess, - CloudSyncer::CloudTaskInfo &info); - int CleanWaterMark(SQLiteSingleVerRelationalStorageExecutor *&handle, std::set &clearWaterMarkTable); int InitTrackerSchemaFromMeta(); @@ -178,8 +181,15 @@ private: static int ReFillSyncInfoTable(const std::vector &actualTable, CloudSyncer::CloudTaskInfo &info); - int CheckCloudSchema(const DataBaseSchema &schema); + int CheckTrackerTable(const TrackerSchema &trackerSchema, TableInfo &table, bool &isNoTableInSchema, + bool &isFirstCreate); + +#ifdef USE_DISTRIBUTEDDB_CLOUD + void FillSyncInfo(const CloudSyncOption &option, const SyncProcessCallback &onProcess, + CloudSyncer::CloudTaskInfo &info); + int CheckCloudSchema(const DataBaseSchema &schema); +#endif // use for sync Interactive std::shared_ptr syncAbleEngine_ = nullptr; // For storage operate sync function // use ref obj same as kv diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store_connection.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store_connection.cpp index 45c437bc4097abe5bf37b957263a2c3187f02bb4..a9ddc5dd6727478a8751ca8e788675937370c698 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store_connection.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store_connection.cpp @@ -16,6 +16,7 @@ #include "sqlite_relational_store_connection.h" #include "db_errno.h" #include "log_print.h" +#include "sqlite_relational_utils.h" namespace DistributedDB { SQLiteRelationalStoreConnection::SQLiteRelationalStoreConnection(SQLiteRelationalStore *store) @@ -171,6 +172,7 @@ int SQLiteRelationalStoreConnection::RemoveDeviceData() return errCode; } +#ifdef USE_DISTRIBUTEDDB_CLOUD int32_t SQLiteRelationalStoreConnection::GetCloudSyncTaskCount() { auto *store = GetDB(); @@ -199,6 +201,7 @@ int SQLiteRelationalStoreConnection::DoClean(ClearMode mode) } return errCode; } +#endif int SQLiteRelationalStoreConnection::RemoveDeviceData(const std::string &device) { @@ -300,6 +303,7 @@ int SQLiteRelationalStoreConnection::RemoteQuery(const std::string &device, cons return store->RemoteQuery(device, condition, timeout, GetConnectionId(), result); } +#ifdef USE_DISTRIBUTEDDB_CLOUD int SQLiteRelationalStoreConnection::SetCloudDB(const std::shared_ptr &cloudDb) { auto *store = GetDB(); @@ -340,6 +344,7 @@ int SQLiteRelationalStoreConnection::SetIAssetLoader(const std::shared_ptrUpsertData(status, tableName, records); } +#ifdef USE_DISTRIBUTEDDB_CLOUD int SQLiteRelationalStoreConnection::SetCloudSyncConfig(const CloudSyncConfig &config) { auto *store = GetDB(); @@ -476,5 +482,26 @@ SyncProcess SQLiteRelationalStoreConnection::GetCloudTaskStatus(uint64_t taskId) DecObjRef(this); return process; } +#endif + +int SQLiteRelationalStoreConnection::SetDistributedDbSchema(const DistributedSchema &schema) +{ + auto *store = GetDB(); + if (store == nullptr) { + LOGE("[RelationalConnection] store is null when set distributed schema"); + return -E_INVALID_CONNECTION; + } + return store->SetDistributedSchema(SQLiteRelationalUtils::FilterRepeatDefine(schema)); +} + +int SQLiteRelationalStoreConnection::GetDownloadingAssetsCount(int32_t &count) +{ + auto *store = GetDB(); + if (store == nullptr) { + LOGE("[RelationalConnection] store is null, get executor failed!"); + return -E_INVALID_CONNECTION; + } + return store->GetDownloadingAssetsCount(count); +} } #endif \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store_connection.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store_connection.h index 0107f9b2faffff873200562aeed76338c6985d67..5d4bd5caaca35365f60644ed534a407de8fbbd94 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store_connection.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store_connection.h @@ -35,11 +35,9 @@ public: // Close and release the connection. int Close() override; int SyncToDevice(SyncInfo &info) override; - int32_t GetCloudSyncTaskCount() override; std::string GetIdentifier() override; int CreateDistributedTable(const std::string &tableName, TableSyncType syncType) override; int RegisterLifeCycleCallback(const DatabaseLifeCycleNotifier ¬ifier) override; - int DoClean(ClearMode mode) override; int RemoveDeviceData() override; int RemoveDeviceData(const std::string &device) override; int RemoveDeviceData(const std::string &device, const std::string &tableName) override; @@ -47,9 +45,6 @@ public: int UnRegisterObserverAction(const StoreObserver *observer) override; int RemoteQuery(const std::string &device, const RemoteCondition &condition, uint64_t timeout, std::shared_ptr &result) override; - int SetCloudDB(const std::shared_ptr &cloudDb) override; - int PrepareAndSetCloudDbSchema(const DataBaseSchema &schema) override; - int SetIAssetLoader(const std::shared_ptr &loader) override; int GetStoreInfo(std::string &userId, std::string &appId, std::string &storeId) override; @@ -63,11 +58,26 @@ public: int UpsertData(RecordStatus status, const std::string &tableName, const std::vector &records) override; + int SetDistributedDbSchema(const DistributedSchema &schema) override; + + int GetDownloadingAssetsCount(int32_t &count) override; +#ifdef USE_DISTRIBUTEDDB_CLOUD + int DoClean(ClearMode mode) override; + + int32_t GetCloudSyncTaskCount() override; + + int SetCloudDB(const std::shared_ptr &cloudDb) override; + + int PrepareAndSetCloudDbSchema(const DataBaseSchema &schema) override; + + int SetIAssetLoader(const std::shared_ptr &loader) override; + int SetCloudSyncConfig(const CloudSyncConfig &config) override; int Sync(const CloudSyncOption &option, const SyncProcessCallback &onProcess, uint64_t taskId) override; SyncProcess GetCloudTaskStatus(uint64_t taskId) override; +#endif protected: int Pragma(int cmd, void *parameter) override; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.cpp index b81e8bacc1a900a01f672604f203c5db70f4652a..e8a18f5fcd3bc5898b8694189ffcff8edfdfeb2e 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.cpp @@ -465,4 +465,273 @@ int SQLiteRelationalUtils::GetCursor(sqlite3 *db, const std::string &tableName, } return cursor == DBConstant::INVALID_CURSOR ? errCode : E_OK; } + +void GetFieldsNeedContain(const TableInfo &tableInfo, const std::vector &syncFields, + std::set &fieldsNeedContain, std::set &requiredNotNullFields) +{ + // should not decrease distributed field + for (const auto &syncField : syncFields) { + if (!tableInfo.IsPrimaryKey(syncField.GetFieldName())) { + fieldsNeedContain.insert(syncField.GetFieldName()); + } + } + const std::vector &uniqueDefines = tableInfo.GetUniqueDefine(); + for (const auto &compositeFields : uniqueDefines) { + for (const auto &fieldName : compositeFields) { + if (tableInfo.IsPrimaryKey(fieldName)) { + continue; + } + fieldsNeedContain.insert(fieldName); + } + } + const FieldInfoMap &fieldInfoMap = tableInfo.GetFields(); + for (const auto &entry : fieldInfoMap) { + const FieldInfo &fieldInfo = entry.second; + if (fieldInfo.IsNotNull() && fieldInfo.GetDefaultValue().empty()) { + requiredNotNullFields.insert(fieldInfo.GetFieldName()); + } + } +} + +bool CheckRequireFieldsInMap(const std::set &fieldsNeedContain, + const std::map &fieldsMap) +{ + for (auto &fieldNeedContain : fieldsNeedContain) { + if (fieldsMap.find(fieldNeedContain) == fieldsMap.end()) { + LOGE("Required column[%s [%zu]] not found", DBCommon::StringMiddleMasking(fieldNeedContain).c_str(), + fieldNeedContain.size()); + return false; + } + if (!fieldsMap.at(fieldNeedContain)) { + LOGE("The isP2pSync of required column[%s [%zu]] is false", + DBCommon::StringMiddleMasking(fieldNeedContain).c_str(), fieldNeedContain.size()); + return false; + } + } + return true; +} + +bool IsDistributedPkInvalid(const TableInfo &tableInfo, + const std::set &distributedPk, + const std::vector &originFields) +{ + auto lastDistributedPk = DBCommon::TransformToCaseInsensitive(tableInfo.GetSyncDistributedPk()); + if (!lastDistributedPk.empty() && distributedPk != lastDistributedPk) { + LOGE("distributed pk has change last %zu now %zu", lastDistributedPk.size(), distributedPk.size()); + return true; + } + // check pk is same or local pk is auto increase and set pk is unique + if (tableInfo.IsNoPkTable()) { + return false; + } + if (tableInfo.GetAutoIncrement()) { + if (distributedPk.empty()) { + return false; + } + auto uniqueDefine = tableInfo.GetUniqueDefine(); + bool isMissMatch = true; + for (const auto &item : uniqueDefine) { + // unique index field count should be same + if (item.size() != distributedPk.size()) { + continue; + } + if (distributedPk == DBCommon::TransformToCaseInsensitive(item)) { + isMissMatch = false; + break; + } + } + if (isMissMatch) { + LOGE("Miss match distributed pk size %zu in auto increment table %s", distributedPk.size(), + DBCommon::StringMiddleMasking(tableInfo.GetTableName()).c_str()); + } + return isMissMatch; + } + for (const auto &field : originFields) { + bool isLocalPk = tableInfo.IsPrimaryKey(field.colName); + if (field.isSpecified && !isLocalPk) { + LOGE("Column[%s [%zu]] is not primary key but mark specified", + DBCommon::StringMiddleMasking(field.colName).c_str(), field.colName.size()); + return true; + } + if (isLocalPk && !field.isP2pSync) { + LOGE("Column[%s [%zu]] is primary key but set isP2pSync false", + DBCommon::StringMiddleMasking(field.colName).c_str(), field.colName.size()); + return true; + } + } + return false; +} + +int CheckDistributedSchemaFields(const TableInfo &tableInfo, const std::vector &syncFields, + const std::vector &fields) +{ + if (fields.empty()) { + LOGE("fields cannot be empty"); + return -E_SCHEMA_MISMATCH; + } + std::set distributedPk; + for (const auto &field : fields) { + if (!tableInfo.IsFieldExist(field.colName)) { + LOGE("Column[%s [%zu]] not found in table", DBCommon::StringMiddleMasking(field.colName).c_str(), + field.colName.size()); + return -E_SCHEMA_MISMATCH; + } + if (field.isSpecified && field.isP2pSync) { + distributedPk.insert(field.colName); + } + } + if (IsDistributedPkInvalid(tableInfo, distributedPk, fields)) { + return -E_SCHEMA_MISMATCH; + } + std::set fieldsNeedContain; + std::set requiredNotNullFields; + GetFieldsNeedContain(tableInfo, syncFields, fieldsNeedContain, requiredNotNullFields); + std::map fieldsMap; + for (auto &field : fields) { + fieldsMap.insert({field.colName, field.isP2pSync}); + } + if (!CheckRequireFieldsInMap(fieldsNeedContain, fieldsMap)) { + LOGE("The required fields are not found in fieldsMap"); + return -E_DISTRIBUTED_FIELD_DECREASE; + } + if (!CheckRequireFieldsInMap(requiredNotNullFields, fieldsMap)) { + LOGE("The required not-null fields are not found in fieldsMap"); + return -E_SCHEMA_MISMATCH; + } + return E_OK; +} + +int SQLiteRelationalUtils::CheckDistributedSchemaValid(const RelationalSchemaObject &schemaObj, + const DistributedSchema &schema, SQLiteSingleVerRelationalStorageExecutor *executor) +{ + if (executor == nullptr) { + LOGE("[RDBUtils][CheckDistributedSchemaValid] executor is null"); + return -E_INVALID_ARGS; + } + sqlite3 *db; + int errCode = executor->GetDbHandle(db); + if (errCode != E_OK) { + LOGE("[RDBUtils][CheckDistributedSchemaValid] sqlite handle failed %d", errCode); + return errCode; + } + for (const auto &table : schema.tables) { + if (table.tableName.empty()) { + LOGE("[RDBUtils][CheckDistributedSchemaValid] Table name cannot be empty"); + return -E_SCHEMA_MISMATCH; + } + TableInfo tableInfo; + errCode = SQLiteUtils::AnalysisSchema(db, table.tableName, tableInfo); + if (errCode != E_OK) { + LOGE("[RDBUtils][CheckDistributedSchemaValid] analyze table %s failed %d", + DBCommon::StringMiddleMasking(table.tableName).c_str(), errCode); + return errCode == -E_NOT_FOUND ? -E_SCHEMA_MISMATCH : errCode; + } + tableInfo.SetDistributedTable(schemaObj.GetDistributedTable(table.tableName)); + errCode = CheckDistributedSchemaFields(tableInfo, schemaObj.GetSyncFieldInfo(table.tableName, false), + table.fields); + if (errCode != E_OK) { + LOGE("[CheckDistributedSchema] Check fields of [%s [%zu]] fail", + DBCommon::StringMiddleMasking(table.tableName).c_str(), table.tableName.size()); + return errCode; + } + } + return E_OK; +} + +DistributedSchema SQLiteRelationalUtils::FilterRepeatDefine(const DistributedSchema &schema) +{ + DistributedSchema res; + res.version = schema.version; + std::set tableName; + std::list tableList; + for (auto it = schema.tables.rbegin();it != schema.tables.rend(); it++) { + if (tableName.find(it->tableName) != tableName.end()) { + continue; + } + tableName.insert(it->tableName); + tableList.push_front(FilterRepeatDefine(*it)); + } + for (auto &item : tableList) { + res.tables.push_back(std::move(item)); + } + return res; +} + +DistributedTable SQLiteRelationalUtils::FilterRepeatDefine(const DistributedTable &table) +{ + DistributedTable res; + res.tableName = table.tableName; + std::set fieldName; + std::list fieldList; + for (auto it = table.fields.rbegin();it != table.fields.rend(); it++) { + if (fieldName.find(it->colName) != fieldName.end()) { + continue; + } + fieldName.insert(it->colName); + fieldList.push_front(*it); + } + for (auto &item : fieldList) { + res.fields.push_back(std::move(item)); + } + return res; +} + +int SQLiteRelationalUtils::GetLogData(sqlite3_stmt *logStatement, LogInfo &logInfo) +{ + logInfo.dataKey = sqlite3_column_int64(logStatement, 0); // 0 means dataKey index + + std::vector dev; + int errCode = SQLiteUtils::GetColumnBlobValue(logStatement, 1, dev); // 1 means dev index + if (errCode != E_OK) { + LOGE("[SQLiteRDBUtils] Get dev failed %d", errCode); + return errCode; + } + logInfo.device = std::string(dev.begin(), dev.end()); + + std::vector oriDev; + errCode = SQLiteUtils::GetColumnBlobValue(logStatement, 2, oriDev); // 2 means ori_dev index + if (errCode != E_OK) { + LOGE("[SQLiteRDBUtils] Get ori dev failed %d", errCode); + return errCode; + } + logInfo.originDev = std::string(oriDev.begin(), oriDev.end()); + logInfo.timestamp = static_cast(sqlite3_column_int64(logStatement, 3)); // 3 means timestamp index + logInfo.wTimestamp = static_cast(sqlite3_column_int64(logStatement, 4)); // 4 means w_timestamp index + logInfo.flag = static_cast(sqlite3_column_int64(logStatement, 5)); // 5 means flag index + logInfo.flag &= (~DataItem::LOCAL_FLAG); + logInfo.flag &= (~DataItem::UPDATE_FLAG); + errCode = SQLiteUtils::GetColumnBlobValue(logStatement, 6, logInfo.hashKey); // 6 means hashKey index + if (errCode != E_OK) { + LOGE("[SQLiteRDBUtils] Get hashKey failed %d", errCode); + } + return errCode; +} + +int SQLiteRelationalUtils::GetLogInfoPre(sqlite3_stmt *queryStmt, DistributedTableMode mode, + const DataItem &dataItem, LogInfo &logInfoGet) +{ + if (queryStmt == nullptr) { + return -E_INVALID_ARGS; + } + int errCode = SQLiteUtils::BindBlobToStatement(queryStmt, 1, dataItem.hashKey); // 1 means hash key index. + if (errCode != E_OK) { + LOGE("[SQLiteRDBUtils] Bind hashKey failed %d", errCode); + return errCode; + } + if (mode != DistributedTableMode::COLLABORATION) { + errCode = SQLiteUtils::BindTextToStatement(queryStmt, 2, dataItem.dev); // 2 means device index. + if (errCode != E_OK) { + LOGE("[SQLiteRDBUtils] Bind dev failed %d", errCode); + return errCode; + } + } + + errCode = SQLiteUtils::StepWithRetry(queryStmt, false); // rdb not exist mem db + if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + errCode = -E_NOT_FOUND; + } else { + errCode = SQLiteRelationalUtils::GetLogData(queryStmt, logInfoGet); + } + return errCode; +} } // namespace DistributedDB \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.h index e48299af6230a095504d4d5451ec5b79769ac8d6..e57f8d2c98f68d36c3de440e696666aefaef0a72 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_utils.h @@ -20,6 +20,7 @@ #include "cloud/cloud_store_types.h" #include "data_value.h" #include "sqlite_import.h" +#include "sqlite_single_ver_relational_storage_executor.h" #include "table_info.h" namespace DistributedDB { @@ -49,6 +50,18 @@ public: static int QueryCount(sqlite3 *db, const std::string &tableName, int64_t &count); static int GetCursor(sqlite3 *db, const std::string &tableName, uint64_t &cursor); + + static int CheckDistributedSchemaValid(const RelationalSchemaObject &schemaObj, const DistributedSchema &schema, + SQLiteSingleVerRelationalStorageExecutor *executor); + + static DistributedSchema FilterRepeatDefine(const DistributedSchema &schema); + + static DistributedTable FilterRepeatDefine(const DistributedTable &table); + + static int GetLogData(sqlite3_stmt *logStatement, LogInfo &logInfo); + + static int GetLogInfoPre(sqlite3_stmt *queryStmt, DistributedTableMode mode, const DataItem &dataItem, + LogInfo &logInfoGet); private: static int BindExtendStatementByType(sqlite3_stmt *statement, int cid, Type &typeVal); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_relational_storage_engine.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_relational_storage_engine.cpp index 4b200c9bc703ce3c4e788627d9dbba1c615c0074..18e0cc54e0c1fe07799e0ff949263ef9a0451f5f 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_relational_storage_engine.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_relational_storage_engine.cpp @@ -34,8 +34,7 @@ SQLiteSingleRelationalStorageEngine::~SQLiteSingleRelationalStorageEngine() StorageExecutor *SQLiteSingleRelationalStorageEngine::NewSQLiteStorageExecutor(sqlite3 *dbHandle, bool isWrite, bool isMemDb) { - auto mode = static_cast(properties_.GetIntProp(RelationalDBProperties::DISTRIBUTED_TABLE_MODE, - DistributedTableMode::SPLIT_BY_DEVICE)); + auto mode = properties_.GetDistributedTableMode(); return new (std::nothrow) SQLiteSingleVerRelationalStorageExecutor(dbHandle, isWrite, mode); } @@ -188,7 +187,7 @@ int SaveSyncTableTypeAndDropFlagToMeta(SQLiteSingleVerRelationalStorageExecutor LOGE("Save sync table type to meta table failed. %d", errCode); return errCode; } - DBCommon::StringToVector(DBConstant::TABLE_IS_DROPPED + tableName, key); + DBCommon::StringToVector(DBConstant::TABLE_WAS_DROPPED + tableName, key); errCode = handle->DeleteMetaData({ key }); if (errCode != E_OK) { LOGE("Save table drop flag to meta table failed. %d", errCode); @@ -281,14 +280,10 @@ int SQLiteSingleRelationalStorageEngine::CreateDistributedTable(const std::strin table.SetTableName(tableName); table.SetTableSyncType(tableSyncType); table.SetTrackerTable(GetTrackerSchema().GetTrackerTable(tableName)); + table.SetDistributedTable(schema.GetDistributedTable(tableName)); if (isUpgraded) { table.SetSourceTableReference(schema.GetTable(tableName).GetTableReference()); } - if (!table.GetTrackerTable().IsEmpty() && tableSyncType == TableSyncType::DEVICE_COOPERATION) { - LOGE("current is trackerTable, not support creating device distributed table. %d", errCode); - (void)handle->Rollback(); - return -E_NOT_SUPPORT; - } errCode = CreateDistributedTable(handle, isUpgraded, identity, table, schema); if (errCode != E_OK) { LOGE("create distributed table failed. %d", errCode); @@ -305,8 +300,7 @@ int SQLiteSingleRelationalStorageEngine::CreateDistributedTable(const std::strin int SQLiteSingleRelationalStorageEngine::CreateDistributedTable(SQLiteSingleVerRelationalStorageExecutor *&handle, bool isUpgraded, const std::string &identity, TableInfo &table, RelationalSchemaObject &schema) { - auto mode = static_cast(properties_.GetIntProp( - RelationalDBProperties::DISTRIBUTED_TABLE_MODE, DistributedTableMode::SPLIT_BY_DEVICE)); + auto mode = properties_.GetDistributedTableMode(); TableSyncType tableSyncType = table.GetTableSyncType(); std::string tableName = table.GetTableName(); int errCode = handle->InitCursorToMeta(tableName); @@ -314,7 +308,7 @@ int SQLiteSingleRelationalStorageEngine::CreateDistributedTable(SQLiteSingleVerR LOGE("init cursor to meta failed. %d", errCode); return errCode; } - errCode = handle->CreateDistributedTable(mode, isUpgraded, identity, table, tableSyncType); + errCode = handle->CreateDistributedTable(mode, isUpgraded, identity, table); if (errCode != E_OK) { LOGE("create distributed table failed. %d", errCode); return errCode; @@ -355,8 +349,7 @@ int SQLiteSingleRelationalStorageEngine::UpgradeDistributedTable(const std::stri return errCode; } - auto mode = static_cast(properties_.GetIntProp( - RelationalDBProperties::DISTRIBUTED_TABLE_MODE, DistributedTableMode::SPLIT_BY_DEVICE)); + auto mode = properties_.GetDistributedTableMode(); errCode = handle->UpgradeDistributedTable(tableName, mode, schemaChanged, schema, syncType); if (errCode != E_OK) { LOGE("Upgrade distributed table failed. %d", errCode); @@ -456,7 +449,8 @@ int SQLiteSingleRelationalStorageEngine::CreateRelationalMetaTable(sqlite3 *db) return errCode; } -int SQLiteSingleRelationalStorageEngine::SetTrackerTable(const TrackerSchema &schema) +int SQLiteSingleRelationalStorageEngine::SetTrackerTable(const TrackerSchema &schema, const TableInfo &tableInfo, + bool isFirstCreate) { int errCode = E_OK; auto *handle = static_cast(FindExecutor(true, OperatePerm::NORMAL_PERM, @@ -471,15 +465,8 @@ int SQLiteSingleRelationalStorageEngine::SetTrackerTable(const TrackerSchema &sc return errCode; } RelationalSchemaObject tracker = trackerSchema_; - if (!tracker.GetTrackerTable(schema.tableName).IsChanging(schema) && !schema.isForceUpgrade) { - (void)handle->Rollback(); - ReleaseExecutor(handle); - LOGW("tracker schema is no change."); - return E_OK; - } - bool isFirstCreate = tracker.GetTrackerTable(schema.tableName).GetTableName().empty(); tracker.InsertTrackerSchema(schema); - int ret = handle->CreateTrackerTable(tracker.GetTrackerTable(schema.tableName), isFirstCreate); + int ret = handle->CreateTrackerTable(tracker.GetTrackerTable(schema.tableName), tableInfo, isFirstCreate); if (ret != E_OK && ret != -E_WITH_INVENTORY_DATA) { (void)handle->Rollback(); ReleaseExecutor(handle); @@ -507,42 +494,13 @@ int SQLiteSingleRelationalStorageEngine::SetTrackerTable(const TrackerSchema &sc return ret; } -int SQLiteSingleRelationalStorageEngine::CheckAndCacheTrackerSchema(const TrackerSchema &schema, TableInfo &tableInfo, - bool &isFirstCreate) +void SQLiteSingleRelationalStorageEngine::CacheTrackerSchema(const TrackerSchema &schema) { - if (tableInfo.GetTableSyncType() == TableSyncType::DEVICE_COOPERATION) { - return -E_NOT_SUPPORT; - } - int errCode = E_OK; - auto *handle = static_cast(FindExecutor(true, - OperatePerm::NORMAL_PERM, errCode)); - if (handle == nullptr) { - return errCode; - } - RelationalSchemaObject tracker = trackerSchema_; - if (!tracker.GetTrackerTable(schema.tableName).IsChanging(schema) && !schema.isForceUpgrade) { // LCOV_EXCL_BR_LINE - ReleaseExecutor(handle); - LOGW("tracker schema is no change for distributed table."); - return -E_IGNORE_DATA; - } - isFirstCreate = tracker.GetTrackerTable(schema.tableName).GetTableName().empty(); - tracker.InsertTrackerSchema(schema); - tableInfo.SetTrackerTable(tracker.GetTrackerTable(schema.tableName)); - errCode = tableInfo.CheckTrackerTable(); - if (errCode != E_OK) { - LOGE("check tracker table schema failed. %d", errCode); - ReleaseExecutor(handle); - return errCode; - } - + trackerSchema_.InsertTrackerSchema(schema); if (!schema.isTrackAction && schema.trackerColNames.empty()) { // if isTrackAction be false and trackerColNames is empty, will remove the tracker schema. - tracker.RemoveTrackerSchema(schema); + trackerSchema_.RemoveTrackerSchema(schema); } - - trackerSchema_ = tracker; - ReleaseExecutor(handle); - return errCode; } int SQLiteSingleRelationalStorageEngine::GetOrInitTrackerSchemaFromMeta() @@ -670,8 +628,7 @@ int SQLiteSingleRelationalStorageEngine::SetReference(const std::vector(properties_.GetIntProp( - RelationalDBProperties::DISTRIBUTED_TABLE_MODE, DistributedTableMode::SPLIT_BY_DEVICE)); + auto mode = properties_.GetDistributedTableMode(); for (auto &table : schema.GetTables()) { if (table.second.GetTableSyncType() == TableSyncType::DEVICE_COOPERATION) { continue; @@ -1085,12 +1042,6 @@ int SQLiteSingleRelationalStorageEngine::UpdateExtendField(const DistributedDB:: if (schema.extendColNames.empty()) { return E_OK; } - RelationalSchemaObject tracker = trackerSchema_; - if (!tracker.GetTrackerTable(schema.tableName).IsChanging(schema) && !schema.isForceUpgrade) { - LOGI("[%s [%zu]] tracker schema is no change.", DBCommon::StringMiddleMasking(schema.tableName).c_str(), - schema.tableName.size()); - return E_OK; - } int errCode = E_OK; auto *handle = static_cast(FindExecutor(true, OperatePerm::NORMAL_PERM, errCode)); @@ -1112,6 +1063,7 @@ int SQLiteSingleRelationalStorageEngine::UpdateExtendField(const DistributedDB:: return errCode; } + RelationalSchemaObject tracker = trackerSchema_; TrackerTable oldTrackerTable = tracker.GetTrackerTable(schema.tableName); const std::set& oldExtendColNames = oldTrackerTable.GetExtendNames(); const std::string lowVersionExtendColName = oldTrackerTable.GetExtendName(); @@ -1127,5 +1079,78 @@ int SQLiteSingleRelationalStorageEngine::UpdateExtendField(const DistributedDB:: } return handle->Commit(); } + +std::pair SQLiteSingleRelationalStorageEngine::SetDistributedSchema(const DistributedSchema &schema) +{ + std::lock_guard autoLock(createDistributedTableMutex_); + auto schemaObj = GetSchema(); + std::pair res = {E_OK, schemaObj.CheckDistributedSchemaChange(schema)}; + auto &[errCode, isSchemaChange] = res; + if (properties_.GetDistributedTableMode() == DistributedTableMode::SPLIT_BY_DEVICE) { + LOGE("tableMode SPLIT_BY_DEVICE not support set distributed schema"); + errCode = -E_NOT_SUPPORT; + return res; + } + if (!isSchemaChange) { + return res; + } + auto localSchema = schemaObj.GetDistributedSchema(); + if (localSchema.version != 0 && localSchema.version >= schema.version) { + LOGE("new schema version no upgrade old:%" PRIu32 " new:%" PRIu32, localSchema.version, schema.version); + errCode = -E_INVALID_ARGS; + } else { + errCode = SetDistributedSchemaInner(schemaObj, schema); + } + if (errCode == E_OK) { + SetSchema(schemaObj); + } + return res; +} + +int SQLiteSingleRelationalStorageEngine::SetDistributedSchemaInner(RelationalSchemaObject &schemaObj, + const DistributedSchema &schema) +{ + int errCode = E_OK; + auto *handle = static_cast(FindExecutor(true, OperatePerm::NORMAL_PERM, + errCode)); + if (handle == nullptr) { + return errCode; + } + ResFinalizer resFinalizer([this, handle]() { + auto rdbHandle = handle; + ReleaseExecutor(rdbHandle); + }); + + errCode = handle->StartTransaction(TransactType::IMMEDIATE); + if (errCode != E_OK) { + return errCode; + } + errCode = SQLiteRelationalUtils::CheckDistributedSchemaValid(schemaObj, schema, handle); + if (errCode != E_OK) { + (void)handle->Rollback(); + return errCode; + } + schemaObj.SetDistributedSchema(schema); + for (const auto &table : schema.tables) { + TableInfo tableInfo = schemaObj.GetTable(table.tableName); + if (tableInfo.Empty()) { + continue; + } + tableInfo.SetDistributedTable(schemaObj.GetDistributedTable(table.tableName)); + errCode = handle->RenewTableTrigger(schemaObj.GetTableMode(), tableInfo, tableInfo.GetTableSyncType()); + if (errCode != E_OK) { + LOGE("Failed to refresh trigger while setting up distributed schema: %d", errCode); + (void)handle->Rollback(); + return errCode; + } + } + errCode = SaveSchemaToMetaTable(handle, schemaObj); + if (errCode != E_OK) { + LOGE("Save schema to meta table for set distributed schema failed. %d", errCode); + (void)handle->Rollback(); + return errCode; + } + return handle->Commit(); +} } #endif \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_relational_storage_engine.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_relational_storage_engine.h index ee3f36a20b2871f42ce6b356a98fba24eec23935..c7e8f359edcdd3b46c9ba88f89e4be18ddcf0551 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_relational_storage_engine.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_relational_storage_engine.h @@ -43,8 +43,8 @@ public: const RelationalDBProperties &GetProperties() const; void SetProperties(const RelationalDBProperties &properties); - int SetTrackerTable(const TrackerSchema &schema); - int CheckAndCacheTrackerSchema(const TrackerSchema &schema, TableInfo &tableInfo, bool &isFirstCreate); + int SetTrackerTable(const TrackerSchema &schema, const TableInfo &tableInfo, bool isFirstCreate); + void CacheTrackerSchema(const TrackerSchema &schema); int GetOrInitTrackerSchemaFromMeta(); int SaveTrackerSchema(const std::string &tableName, bool isFirstCreate); @@ -61,6 +61,8 @@ public: std::pair, int> CalTableRef(const std::vector &tableNames, const std::map &sharedTableOriginNames); int UpdateExtendField(const TrackerSchema &schema); + + std::pair SetDistributedSchema(const DistributedSchema &schema); protected: StorageExecutor *NewSQLiteStorageExecutor(sqlite3 *dbHandle, bool isWrite, bool isMemDb) override; int Upgrade(sqlite3 *db) override; @@ -122,6 +124,8 @@ private: int CheckIfExistUserTable(SQLiteSingleVerRelationalStorageExecutor *&handle, const DataBaseSchema &cloudSchema, const std::map &alterTableNames, const RelationalSchemaObject &schema); + int SetDistributedSchemaInner(RelationalSchemaObject &schemaObj, const DistributedSchema &schema); + RelationalSchemaObject schema_; RelationalSchemaObject trackerSchema_; mutable std::mutex schemaMutex_; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_continue_token.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_continue_token.cpp index 3b355030ca5c29f8de5550d6b4d3135a837a5e18..1a66c016b7b095d0c6c6b5fb0b485db56d7a2f46 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_continue_token.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_continue_token.cpp @@ -20,7 +20,8 @@ namespace DistributedDB { SQLiteSingleVerRelationalContinueToken::SQLiteSingleVerRelationalContinueToken( const SyncTimeRange &timeRange, const QueryObject &queryObject) : isGettingDeletedData_(false), queryObj_(queryObject), tableName_(queryObj_.GetTableName()), timeRange_(timeRange) -{} +{ +} bool SQLiteSingleVerRelationalContinueToken::CheckValid() const { @@ -211,5 +212,15 @@ int SQLiteSingleVerRelationalContinueToken::ReleaseCloudStatement() queryStmt_ = nullptr; return errCode; } + +bool SQLiteSingleVerRelationalContinueToken::IsUseLocalSchema() const +{ + return queryObj_.IsUseLocalSchema(); +} + +std::string SQLiteSingleVerRelationalContinueToken::GetRemoteDev() const +{ + return queryObj_.GetRemoteDev(); +} } // namespace DistributedDB #endif \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_continue_token.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_continue_token.h index 8be8e6197167106f2ee84fa2ea1d06320362c666..8ebb63175bce15dd69dc431acd945a00c7f8759d 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_continue_token.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_continue_token.h @@ -43,6 +43,8 @@ public: int GetCloudStatement(sqlite3 *db, CloudSyncData &cloudDataResult, sqlite3_stmt *&queryStmt, bool &isFirstTime); void GetCloudTableSchema(TableSchema &tableSchema) const; int ReleaseCloudStatement(); + bool IsUseLocalSchema() const; + std::string GetRemoteDev() const; private: std::string GetDeletedDataSQL() const; int GetQuerySyncStatement(sqlite3 *db, sqlite3_stmt *&stmt); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor.cpp index 6d3c932f91b35e0b9a32c8751a52a46c8c965b97..f04ef6de997df8e7a9c3d85368cae6f5507bde53 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor.cpp @@ -30,6 +30,7 @@ #include "sqlite_relational_utils.h" #include "time_helper.h" #include "value_hash_calc.h" +#include "device_tracker_log_table_manager.h" namespace DistributedDB { namespace { @@ -113,11 +114,6 @@ int CheckTableConstraint(const TableInfo &table, DistributedTableMode mode, Tabl return -E_NOT_SUPPORT; } - if (DBCommon::HasConstraint(trimedSql, "ON CONFLICT", " )", " ")) { - LOGE("[CreateDistributedTable] Not support create distributed table with 'ON CONFLICT' constraint."); - return -E_NOT_SUPPORT; - } - if (mode == DistributedTableMode::COLLABORATION) { if (DBCommon::HasConstraint(trimedSql, "REFERENCES", " )", " ")) { LOGE("[CreateDistributedTable] Not support create distributed table with 'FOREIGN KEY' constraint."); @@ -162,6 +158,24 @@ int GetExistedDataTimeOffset(sqlite3 *db, const std::string &tableName, bool isM SQLiteUtils::ResetStatement(stmt, true, errCode); return errCode; } + +int GetMetaLocalTimeOffset(sqlite3 *db, int64_t &timeOffset) +{ + std::string sql = "SELECT value FROM " + DBCommon::GetMetaTableName() + " WHERE key=x'" + + DBCommon::TransferStringToHex(std::string(DBConstant::LOCALTIME_OFFSET_KEY)) + "';"; + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(db, sql, stmt); + if (errCode != E_OK) { + return errCode; + } + errCode = SQLiteUtils::StepWithRetry(stmt); + if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + timeOffset = static_cast(sqlite3_column_int64(stmt, 0)); + errCode = E_OK; + } + SQLiteUtils::ResetStatement(stmt, true, errCode); + return errCode; +} } std::string GetExtendValue(const TrackerTable &trackerTable) @@ -181,9 +195,13 @@ std::string GetExtendValue(const TrackerTable &trackerTable) return extendValue; } -int SQLiteSingleVerRelationalStorageExecutor::GeneLogInfoForExistedData(sqlite3 *db, const std::string &tableName, - const std::string &calPrimaryKeyHash, TableInfo &tableInfo) +int SQLiteSingleVerRelationalStorageExecutor::GeneLogInfoForExistedData(sqlite3 *db, const std::string &identity, + const TableInfo &tableInfo, std::unique_ptr &logMgrPtr) { + std::string tableName = tableInfo.GetTableName(); + if (tableInfo.GetTableSyncType() == TableSyncType::DEVICE_COOPERATION) { + return UpdateTrackerTableTimeStamp(db, identity, tableInfo, logMgrPtr, false); + } int64_t timeOffset = 0; int errCode = GetExistedDataTimeOffset(db, tableName, isMemDb_, timeOffset); if (errCode != E_OK) { @@ -198,18 +216,9 @@ int SQLiteSingleVerRelationalStorageExecutor::GeneLogInfoForExistedData(sqlite3 std::string rowid = std::string(DBConstant::SQLITE_INNER_ROWID); std::string flag = std::to_string(static_cast(LogInfoFlag::FLAG_LOCAL) | static_cast(LogInfoFlag::FLAG_DEVICE_CLOUD_INCONSISTENCY)); - if (tableInfo.GetTableSyncType() == TableSyncType::DEVICE_COOPERATION) { - std::string sql = "INSERT OR REPLACE INTO " + logTable + " SELECT " + rowid + ", '', '', " + timeOffsetStr + - " + " + rowid + ", " + timeOffsetStr + " + " + rowid + ", " + flag + ", " + calPrimaryKeyHash + ", '', " + - "'', '', '', '', 0 FROM '" + tableName + "' AS a WHERE 1=1;"; - errCode = SQLiteUtils::ExecuteRawSQL(db, sql); - if (errCode != E_OK) { - LOGE("Failed to initialize device type log data.%d", errCode); - } - return errCode; - } TrackerTable trackerTable = tableInfo.GetTrackerTable(); trackerTable.SetTableName(tableName); + std::string calPrimaryKeyHash = logMgrPtr->CalcPrimaryKeyHash("a.", tableInfo, identity); std::string sql = "INSERT OR REPLACE INTO " + logTable + " SELECT " + rowid + ", '', '', " + timeOffsetStr + " + " + rowid + ", " + timeOffsetStr + " + " + rowid + ", " + flag + ", " + calPrimaryKeyHash + ", '', "; @@ -241,11 +250,54 @@ int SQLiteSingleVerRelationalStorageExecutor::ResetLogStatus(std::string &tableN return errCode; } +int SQLiteSingleVerRelationalStorageExecutor::UpdateTrackerTableTimeStamp(sqlite3 *db, const std::string &identity, + const TableInfo &tableInfo, std::unique_ptr &logMgrPtr, bool isRowReplace) +{ + int64_t errCode = SetLogTriggerStatus(false); + if (errCode != E_OK) { + return errCode; + } + int64_t localTimeOffset = 0; + errCode = GetMetaLocalTimeOffset(db, localTimeOffset); + if (errCode != E_OK) { + LOGE("Failed to get local timeOffset.%d", errCode); + return errCode; + } + std::string tableName = tableInfo.GetTableName(); + std::string logTable = DBCommon::GetLogTableName(tableName); + std::string rowid = std::string(DBConstant::SQLITE_INNER_ROWID); + std::string flag = std::to_string(static_cast(LogInfoFlag::FLAG_LOCAL) | + static_cast(LogInfoFlag::FLAG_DEVICE_CLOUD_INCONSISTENCY)); + Timestamp currentSysTime = TimeHelper::GetSysCurrentTime(); + Timestamp currentLocalTime = currentSysTime + localTimeOffset; + std::string currentLocalTimeStr = std::to_string(currentLocalTime); + std::string insertPrefix = isRowReplace ? "INSERT OR REPLACE INTO " : "INSERT INTO "; + std::string insertSuffix = isRowReplace ? ";" : " " + logMgrPtr->GetConflictPkSql(tableInfo) + " DO UPDATE SET " + "data_key=excluded.data_key, device=excluded.device, ori_device=excluded.ori_device, " + "flag=excluded.flag, cloud_gid=excluded.cloud_gid, extend_field=excluded.extend_field, " + "cursor=excluded.cursor, version=excluded.version, sharing_resource=excluded.sharing_resource, " + "status=excluded.status;"; + std::string calPrimaryKeyHash = logMgrPtr->CalcPrimaryKeyHash("a.", tableInfo, identity); + std::string sql = insertPrefix + logTable + " SELECT " + rowid + ", '', '', " + + currentLocalTimeStr + " + " + rowid + ", " + currentLocalTimeStr + " + " + rowid + ", " + flag + ", " + + calPrimaryKeyHash + ", '', " + "'', '', '', '', 0 FROM '" + tableName + "' AS a WHERE 1=1" + insertSuffix; + errCode = SQLiteUtils::ExecuteRawSQL(db, sql); + if (errCode != E_OK) { + LOGE("Failed to initialize device type log data.%d", errCode); + } + return errCode; +} + int SQLiteSingleVerRelationalStorageExecutor::CreateRelationalLogTable(DistributedTableMode mode, bool isUpgraded, - const std::string &identity, TableInfo &table, TableSyncType syncType) + const std::string &identity, TableInfo &table) { // create log table - auto tableManager = LogTableManagerFactory::GetTableManager(mode, syncType); + std::unique_ptr tableManager; + if (!table.GetTrackerTable().IsEmpty() && table.GetTableSyncType() == TableSyncType::DEVICE_COOPERATION) { + tableManager = std::make_unique(); + } else { + tableManager = LogTableManagerFactory::GetTableManager(mode, table.GetTableSyncType()); + } if (tableManager == nullptr) { LOGE("[CreateRelationalLogTable] get table manager failed"); return -E_INVALID_DB; @@ -255,16 +307,18 @@ int SQLiteSingleVerRelationalStorageExecutor::CreateRelationalLogTable(Distribut LOGE("[CreateDistributedTable] create log table failed"); return errCode; } - std::string tableName = table.GetTableName(); - if ((!isUpgraded) && table.GetTrackerTable().GetTableName().empty()) { - std::string calPrimaryKeyHash = tableManager->CalcPrimaryKeyHash("a.", table, identity); - errCode = GeneLogInfoForExistedData(dbHandle_, tableName, calPrimaryKeyHash, table); - if (errCode != E_OK) { - return errCode; + if (!isUpgraded) { + if (table.GetTrackerTable().GetTableName().empty()) { + // user table -> distributed table + errCode = GeneLogInfoForExistedData(dbHandle_, identity, table, tableManager); + } else if (table.GetTableSyncType() == TableSyncType::DEVICE_COOPERATION) { + // tracker table -> distributed device table + errCode = UpdateTrackerTableTimeStamp(dbHandle_, tableName, table, tableManager, true); + } else { + // tracker table -> distributed cloud table + errCode = ResetLogStatus(tableName); } - } else if (!isUpgraded) { - errCode = ResetLogStatus(tableName); if (errCode != E_OK) { return errCode; } @@ -280,7 +334,7 @@ int SQLiteSingleVerRelationalStorageExecutor::CreateRelationalLogTable(Distribut } int SQLiteSingleVerRelationalStorageExecutor::CreateDistributedTable(DistributedTableMode mode, bool isUpgraded, - const std::string &identity, TableInfo &table, TableSyncType syncType) + const std::string &identity, TableInfo &table) { if (dbHandle_ == nullptr) { return -E_INVALID_DB; @@ -303,17 +357,43 @@ int SQLiteSingleVerRelationalStorageExecutor::CreateDistributedTable(Distributed if (!isEmpty) { LOGW("[CreateDistributedTable] generate %.3s log for existed data, table type %d", DBCommon::TransferStringToHex(DBCommon::TransferHashString(tableName)).c_str(), - static_cast(syncType)); + static_cast(table.GetTableSyncType())); } } - errCode = CheckTableConstraint(table, mode, syncType); + errCode = CheckTableConstraint(table, mode, table.GetTableSyncType()); if (errCode != E_OK) { LOGE("[CreateDistributedTable] check table constraint failed."); return errCode; } - return CreateRelationalLogTable(mode, isUpgraded, identity, table, syncType); + return CreateRelationalLogTable(mode, isUpgraded, identity, table); +} + +int SQLiteSingleVerRelationalStorageExecutor::CompareSchemaTableColumns(const std::string &tableName) +{ + bool onceDropped = false; + int errCode = IsTableOnceDropped(tableName, onceDropped); + if (!onceDropped) { + // do not return error code to make sure main procedure will continue + return E_OK; + } + LOGI("[CompareSchemaTableColumns] table once dropped check schema. table name is %s length is %zu", + DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + TableInfo newTableInfo; + errCode = SQLiteUtils::AnalysisSchema(dbHandle_, tableName, newTableInfo); + if (errCode != E_OK) { + LOGE("[CompareSchemaTableColumns] analysis table schema failed. %d", errCode); + return errCode; + } + // new table should has same or compatible upgrade + TableInfo tableInfo = localSchema_.GetTable(tableName); + errCode = tableInfo.CompareWithTable(newTableInfo, localSchema_.GetSchemaVersion()); + if (errCode == -E_RELATIONAL_TABLE_INCOMPATIBLE) { + LOGE("[CompareSchemaTableColumns] Not support with incompatible table."); + return -E_SCHEMA_MISMATCH; + } + return errCode; } int SQLiteSingleVerRelationalStorageExecutor::UpgradeDistributedTable(const std::string &tableName, @@ -580,7 +660,7 @@ int SQLiteSingleVerRelationalStorageExecutor::Rollback() } int errCode = SQLiteUtils::RollbackTransaction(dbHandle_); if (errCode != E_OK) { - LOGE("sqlite single ver storage executor rollback fail! errCode = [%d]", errCode); + LOGE("sqlite single ver relation storage executor rollback fail! errCode = [%d]", errCode); } return errCode; } @@ -590,31 +670,6 @@ void SQLiteSingleVerRelationalStorageExecutor::SetTableInfo(const TableInfo &tab table_ = tableInfo; } -static int GetLogData(sqlite3_stmt *logStatement, LogInfo &logInfo) -{ - logInfo.dataKey = sqlite3_column_int64(logStatement, 0); // 0 means dataKey index - - std::vector dev; - int errCode = SQLiteUtils::GetColumnBlobValue(logStatement, 1, dev); // 1 means dev index - if (errCode != E_OK) { - return errCode; - } - logInfo.device = std::string(dev.begin(), dev.end()); - - std::vector oriDev; - errCode = SQLiteUtils::GetColumnBlobValue(logStatement, 2, oriDev); // 2 means ori_dev index - if (errCode != E_OK) { - return errCode; - } - logInfo.originDev = std::string(oriDev.begin(), oriDev.end()); - logInfo.timestamp = static_cast(sqlite3_column_int64(logStatement, 3)); // 3 means timestamp index - logInfo.wTimestamp = static_cast(sqlite3_column_int64(logStatement, 4)); // 4 means w_timestamp index - logInfo.flag = static_cast(sqlite3_column_int64(logStatement, 5)); // 5 means flag index - logInfo.flag &= (~DataItem::LOCAL_FLAG); - logInfo.flag &= (~DataItem::UPDATE_FLAG); - return SQLiteUtils::GetColumnBlobValue(logStatement, 6, logInfo.hashKey); // 6 means hashKey index -} - namespace { void GetCloudLog(sqlite3_stmt *logStatement, VBucket &logInfo, uint32_t &totalSize, int64_t &revisedTime, int64_t &invalidTime) @@ -819,68 +874,6 @@ int SQLiteSingleVerRelationalStorageExecutor::GetAllMetaKeys(std::vector &k return errCode; } -int SQLiteSingleVerRelationalStorageExecutor::GetLogInfoPre(sqlite3_stmt *queryStmt, const DataItem &dataItem, - LogInfo &logInfoGet) -{ - if (queryStmt == nullptr) { - return -E_INVALID_ARGS; - } - int errCode = SQLiteUtils::BindBlobToStatement(queryStmt, 1, dataItem.hashKey); // 1 means hashkey index. - if (errCode != E_OK) { - return errCode; - } - if (mode_ != DistributedTableMode::COLLABORATION) { - errCode = SQLiteUtils::BindTextToStatement(queryStmt, 2, dataItem.dev); // 2 means device index. - if (errCode != E_OK) { - return errCode; - } - } - - errCode = SQLiteUtils::StepWithRetry(queryStmt, isMemDb_); - if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { - errCode = -E_NOT_FOUND; - } else { - errCode = GetLogData(queryStmt, logInfoGet); - } - return errCode; -} - -int SQLiteSingleVerRelationalStorageExecutor::SaveSyncLog(sqlite3_stmt *statement, sqlite3_stmt *queryStmt, - const DataItem &dataItem, int64_t rowid) -{ - LogInfo logInfoGet; - int errCode = GetLogInfoPre(queryStmt, dataItem, logInfoGet); - LogInfo logInfoBind; - logInfoBind.hashKey = dataItem.hashKey; - logInfoBind.device = dataItem.dev; - logInfoBind.timestamp = dataItem.timestamp; - logInfoBind.flag = dataItem.flag; - - if (errCode == -E_NOT_FOUND) { // insert - logInfoBind.wTimestamp = dataItem.writeTimestamp; - logInfoBind.originDev = dataItem.dev; - } else if (errCode == E_OK) { // update - logInfoBind.wTimestamp = logInfoGet.wTimestamp; - logInfoBind.originDev = logInfoGet.originDev; - } else { - return errCode; - } - - // bind - SQLiteUtils::BindInt64ToStatement(statement, 1, rowid); // 1 means dataKey index - std::vector originDev(logInfoBind.originDev.begin(), logInfoBind.originDev.end()); - SQLiteUtils::BindBlobToStatement(statement, 2, originDev); // 2 means ori_dev index - SQLiteUtils::BindInt64ToStatement(statement, 3, logInfoBind.timestamp); // 3 means timestamp index - SQLiteUtils::BindInt64ToStatement(statement, 4, logInfoBind.wTimestamp); // 4 means w_timestamp index - SQLiteUtils::BindInt64ToStatement(statement, 5, logInfoBind.flag); // 5 means flag index - SQLiteUtils::BindBlobToStatement(statement, 6, logInfoBind.hashKey); // 6 means hashKey index - errCode = SQLiteUtils::StepWithRetry(statement, isMemDb_); - if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { - return E_OK; - } - return errCode; -} - int SQLiteSingleVerRelationalStorageExecutor::DeleteSyncDataItem(const DataItem &dataItem, RelationalSyncDataInserter &inserter, sqlite3_stmt *&stmt) { @@ -892,18 +885,10 @@ int SQLiteSingleVerRelationalStorageExecutor::DeleteSyncDataItem(const DataItem } } - int errCode = SQLiteUtils::BindBlobToStatement(stmt, 1, dataItem.hashKey); // 1 means hash_key index + int errCode = inserter.BindHashKeyAndDev(dataItem, stmt, 1); // 1 is hashKey begin index if (errCode != E_OK) { - SQLiteUtils::ResetStatement(stmt, true, errCode); return errCode; } - if (mode_ != DistributedTableMode::COLLABORATION) { - errCode = SQLiteUtils::BindTextToStatement(stmt, 2, dataItem.dev); // 2 means device index - if (errCode != E_OK) { - SQLiteUtils::ResetStatement(stmt, true, errCode); - return errCode; - } - } errCode = SQLiteUtils::StepWithRetry(stmt, isMemDb_); if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { errCode = E_OK; @@ -912,32 +897,28 @@ int SQLiteSingleVerRelationalStorageExecutor::DeleteSyncDataItem(const DataItem return errCode; } -int SQLiteSingleVerRelationalStorageExecutor::SaveSyncDataItem(const DataItem &dataItem, SaveSyncDataStmt &saveStmt, - RelationalSyncDataInserter &inserter, int64_t &rowid) +int SQLiteSingleVerRelationalStorageExecutor::SaveSyncDataItem(const DataItem &dataItem, bool isUpdate, + SaveSyncDataStmt &saveStmt, RelationalSyncDataInserter &inserter, int64_t &rowid) { if ((dataItem.flag & DataItem::DELETE_FLAG) != 0) { + rowid = -1; return DeleteSyncDataItem(dataItem, inserter, saveStmt.rmDataStmt); } - if ((mode_ == DistributedTableMode::COLLABORATION && inserter.GetLocalTable().GetIdentifyKey().size() == 1u && - inserter.GetLocalTable().GetIdentifyKey().at(0) == "rowid") || - (mode_ == DistributedTableMode::SPLIT_BY_DEVICE && inserter.GetLocalTable().GetPrimaryKey().size() == 1u && - inserter.GetLocalTable().GetPrimaryKey().at(0) == "rowid") || - inserter.GetLocalTable().GetAutoIncrement()) { // No primary key of auto increment + // we don't know the rowid if user drop device table + // SPLIT_BY_DEVICE use insert or replace to update data + // no pk table should delete by hash key(rowid) first + if ((mode_ == DistributedTableMode::SPLIT_BY_DEVICE && inserter.GetLocalTable().IsNoPkTable())) { int errCode = DeleteSyncDataItem(dataItem, inserter, saveStmt.rmDataStmt); if (errCode != E_OK) { LOGE("Delete no pk data before insert failed, errCode=%d.", errCode); return errCode; } } - - int errCode = inserter.BindInsertStatement(saveStmt.saveDataStmt, dataItem); - if (errCode != E_OK) { - LOGE("Bind data failed, errCode=%d.", errCode); - return errCode; - } - errCode = SQLiteUtils::StepWithRetry(saveStmt.saveDataStmt, isMemDb_); + int errCode = inserter.SaveData(isUpdate, dataItem, saveStmt); if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { - rowid = SQLiteUtils::GetLastRowId(dbHandle_); + if (!isUpdate) { + rowid = SQLiteUtils::GetLastRowId(dbHandle_); + } errCode = E_OK; } return errCode; @@ -954,18 +935,10 @@ int SQLiteSingleVerRelationalStorageExecutor::DeleteSyncLog(const DataItem &data } } - int errCode = SQLiteUtils::BindBlobToStatement(stmt, 1, dataItem.hashKey); // 1 means hashkey index + int errCode = inserter.BindHashKeyAndDev(dataItem, stmt, 1); // 1 is hashKey begin index if (errCode != E_OK) { - SQLiteUtils::ResetStatement(stmt, true, errCode); return errCode; } - if (mode_ != DistributedTableMode::COLLABORATION) { - errCode = SQLiteUtils::BindTextToStatement(stmt, 2, dataItem.dev); // 2 means device index - if (errCode != E_OK) { - SQLiteUtils::ResetStatement(stmt, true, errCode); - return errCode; - } - } errCode = SQLiteUtils::StepWithRetry(stmt, isMemDb_); if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { errCode = E_OK; @@ -984,32 +957,28 @@ int SQLiteSingleVerRelationalStorageExecutor::ProcessMissQueryData(const DataIte return DeleteSyncLog(item, inserter, rmLogStmt); } -int SQLiteSingleVerRelationalStorageExecutor::GetSyncDataPre(const DataItem &dataItem, sqlite3_stmt *queryStmt, - DataItem &itemGet) -{ - LogInfo logInfoGet; - int errCode = GetLogInfoPre(queryStmt, dataItem, logInfoGet); - itemGet.timestamp = logInfoGet.timestamp; - SQLiteUtils::ResetStatement(queryStmt, false, errCode); - return errCode; -} - int SQLiteSingleVerRelationalStorageExecutor::CheckDataConflictDefeated(const DataItem &dataItem, - sqlite3_stmt *queryStmt, bool &isDefeated) + sqlite3_stmt *queryStmt, bool &isDefeated, bool &isExist, int64_t &rowId) { + LogInfo logInfoGet; + int errCode = SQLiteRelationalUtils::GetLogInfoPre(queryStmt, mode_, dataItem, logInfoGet); + int ret = E_OK; + SQLiteUtils::ResetStatement(queryStmt, false, ret); + if (errCode != E_OK && errCode != -E_NOT_FOUND) { + LOGE("Failed to get raw data. %d", errCode); + return errCode; + } + rowId = logInfoGet.dataKey; + isExist = (errCode != -E_NOT_FOUND) && ((logInfoGet.flag & static_cast(LogInfoFlag::FLAG_DELETE)) == 0); if ((dataItem.flag & DataItem::REMOTE_DEVICE_DATA_MISS_QUERY) != DataItem::REMOTE_DEVICE_DATA_MISS_QUERY && mode_ == DistributedTableMode::SPLIT_BY_DEVICE) { isDefeated = false; // no need to solve conflict except miss query data return E_OK; } - - DataItem itemGet; - int errCode = GetSyncDataPre(dataItem, queryStmt, itemGet); - if (errCode != E_OK && errCode != -E_NOT_FOUND) { - LOGE("Failed to get raw data. %d", errCode); - return errCode; + if (dataItem.dev != logInfoGet.device) { + // defeated if item timestamp is earlier than raw data + isDefeated = (dataItem.timestamp <= logInfoGet.timestamp); } - isDefeated = (dataItem.timestamp <= itemGet.timestamp); // defeated if item timestamp is earlier then raw data return E_OK; } @@ -1017,7 +986,9 @@ int SQLiteSingleVerRelationalStorageExecutor::SaveSyncDataItem(RelationalSyncDat SaveSyncDataStmt &saveStmt, DataItem &item) { bool isDefeated = false; - int errCode = CheckDataConflictDefeated(item, saveStmt.queryStmt, isDefeated); + bool isExist = false; + int64_t rowid = -1; + int errCode = CheckDataConflictDefeated(item, saveStmt.queryStmt, isDefeated, isExist, rowid); if (errCode != E_OK) { LOGE("check data conflict failed. %d", errCode); return errCode; @@ -1030,10 +1001,10 @@ int SQLiteSingleVerRelationalStorageExecutor::SaveSyncDataItem(RelationalSyncDat if ((item.flag & DataItem::REMOTE_DEVICE_DATA_MISS_QUERY) != 0) { return ProcessMissQueryData(item, inserter, saveStmt.rmDataStmt, saveStmt.rmLogStmt); } - int64_t rowid = -1; - errCode = SaveSyncDataItem(item, saveStmt, inserter, rowid); + bool isUpdate = isExist && mode_ == DistributedTableMode::COLLABORATION; + errCode = SaveSyncDataItem(item, isUpdate, saveStmt, inserter, rowid); if (errCode == E_OK || errCode == -E_NOT_FOUND) { - errCode = SaveSyncLog(saveStmt.saveLogStmt, saveStmt.queryStmt, item, rowid); + errCode = inserter.SaveSyncLog(dbHandle_, saveStmt.saveLogStmt, saveStmt.queryStmt, item, rowid); } return errCode; } @@ -1073,18 +1044,11 @@ int SQLiteSingleVerRelationalStorageExecutor::SaveSyncItems(RelationalSyncDataIn } } - int errCode = SetLogTriggerStatus(false); - if (errCode != E_OK) { - goto END; - } - - errCode = SaveSyncDataItems(inserter); + int errCode = SaveSyncDataItems(inserter); if (errCode != E_OK) { LOGE("Save sync data items failed. errCode=%d", errCode); goto END; } - - errCode = SetLogTriggerStatus(true); END: if (useTrans) { if (errCode == E_OK) { @@ -1100,14 +1064,18 @@ int SQLiteSingleVerRelationalStorageExecutor::GetDataItemForSync(sqlite3_stmt *s bool isGettingDeletedData) const { RowDataWithLog data; - int errCode = GetLogData(stmt, data.logInfo); + int errCode = SQLiteRelationalUtils::GetLogData(stmt, data.logInfo); if (errCode != E_OK) { LOGE("relational data value transfer to kv fail"); return errCode; } - + std::vector serializeFields; if (!isGettingDeletedData) { - for (size_t cid = 0; cid < table_.GetFields().size(); ++cid) { + auto fields = table_.GetFieldInfos(); + for (size_t cid = 0; cid < fields.size(); ++cid) { + if (localSchema_.IsNeedSkipSyncField(fields[cid], table_.GetTableName())) { + continue; + } DataValue value; errCode = SQLiteRelationalUtils::GetDataValueByType(stmt, cid + DBConstant::RELATIONAL_LOG_TABLE_FIELD_NUM, value); @@ -1115,11 +1083,12 @@ int SQLiteSingleVerRelationalStorageExecutor::GetDataItemForSync(sqlite3_stmt *s return errCode; } data.rowData.push_back(std::move(value)); // sorted by cid + serializeFields.push_back(fields[cid]); } } errCode = DataTransformer::SerializeDataItem(data, - isGettingDeletedData ? std::vector() : table_.GetFieldInfos(), dataItem); + isGettingDeletedData ? std::vector() : serializeFields, dataItem); if (errCode != E_OK) { LOGE("relational data value transfer to kv fail"); } @@ -1340,33 +1309,22 @@ int SQLiteSingleVerRelationalStorageExecutor::DeleteDistributedLogTable(const st return errCode; } -int SQLiteSingleVerRelationalStorageExecutor::IsTableOnceDropped(const std::string &tableName, int execCode, - bool &onceDropped) +int SQLiteSingleVerRelationalStorageExecutor::IsTableOnceDropped(const std::string &tableName, bool &onceDropped) { - if (execCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { // The table in schema was dropped + std::string keyStr = DBConstant::TABLE_WAS_DROPPED + tableName; + Key key; + DBCommon::StringToVector(keyStr, key); + Value value; + + int errCode = GetKvData(key, value); + if (errCode == E_OK) { onceDropped = true; return E_OK; - } else if (execCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { - std::string keyStr = DBConstant::TABLE_IS_DROPPED + tableName; - Key key; - DBCommon::StringToVector(keyStr, key); - Value value; - - int errCode = GetKvData(key, value); - if (errCode == E_OK) { - // if user drop table first, then create again(but don't create distributed table), will reach this branch - onceDropped = true; - return E_OK; - } else if (errCode == -E_NOT_FOUND) { - onceDropped = false; - return E_OK; - } else { - LOGE("[IsTableOnceDropped] query is table dropped failed, %d", errCode); - return errCode; - } - } else { - return execCode; + } else if (errCode == -E_NOT_FOUND) { + onceDropped = false; + return E_OK; } + return errCode; } int SQLiteSingleVerRelationalStorageExecutor::CleanResourceForDroppedTable(const std::string &tableName) @@ -1410,20 +1368,19 @@ int SQLiteSingleVerRelationalStorageExecutor::CheckAndCleanDistributedTable(cons } errCode = SQLiteUtils::StepWithRetry(stmt, false); - bool onceDropped = false; - errCode = IsTableOnceDropped(tableName, errCode, onceDropped); - if (errCode != E_OK) { - LOGE("query is table once dropped failed. %d", errCode); - break; - } - SQLiteUtils::ResetStatement(stmt, false, ret); - if (onceDropped) { // The table in schema was once dropped + if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { // The table in schema was dropped errCode = CleanResourceForDroppedTable(tableName); if (errCode != E_OK) { + LOGE("Clean resource for dropped table failed. %d", errCode); break; } missingTables.emplace_back(tableName); + } else if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + LOGE("Check distributed table failed. %d", errCode); + break; } + errCode = E_OK; // Check result ok for distributed table is still exists + SQLiteUtils::ResetStatement(stmt, false, ret); } SQLiteUtils::ResetStatement(stmt, true, ret); return CheckCorruptedStatus(errCode); @@ -1823,11 +1780,13 @@ int SQLiteSingleVerRelationalStorageExecutor::SetDataOnUserTableWithLogicDelete( LOGE("Failed to create updateCursor func on userTable errCode=%d.", errCode); return errCode; } + // data from cloud and not modified by local or consistency with cloud to flag logout std::string sql = "UPDATE '" + logTableName + "' SET " + CloudDbConstant::FLAG + " = " + SET_FLAG_WHEN_LOGOUT + ", " + VERSION + " = '', " + DEVICE_FIELD + " = '', " + CLOUD_GID_FIELD + " = '', " + SHARING_RESOURCE + " = '', " + UPDATE_CURSOR_SQL + - " WHERE (CLOUD_GID IS NOT NULL AND CLOUD_GID != '' AND " + FLAG_IS_CLOUD_CONSISTENCY + - " AND NOT (" + DATA_IS_DELETE + ") " + " AND NOT (" + FLAG_IS_LOGIC_DELETE + "));"; + " WHERE (CLOUD_GID IS NOT NULL AND CLOUD_GID != '' AND (" + FLAG_IS_CLOUD_CONSISTENCY + " OR " + + FLAG_IS_CLOUD + ") AND NOT (" + DATA_IS_DELETE + ") " + " AND NOT (" + FLAG_IS_LOGIC_DELETE + + "));"; errCode = SQLiteUtils::ExecuteRawSQL(dbHandle_, sql); // here just clear updateCursor func, fail will not influence other function (void)CreateFuncUpdateCursor(context, nullptr); @@ -1956,7 +1915,7 @@ int SQLiteSingleVerRelationalStorageExecutor::GetUpdateLogRecordStatement(const return errCode; } } else { - updateLogSql += GetUpdateDataFlagSql() + ", cloud_gid = ?"; + updateLogSql += GetUpdateDataFlagSql(vBucket) + ", cloud_gid = ?"; updateColName.push_back(CloudDbConstant::GID_FIELD); CloudStorageUtils::AddUpdateColForShare(tableSchema, updateLogSql, updateColName); } @@ -1973,5 +1932,31 @@ int SQLiteSingleVerRelationalStorageExecutor::GetUpdateLogRecordStatement(const } return errCode; } + +int SQLiteSingleVerRelationalStorageExecutor::GetLockStatusByGid(const std::string &tableName, const std::string &gid, + LockStatus &status) +{ + std::string sql = "select status from " + DBCommon::GetLogTableName(tableName) + " where cloud_gid = '" + + gid + "';"; + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(dbHandle_, sql, stmt); + if (errCode != E_OK) { + LOGE("Get stmt failed when get lock status: %d", errCode); + return errCode; + } + errCode = SQLiteUtils::StepWithRetry(stmt); + if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + status = static_cast(sqlite3_column_int(stmt, 0)); + errCode = E_OK; + } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + LOGE("Not found lock status."); + errCode = -E_NOT_FOUND; + } else { + LOGE("Get lock status failed: %d", errCode); + } + int resetRet; + SQLiteUtils::ResetStatement(stmt, true, resetRet); + return errCode; +} } // namespace DistributedDB #endif diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor.h index 863c748ebc5e55354aee117322e14378f4061794..6f3093ca48fb1363f93ccb4ad59f8c3838017068 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor.h @@ -29,6 +29,7 @@ #include "relational_row_data.h" #include "relational_store_delegate.h" #include "relational_sync_data_inserter.h" +#include "sqlite_log_table_manager.h" #include "sqlite_single_ver_relational_continue_token.h" #include "sqlite_storage_executor.h" #include "sqlite_utils.h" @@ -60,11 +61,11 @@ public: int ResetLogStatus(std::string &tableName); int CreateRelationalLogTable(DistributedTableMode mode, bool isUpgraded, const std::string &identity, - TableInfo &table, TableSyncType syncType); + TableInfo &table); // The parameter "identity" is a hash string that identifies a device int CreateDistributedTable(DistributedTableMode mode, bool isUpgraded, const std::string &identity, - TableInfo &table, TableSyncType syncType); + TableInfo &table); int UpgradeDistributedTable(const std::string &tableName, DistributedTableMode mode, bool &schemaChanged, RelationalSchemaObject &schema, TableSyncType syncType); @@ -139,7 +140,11 @@ public: int PutCloudSyncData(const std::string &tableName, const TableSchema &tableSchema, const TrackerTable &trackerTable, DownloadData &downloadData); - int FillCloudAssetForDownload(const TableSchema &tableSchema, VBucket &vBucket, bool isDownloadSuccess); + int UpdateAssetStatusForAssetOnly(const TableSchema &tableSchema, VBucket &asset); + + int FillCloudAssetForDownload(const TableSchema &tableSchema, VBucket &vBucket, bool isDownloadSuccess, + uint64_t &currCursor); + int FillCloudAssetForAsyncDownload(const TableSchema &tableSchema, VBucket &vBucket, bool isDownloadSuccess); int DoCleanInner(ClearMode mode, const std::vector &tableNameList, const RelationalSchemaObject &localSchema, std::vector &assets, std::vector ¬ifyTableList); @@ -153,7 +158,7 @@ public: int GetCursor(const std::string &tableName, uint64_t &cursor); int AnalysisTrackerTable(const TrackerTable &trackerTable, TableInfo &tableInfo); - int CreateTrackerTable(const TrackerTable &trackerTable, bool checkData); + int CreateTrackerTable(const TrackerTable &trackerTable, const TableInfo &table, bool checkData); int GetOrInitTrackerSchemaFromMeta(RelationalSchemaObject &schema); int ExecuteSql(const SqlCondition &condition, std::vector &records); @@ -196,17 +201,22 @@ public: int UpdateRecordFlag(const std::string &tableName, const std::string &sql, const LogInfo &logInfo); - void MarkFlagAsUploadFinished(const std::string &tableName, const Key &hashKey, Timestamp timestamp); + void MarkFlagAsUploadFinished(const std::string &tableName, const Key &hashKey, Timestamp timestamp, + bool isExistAssetsDownload); int CleanUploadFinishedFlag(const std::string &tableName); - int GetWaitCompensatedSyncDataPk(const TableSchema &table, std::vector &data); + int GetWaitCompensatedSyncDataPk(const TableSchema &table, std::vector &data, + bool isQueryDownloadRecords); int ClearUnLockingStatus(const std::string &tableName); int MarkFlagAsConsistent(const std::string &tableName, const DownloadData &downloadData, const std::set &gidFilters); + int MarkFlagAsAssetAsyncDownload(const std::string &tableName, const DownloadData &downloadData, + const std::set &gidFilters); + int CheckInventoryData(const std::string &tableName); int UpdateRecordStatus(const std::string &tableName, const std::string &status, const Key &hashKey); @@ -225,6 +235,30 @@ public: int UpdateDeleteDataExtendField(const std::string &tableName, const std::string &lowVersionExtendColName, const std::set &oldExtendColNames, const std::set &extendColNames); + + void CheckAndCreateTrigger(const TrackerTable &trackerTable); + + int GetDownloadingAssetsCount(const TableSchema &tableSchema, int32_t &totalCount); + + int GetDownloadingCount(const std::string &tableName, int32_t &count); + + int GetDownloadAssetGid(const TableSchema &tableSchema, std::vector &gids, + int64_t beginTime = 0, bool abortWithLimit = false); + + int GetDownloadAssetRecordsInner(const TableSchema &tableSchema, int64_t beginTime, std::vector &gids); + + int GetDownloadAssetRecordsByGid(const TableSchema &tableSchema, const std::string gid, + std::vector &assets); + + int CleanDownloadingFlag(const std::string &tableName); + + int CleanDownloadingFlagByGid(const std::string &tableName, const std::string &gid, VBucket dbAssets); + + int CompareSchemaTableColumns(const std::string &tableName); + + void CheckAndCreateTrigger(const TableInfo &table); + + int GetLockStatusByGid(const std::string &tableName, const std::string &gid, LockStatus &status); private: int DoCleanLogs(const std::vector &tableNameList, const RelationalSchemaObject &localSchema); @@ -247,7 +281,7 @@ private: int SetCursor(const std::string &tableName, uint64_t cursor); - int IncreaseCursorOnAssetData(const std::string &tableName, const std::string &gid); + int IncreaseCursorOnAssetData(const std::string &tableName, const std::string &gid, uint64_t &currCursor); int GetCleanCloudDataKeys(const std::string &logTableName, std::vector &dataKeys, bool distinguishCloudFlag); @@ -263,21 +297,16 @@ private: int GetDataItemForSync(sqlite3_stmt *statement, DataItem &dataItem, bool isGettingDeletedData) const; - int GetSyncDataPre(const DataItem &dataItem, sqlite3_stmt *queryStmt, DataItem &itemGet); - - int CheckDataConflictDefeated(const DataItem &item, sqlite3_stmt *queryStmt, bool &isDefeated); + int CheckDataConflictDefeated(const DataItem &item, sqlite3_stmt *queryStmt, + bool &isDefeated, bool &isExist, int64_t &rowId); int SaveSyncDataItem(RelationalSyncDataInserter &inserter, SaveSyncDataStmt &saveStmt, DataItem &item); - int SaveSyncDataItem(const DataItem &dataItem, SaveSyncDataStmt &saveStmt, RelationalSyncDataInserter &inserter, - int64_t &rowid); + int SaveSyncDataItem(const DataItem &dataItem, bool isUpdate, SaveSyncDataStmt &saveStmt, + RelationalSyncDataInserter &inserter, int64_t &rowid); int DeleteSyncDataItem(const DataItem &dataItem, RelationalSyncDataInserter &inserter, sqlite3_stmt *&rmDataStmt); - int GetLogInfoPre(sqlite3_stmt *queryStmt, const DataItem &dataItem, LogInfo &logInfoGet); - - int SaveSyncLog(sqlite3_stmt *statement, sqlite3_stmt *queryStmt, const DataItem &dataItem, int64_t rowid); - int AlterAuxTableForUpgrade(const TableInfo &oldTableInfo, const TableInfo &newTableInfo); int DeleteSyncLog(const DataItem &item, RelationalSyncDataInserter &inserter, sqlite3_stmt *&rmLogStmt); @@ -290,8 +319,9 @@ private: void SetTableInfo(const TableInfo &tableInfo); // When put or get sync data, must call the func first. - int GeneLogInfoForExistedData(sqlite3 *db, const std::string &tableName, const std::string &calPrimaryKeyHash, - TableInfo &tableInfo); + int GeneLogInfoForExistedData(sqlite3 *db, const std::string &identity, const TableInfo &tableInfo, + std::unique_ptr &logMgrPtr); + int CleanExtendAndCursorForDeleteData(const std::string &tableName); int GetCloudDataForSync(const CloudUploadRecorder &uploadRecorder, sqlite3_stmt *statement, @@ -299,6 +329,8 @@ private: int PutVBucketByType(VBucket &vBucket, const Field &field, Type &cloudValue); + int GetDownloadAsset(std::vector &assetsV, const Field &field, Type &cloudValue); + int ExecutePutCloudData(const std::string &tableName, const TableSchema &tableSchema, const TrackerTable &trackerTable, DownloadData &downloadData, std::map &statisticMap); @@ -370,12 +402,15 @@ private: int GetDeleteStatementForCloudSync(const TableSchema &tableSchema, const std::set &pkSet, const VBucket &vBucket, sqlite3_stmt *&deleteStmt); + int UpdateTrackerTableTimeStamp(sqlite3 *db, const std::string &identity, const TableInfo &tableInfo, + std::unique_ptr &logMgrPtr, bool isRowReplace); + int DeleteCloudData(const std::string &tableName, const VBucket &vBucket, const TableSchema &tableSchema, const TrackerTable &trackerTable); - int OnlyUpdateLogTable(const VBucket &vBucket, const TableSchema &tableSchema, OpType opType); + int IsTableOnceDropped(const std::string &tableName, bool &onceDropped); - int IsTableOnceDropped(const std::string &tableName, int execCode, bool &onceDropped); + int OnlyUpdateLogTable(const VBucket &vBucket, const TableSchema &tableSchema, OpType opType); int BindUpdateVersionStatement(const VBucket &vBucket, const Bytes &hashKey, sqlite3_stmt *&stmt); int DoCleanShareTableDataAndLog(const std::vector &tableNameList); @@ -451,17 +486,17 @@ private: int UpdateAssetsIdForOneRecord(const TableSchema &tableSchema, const std::string &sql, const std::vector &assetOfOneRecord, const std::vector &assetsOfOneRecord); - bool IsNeedUpdateAssetId(const TableSchema &tableSchema, int64_t dataKey, const VBucket &vBucket, - bool &isNotIncCursor); - bool IsNeedUpdateAssetIdInner(sqlite3_stmt *selectStmt, const VBucket &vBucket, const Field &field, VBucket &assetInfo, bool &isNotIncCursor); + bool IsNeedUpdateAssetId(const TableSchema &tableSchema, int64_t dataKey, const VBucket &vBucket, + bool &isNotIncCursor); + int UpdateAssetId(const TableSchema &tableSchema, int64_t dataKey, const VBucket &vBucket); int64_t GetDataFlag(); - std::string GetUpdateDataFlagSql(); + std::string GetUpdateDataFlagSql(const VBucket &data); std::string GetDev(); @@ -478,11 +513,16 @@ private: int LogicDeleteCloudData(const std::string &tableName, const VBucket &vBucket, const TableSchema &tableSchema, const TrackerTable &trackerTable); + bool AbortGetDownloadAssetGidIfNeed(const TableSchema &tableSchema, const std::string &gid, bool abortWithLimit, + uint32_t &count); + static constexpr const char *CONSISTENT_FLAG = "0x20"; - static constexpr const char *UPDATE_FLAG_CLOUD = "flag = flag & 0x20"; + static constexpr const char *UPDATE_FLAG_CLOUD = "flag = 0"; static constexpr const char *UPDATE_FLAG_WAIT_COMPENSATED_SYNC = "flag = flag | 0x10"; static constexpr const char *FLAG_IS_WAIT_COMPENSATED_SYNC = "(a.flag & 0x10 != 0 and a.status = 0) or a.status = 1"; + static constexpr const char *FLAG_IS_WAIT_COMPENSATED_CONTAIN_DOWNLOAD_SYNC = + "(a.flag & 0x10 != 0 and a.status = 0) or a.status = 1 or (a.flag & 0x1000 != 0 and a.status = 0)"; std::string baseTblName_; TableInfo table_; // Always operating table, user table when get, device table when put. diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor_extend.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor_extend.cpp index 150a4e565f44396e159b54a7c1cbbf047da66e35..75b9e38d1e65e500abd65413e24393c6d798dd2d 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor_extend.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_executor_extend.cpp @@ -323,6 +323,14 @@ int SQLiteSingleVerRelationalStorageExecutor::DoCleanInner(ClearMode mode, } notifyTableList = tableNameList; } + for (const auto &tableName: tableNameList) { + errCode = CleanDownloadingFlag(tableName); + if (errCode != E_OK) { + LOGE("Fail to clean downloading flag, %d, tableName:%s, length:%zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + return errCode; + } + } errCode = SetLogTriggerStatus(true); if (errCode != E_OK) { LOGE("Fail to set log trigger on when clean cloud data, %d", errCode); @@ -614,6 +622,32 @@ int SQLiteSingleVerRelationalStorageExecutor::PutCloudSyncData(const std::string return errCode == E_OK ? ret : errCode; } +int SQLiteSingleVerRelationalStorageExecutor::UpdateAssetStatusForAssetOnly( + const TableSchema &tableSchema, VBucket &vBucket) +{ + std::string cloudGid; + int errCode = CloudStorageUtils::GetValueFromVBucket(CloudDbConstant::GID_FIELD, vBucket, cloudGid); + if (errCode != E_OK) { + LOGE("Miss gid when fill Asset %d.", errCode); + return errCode; + } + std::vector assetsField; + errCode = CloudStorageUtils::GetAssetFieldsFromSchema(tableSchema, vBucket, assetsField); + if (errCode != E_OK) { + LOGE("No assets need to be filled when download assets only, err:%d.", errCode); + return errCode; + } + + sqlite3_stmt *stmt = nullptr; + errCode = GetFillDownloadAssetStatement(tableSchema.name, vBucket, assetsField, stmt); + if (errCode != E_OK) { + LOGE("can not get assetsField from tableSchema:%s err:%d when download assets only.", + tableSchema.name.c_str(), errCode); + return errCode; + } + return ExecuteFillDownloadAssetStatement(stmt, assetsField.size() + 1, cloudGid); +} + int SQLiteSingleVerRelationalStorageExecutor::InsertCloudData(VBucket &vBucket, const TableSchema &tableSchema, const TrackerTable &trackerTable, int64_t dataKey) { @@ -775,9 +809,9 @@ int BindExtendValue(const VBucket &vBucket, const TrackerTable &trackerTable, sq errCode = SQLiteRelationalUtils::BindStatementByType(stmt, extendValueIndex++, extendValue); } if (errCode != E_OK) { - const char *tableName = DBCommon::StringMiddleMasking(trackerTable.GetTableName()).c_str(); + const std::string tableName = DBCommon::StringMiddleMasking(trackerTable.GetTableName()); size_t nameLength = trackerTable.GetTableName().size(); - LOGE("[%s [%zu]] Bind extend field failed: %d", tableName, nameLength, errCode); + LOGE("[%s [%zu]] Bind extend field failed: %d", tableName.c_str(), nameLength, errCode); return errCode; } } @@ -1294,13 +1328,11 @@ bool SQLiteSingleVerRelationalStorageExecutor::IsNeedUpdateAssetIdInner(sqlite3_ UpdateLocalAssetId(vBucket, field.colName, asset); Asset *assetDBPtr = std::get_if(&assetInfo[field.colName]); if (assetDBPtr == nullptr) { + isNotIncCursor = true; return true; } const Asset &assetDB = *assetDBPtr; - if (assetDB.assetId != asset.assetId) { - return true; - } - if (asset.status != AssetStatus::NORMAL) { + if (assetDB.assetId != asset.assetId || asset.status != AssetStatus::NORMAL) { isNotIncCursor = true; return true; } @@ -1310,17 +1342,16 @@ bool SQLiteSingleVerRelationalStorageExecutor::IsNeedUpdateAssetIdInner(sqlite3_ UpdateLocalAssetsId(vBucket, field.colName, assets); Assets *assetsDBPtr = std::get_if(&assetInfo[field.colName]); if (assetsDBPtr == nullptr) { + isNotIncCursor = true; return true; } Assets &assetsDB = *assetsDBPtr; if (assets.size() != assetsDB.size()) { + isNotIncCursor = true; return true; } for (uint32_t i = 0; i < assets.size(); ++i) { - if (assets[i].assetId != assetsDB[i].assetId) { - return true; - } - if (assets[i].status != AssetStatus::NORMAL) { + if (assets[i].assetId != assetsDB[i].assetId || assets[i].status != AssetStatus::NORMAL) { isNotIncCursor = true; return true; } @@ -1407,6 +1438,46 @@ int SQLiteSingleVerRelationalStorageExecutor::MarkFlagAsConsistent(const std::st return errCode == E_OK ? ret : errCode; } +int SQLiteSingleVerRelationalStorageExecutor::MarkFlagAsAssetAsyncDownload(const std::string &tableName, + const DownloadData &downloadData, const std::set &gidFilters) +{ + if (downloadData.data.empty()) { + return E_OK; + } + if (downloadData.data.size() != downloadData.opType.size()) { + LOGE("The num of data:%zu an opType:%zu is not equal.", downloadData.data.size(), downloadData.opType.size()); + return -E_CLOUD_ERROR; + } + std::string sql = "UPDATE " + DBCommon::GetLogTableName(tableName) + " SET flag=flag|0x1000 WHERE cloud_gid=?;"; + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(dbHandle_, sql, stmt); + if (errCode != E_OK) { + LOGE("[Storage Executor]Get mark flag as asset async download stmt failed, %d.", errCode); + return errCode; + } + int ret = E_OK; + for (const auto &gid : gidFilters) { + SQLiteUtils::ResetStatement(stmt, false, ret); + if (ret != E_OK) { + LOGE("[Storage Executor]Reset stmt failed:%d", ret); + break; + } + errCode = SQLiteUtils::BindTextToStatement(stmt, 1, gid); + if (errCode != E_OK) { + break; + } + errCode = SQLiteUtils::StepWithRetry(stmt); + if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + errCode = E_OK; + } else { + LOGW("[Storage Executor]Step mark flag as asset async download stmt failed %d gid %s", + errCode, gid.c_str()); + } + } + SQLiteUtils::ResetStatement(stmt, true, ret); + return errCode == E_OK ? ret : errCode; +} + int SQLiteSingleVerRelationalStorageExecutor::FillCloudVersionForUpload(const std::string &tableName, const CloudSyncBatch &batchData) { @@ -1590,6 +1661,40 @@ int SQLiteSingleVerRelationalStorageExecutor::PutVBucketByType(VBucket &vBucket, return E_OK; } +int SQLiteSingleVerRelationalStorageExecutor::GetDownloadAsset(std::vector &assetsV, const Field &field, + Type &cloudValue) +{ + if (field.type == TYPE_INDEX && cloudValue.index() == TYPE_INDEX) { + Asset asset; + VBucket bucket; + int errCode = RuntimeContext::GetInstance()->BlobToAsset(std::get(cloudValue), asset); + if (errCode != E_OK) { + return errCode; + } + if (AssetOperationUtils::IsAssetNeedDownload(asset)) { + bucket.insert_or_assign(field.colName, asset); + assetsV.push_back(bucket); + } + } else if (field.type == TYPE_INDEX && cloudValue.index() == TYPE_INDEX) { + Assets assets; + int errCode = RuntimeContext::GetInstance()->BlobToAssets(std::get(cloudValue), assets); + if (errCode != E_OK) { + return errCode; + } + if (CloudStorageUtils::IsAssetsContainDuplicateAsset(assets)) { + return E_OK; + } + for (const auto &asset : assets) { + if (AssetOperationUtils::IsAssetNeedDownload(asset)) { + VBucket bucket; + bucket.insert_or_assign(field.colName, asset); + assetsV.push_back(bucket); + } + } + } + return E_OK; +} + int SQLiteSingleVerRelationalStorageExecutor::GetAssetInfoOnTable(sqlite3_stmt *&stmt, const std::vector &assetFields, VBucket &assetInfo) { @@ -1763,5 +1868,183 @@ int SQLiteSingleVerRelationalStorageExecutor::UpdateDeleteDataExtendField(const } return errCode; } + +int SQLiteSingleVerRelationalStorageExecutor::GetDownloadAssetGid(const TableSchema &tableSchema, + std::vector &gids, int64_t beginTime, bool abortWithLimit) +{ + std::string sql = "SELECT cloud_gid FROM " + DBCommon::GetLogTableName(tableSchema.name) + + " WHERE flag&0x1000=0x1000 AND timestamp >= ?;"; + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(dbHandle_, sql, stmt); + if (errCode != E_OK) { + LOGE("[RDBExecutor]Get gid statement failed, %d", errCode); + return errCode; + } + errCode = SQLiteUtils::BindInt64ToStatement(stmt, 1, beginTime); + if (errCode != E_OK) { + LOGE("[RDBExecutor] bind time failed %d when get download asset gid", errCode); + SQLiteUtils::ResetStatement(stmt, true, errCode); + return errCode; + } + uint32_t count = 0; + do { + errCode = SQLiteUtils::StepWithRetry(stmt, false); + if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + errCode = E_OK; + break; + } else if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + LOGE("[RDBExecutor]Get downloading assets gid failed. %d", errCode); + break; + } + std::string gid; + errCode = SQLiteUtils::GetColumnTextValue(stmt, 0, gid); + if (errCode != E_OK) { + LOGW("[RDBExecutor]Get downloading assets gid failed %d when get col", errCode); + continue; + } + gids.push_back(gid); + if (AbortGetDownloadAssetGidIfNeed(tableSchema, gid, abortWithLimit, count)) { + break; + } + } while (errCode == E_OK); + int ret = E_OK; + SQLiteUtils::ResetStatement(stmt, true, ret); + return errCode == E_OK ? ret : errCode; +} + +int SQLiteSingleVerRelationalStorageExecutor::GetDownloadAssetRecordsByGid(const TableSchema &tableSchema, + const std::string gid, std::vector &assets) +{ + std::vector assetFields; + std::string sql = "SELECT"; + for (const auto &field: tableSchema.fields) { + if (field.type == TYPE_INDEX || field.type == TYPE_INDEX) { + assetFields.emplace_back(field); + sql += " b." + field.colName + ","; + } + } + if (assetFields.empty()) { + return E_OK; + } + sql.pop_back(); // remove last , + sql += CloudStorageUtils::GetLeftJoinLogSql(tableSchema.name) + " WHERE a.cloud_gid = ?;"; + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(dbHandle_, sql, stmt); + if (errCode != E_OK) { + LOGE("Get downloading asset records statement failed, %d", errCode); + return errCode; + } + errCode = SQLiteUtils::BindTextToStatement(stmt, 1, gid); + if (errCode != E_OK) { + SQLiteUtils::ResetStatement(stmt, true, errCode); + return errCode; + } + errCode = SQLiteUtils::StepWithRetry(stmt); + if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + int index = 0; + for (const auto &field: assetFields) { + Type value; + errCode = SQLiteRelationalUtils::GetCloudValueByType(stmt, field.type, index++, value); + if (errCode != E_OK) { + break; + } + errCode = GetDownloadAsset(assets, field, value); + if (errCode != E_OK) { + break; + } + } + } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + errCode = E_OK; + } else { + LOGE("step get downloading asset records statement failed %d.", errCode); + } + int ret = E_OK; + SQLiteUtils::ResetStatement(stmt, true, ret); + return errCode == E_OK ? ret : errCode; +} + +int SQLiteSingleVerRelationalStorageExecutor::GetDownloadingCount(const std::string &tableName, int32_t &count) +{ + std::string sql = "SELECT count(*) FROM " + DBCommon::GetLogTableName(tableName) + " WHERE flag&0x1000=0x1000;"; + int errCode = SQLiteUtils::GetCountBySql(dbHandle_, sql, count); + if (errCode != E_OK) { + LOGE("[RDBExecutor] Query local data count failed: %d", errCode); + } + return errCode; +} + +int SQLiteSingleVerRelationalStorageExecutor::GetDownloadingAssetsCount( + const TableSchema &tableSchema, int32_t &totalCount) +{ + std::vector gids; + int errCode = GetDownloadAssetGid(tableSchema, gids); + if (errCode != E_OK) { + LOGE("[RDBExecutor]Get downloading assets gid failed: %d", errCode); + return errCode; + } + for (const auto &gid : gids) { + std::vector assets; + errCode = GetDownloadAssetRecordsByGid(tableSchema, gid, assets); + if (errCode != E_OK) { + LOGE("[RDBExecutor]Get downloading assets records by gid failed: %d", errCode); + return errCode; + } + totalCount += static_cast(assets.size()); + } + return E_OK; +} + +int SQLiteSingleVerRelationalStorageExecutor::GetDownloadAssetRecordsInner( + const TableSchema &tableSchema, int64_t beginTime, std::vector &gids) +{ + int errCode = GetDownloadAssetGid(tableSchema, gids, beginTime, true); + if (errCode != E_OK) { + LOGE("[RDBExecutor]Get downloading assets gid failed: %d", errCode); + } + return errCode; +} + +int SQLiteSingleVerRelationalStorageExecutor::CleanDownloadingFlag(const std::string &tableName) +{ + std::string sql; + sql += "UPDATE " + DBCommon::GetLogTableName(tableName) + " SET flag=flag&(~0x1000);"; + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(dbHandle_, sql, stmt); + if (errCode != E_OK) { + LOGE("[RDBExecutor]Get stmt failed clean downloading flag: %d, tableName: %s, length: %zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + return errCode; + } + errCode = SQLiteUtils::StepWithRetry(stmt); + if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + errCode = E_OK; + } else { + LOGE("[RDBExecutor]Clean downloading flag failed: %d, tableName: %s, length: %zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + } + int ret = E_OK; + SQLiteUtils::ResetStatement(stmt, true, ret); + if (ret != E_OK) { + LOGE("[RDBExecutor]Reset stmt failed clean downloading flag: %d", ret); + } + return errCode != E_OK ? errCode : ret; +} + +bool SQLiteSingleVerRelationalStorageExecutor::AbortGetDownloadAssetGidIfNeed( + const DistributedDB::TableSchema &tableSchema, const std::string &gid, bool abortWithLimit, + uint32_t &count) +{ + if (!abortWithLimit) { + return false; + } + std::vector assets; + int errCode = GetDownloadAssetRecordsByGid(tableSchema, gid, assets); + if (errCode != E_OK) { + LOGW("[RDBExecutor]Get downloading assets failed %d gid %s", errCode, gid.c_str()); + return false; + } + count += assets.size(); + return count >= RuntimeContext::GetInstance()->GetAssetsDownloadManager()->GetMaxDownloadAssetsCount(); +} } // namespace DistributedDB #endif diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_extend_executor.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_extend_executor.cpp index 174978e8cead7256a613f1774d76cdaf0a1017ef..f0cbd2bf11db99284ba19867814ecb544296669c 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_extend_executor.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_single_ver_relational_storage_extend_executor.cpp @@ -93,8 +93,46 @@ int SQLiteSingleVerRelationalStorageExecutor::GetFillDownloadAssetStatement(cons return errCode; } +int SQLiteSingleVerRelationalStorageExecutor::CleanDownloadingFlagByGid(const std::string &tableName, + const std::string &gid, VBucket dbAssets) +{ + if (CloudStorageUtils::IsAssetsContainDownloadRecord(dbAssets)) { + return E_OK; + } + std::string sql; + sql += "UPDATE " + DBCommon::GetLogTableName(tableName) + " SET flag=flag&(~0x1000) where cloud_gid = ?;"; + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(dbHandle_, sql, stmt); + if (errCode != E_OK) { + LOGE("[RDBExecutor]Get stmt failed clean downloading flag:%d, tableName:%s, length:%zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + return errCode; + } + errCode = SQLiteUtils::BindTextToStatement(stmt, 1, gid); + if (errCode != E_OK) { + LOGE("[RDBExecutor]bind gid failed when clean downloading flag:%d, tableName:%s, length:%zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + SQLiteUtils::ResetStatement(stmt, true, errCode); + return errCode; + } + errCode = SQLiteUtils::StepWithRetry(stmt); + if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + errCode = E_OK; + } else { + LOGE("[RDBExecutor]clean downloading flag failed:%d, tableName:%s, length:%zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + } + int ret = E_OK; + SQLiteUtils::ResetStatement(stmt, true, ret); + if (ret != E_OK) { + LOGE("[RDBExecutor]reset stmt when clean downloading flag:%d, tableName:%s, length:%zu", + errCode, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + } + return errCode != E_OK ? errCode : ret; +} + int SQLiteSingleVerRelationalStorageExecutor::FillCloudAssetForDownload(const TableSchema &tableSchema, - VBucket &vBucket, bool isDownloadSuccess) + VBucket &vBucket, bool isDownloadSuccess, uint64_t &currCursor) { std::string cloudGid; int errCode = CloudStorageUtils::GetValueFromVBucket(CloudDbConstant::GID_FIELD, vBucket, cloudGid); @@ -124,7 +162,7 @@ int SQLiteSingleVerRelationalStorageExecutor::FillCloudAssetForDownload(const Ta if (isDownloadSuccess) { CloudStorageUtils::FillAssetFromVBucketFinish(assetOpType, vBucket, dbAssets, CloudStorageUtils::FillAssetAfterDownload, CloudStorageUtils::FillAssetsAfterDownload); - errCode = IncreaseCursorOnAssetData(tableSchema.name, cloudGid); + errCode = IncreaseCursorOnAssetData(tableSchema.name, cloudGid, currCursor); if (errCode != E_OK) { return errCode; } @@ -132,19 +170,22 @@ int SQLiteSingleVerRelationalStorageExecutor::FillCloudAssetForDownload(const Ta CloudStorageUtils::FillAssetFromVBucketFinish(assetOpType, vBucket, dbAssets, CloudStorageUtils::FillAssetAfterDownloadFail, CloudStorageUtils::FillAssetsAfterDownloadFail); } - sqlite3_stmt *stmt = nullptr; errCode = GetFillDownloadAssetStatement(tableSchema.name, dbAssets, assetsField, stmt); if (errCode != E_OK) { return errCode; } errCode = ExecuteFillDownloadAssetStatement(stmt, assetsField.size() + 1, cloudGid); + if (errCode != E_OK) { + return errCode; + } + errCode = CleanDownloadingFlagByGid(tableSchema.name, cloudGid, dbAssets); int ret = CleanDownloadChangedAssets(vBucket, assetOpType); return errCode == E_OK ? ret : errCode; } int SQLiteSingleVerRelationalStorageExecutor::IncreaseCursorOnAssetData(const std::string &tableName, - const std::string &gid) + const std::string &gid, uint64_t &currCursor) { uint64_t cursor = DBConstant::INVALID_CURSOR; int errCode = SQLiteRelationalUtils::GetCursor(dbHandle_, tableName, cursor); @@ -186,7 +227,7 @@ int SQLiteSingleVerRelationalStorageExecutor::IncreaseCursorOnAssetData(const st LOGE("Fill upload asset failed:%d.", errCode); return errCode; } - LOGI("Upgrade cursor to %d after asset download success.", cursor); + currCursor = cursor; errCode = SetCursor(tableName, cursor); if (errCode != E_OK) { LOGE("Upgrade cursor failed after asset download success %d.", errCode); @@ -333,22 +374,17 @@ int SQLiteSingleVerRelationalStorageExecutor::AnalysisTrackerTable(const Tracker return SQLiteRelationalUtils::AnalysisTrackerTable(dbHandle_, trackerTable, tableInfo); } -int SQLiteSingleVerRelationalStorageExecutor::CreateTrackerTable(const TrackerTable &trackerTable, bool checkData) +int SQLiteSingleVerRelationalStorageExecutor::CreateTrackerTable(const TrackerTable &trackerTable, + const TableInfo &table, bool checkData) { - TableInfo table; - table.SetTableSyncType(TableSyncType::CLOUD_COOPERATION); - int errCode = AnalysisTrackerTable(trackerTable, table); - if (errCode != E_OK) { - return errCode; - } - auto tableManager = std::make_unique(); + std::unique_ptr tableManager = std::make_unique(); if (trackerTable.IsEmpty()) { // drop trigger return tableManager->AddRelationalLogTableTrigger(dbHandle_, table, ""); } // create log table - errCode = tableManager->CreateRelationalLogTable(dbHandle_, table); + int errCode = tableManager->CreateRelationalLogTable(dbHandle_, table); if (errCode != E_OK) { return errCode; } @@ -357,13 +393,12 @@ int SQLiteSingleVerRelationalStorageExecutor::CreateTrackerTable(const TrackerTa if (errCode != E_OK) { return errCode; } - std::string calPrimaryKeyHash = tableManager->CalcPrimaryKeyHash("a.", table, ""); errCode = CleanExtendAndCursorForDeleteData(table.GetTableName()); if (errCode != E_OK) { LOGE("clean tracker log info for deleted data failed %d.", errCode); return errCode; } - errCode = GeneLogInfoForExistedData(dbHandle_, trackerTable.GetTableName(), calPrimaryKeyHash, table); + errCode = GeneLogInfoForExistedData(dbHandle_, "", table, tableManager); if (errCode != E_OK) { LOGE("general tracker log info for existed data failed %d.", errCode); return errCode; @@ -479,9 +514,6 @@ int SQLiteSingleVerRelationalStorageExecutor::GetClearWaterMarkTables( int SQLiteSingleVerRelationalStorageExecutor::UpgradedLogForExistedData(TableInfo &tableInfo, bool schemaChanged) { - if (tableInfo.GetTableSyncType() == TableSyncType::DEVICE_COOPERATION) { - return E_OK; - } std::string logTable = DBCommon::GetLogTableName(tableInfo.GetTableName()); if (schemaChanged) { std::string markAsInconsistent = "UPDATE " + logTable + " SET flag=" + @@ -1711,15 +1743,21 @@ int64_t SQLiteSingleVerRelationalStorageExecutor::GetDataFlag() return static_cast(flag); } -std::string SQLiteSingleVerRelationalStorageExecutor::GetUpdateDataFlagSql() +std::string SQLiteSingleVerRelationalStorageExecutor::GetUpdateDataFlagSql(const VBucket &data) { + std::string retentionFlag = "flag = flag & " + + std::to_string(static_cast(LogInfoFlag::FLAG_DEVICE_CLOUD_INCONSISTENCY) | + static_cast(LogInfoFlag::FLAG_ASSET_DOWNLOADING_FOR_ASYNC)); if (putDataMode_ == PutDataMode::SYNC) { + if (CloudStorageUtils::IsAssetsContainDownloadRecord(data)) { + return retentionFlag; + } return UPDATE_FLAG_CLOUD; } if (markFlagOption_ == MarkFlagOption::SET_WAIT_COMPENSATED_SYNC) { return UPDATE_FLAG_WAIT_COMPENSATED_SYNC; } - return UPDATE_FLAG_CLOUD; + return retentionFlag; } std::string SQLiteSingleVerRelationalStorageExecutor::GetDev() @@ -1803,11 +1841,11 @@ int SQLiteSingleVerRelationalStorageExecutor::UpdateRecordFlag(const std::string } void SQLiteSingleVerRelationalStorageExecutor::MarkFlagAsUploadFinished(const std::string &tableName, - const Key &hashKey, Timestamp timestamp) + const Key &hashKey, Timestamp timestamp, bool isExistAssetsDownload) { sqlite3_stmt *stmt = nullptr; - int errCode = SQLiteUtils::GetStatement(dbHandle_, CloudStorageUtils::GetUpdateUploadFinishedSql(tableName), - stmt); + int errCode = SQLiteUtils::GetStatement(dbHandle_, CloudStorageUtils::GetUpdateUploadFinishedSql(tableName, + isExistAssetsDownload), stmt); int index = 1; errCode = SQLiteUtils::BindInt64ToStatement(stmt, index++, timestamp); if (errCode != E_OK) { @@ -1831,7 +1869,7 @@ void SQLiteSingleVerRelationalStorageExecutor::MarkFlagAsUploadFinished(const st } int SQLiteSingleVerRelationalStorageExecutor::GetWaitCompensatedSyncDataPk(const TableSchema &table, - std::vector &data) + std::vector &data, bool isQueryDownloadRecords) { std::string sql = "SELECT "; std::vector pkFields; @@ -1847,7 +1885,12 @@ int SQLiteSingleVerRelationalStorageExecutor::GetWaitCompensatedSyncDataPk(const return E_OK; } sql.pop_back(); - sql += CloudStorageUtils::GetLeftJoinLogSql(table.name) + " WHERE " + FLAG_IS_WAIT_COMPENSATED_SYNC; + if (isQueryDownloadRecords) { + sql += CloudStorageUtils::GetLeftJoinLogSql(table.name) + " WHERE " + + FLAG_IS_WAIT_COMPENSATED_CONTAIN_DOWNLOAD_SYNC; + } else { + sql += CloudStorageUtils::GetLeftJoinLogSql(table.name) + " WHERE " + FLAG_IS_WAIT_COMPENSATED_SYNC; + } sqlite3_stmt *stmt = nullptr; int errCode = SQLiteUtils::GetStatement(dbHandle_, sql, stmt); if (errCode != E_OK) { @@ -1952,5 +1995,11 @@ int SQLiteSingleVerRelationalStorageExecutor::BindShareValueToInsertLogStatement } return errCode; } + +void SQLiteSingleVerRelationalStorageExecutor::CheckAndCreateTrigger(const TableInfo &table) +{ + auto tableManager = std::make_unique(); + tableManager->CheckAndCreateTrigger(dbHandle_, table, ""); +} } // namespace DistributedDB #endif diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_cloud_kv_executor_utils.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_cloud_kv_executor_utils.cpp index b01aa5d8a74b850d849adc8b2410c70a887e2c1e..d4d260208b9d73e6341d725196ad32da87a17c3b 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_cloud_kv_executor_utils.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_cloud_kv_executor_utils.cpp @@ -470,9 +470,57 @@ int SqliteCloudKvExecutorUtils::OperateCloudData(sqlite3 *db, bool isMemory, int }); errCode = BindStmt(logStmt, dataStmt, index, opType, downloadData); if (errCode != E_OK) { + LOGE("[SqliteCloudKvExecutorUtils] BindStmt data stmt failed %d opType %d", errCode, static_cast(opType)); return errCode; } - return StepStmt(logStmt, dataStmt, isMemory); + errCode = StepStmt(logStmt, dataStmt, isMemory); + if (errCode != E_OK) { + LOGE("[SqliteCloudKvExecutorUtils] StepStmt data stmt failed %d opType %d", errCode, static_cast(opType)); + return errCode; + } + if (opType == OpType::INSERT || opType == OpType::UPDATE || opType == OpType::DELETE) { + return OperateOtherUserLog(db, isMemory, index, downloadData); + } + return errCode; +} + +int SqliteCloudKvExecutorUtils::OperateOtherUserLog(sqlite3 *db, bool isMemory, int index, DownloadData &downloadData) +{ + auto [errCode, dataItem] = GetDataItem(index, downloadData); + if (errCode != E_OK) { + return errCode; + } + sqlite3_stmt *logStmt = nullptr; + std::string sql = "UPDATE naturalbase_kv_aux_sync_data_log SET cloud_flag = cloud_flag & ~0x2000" + "WHERE userid != ? AND hash_key = ?"; + errCode = SQLiteUtils::GetStatement(db, sql, logStmt); + if (errCode != E_OK) { + LOGE("[SqliteCloudKvExecutorUtils] Get operate other log statement failed %d", errCode); + return errCode; + } + ResFinalizer finalizerData([logStmt]() { + sqlite3_stmt *statement = logStmt; + int ret = E_OK; + SQLiteUtils::ResetStatement(statement, true, ret); + if (ret != E_OK) { + LOGW("[SqliteCloudKvExecutorUtils] Reset operate other log stmt failed %d ", ret); + } + }); + errCode = SQLiteUtils::BindTextToStatement(logStmt, BIND_INSERT_USER_INDEX, downloadData.user); + if (errCode != E_OK) { + LOGE("[SqliteCloudKvExecutorUtils] Bind operate other log user failed %d when insert", errCode); + return errCode; + } + errCode = SQLiteUtils::BindBlobToStatement(logStmt, BIND_INSERT_HASH_KEY_INDEX, dataItem.hashKey); + if (errCode != E_OK) { + LOGE("[SqliteCloudKvExecutorUtils] Bind operate other log hashKey failed %d when insert", errCode); + return errCode; + } + errCode = SQLiteUtils::StepNext(logStmt, isMemory); + if (errCode == -E_FINISHED) { + return E_OK; + } + return errCode; } std::string SqliteCloudKvExecutorUtils::GetOperateDataSql(OpType opType) @@ -597,7 +645,7 @@ int SqliteCloudKvExecutorUtils::BindInsertStmt(sqlite3_stmt *logStmt, sqlite3_st } int SqliteCloudKvExecutorUtils::BindInsertLogStmt(sqlite3_stmt *logStmt, const std::string &user, - const DataItem &dataItem) + const DataItem &dataItem, bool isTagLogin) { int errCode = SQLiteUtils::BindTextToStatement(logStmt, BIND_INSERT_USER_INDEX, user); if (errCode != E_OK) { @@ -619,7 +667,8 @@ int SqliteCloudKvExecutorUtils::BindInsertLogStmt(sqlite3_stmt *logStmt, const s LOGE("[SqliteCloudKvExecutorUtils] Bind version failed %d when insert", errCode); return errCode; } - errCode = SQLiteUtils::BindInt64ToStatement(logStmt, BIND_INSERT_CLOUD_FLAG_INDEX, dataItem.cloud_flag); + int64_t flag = dataItem.cloud_flag | (isTagLogin ? static_cast(LogInfoFlag::FLAG_LOGIN_USER) : 0x00); + errCode = SQLiteUtils::BindInt64ToStatement(logStmt, BIND_INSERT_CLOUD_FLAG_INDEX, flag); if (errCode != E_OK) { LOGE("[SqliteCloudKvExecutorUtils] Bind cloud_flag failed %d when insert", errCode); } @@ -1441,7 +1490,7 @@ int SqliteCloudKvExecutorUtils::BindFillGidLogStmt(sqlite3_stmt *logStmt, const errCode = BindUpdateLogStmt(logStmt, user, wItem); } } else { - errCode = BindInsertLogStmt(logStmt, user, wItem); + errCode = BindInsertLogStmt(logStmt, user, wItem, false); } if (errCode != E_OK) { LOGE("[SqliteCloudKvExecutorUtils] fill cloud gid failed. %d", errCode); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_cloud_kv_executor_utils.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_cloud_kv_executor_utils.h index 85d1d20a16383949ce13f6482842c1d59b57f799..ca747b6560042b7dc6e7318cbbd3d184c02cc9f9 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_cloud_kv_executor_utils.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_cloud_kv_executor_utils.h @@ -90,6 +90,8 @@ private: static int OperateCloudData(sqlite3 *db, bool isMemory, int index, OpType opType, DownloadData &downloadData); + static int OperateOtherUserLog(sqlite3 *db, bool isMemory, int index, DownloadData &downloadData); + static std::string GetOperateDataSql(OpType opType); static std::string GetOperateLogSql(OpType opType); @@ -105,7 +107,7 @@ private: const DataItem &dataItem); static int BindInsertLogStmt(sqlite3_stmt *logStmt, const std::string &user, - const DataItem &dataItem); + const DataItem &dataItem, bool isTagLogin = true); static int BindUpdateStmt(sqlite3_stmt *logStmt, sqlite3_stmt *dataStmt, const std::string &user, const DataItem &dataItem); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_cloud_kv_store.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_cloud_kv_store.cpp index d0f9899f85aa4b624c4edbef584f4498b23dfc94..524f469bffe80faafb5820f3a3ec61deabefcebb 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_cloud_kv_store.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_cloud_kv_store.cpp @@ -260,6 +260,11 @@ int SqliteCloudKvStore::PutCloudSyncData([[gnu::unused]] const std::string &tabl return SqliteCloudKvExecutorUtils::PutCloudData(db, isMemory, downloadData); } +int SqliteCloudKvStore::UpdateAssetStatusForAssetOnly(const std::string &tableName, VBucket &asset) +{ + return E_OK; +} + int SqliteCloudKvStore::FillCloudLogAndAsset(OpType opType, const CloudSyncData &data, bool fillAsset, bool ignoreEmptyGid) { @@ -369,11 +374,22 @@ int SqliteCloudKvStore::FillCloudAssetForDownload(const std::string &tableName, return E_OK; } +int SqliteCloudKvStore::FillCloudAssetForAsyncDownload(const std::string &tableName, VBucket &asset, + bool isDownloadSuccess) +{ + return E_OK; +} + int SqliteCloudKvStore::SetLogTriggerStatus(bool status) { return E_OK; } +int SqliteCloudKvStore::SetLogTriggerStatusForAsyncDownload(bool status) +{ + return E_OK; +} + int SqliteCloudKvStore::SetCursorIncFlag(bool status) { return E_OK; @@ -384,6 +400,17 @@ int SqliteCloudKvStore::CheckQueryValid(const QuerySyncObject &query) return E_OK; } +std::pair> SqliteCloudKvStore::GetDownloadAssetTable() +{ + return {}; +} + +std::pair> SqliteCloudKvStore::GetDownloadAssetRecords( + const std::string &tableName, int64_t beginTime) +{ + return {}; +} + bool SqliteCloudKvStore::IsSharedTable(const std::string &tableName) { return false; @@ -548,6 +575,12 @@ void SqliteCloudKvStore::ReleaseUploadRecord(const std::string &tableName, const bool SqliteCloudKvStore::IsTagCloudUpdateLocal(const LogInfo &localInfo, const LogInfo &cloudInfo, SingleVerConflictResolvePolicy policy) { + // if local not delete and cloud is different user, insert data to local by timestamp + if (localInfo.dataKey != -1 && (localInfo.flag & static_cast(LogInfoFlag::FLAG_LOCAL)) == 0 && + (localInfo.cloud_flag & static_cast(LogInfoFlag::FLAG_LOGIN_USER)) == 0 && + localInfo.wTimestamp > cloudInfo.wTimestamp) { + return false; + } std::string cloudInfoDev; auto decodeCloudInfoDev = DBBase64Utils::Decode(cloudInfo.device); if (!decodeCloudInfoDev.empty()) { @@ -576,7 +609,7 @@ bool SqliteCloudKvStore::IsTagCloudUpdateLocal(const LogInfo &localInfo, const L } int SqliteCloudKvStore::GetCompensatedSyncQuery(std::vector &syncQuery, - std::vector &users) + std::vector &users, bool isQueryDownloadRecords) { std::shared_ptr cloudSchema; (void)GetCloudDbSchema(cloudSchema); @@ -604,13 +637,11 @@ int SqliteCloudKvStore::GetCompensatedSyncQuery(std::vector &sy if (syncDataPk.empty()) { continue; } - QuerySyncObject syncObject; - errCode = CloudStorageUtils::GetSyncQueryByPk(table.name, syncDataPk, true, syncObject); + errCode = CloudStorageUtils::GetSyncQueryByPk(table.name, syncDataPk, true, syncQuery); if (errCode != E_OK) { LOGW("[SqliteCloudKvStore] Get compensated sync query happen error, ignore it! errCode = %d", errCode); continue; } - syncQuery.push_back(syncObject); for (auto &oneRow : syncDataUserId) { std::string user; errCode = CloudStorageUtils::GetStringFromCloudData(CloudDbConstant::CLOUD_KV_FIELD_USERID, oneRow, user); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_cloud_kv_store.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_cloud_kv_store.h index d5533b9de15b687c9093994360ae52d1b74c7682..ba351dad6a814aac91c8073a0b06c3681d432b67 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_cloud_kv_store.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_cloud_kv_store.h @@ -64,11 +64,18 @@ public: int PutCloudSyncData(const std::string &tableName, DownloadData &downloadData) override; + int UpdateAssetStatusForAssetOnly(const std::string &tableName, VBucket &vBucket) override; + void TriggerObserverAction(const std::string &deviceName, ChangedData &&changedData, bool isChangedData) override; int FillCloudAssetForDownload(const std::string &tableName, VBucket &asset, bool isDownloadSuccess) override; + int FillCloudAssetForAsyncDownload(const std::string &tableName, VBucket &asset, bool isDownloadSuccess) override; + int SetLogTriggerStatus(bool status) override; + + int SetLogTriggerStatusForAsyncDownload(bool status) override; + int SetCursorIncFlag(bool status) override; int FillCloudLogAndAsset(OpType opType, const CloudSyncData &data, bool fillAsset, bool ignoreEmptyGid) override; @@ -102,12 +109,18 @@ public: bool IsTagCloudUpdateLocal(const LogInfo &localInfo, const LogInfo &cloudInfo, SingleVerConflictResolvePolicy policy) override; - int GetCompensatedSyncQuery(std::vector &syncQuery, std::vector &users) override; + int GetCompensatedSyncQuery(std::vector &syncQuery, std::vector &users, + bool isQueryDownloadRecords) override; int ReviseLocalModTime(const std::string &tableName, const std::vector &revisedData) override; int GetLocalDataCount(const std::string &tableName, int &dataCount, int &logicDeleteDataCount) override; + + std::pair> GetDownloadAssetTable() override; + + std::pair> GetDownloadAssetRecords(const std::string &tableName, + int64_t beginTime) override; private: std::pair GetTransactionDbHandleAndMemoryStatus(); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_log_table_manager.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_log_table_manager.cpp index e854890e438d1c5e67892aa213599dcefc87f7e6..811bc30c48d2168930f24654b4879f9797b1b365 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_log_table_manager.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_log_table_manager.cpp @@ -13,6 +13,7 @@ * limitations under the License. */ +#include "db_common.h" #include "sqlite_log_table_manager.h" namespace DistributedDB { @@ -32,7 +33,11 @@ int SqliteLogTableManager::AddRelationalLogTableTrigger(sqlite3 *db, const Table if (!deleteTrigger.empty()) { sqls.emplace_back(deleteTrigger); } - // add insert,update,delete trigger + std::string updatePkTrigger = GetUpdatePkTrigger(table, identity); + if (!updatePkTrigger.empty()) { + sqls.emplace_back(updatePkTrigger); + } + // add insert,update,delete,update pk trigger for (const auto &sql : sqls) { int errCode = SQLiteUtils::ExecuteRawSQL(db, sql); if (errCode != E_OK) { @@ -149,4 +154,113 @@ int SqliteLogTableManager::CreateKvCloudFlagIndex(const std::string &tableName, } return errCode; } + +std::string SqliteLogTableManager::GetUpdatePkTrigger([[gnu::unused]] const TableInfo &table, + [[gnu::unused]] const std::string &identity) +{ + return ""; +} + +std::string SqliteLogTableManager::GetUpdateTimestamp(const TableInfo &table, bool defaultNewTime) +{ + return GetUpdateWithAssignSql(table, "get_sys_time(0)", "get_sys_time(0)", + defaultNewTime ? "get_sys_time(0)" : "timestamp"); +} + +std::string SqliteLogTableManager::GetUpdateWithAssignSql(const TableInfo &table, const std::string &emptyValue, + const std::string &matchValue, const std::string &missMatchValue) +{ + auto syncFields = table.GetSyncField(); + if (syncFields.empty() || table.GetFields().size() <= syncFields.size()) { + return emptyValue; + } + std::string sql = " CASE WHEN ("; + for (const auto &field : syncFields) { + sql.append("(").append("OLD.'").append(field).append("'!= NEW.'").append(field).append("') OR"); + } + // pop last OR + sql.pop_back(); + sql.pop_back(); + sql.append(") THEN ").append(matchValue).append(" ELSE ").append(missMatchValue).append(" END"); + return sql; +} + +int CheckTriggerExist(sqlite3 *db, const TableInfo &table, const std::string &triggerType, bool &exist) +{ + std::string checkSql = "select count(*) from sqlite_master where type = 'trigger' and tbl_name = '" + + table.GetTableName() + "' and name = 'naturalbase_rdb_" + table.GetTableName() + "_ON_" + triggerType + "';"; + int count = 0; + int errCode = SQLiteUtils::GetCountBySql(db, checkSql, count); + if (errCode != E_OK) { + LOGW("query trigger from db fail, errCode=%d", errCode); + return errCode; + } + exist = count != 0; + return E_OK; +} + +void SqliteLogTableManager::CheckAndCreateTrigger(sqlite3 *db, const TableInfo &table, const std::string &identity) +{ + std::vector sqls; + bool insertTriggerExist = false; + const std::string &tableName = table.GetTableName(); + if (CheckTriggerExist(db, table, "INSERT", insertTriggerExist) == E_OK && !insertTriggerExist) { + LOGW("[%s [%zu]] Insert trigger does not exist, will be recreated", + DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + std::string insertTriggerSql = GetInsertTrigger(table, identity); + if (!insertTriggerSql.empty()) { + sqls.emplace_back(insertTriggerSql); + } + } + + bool updateTriggerExist = false; + if (CheckTriggerExist(db, table, "UPDATE", updateTriggerExist) == E_OK && !updateTriggerExist) { + LOGW("[%s [%zu]] Update trigger does not exist, will be recreated", + DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + std::string updateTriggerSql = GetUpdateTrigger(table, identity); + if (!updateTriggerSql.empty()) { + sqls.emplace_back(updateTriggerSql); + } + } + + bool deleteTriggerExist = false; + if (CheckTriggerExist(db, table, "DELETE", deleteTriggerExist) == E_OK && !deleteTriggerExist) { + LOGW("[%s [%zu]] Delete trigger does not exist, will be recreated", + DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size()); + std::string deleteTriggerSql = GetDeleteTrigger(table, identity); + if (!deleteTriggerSql.empty()) { + sqls.emplace_back(deleteTriggerSql); + } + } + + for (const auto &sql : sqls) { + int errCode = SQLiteUtils::ExecuteRawSQL(db, sql); + if (errCode != E_OK) { + LOGW("[%s [%zu]] Failed to recreate trigger, errCode=%d", DBCommon::StringMiddleMasking(tableName).c_str(), + tableName.size(), errCode); + } + } +} + +std::string SqliteLogTableManager::CalcPkHash(const std::string &references, const std::vector &pk) +{ + std::string sql; + if (pk.size() == 1u) { + sql = "calc_hash(" + references + "'" + pk.at(0) + "', 0)"; + } else { + sql = "calc_hash("; + for (const auto &it : pk) { + sql += "calc_hash(" + references + "'" + it + "', 0)||"; + } + sql.pop_back(); + sql.pop_back(); + sql += ", 0)"; + } + return sql; +} + +std::string SqliteLogTableManager::GetConflictPkSql(const TableInfo &table) +{ + return "ON CONFLICT(hash_key)"; +} } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_log_table_manager.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_log_table_manager.h index 6de55c1ce334df2def06e240af92f86fc4a14540..41ac1ce7e700ba00361a0c4cac3969c2b29fa051 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_log_table_manager.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_log_table_manager.h @@ -34,10 +34,22 @@ public: int CreateRelationalLogTable(sqlite3 *db, const TableInfo &table); static int CreateKvSyncLogTable(sqlite3 *db); + + void CheckAndCreateTrigger(sqlite3 *db, const TableInfo &table, const std::string &identity); + + virtual std::string GetConflictPkSql(const TableInfo &table); protected: virtual void GetIndexSql(const TableInfo &table, std::vector &schema); std::string GetLogTableName(const TableInfo &table) const; + virtual std::string GetUpdatePkTrigger(const TableInfo &table, const std::string &identity); + + static std::string GetUpdateTimestamp(const TableInfo &table, bool defaultNewTime); + + static std::string GetUpdateWithAssignSql(const TableInfo &table, const std::string &emptyValue, + const std::string &matchValue, const std::string &missMatchValue); + + static std::string CalcPkHash(const std::string &references, const std::vector &pk); private: virtual std::string GetInsertTrigger(const TableInfo &table, const std::string &identity) = 0; virtual std::string GetUpdateTrigger(const TableInfo &table, const std::string &identity) = 0; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_query_helper.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_query_helper.cpp index fbcd9902dba849fcb4cccc5d48a25661981eed60..a96ebf21d2849e01eb1888064a2700c3a0c9d2f2 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_query_helper.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_query_helper.cpp @@ -1181,11 +1181,23 @@ void SqliteQueryHelper::AppendCloudQuery(bool isCloudForcePush, bool isCompensat { sql += CloudStorageUtils::GetLeftJoinLogSql(tableName_, false); sql += " WHERE "; - if (isCompensatedTask && mode == CloudWaterType::DELETE) { + // let data after remove device data at flag_only and logic delete mode and deleted by others to upload to cloud. + if (mode == CloudWaterType::INSERT) { + sql += "(b.cloud_gid == '' and (b.flag & 0x20 != 0) and (b.flag & 0x02 = 0) and (b.flag & 0x08 != 0x08) and"; + sql += " (b.flag & 0x01 = 0) and (b.status = 0)) OR "; + } + if (mode == CloudWaterType::DELETE && isCompensatedTask) { // deleted data does not have primary key, requires gid to compensate sync sql += "(b.status = 1 AND (b.flag & 0x01 = 0x01) AND b.cloud_gid != '') OR "; - } else if (queryObjNodes_.empty() && mode != CloudWaterType::INSERT) { // means unPriorityTask and not insert - sql += "(b.status != 1) AND "; + } + if (mode == CloudWaterType::DELETE || mode == CloudWaterType::UPDATE) { + if (queryObjNodes_.empty() && isCompensatedTask) { + sql += "0 "; + return; + } + if (queryObjNodes_.empty()) { + sql += "(b.status != 1) AND "; + } } if (isCloudForcePush) { sql += " (b.flag & 0x04 != 0x04)"; @@ -1226,7 +1238,11 @@ void SqliteQueryHelper::AppendCloudGidQuery(bool isCloudForcePush, bool isCompen sql += " WHERE "; if (isCompensatedTask) { // deleted data does not have primary key, requires gid to compensate sync - sql += " (b.status = 1 AND (b.flag & 0x01 = 0x01)) OR "; + sql += "(b.status = 1 AND (b.flag & 0x01 = 0x01)) "; + if (queryObjNodes_.empty()) { + return; + } + sql += "OR "; } // actually, b.cloud_gid will not be null. sql += isCloudForcePush ? " (b.flag & 0x04 != 0x04) AND (b.cloud_gid != '') " : " (b.cloud_gid != '') "; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.cpp index e10b01f849390b561c173febbc9a1f9eff2f1378..7476c7911fac2792949dd761b7c1a7b366ec74ab 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.cpp @@ -298,7 +298,7 @@ int SQLiteSingleVerNaturalStore::CheckValueAndAmendIfNeed(ValueSource sourceType Value &amendValue, bool &useAmendValue) const { // oriValue size may already be checked previously, but check here const little - if (oriValue.size() > DBConstant::MAX_VALUE_SIZE) { + if (oriValue.size() > GetMaxValueSize()) { return -E_INVALID_ARGS; } const SchemaObject &schemaObjRef = MyProp().GetSchemaConstRef(); @@ -319,7 +319,7 @@ int SQLiteSingleVerNaturalStore::CheckValueAndAmendIfNeed(ValueSource sourceType } if (AmendValueShouldBeUse(errCode)) { std::string amended = valueObj.ToString(); - if (amended.size() > DBConstant::MAX_VALUE_SIZE) { + if (amended.size() > GetMaxValueSize()) { LOGE("[SqlSinStore][CheckAmendValue] ValueSize=%zu exceed limit after amend.", amended.size()); return -E_INVALID_FORMAT; } @@ -793,6 +793,10 @@ int SQLiteSingleVerNaturalStore::GetSyncDataNext(std::vector std::vector dataItems; auto token = static_cast(continueStmtToken); + if (token == nullptr) { + LOGE("[SingleVerNStore] Allocate continue stmt token failed."); + return -E_OUT_OF_MEMORY; + } if (token->IsQuerySync()) { errCode = GetSyncDataForQuerySync(dataItems, token, dataSizeInfo); continueStmtToken = static_cast(token); @@ -1017,8 +1021,10 @@ int SQLiteSingleVerNaturalStore::RemoveDeviceData(const std::string &deviceName, if (syncer == nullptr) { errCode = removeFunc(); } else { +#ifdef USE_DISTRIBUTEDDB_CLOUD errCode = syncer->CleanKvCloudData(removeFunc); DecObjRef(syncer); +#endif } if (errCode != E_OK) { LOGE("[SingleVerNStore] CleanKvCloudData with notify failed:%d", errCode); @@ -1035,14 +1041,18 @@ int SQLiteSingleVerNaturalStore::RemoveDeviceData(const std::string &deviceName, if (syncer == nullptr) { errCode = removeFunc(); } else { +#ifdef USE_DISTRIBUTEDDB_CLOUD errCode = syncer->CleanKvCloudData(removeFunc); DecObjRef(syncer); +#endif } if (errCode != E_OK) { LOGE("[SingleVerNStore] CleanKvCloudData with mode [%d] failed:%d", mode, errCode); return errCode; } +#ifdef USE_DISTRIBUTEDDB_CLOUD CleanAllWaterMark(); +#endif errCode = EraseAllDeviceWaterMark(DBCommon::TransferHashString(deviceName)); if (errCode != E_OK) { LOGE("[SingleVerNStore] Erase all device water mark failed %d with mode [%d]", errCode, mode); @@ -1060,14 +1070,18 @@ int SQLiteSingleVerNaturalStore::RemoveDeviceData(const std::string &deviceName, if (syncer == nullptr) { errCode = removeFunc(); } else { +#ifdef USE_DISTRIBUTEDDB_CLOUD errCode = syncer->CleanKvCloudData(removeFunc); DecObjRef(syncer); +#endif } if (errCode != E_OK) { LOGE("[SingleVerNStore] CleanKvCloudData with user and mode [%d] failed:%d", mode, errCode); return errCode; } +#ifdef USE_DISTRIBUTEDDB_CLOUD CleanAllWaterMark(); +#endif errCode = EraseAllDeviceWaterMark(DBCommon::TransferHashString(deviceName)); if (errCode != E_OK) { LOGE("[SingleVerNStore] Erase all device water mark failed %d with user and mode [%d]", errCode, mode); @@ -1136,7 +1150,7 @@ void SQLiteSingleVerNaturalStore::NotifyRemovedData(std::vector &entries) // ignore the invalid key. if (entries[index].key.size() > DBConstant::MAX_KEY_SIZE || - entries[index].value.size() > DBConstant::MAX_VALUE_SIZE) { + entries[index].value.size() > GetMaxValueSize()) { index++; continue; } @@ -1290,17 +1304,24 @@ int SQLiteSingleVerNaturalStore::SaveSyncDataItems(const QueryObject &query, std } int errCode = E_OK; auto offset = GetLocalTimeOffset(); + std::vector dataItemsRet; for (auto &item : dataItems) { // Check only the key and value size errCode = CheckDataStatus(item.key, item.value, (item.flag & DataItem::DELETE_FLAG) != 0); if (errCode != E_OK) { - return errCode; + if (item.key.empty() || item.key.size() > DBConstant::MAX_KEY_SIZE) { + return errCode; + } else { + LOGI("save sync data failed because of check data status fail errCode %d!", errCode); + } } if (offset != 0) { item.modifyTime = static_cast(static_cast(item.timestamp) - offset); item.createTime = static_cast(static_cast(item.writeTimestamp) - offset); } + dataItemsRet.push_back(item); } + dataItems = dataItemsRet; if (checkValueContent) { // LCOV_EXCL_BR_LINE CheckAmendValueContentForSyncProcedure(dataItems); } @@ -2069,6 +2090,7 @@ void SQLiteSingleVerNaturalStore::GetAndResizeLocalIdentity(std::string &outTarg } } +#ifdef USE_DISTRIBUTEDDB_CLOUD ICloudSyncStorageInterface *SQLiteSingleVerNaturalStore::GetICloudSyncInterface() const { std::lock_guard autoLock(cloudStoreMutex_); @@ -2081,12 +2103,6 @@ int SQLiteSingleVerNaturalStore::SetCloudDbSchema(const std::mapSetCloudDbSchema(schema); } -std::map SQLiteSingleVerNaturalStore::GetDataBaseSchemas() -{ - std::lock_guard autoLock(cloudStoreMutex_); - return sqliteCloudKvStore_->GetDataBaseSchemas(); -} - bool SQLiteSingleVerNaturalStore::CheckSchemaSupportForCloudSync() const { auto schemaType = GetSchemaObject().GetSchemaType(); @@ -2096,5 +2112,12 @@ bool SQLiteSingleVerNaturalStore::CheckSchemaSupportForCloudSync() const } return true; } +#endif + +std::map SQLiteSingleVerNaturalStore::GetDataBaseSchemas() +{ + std::lock_guard autoLock(cloudStoreMutex_); + return sqliteCloudKvStore_->GetDataBaseSchemas(); +} DEFINE_OBJECT_TAG_FACILITIES(SQLiteSingleVerNaturalStore) } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.h index 15ebd3424dfde6c0aa9f53098e67dd2843a6fb81..dfe61c03cb9a8254ac7eef28191076354e531894 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.h @@ -197,6 +197,10 @@ public: uint64_t GetMaxLogSize() const; + int SetMaxValueSize(uint32_t maxValueSize); + + uint32_t GetMaxValueSize() const override; + void Dump(int fd) override; int IsSupportSubscribe() const override; @@ -237,11 +241,13 @@ protected: void ReleaseResources(); - ICloudSyncStorageInterface *GetICloudSyncInterface() const override; - std::map GetDataBaseSchemas() override; +#ifdef USE_DISTRIBUTEDDB_CLOUD + ICloudSyncStorageInterface *GetICloudSyncInterface() const override; + bool CheckSchemaSupportForCloudSync() const override; +#endif private: int CheckDatabaseRecovery(const KvDBProperties &kvDBProp); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_connection.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_connection.cpp index cf1374db8cf7df6c65b01f4f5400626f86b92294..145779495bf9d5e1b78102081ce0813b1f64c77e 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_connection.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_connection.cpp @@ -357,6 +357,21 @@ int SQLiteSingleVerNaturalStoreConnection::Pragma(int cmd, void *parameter) return PragmaSetMaxLogSize(static_cast(parameter)); case PRAGMA_EXEC_CHECKPOINT: return ForceCheckPoint(); + default: + // Call of others. + errCode = PragmaNext(cmd, parameter); + break; + } + + return errCode; +} + +int SQLiteSingleVerNaturalStoreConnection::PragmaNext(int cmd, void *parameter) +{ + int errCode = E_OK; + switch (cmd) { + case PRAGMA_SET_MAX_VALUE_SIZE: + return SetMaxValueSize(*static_cast(parameter)); default: // Call Pragma() of super class. errCode = SyncAbleKvDBConnection::Pragma(cmd, parameter); @@ -712,6 +727,19 @@ int SQLiteSingleVerNaturalStoreConnection::PragmaSetMaxLogSize(uint64_t *limit) return naturalStore->SetMaxLogSize(*limit); } +int SQLiteSingleVerNaturalStoreConnection::SetMaxValueSize(uint32_t maxValueSize) +{ + SQLiteSingleVerNaturalStore *naturalStore = GetDB(); + if (naturalStore == nullptr) { + LOGE("[SingleVerConnection] db is nullptr for max value size set."); + return -E_INVALID_DB; + } + if (maxValueSize > DBConstant::MAX_SET_VALUE_SIZE || maxValueSize < DBConstant::MAX_VALUE_SIZE) { + return -E_INVALID_ARGS; + } + return naturalStore->SetMaxValueSize(maxValueSize); +} + int SQLiteSingleVerNaturalStoreConnection::ForceCheckPoint() const { int errCode = E_OK; @@ -1492,7 +1520,7 @@ int SQLiteSingleVerNaturalStoreConnection::PublishInner(SingleVerNaturalStoreCom } } - // begin to insert entry to sync table + // begin to insert entry to sync table, no more than 4M errCode = CheckDataStatus(localRecord.key, localRecord.value, false); if (errCode != E_OK) { return errCode; @@ -1654,7 +1682,7 @@ int SQLiteSingleVerNaturalStoreConnection::UnpublishOper(SingleVerNaturalStoreCo void SQLiteSingleVerNaturalStoreConnection::ReleaseCommitData(SingleVerNaturalStoreCommitNotifyData *&committedData) { if (committedData != nullptr) { - committedData->DecObjRef(committedData); + RefObject::DecObjRef(committedData); committedData = nullptr; } } @@ -1863,6 +1891,7 @@ int SQLiteSingleVerNaturalStoreConnection::UpdateKey(const DistributedDB::Update return errCode; } +#ifdef USE_DISTRIBUTEDDB_CLOUD int SQLiteSingleVerNaturalStoreConnection::SetCloudDbSchema(const std::map &schema) { int errCode = E_OK; @@ -1897,6 +1926,7 @@ int SQLiteSingleVerNaturalStoreConnection::SetCloudDbSchema(const std::mapSetCloudDbSchema(schema); } +#endif int SQLiteSingleVerNaturalStoreConnection::RegisterObserverAction(const KvStoreObserver *observer, const ObserverAction &action) @@ -1950,6 +1980,7 @@ int SQLiteSingleVerNaturalStoreConnection::RemoveDeviceData(const std::string &d return naturalStore->RemoveDeviceData(device, user, mode); } +#ifdef USE_DISTRIBUTEDDB_CLOUD int SQLiteSingleVerNaturalStoreConnection::GetCloudVersion(const std::string &device, std::map &versionMap) { @@ -1969,6 +2000,7 @@ int SQLiteSingleVerNaturalStoreConnection::SetCloudSyncConfig(const CloudSyncCon } return naturalStore->SetCloudSyncConfig(config); } +#endif void SQLiteSingleVerNaturalStoreConnection::RecordTimeIntoDataItem(Timestamp existCreateTime, DataItem &dataItem, SQLiteSingleVerNaturalStore &naturalStore) diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_connection.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_connection.h index 51d903ed53faf21f0b0503810e6eb16491fe18e9..e1755419f6aea2c5f6341bd850a866ce933c4a1f 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_connection.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_connection.h @@ -72,6 +72,7 @@ public: // Pragma interface. int Pragma(int cmd, void *parameter) override; + int PragmaNext(int cmd, void *parameter); // Parse event types(from observer mode). int TranslateObserverModeToEventTypes(unsigned mode, std::list &eventTypes) const override; @@ -105,8 +106,6 @@ public: int UpdateKey(const UpdateKeyCallback &callback) override; - int SetCloudDbSchema(const std::map &schema) override; - int RegisterObserverAction(const KvStoreObserver *observer, const ObserverAction &action) override; int UnRegisterObserverAction(const KvStoreObserver *observer) override; @@ -115,11 +114,16 @@ public: int RemoveDeviceData(const std::string &device, const std::string &user, ClearMode mode) override; + int GetEntries(const std::string &device, std::vector &entries) const override; + +#ifdef USE_DISTRIBUTEDDB_CLOUD + int SetCloudDbSchema(const std::map &schema) override; + int GetCloudVersion(const std::string &device, std::map &versionMap) override; int SetCloudSyncConfig(const CloudSyncConfig &config) override; +#endif - int GetEntries(const std::string &device, std::vector &entries) const override; private: int CheckMonoStatus(OperatePerm perm); @@ -212,6 +216,7 @@ private: bool IsFileAccessControlled() const; int PragmaSetMaxLogSize(uint64_t *limit); + int SetMaxValueSize(uint32_t maxValueSize); int ForceCheckPoint() const; bool CheckLogOverLimit(SQLiteSingleVerStorageExecutor *executor) const; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_extend.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_extend.cpp index 208b67b1bf9851d128724fa35ff5b8a5e68787ed..3658730b2001098932a6f4f1f3beded9648aa9d1 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_extend.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_extend.cpp @@ -431,6 +431,23 @@ int SQLiteSingleVerNaturalStore::SetMaxLogSize(uint64_t limit) maxLogSize_.store(limit); return E_OK; } + +int SQLiteSingleVerNaturalStore::SetMaxValueSize(uint32_t maxValueSize) +{ + LOGI("Set the max value size to %" PRIu32, maxValueSize); + storageEngine_->SetMaxValueSize(maxValueSize); + return E_OK; +} + +uint32_t SQLiteSingleVerNaturalStore::GetMaxValueSize() const +{ + if (storageEngine_ == nullptr) { + LOGE("[SingleVerNStore] Get max value size storage engine is invalid."); + return DBConstant::MAX_VALUE_SIZE; + } + return storageEngine_->GetMaxValueSize(); +} + uint64_t SQLiteSingleVerNaturalStore::GetMaxLogSize() const { return maxLogSize_.load(); @@ -507,7 +524,9 @@ std::function SQLiteSingleVerNaturalStore::RemoveDeviceDataInner(cons return errCode; } +#ifdef USE_DISTRIBUTEDDB_CLOUD CleanAllWaterMark(); +#endif if (IsExtendedCacheDBMode()) { errCode = RemoveDeviceDataInCacheMode(hashDev, isNeedNotify); } else { diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_schema_database_upgrader.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_schema_database_upgrader.cpp index 70cf68ecb843d10182aef25a11e827a4d335618e..8cb4ee92c57d768b560e184a645509d615f6c1dd 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_schema_database_upgrader.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_schema_database_upgrader.cpp @@ -95,7 +95,7 @@ void CheckGetForJsonSchema(sqlite3_context *ctx, ValueUpgradeContext &context, c } std::vector valueAmended; valueObj.WriteIntoVector(valueAmended); - if (valueAmended.size() > DBConstant::MAX_VALUE_SIZE) { + if (valueAmended.size() > DBConstant::MAX_SET_VALUE_SIZE) { sqlite3_result_error(ctx, "[SqlSingleSchemaUp][CheckGet] ValSize exceed limit after amend.", USING_STR_LEN); LOGE("[SqlSingleSchemaUp][CheckGet] Value(cnt=%u) size=%zu exceed limit after amend.", context.getCount, valueAmended.size()); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_engine.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_engine.cpp index 0cc51e10d2a983cecdeb8af2f2336abc3f37b849..c34d3896d45e236ae211ad8860ac523fa76ee29a 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_engine.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_engine.cpp @@ -26,6 +26,7 @@ #include "platform_specific.h" #include "runtime_context.h" #include "single_ver_utils.h" +#include "sqlite_log_table_manager.h" #include "sqlite_single_ver_database_upgrader.h" #include "sqlite_single_ver_natural_store.h" #include "sqlite_single_ver_schema_database_upgrader.h" @@ -35,7 +36,8 @@ SQLiteSingleVerStorageEngine::SQLiteSingleVerStorageEngine() : executorState_(ExecutorState::INVALID), cacheRecordVersion_(CACHE_RECORD_DEFAULT_VERSION), isCorrupted_(false), - isNeedUpdateSecOpt_(false) + isNeedUpdateSecOpt_(false), + maxValueSize_(DBConstant::MAX_VALUE_SIZE) {} SQLiteSingleVerStorageEngine::~SQLiteSingleVerStorageEngine() @@ -556,13 +558,6 @@ StorageExecutor *SQLiteSingleVerStorageEngine::NewSQLiteStorageExecutor(sqlite3 return executor; } executor->SetConflictResolvePolicy(option_.conflictReslovePolicy); - - int errCode = executor->CreateCloudLogTable(); - if (errCode != E_OK) { - LOGE("[SQLiteSingleVerStorageEngine] create cloud log table failed, errCode = [%d]", errCode); - delete executor; - executor = nullptr; - } return executor; } @@ -803,10 +798,17 @@ int SQLiteSingleVerStorageEngine::EndCreateExecutor(sqlite3 *db, SecurityOption errCode = SQLiteUtils::ExecuteRawSQL(db, "DETACH 'meta'"); if (errCode != E_OK) { LOGE("Detach meta db failed %d", errCode); + return errCode; } else { LOGI("Detach meta db success"); } } + errCode = SqliteLogTableManager::CreateKvSyncLogTable(db); + if (errCode != E_OK) { + LOGE("[SQLiteSingleVerStorageEngine] create cloud log table failed, errCode = [%d]", errCode); + } else { + LOGI("[SQLiteSingleVerStorageEngine] create cloud log table success"); + } return errCode; } @@ -1051,6 +1053,17 @@ void SQLiteSingleVerStorageEngine::InitConflictNotifiedFlag(SingleVerNaturalStor committedData->SetConflictedNotifiedFlag(static_cast(conflictFlag)); } +void SQLiteSingleVerStorageEngine::SetMaxValueSize(uint32_t maxValueSize) +{ + LOGI("Set the max value size to %" PRIu32, maxValueSize); + maxValueSize_ = maxValueSize; +} + +uint32_t SQLiteSingleVerStorageEngine::GetMaxValueSize() +{ + return maxValueSize_; +} + void SQLiteSingleVerStorageEngine::CommitNotifyForMigrateCache(NotifyMigrateSyncData &syncData) const { const auto &isRemote = syncData.isRemote; @@ -1083,8 +1096,7 @@ void SQLiteSingleVerStorageEngine::CommitNotifyForMigrateCache(NotifyMigrateSync return; } } - if (entry.key.size() > DBConstant::MAX_KEY_SIZE || - entry.value.size() > DBConstant::MAX_VALUE_SIZE) { // LCOV_EXCL_BR_LINE + if (entry.key.size() > DBConstant::MAX_KEY_SIZE || entry.value.size() > maxValueSize_) { // LCOV_EXCL_BR_LINE iter++; continue; } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_engine.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_engine.h index 763a56fbe7bf2fa36a769986b0f19d1a3a296c80..8c07dff2455ced7bd7873e70f061b347589aa823 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_engine.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_engine.h @@ -62,6 +62,10 @@ public: int UpgradeLocalMetaData(); + void SetMaxValueSize(uint32_t maxValueSize); + + uint32_t GetMaxValueSize(); + protected: virtual StorageExecutor *NewSQLiteStorageExecutor(sqlite3 *dbHandle, bool isWrite, bool isMemDb) override; @@ -130,6 +134,7 @@ private: std::mutex subscribeMutex_; std::map subscribeQuery_; + uint32_t maxValueSize_; }; } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor.cpp index 3ab3b288a8153c8a2efdcdded40547967e5fea15..376167a8ca23f20511b12aee3c09d7f7e3f81922 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor.cpp @@ -1040,6 +1040,7 @@ int SQLiteSingleVerStorageExecutor::Commit() } int errCode = SQLiteUtils::CommitTransaction(dbHandle_); if (errCode != E_OK) { + LOGE("sqlite single ver storage executor commit fail! errCode = [%d]", errCode); return CheckCorruptedStatus(errCode); } isTransactionOpen_ = false; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_utils.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_utils.cpp index a66a0f8ca580fe06c0fdf11a3ffc2ef3b672aec4..04cb1941941b7a2164e735eb511d448f55c109b6 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_utils.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_utils.cpp @@ -47,7 +47,7 @@ namespace { const int BIND_KEY_INDEX = 1; const int BIND_VAL_INDEX = 2; const int USING_STR_LEN = -1; - const int MAX_BLOB_READ_SIZE = 5 * 1024 * 1024; // 5M limit + const int MAX_BLOB_READ_SIZE = 64 * 1024 * 1024; // 64M limit const int MAX_TEXT_READ_SIZE = 5 * 1024 * 1024; // 5M limit const int HEAD_SIZE = 3; const int END_SIZE = 3; @@ -332,7 +332,7 @@ void SQLiteUtils::ResetStatement(sqlite3_stmt *&statement, bool isNeedFinalize, if (isNeedFinalize) { int finalizeResult = sqlite3_finalize(statement); if (finalizeResult != SQLITE_OK) { - LOGD("[SQLiteUtils] finalize statement error:%d, sys:%d", finalizeResult, errno); + LOGE("[SQLiteUtils] finalize statement error:%d, sys:%d", finalizeResult, errno); innerCode = finalizeResult; } statement = nullptr; @@ -410,23 +410,23 @@ int SQLiteUtils::BindPrefixKey(sqlite3_stmt *statement, int index, const Key &ke int SQLiteUtils::BeginTransaction(sqlite3 *db, TransactType type) { if (type == TransactType::IMMEDIATE) { - return ExecuteRawSQL(db, BEGIN_IMMEDIATE_SQL); + return ExecuteRawSQL(db, BEGIN_IMMEDIATE_SQL, true); } - return ExecuteRawSQL(db, BEGIN_SQL); + return ExecuteRawSQL(db, BEGIN_SQL, true); } int SQLiteUtils::CommitTransaction(sqlite3 *db) { - return ExecuteRawSQL(db, COMMIT_SQL); + return ExecuteRawSQL(db, COMMIT_SQL, true); } int SQLiteUtils::RollbackTransaction(sqlite3 *db) { - return ExecuteRawSQL(db, ROLLBACK_SQL); + return ExecuteRawSQL(db, ROLLBACK_SQL, true); } -int SQLiteUtils::ExecuteRawSQL(sqlite3 *db, const std::string &sql) +int SQLiteUtils::ExecuteRawSQL(sqlite3 *db, const std::string &sql, bool ignoreResetFail) { if (db == nullptr) { return -E_INVALID_DB; @@ -452,7 +452,10 @@ int SQLiteUtils::ExecuteRawSQL(sqlite3 *db, const std::string &sql) int ret = E_OK; SQLiteUtils::ResetStatement(stmt, true, ret); - return errCode != E_OK ? errCode : ret; + if (!ignoreResetFail && ret != E_OK) { + return errCode != E_OK ? errCode : ret; + } + return errCode; } int SQLiteUtils::SetKey(sqlite3 *db, CipherType type, const CipherPassword &passwd, bool setWal, uint32_t iterTimes) @@ -494,9 +497,11 @@ int SQLiteUtils::SetKey(sqlite3 *db, CipherType type, const CipherPassword &pass return errCode; } #ifndef OMIT_ENCRYPT - errCode = UpdateCipherShaAlgo(db, setWal, type, passwd, iterTimes); - if (errCode != E_OK) { - LOGE("[SQLiteUtils][Setkey] upgrade cipher sha algo failed:%d", errCode); + if (passwd.GetSize() != 0) { + errCode = UpdateCipherShaAlgo(db, setWal, type, passwd, iterTimes); + if (errCode != E_OK) { + LOGE("[SQLiteUtils][Setkey] upgrade cipher sha algo failed:%d", errCode); + } } #endif } @@ -763,11 +768,10 @@ int GetSchemaIndexList(sqlite3 *db, const std::string &tableName, std::vector *inCache) { - delete inCache; + if (inCache != nullptr) { + delete inCache; + } } } @@ -608,45 +612,39 @@ int SQLiteUtils::BindDataValueByType(sqlite3_stmt *statement, const std::optiona int SQLiteUtils::UpdateCipherShaAlgo(sqlite3 *db, bool setWal, CipherType type, const CipherPassword &passwd, uint32_t iterTimes) { - if (passwd.GetSize() != 0) { - int errCode = SetKeyInner(db, type, passwd, iterTimes); - if (errCode != E_OK) { - return errCode; - } - // set sha1 algo for old version - errCode = SQLiteUtils::ExecuteRawSQL(db, SHA1_ALGO_SQL); - if (errCode != E_OK) { - LOGE("[SQLiteUtils][UpdateCipherShaAlgo] set sha algo failed:%d", errCode); - return errCode; - } - // try to get user version - errCode = SQLiteUtils::ExecuteRawSQL(db, USER_VERSION_SQL); - if (errCode != E_OK) { - LOGE("[SQLiteUtils][UpdateCipherShaAlgo] verify version failed:%d", errCode); - if (errno == EKEYREVOKED) { - return -E_EKEYREVOKED; - } - if (errCode == -E_BUSY) { - return errCode; - } - return -E_INVALID_PASSWD_OR_CORRUPTED_DB; + int errCode = SetKeyInner(db, type, passwd, iterTimes); + if (errCode != E_OK) { + return errCode; + } + // set sha1 algo for old version + errCode = SQLiteUtils::ExecuteRawSQL(db, SHA1_ALGO_SQL); + if (errCode != E_OK) { + LOGE("[SQLiteUtils][UpdateCipherShaAlgo] set sha algo failed:%d", errCode); + return errCode; + } + // try to get user version + errCode = SQLiteUtils::ExecuteRawSQL(db, USER_VERSION_SQL); + if (errCode != E_OK) { + LOGE("[SQLiteUtils][UpdateCipherShaAlgo] verify version failed:%d", errCode); + if (errno == EKEYREVOKED) { + return -E_EKEYREVOKED; } - // try to update rekey sha algo by rekey operation - errCode = SQLiteUtils::ExecuteRawSQL(db, SHA256_ALGO_REKEY_SQL); + return errCode; + } + // try to update rekey sha algo by rekey operation + errCode = SQLiteUtils::ExecuteRawSQL(db, SHA256_ALGO_REKEY_SQL); + if (errCode != E_OK) { + LOGE("[SQLiteUtils][UpdateCipherShaAlgo] set rekey sha algo failed:%d", errCode); + return errCode; + } + if (setWal) { + errCode = SQLiteUtils::ExecuteRawSQL(db, WAL_MODE_SQL); if (errCode != E_OK) { - LOGE("[SQLiteUtils][UpdateCipherShaAlgo] set rekey sha algo failed:%d", errCode); + LOGE("[SQLite][UpdateCipherShaAlgo] execute wal sql failed: %d", errCode); return errCode; } - if (setWal) { - errCode = SQLiteUtils::ExecuteRawSQL(db, WAL_MODE_SQL); - if (errCode != E_OK) { - LOGE("[SQLite][UpdateCipherShaAlgo] execute wal sql failed: %d", errCode); - return errCode; - } - } - return Rekey(db, passwd); } - return -E_INVALID_PASSWD_OR_CORRUPTED_DB; + return Rekey(db, passwd); } int SQLiteUtils::CheckTableExists(sqlite3 *db, const std::string &tableName, bool &isCreated, bool isCheckMeta) diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/storage_engine.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/storage_engine.cpp index 7245aef5c23766ed889c2bdf6c6840e08ffb854c..7536ee532a225a16ab11559f2aa4f751ff7a23f9 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/storage_engine.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/storage_engine.cpp @@ -378,7 +378,7 @@ EngineState StorageEngine::GetEngineState() const void StorageEngine::SetEngineState(EngineState state) { if (state != EngineState::MAINDB) { - LOGI("Storage engine state to [%d]!", state); + LOGD("Storage engine state to [%d]!", state); } engineState_ = state; } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/storage_proxy.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/storage_proxy.cpp index a06be3273ec8f46bf6979520da19d08309c1ead2..b338aab4b7ff6ce70ac471efad8d6331d6589c01 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/storage_proxy.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/storage_proxy.cpp @@ -274,19 +274,19 @@ int StorageProxy::GetCloudGid(const QuerySyncObject &querySyncObject, bool isClo return store_->GetCloudGid(tableSchema, querySyncObject, isCloudForcePush, isCompensatedTask, cloudGid); } -int StorageProxy::GetInfoByPrimaryKeyOrGid(const std::string &tableName, const VBucket &vBucket, +int StorageProxy::GetInfoByPrimaryKeyOrGid(const std::string &tableName, const VBucket &vBucket, bool useTransaction, DataInfoWithLog &dataInfoWithLog, VBucket &assetInfo) { std::shared_lock readLock(storeMutex_); if (store_ == nullptr) { return -E_INVALID_DB; } - if (!transactionExeFlag_.load()) { + if (useTransaction && !transactionExeFlag_.load()) { LOGE("the transaction has not been started"); return -E_TRANSACT_STATE; } - int errCode = store_->GetInfoByPrimaryKeyOrGid(tableName, vBucket, dataInfoWithLog, assetInfo); + int errCode = store_->GetInfoByPrimaryKeyOrGid(tableName, vBucket, useTransaction, dataInfoWithLog, assetInfo); if (errCode == E_OK) { dataInfoWithLog.logInfo.timestamp = EraseNanoTime(dataInfoWithLog.logInfo.timestamp); dataInfoWithLog.logInfo.wTimestamp = EraseNanoTime(dataInfoWithLog.logInfo.wTimestamp); @@ -329,6 +329,44 @@ int StorageProxy::PutCloudSyncData(const std::string &tableName, DownloadData &d return store_->PutCloudSyncData(tableName, downloadData); } +int StorageProxy::UpdateAssetStatusForAssetOnly(const std::string &tableName, VBucket &asset) +{ + std::shared_lock readLock(storeMutex_); + if (store_ == nullptr) { + LOGE("the store is nullptr"); + return -E_INVALID_DB; + } + if (!transactionExeFlag_.load()) { + LOGE("the transaction has not been started"); + return -E_TRANSACT_STATE; + } + int ret = SetCursorIncFlag(false); + if (ret != E_OK) { + LOGE("set curosr inc flag false fail when update for assets only. [table: %s length: %lu] err:%d", + DBCommon::StringMiddleMasking(tableName).c_str(), tableName.length(), ret); + return ret; + } + ret = SetLogTriggerStatus(false); + if (ret != E_OK) { + LOGE("set log trigger false fail when update for assets only. [table: %s length: %lu] err:%d", + DBCommon::StringMiddleMasking(tableName).c_str(), tableName.length(), ret); + return ret; + } + ret = store_->UpdateAssetStatusForAssetOnly(tableName, asset); + if (ret != E_OK) { + LOGE("update for assets only fail. [table: %s length: %lu] err:%d", + DBCommon::StringMiddleMasking(tableName).c_str(), tableName.length(), ret); + return ret; + } + ret = SetLogTriggerStatus(true); + if (ret != E_OK) { + LOGE("set log trigger false true when update for assets only. table: %s err:%d", + DBCommon::StringMiddleMasking(tableName).c_str(), ret); + return ret; + } + return SetCursorIncFlag(true); +} + int StorageProxy::CleanCloudData(ClearMode mode, const std::vector &tableNameList, const RelationalSchemaObject &localSchema, std::vector &assets) { @@ -421,6 +459,25 @@ int StorageProxy::NotifyChangedData(const std::string &deviceName, ChangedData & return E_OK; } +int StorageProxy::FillCloudAssetForAsyncDownload(const std::string &tableName, VBucket &asset, bool isDownloadSuccess) +{ + std::shared_lock readLock(storeMutex_); + if (store_ == nullptr) { + LOGE("[StorageProxy]the store is nullptr when fill asset for async download"); + return -E_INVALID_DB; + } + return store_->FillCloudAssetForAsyncDownload(tableName, asset, isDownloadSuccess); +} + +void StorageProxy::PrintCursorChange(const std::string &tableName) +{ + std::shared_lock readLock(storeMutex_); + if (store_ == nullptr) { + return; + } + store_->PrintCursorChange(tableName); +} + int StorageProxy::FillCloudAssetForDownload(const std::string &tableName, VBucket &asset, bool isDownloadSuccess) { std::shared_lock readLock(storeMutex_); @@ -434,13 +491,17 @@ int StorageProxy::FillCloudAssetForDownload(const std::string &tableName, VBucke return store_->FillCloudAssetForDownload(tableName, asset, isDownloadSuccess); } -int StorageProxy::SetLogTriggerStatus(bool status) +int StorageProxy::SetLogTriggerStatus(bool status, bool isAsyncDownload) { std::shared_lock readLock(storeMutex_); if (store_ == nullptr) { return -E_INVALID_DB; } - return store_->SetLogTriggerStatus(status); + if (isAsyncDownload) { + return store_->SetLogTriggerStatusForAsyncDownload(status); + } else { + return store_->SetLogTriggerStatus(status); + } } int StorageProxy::FillCloudLogAndAsset(OpType opType, const CloudSyncData &data) @@ -522,7 +583,7 @@ int StorageProxy::ClearAllTempSyncTrigger() int StorageProxy::IsSharedTable(const std::string &tableName, bool &IsSharedTable) { - std::unique_lock writeLock(storeMutex_); + std::shared_lock readLock(storeMutex_); if (store_ == nullptr) { return -E_INVALID_DB; } @@ -543,8 +604,8 @@ void StorageProxy::FillCloudGidIfSuccess(const OpType opType, const CloudSyncDat } } -std::pair StorageProxy::GetAssetsByGidOrHashKey(const std::string &tableName, const std::string &gid, - const Bytes &hashKey, VBucket &assets) +std::pair StorageProxy::GetAssetsByGidOrHashKey(const std::string &tableName, bool isAsyncDownload, + const std::string &gid, const Bytes &hashKey, VBucket &assets) { std::shared_lock readLock(storeMutex_); if (store_ == nullptr) { @@ -556,7 +617,11 @@ std::pair StorageProxy::GetAssetsByGidOrHashKey(const std::string LOGE("get cloud table schema failed: %d", errCode); return { errCode, static_cast(LockStatus::UNLOCK) }; } - return store_->GetAssetsByGidOrHashKey(tableSchema, gid, hashKey, assets); + if (isAsyncDownload) { + return store_->GetAssetsByGidOrHashKeyForAsyncDownload(tableSchema, gid, hashKey, assets); + } else { + return store_->GetAssetsByGidOrHashKey(tableSchema, gid, hashKey, assets); + } } int StorageProxy::SetIAssetLoader(const std::shared_ptr &loader) @@ -568,22 +633,28 @@ int StorageProxy::SetIAssetLoader(const std::shared_ptr &loader) return store_->SetIAssetLoader(loader); } -int StorageProxy::UpdateRecordFlag(const std::string &tableName, bool recordConflict, const LogInfo &logInfo) +int StorageProxy::UpdateRecordFlag(const std::string &tableName, bool isAsyncDownload, bool recordConflict, + const LogInfo &logInfo) { std::shared_lock readLock(storeMutex_); if (store_ == nullptr) { return -E_INVALID_DB; } - return store_->UpdateRecordFlag(tableName, recordConflict, logInfo); + if (isAsyncDownload) { + return store_->UpdateRecordFlagForAsyncDownload(tableName, recordConflict, logInfo); + } else { + return store_->UpdateRecordFlag(tableName, recordConflict, logInfo); + } } -int StorageProxy::GetCompensatedSyncQuery(std::vector &syncQuery, std::vector &users) +int StorageProxy::GetCompensatedSyncQuery(std::vector &syncQuery, std::vector &users, + bool isQueryDownloadRecords) { std::shared_lock readLock(storeMutex_); if (store_ == nullptr) { return -E_INVALID_DB; } - return store_->GetCompensatedSyncQuery(syncQuery, users); + return store_->GetCompensatedSyncQuery(syncQuery, users, isQueryDownloadRecords); } int StorageProxy::ClearUnLockingNoNeedCompensated() @@ -605,6 +676,16 @@ int StorageProxy::MarkFlagAsConsistent(const std::string &tableName, const Downl return store_->MarkFlagAsConsistent(tableName, downloadData, gidFilters); } +int StorageProxy::MarkFlagAsAssetAsyncDownload(const std::string &tableName, const DownloadData &downloadData, + const std::set &gidFilters) +{ + std::shared_lock readLock(storeMutex_); + if (store_ == nullptr) { + return -E_INVALID_DB; + } + return store_->MarkFlagAsAssetAsyncDownload(tableName, downloadData, gidFilters); +} + void StorageProxy::OnSyncFinish() { std::shared_lock readLock(storeMutex_); @@ -728,4 +809,71 @@ int StorageProxy::GetLocalDataCount(const std::string &tableName, int &dataCount } return store_->GetLocalDataCount(tableName, dataCount, logicDeleteDataCount); } + +std::pair> StorageProxy::GetDownloadAssetTable() +{ + std::shared_lock readLock(storeMutex_); + if (store_ == nullptr) { + LOGE("[StorageProxy] no store found when get downloading assets table"); + return {-E_INVALID_DB, std::vector()}; + } + return store_->GetDownloadAssetTable(); +} + +std::pair> StorageProxy::GetDownloadAssetRecords(const std::string &tableName, + int64_t beginTime) +{ + std::shared_lock readLock(storeMutex_); + if (store_ == nullptr) { + LOGE("[StorageProxy] no store found when get downloading assets"); + return {-E_INVALID_DB, std::vector()}; + } + return store_->GetDownloadAssetRecords(tableName, beginTime); +} + +void StorageProxy::BeforeUploadTransaction() +{ + std::shared_lock readLock(storeMutex_); + if (store_ == nullptr) { + return; + } + store_->DoBeforeUploadTransaction(); +} + +int StorageProxy::GetLockStatusByGid(const std::string &tableName, const std::string &gid, LockStatus &status) +{ + std::shared_lock readLock(storeMutex_); + if (store_ == nullptr) { + LOGE("[StorageProxy] no store found when get lock status"); + return -E_INVALID_DB; + } + return store_->GetLockStatusByGid(tableName, gid, status); +} + +bool StorageProxy::IsContainAssetsTable() +{ + std::shared_lock readLock(storeMutex_); + if (store_ == nullptr) { + LOGE("store is nullptr when check contain assets table"); + return false; + } + std::shared_ptr cloudSchema = nullptr; + int errCode = store_->GetCloudDbSchema(cloudSchema); + if (errCode != E_OK) { + LOGE("Cannot get cloud schema: %d when check contain assets table", errCode); + return false; + } + if (cloudSchema == nullptr) { + LOGE("Not set cloud schema when check contain assets table"); + return false; + } + for (const auto &table : cloudSchema->tables) { + for (const auto &field : table.fields) { + if (field.type == TYPE_INDEX || field.type == TYPE_INDEX) { + return true; + } + } + } + return false; } +} \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_db_proxy.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_db_proxy.cpp index d7ad65159a8710362a1ae6384093cbc37e2f618f..992b60b5c1d81c5ace74afe291df3bb3fa1c6e28 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_db_proxy.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_db_proxy.cpp @@ -21,7 +21,7 @@ namespace DistributedDB { CloudDBProxy::CloudDBProxy() - : timeout_(0) + : isDownloading_(false) { } @@ -66,7 +66,7 @@ void CloudDBProxy::SetIAssetLoader(const std::shared_ptr &loader) iAssetLoader_ = loader; } -static void RecordSyncDataTimeStampLog(std::vector &data, uint8_t action) +void CloudDBProxy::RecordSyncDataTimeStampLog(std::vector &data, InnerActionCode action) { if (data.empty()) { LOGI("[CloudDBProxy] sync data is empty"); @@ -89,7 +89,7 @@ static void RecordSyncDataTimeStampLog(std::vector &data, uint8_t actio } LOGI("[CloudDBProxy] sync action is %d and size is %d, sync data: first timestamp %lld, last timestamp %lld", - action, data.size(), first, last); + static_cast(action), data.size(), first, last); } int CloudDBProxy::BatchInsert(const std::string &tableName, std::vector &record, @@ -103,7 +103,7 @@ int CloudDBProxy::BatchInsert(const std::string &tableName, std::vector std::shared_ptr context = std::make_shared(); context->MoveInRecordAndExtend(record, extend); context->SetTableName(tableName); - int errCode = InnerAction(context, cloudDb, INSERT); + int errCode = InnerAction(context, cloudDb, InnerActionCode::INSERT); uploadInfo = context->GetInfo(); retryCount = context->GetRetryCount(); context->MoveOutRecordAndExtend(record, extend); @@ -121,7 +121,7 @@ int CloudDBProxy::BatchUpdate(const std::string &tableName, std::vector std::shared_ptr context = std::make_shared(); context->SetTableName(tableName); context->MoveInRecordAndExtend(record, extend); - int errCode = InnerAction(context, cloudDb, UPDATE); + int errCode = InnerAction(context, cloudDb, InnerActionCode::UPDATE); uploadInfo = context->GetInfo(); retryCount = context->GetRetryCount(); context->MoveOutRecordAndExtend(record, extend); @@ -139,7 +139,7 @@ int CloudDBProxy::BatchDelete(const std::string &tableName, std::vector std::shared_ptr cloudDb = iCloudDb_; context->MoveInRecordAndExtend(record, extend); context->SetTableName(tableName); - int errCode = InnerAction(context, cloudDb, DELETE); + int errCode = InnerAction(context, cloudDb, InnerActionCode::DELETE); uploadInfo = context->GetInfo(); retryCount = context->GetRetryCount(); context->MoveOutRecordAndExtend(record, extend); @@ -156,7 +156,7 @@ int CloudDBProxy::Query(const std::string &tableName, VBucket &extend, std::vect std::shared_ptr context = std::make_shared(); context->MoveInQueryExtendAndData(extend, data); context->SetTableName(tableName); - int errCode = InnerAction(context, cloudDb, QUERY); + int errCode = InnerAction(context, cloudDb, InnerActionCode::QUERY); context->MoveOutQueryExtendAndData(extend, data); for (auto &item : data) { for (auto &row : item) { @@ -167,7 +167,7 @@ int CloudDBProxy::Query(const std::string &tableName, VBucket &extend, std::vect DBCommon::RemoveDuplicateAssetsData(*assets); } } - RecordSyncDataTimeStampLog(data, QUERY); + RecordSyncDataTimeStampLog(data, InnerActionCode::QUERY); return errCode; } @@ -180,7 +180,7 @@ std::pair CloudDBProxy::Lock() std::shared_ptr cloudDb = iCloudDb_; std::shared_ptr context = std::make_shared(); std::pair lockStatus; - int errCode = InnerAction(context, cloudDb, LOCK); + int errCode = InnerAction(context, cloudDb, InnerActionCode::LOCK); context->MoveOutLockStatus(lockStatus); lockStatus.first = errCode; return lockStatus; @@ -194,7 +194,7 @@ int CloudDBProxy::UnLock() } std::shared_ptr cloudDb = iCloudDb_; std::shared_ptr context = std::make_shared(); - return InnerAction(context, cloudDb, UNLOCK); + return InnerAction(context, cloudDb, InnerActionCode::UNLOCK); } int CloudDBProxy::Close() @@ -241,7 +241,7 @@ int CloudDBProxy::HeartBeat() std::shared_ptr cloudDb = iCloudDb_; std::shared_ptr context = std::make_shared(); - return InnerAction(context, cloudDb, HEARTBEAT); + return InnerAction(context, cloudDb, InnerActionCode::HEARTBEAT); } bool CloudDBProxy::IsNotExistCloudDB() const @@ -261,9 +261,14 @@ int CloudDBProxy::Download(const std::string &tableName, const std::string &gid, LOGE("Asset loader has not been set %d", -E_NOT_SET); return -E_NOT_SET; } + isDownloading_ = true; DBStatus status = iAssetLoader_->Download(tableName, gid, prefix, assets); + isDownloading_ = false; if (status != OK) { LOGW("[CloudDBProxy] download asset failed %d", static_cast(status)); + if (status == SKIP_ASSET) { + return status; + } } return GetInnerErrorCode(status); } @@ -314,7 +319,7 @@ std::pair CloudDBProxy::GetEmptyCursor(const std::string &tabl std::shared_ptr cloudDb = iCloudDb_; std::shared_ptr context = std::make_shared(); context->SetTableName(tableName); - int errCode = InnerAction(context, cloudDb, GET_EMPTY_CURSOR); + int errCode = InnerAction(context, cloudDb, InnerActionCode::GET_EMPTY_CURSOR); std::pair cursorStatus; context->MoveOutCursorStatus(cursorStatus); cursorStatus.first = errCode; @@ -342,19 +347,19 @@ DBStatus CloudDBProxy::DMLActionTask(const std::shared_ptr & uint32_t recordSize = record.size(); switch (action) { - case INSERT: { + case InnerActionCode::INSERT: { status = cloudDb->BatchInsert(context->GetTableName(), std::move(record), extend); context->MoveInExtend(extend); context->SetInfo(CloudWaterType::INSERT, status, recordSize); break; } - case UPDATE: { + case InnerActionCode::UPDATE: { status = cloudDb->BatchUpdate(context->GetTableName(), std::move(record), extend); context->MoveInExtend(extend); context->SetInfo(CloudWaterType::UPDATE, status, recordSize); break; } - case DELETE: { + case InnerActionCode::DELETE: { status = cloudDb->BatchDelete(context->GetTableName(), extend); context->MoveInRecordAndExtend(record, extend); context->SetInfo(CloudWaterType::DELETE, status, recordSize); @@ -380,31 +385,31 @@ void CloudDBProxy::InnerActionTask(const std::shared_ptr &co bool setResAlready = false; LOGD("[CloudDBProxy] action %" PRIu8 " begin", static_cast(action)); switch (action) { - case INSERT: - case UPDATE: - case DELETE: + case InnerActionCode::INSERT: + case InnerActionCode::UPDATE: + case InnerActionCode::DELETE: status = DMLActionTask(context, cloudDb, action); break; - case QUERY: { + case InnerActionCode::QUERY: { status = QueryAction(context, cloudDb); if (status == QUERY_END) { setResAlready = true; } break; } - case GET_EMPTY_CURSOR: + case InnerActionCode::GET_EMPTY_CURSOR: status = InnerActionGetEmptyCursor(context, cloudDb); break; - case LOCK: + case InnerActionCode::LOCK: status = InnerActionLock(context, cloudDb); break; - case UNLOCK: + case InnerActionCode::UNLOCK: status = cloudDb->UnLock(); if (status != OK) { LOGE("[CloudDBProxy] UnLock cloud DB failed: %d", static_cast(status)); } break; - case HEARTBEAT: + case InnerActionCode::HEARTBEAT: status = cloudDb->HeartBeat(); if (status != OK) { LOGE("[CloudDBProxy] Heart beat error: %d", static_cast(status)); @@ -480,6 +485,8 @@ int CloudDBProxy::GetInnerErrorCode(DBStatus status) return -E_CLOUD_VERSION_CONFLICT; case CLOUD_RECORD_EXIST_CONFLICT: return -E_CLOUD_RECORD_EXIST_CONFLICT; + case CLOUD_DISABLED: + return -E_CLOUD_DISABLED; default: return -E_CLOUD_ERROR; } @@ -751,7 +758,9 @@ int CloudDBProxy::BatchOperateAssetsInner(const std::string &tableName, return -E_NOT_SET; } if (operationType == CloudDBProxy::BATCH_DOWNLOAD) { + isDownloading_ = true; iAssetLoader_->BatchDownload(tableName, necessaryRecords); + isDownloading_ = false; } else if (operationType == CloudDBProxy::BATCH_REMOVE_LOCAL) { iAssetLoader_->BatchRemoveLocalAssets(tableName, necessaryRecords); } else { @@ -802,4 +811,20 @@ void CloudDBProxy::CopyAssetsBack(std::vector &origin i++; } } + +void CloudDBProxy::CancelDownload() +{ + std::shared_lock readLock(assetLoaderMutex_); + if (!isDownloading_) { + return; + } + if (iAssetLoader_ == nullptr) { + LOGE("[CloudDBProxy] Asset loader has not been set %d when cancel", -E_NOT_SET); + return; + } + DBStatus status = iAssetLoader_->CancelDownload(); + if (status != OK) { + LOGW("[CloudDBProxy] cancel download failed %d", static_cast(status)); + } +} } diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_db_proxy.h b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_db_proxy.h index 018c987343e33b52b1ec73673bc4fb3548b139f8..c63805571f642c40e8b4dd84260e78ae82bab627 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_db_proxy.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_db_proxy.h @@ -82,6 +82,8 @@ public: int BatchRemoveLocalAssets(const std::string &tableName, std::vector &removeAssets); + void CancelDownload(); + static int GetInnerErrorCode(DBStatus status); protected: class CloudActionContext { @@ -144,7 +146,7 @@ protected: std::pair lockStatus_; std::pair cursorStatus_; }; - enum InnerActionCode : uint8_t { + enum class InnerActionCode : uint8_t { INSERT = 0, UPDATE, DELETE, @@ -194,12 +196,14 @@ protected: static void CopyAssetsBack(std::vector &originalRecords, const std::vector &indexes, std::vector &newRecords); + static void RecordSyncDataTimeStampLog(std::vector &data, InnerActionCode action); + mutable std::shared_mutex cloudMutex_; mutable std::shared_mutex assetLoaderMutex_; std::shared_ptr iCloudDb_; std::map> cloudDbs_; std::shared_ptr iAssetLoader_; - std::atomic timeout_; + std::atomic isDownloading_; mutable std::mutex genVersionMutex_; GenerateCloudVersionCallback genVersionCallback_; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_merge_strategy.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_merge_strategy.cpp index 1d67a71e23f9e4b24990f9259354c19c6cf2e993..526eebaa022db39a41d51e80c13486b285f21925 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_merge_strategy.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_merge_strategy.cpp @@ -52,7 +52,7 @@ OpType CloudMergeStrategy::TagSyncDataStatus(bool existInLocal, bool isCloudWin, if (!localInfo.isNeedUpdateAsset && IsSameRecord(cloudInfo, localInfo)) { return OpType::NOT_HANDLE; } - return TagUpdateLocal(cloudInfo, localInfo); + return TagLoginUserAndUpdate(localInfo, cloudInfo); } bool CloudMergeStrategy::JudgeUpdateCursor() @@ -81,6 +81,15 @@ OpType CloudMergeStrategy::TagLocallyNewer(const LogInfo &localInfo, const LogIn return OpType::NOT_HANDLE; } +OpType CloudMergeStrategy::TagLoginUserAndUpdate(const LogInfo &localInfo, const LogInfo &cloudInfo) +{ + if (JudgeKvScene() && (localInfo.cloud_flag & static_cast(LogInfoFlag::FLAG_LOGIN_USER)) == 0 + && localInfo.wTimestamp > cloudInfo.wTimestamp) { + return OpType::NOT_HANDLE; + } + return TagUpdateLocal(cloudInfo, localInfo); +} + OpType CloudMergeStrategy::TagCloudUpdateLocal(const LogInfo &localInfo, const LogInfo &cloudInfo, bool isCloudDelete, bool isLocalDelete) { diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_merge_strategy.h b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_merge_strategy.h index 3b7532d9c1f289ed70f7ac522b63abcd3539c5a7..b7c6dfa4bc72a59e79760cd508a8ced1a0d7ba94 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_merge_strategy.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_merge_strategy.h @@ -35,6 +35,8 @@ private: OpType TagCloudUpdateLocal(const LogInfo &localInfo, const LogInfo &cloudInfo, bool isCloudDelete, bool isLocalDelete); + OpType TagLoginUserAndUpdate(const LogInfo &localInfo, const LogInfo &cloudInfo); + OpType TagLocalNotExist(bool isCloudDelete); bool JudgeLocallyNewer(const LogInfo &localInfo, const LogInfo &cloudInfo); }; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_tag_assets.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_tag_assets.cpp index a6fe0daf316d0e7a147fb63bcd2c14b8905494bd..9529e785e060c36b5d501b0171381b965b8358c3 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_tag_assets.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_tag_assets.cpp @@ -134,9 +134,12 @@ void TagAssetWithSameHash(const bool isNormalStatus, Asset &beCoveredAsset, Asse AssetOpType::INSERT : AssetOpType::NO_CHANGE, coveredAsset, res, errCode); } -std::pair TagForNotContainsAsset(const std::string &assetFieldName, VBucket &coveredData, - VBucket &beCoveredData, bool setNormalStatus, int &errCode) +std::pair TagForNotContainsAsset( + const std::string &assetFieldName, TagAssetsInfo &tagAssetsInfo, int &errCode) { + bool setNormalStatus = tagAssetsInfo.setNormalStatus; + VBucket &coveredData = tagAssetsInfo.coveredData; + VBucket &beCoveredData = tagAssetsInfo.beCoveredData; std::pair res = { true, {} }; bool beCoveredHasAssets = IsDataContainField(assetFieldName, beCoveredData); bool coveredHasAssets = IsDataContainField(assetFieldName, coveredData); @@ -158,17 +161,18 @@ std::pair TagForNotContainsAsset(const std::string &assetFieldName return { false, {} }; } -// AssetOpType and AssetStatus will be tagged, assets to be changed will be returned -// use VBucket rather than Type because we need to check whether it is empty -Assets TagAssets(const std::string &assetFieldName, VBucket &coveredData, VBucket &beCoveredData, - bool setNormalStatus, int &errCode) +static Assets TagAssetsInner(const std::string &assetFieldName, TagAssetsInfo &tagAssetsInfo, int &errCode) { - auto [isReturn, resAsset] = TagForNotContainsAsset(assetFieldName, coveredData, beCoveredData, - setNormalStatus, errCode); - if (isReturn) { - return resAsset; - } + VBucket &coveredData = tagAssetsInfo.coveredData; + VBucket &beCoveredData = tagAssetsInfo.beCoveredData; + bool setNormalStatus = tagAssetsInfo.setNormalStatus; + bool isFrocePullAssets = tagAssetsInfo.isFrocePullAssets; Assets res = {}; + if (!std::holds_alternative(GetAssetsCaseInsensitive(assetFieldName, coveredData)) || + !std::holds_alternative(GetAssetsCaseInsensitive(assetFieldName, beCoveredData))) { + LOGE("[TagAssetsInner] coveredData or beCoveredData does not have assets"); + return {}; + } Assets &covered = std::get(GetAssetsCaseInsensitive(assetFieldName, coveredData)); Assets &beCovered = std::get(GetAssetsCaseInsensitive(assetFieldName, beCoveredData)); std::map coveredAssetsIndexMap = CloudStorageUtils::GenAssetsIndexMap(covered); @@ -184,7 +188,7 @@ Assets TagAssets(const std::string &assetFieldName, VBucket &coveredData, VBucke // fill asset id for upload data coveredAsset.assetId = beCoveredAsset.assetId; } - if (!setNormalStatus && !beCoveredAsset.hash.empty() && beCoveredAsset.hash != coveredAsset.hash) { + if (!setNormalStatus && (beCoveredAsset.hash != coveredAsset.hash || isFrocePullAssets)) { TagAssetWithNormalStatus(setNormalStatus, AssetOpType::UPDATE, coveredAsset, res, errCode); } else if (setNormalStatus && beCoveredAsset.hash != coveredAsset.hash) { TagAssetWithNormalStatus(setNormalStatus, AssetOpType::UPDATE, coveredAsset, res, errCode); @@ -209,12 +213,27 @@ Assets TagAssets(const std::string &assetFieldName, VBucket &coveredData, VBucke return res; } -static void TagCoveredAssetInner(Asset &covered, const Asset &beCovered, const bool setNormalStatus, Assets &res, +// AssetOpType and AssetStatus will be tagged, assets to be changed will be returned +// use VBucket rather than Type because we need to check whether it is empty +Assets TagAssets(const std::string &assetFieldName, TagAssetsInfo &tagAssetsInfo, int &errCode) +{ + auto [isReturn, resAsset] = TagForNotContainsAsset(assetFieldName, tagAssetsInfo, errCode); + if (isReturn) { + return resAsset; + } + return TagAssetsInner(assetFieldName, tagAssetsInfo, errCode); +} + +static void TagCoveredAssetInner(TagAssetInfo &tagAssetInfo, Assets &res, int &errCode) { - if (!setNormalStatus && beCovered.hash.empty()) { + Asset &covered = tagAssetInfo.covered; + Asset &beCovered = tagAssetInfo.beCovered; + bool setNormalStatus = tagAssetInfo.setNormalStatus; + bool isFrocePullAssets = tagAssetInfo.isFrocePullAssets; + if (!setNormalStatus && AssetOperationUtils::IsAssetNeedDownload(beCovered)) { TagAssetWithNormalStatus(setNormalStatus, AssetOpType::INSERT, covered, res, errCode); - } else if (covered.hash != beCovered.hash) { + } else if (covered.hash != beCovered.hash || isFrocePullAssets) { TagAssetWithNormalStatus(setNormalStatus, AssetOpType::UPDATE, covered, res, errCode); } else { Assets tmpAssets = {}; @@ -222,10 +241,31 @@ static void TagCoveredAssetInner(Asset &covered, const Asset &beCovered, const b } } +void TagAssetCoveredWithNoAsset( + const std::string &assetFieldName, TagAssetsInfo &tagAssetsInfo, Assets &res, int &errCode) +{ + VBucket &coveredData = tagAssetsInfo.coveredData; + VBucket &beCoveredData = tagAssetsInfo.beCoveredData; + bool setNormalStatus = tagAssetsInfo.setNormalStatus; + if (GetAssetsCaseInsensitive(assetFieldName, beCoveredData).index() == TYPE_INDEX) { + TagAssetWithNormalStatus(setNormalStatus, AssetOpType::DELETE, + std::get(GetAssetsCaseInsensitive(assetFieldName, beCoveredData)), res, errCode); + if (!setNormalStatus) { + // only not normal need fillback asset data + coveredData[assetFieldName] = std::get(GetAssetsCaseInsensitive(assetFieldName, beCoveredData)); + } + } else if (GetAssetsCaseInsensitive(assetFieldName, beCoveredData).index() == TYPE_INDEX) { + TagAssetsWithNormalStatus(setNormalStatus, AssetOpType::DELETE, + std::get(GetAssetsCaseInsensitive(assetFieldName, beCoveredData)), res, errCode); + } +} + // AssetOpType and AssetStatus will be tagged, assets to be changed will be returned -Assets TagAsset(const std::string &assetFieldName, VBucket &coveredData, VBucket &beCoveredData, - bool setNormalStatus, int &errCode) +Assets TagAsset(const std::string &assetFieldName, TagAssetsInfo &tagAssetsInfo, int &errCode) { + VBucket &coveredData = tagAssetsInfo.coveredData; + VBucket &beCoveredData = tagAssetsInfo.beCoveredData; + bool setNormalStatus = tagAssetsInfo.setNormalStatus; Assets res = {}; bool beCoveredHasAsset = IsDataContainField(assetFieldName, beCoveredData) || IsDataContainField(assetFieldName, beCoveredData); @@ -240,17 +280,7 @@ Assets TagAsset(const std::string &assetFieldName, VBucket &coveredData, VBucket return res; } if (!coveredHasAsset) { - if (GetAssetsCaseInsensitive(assetFieldName, beCoveredData).index() == TYPE_INDEX) { - TagAssetWithNormalStatus(setNormalStatus, AssetOpType::DELETE, - std::get(GetAssetsCaseInsensitive(assetFieldName, beCoveredData)), res, errCode); - if (!setNormalStatus) { - // only not normal need fillback asset data - coveredData[assetFieldName] = std::get(GetAssetsCaseInsensitive(assetFieldName, beCoveredData)); - } - } else if (GetAssetsCaseInsensitive(assetFieldName, beCoveredData).index() == TYPE_INDEX) { - TagAssetsWithNormalStatus(setNormalStatus, AssetOpType::DELETE, - std::get(GetAssetsCaseInsensitive(assetFieldName, beCoveredData)), res, errCode); - } + TagAssetCoveredWithNoAsset(assetFieldName, tagAssetsInfo, res, errCode); return res; } Asset &covered = std::get(GetAssetsCaseInsensitive(assetFieldName, coveredData)); @@ -274,7 +304,8 @@ Assets TagAsset(const std::string &assetFieldName, VBucket &coveredData, VBucket // fill asset id for upload data covered.assetId = beCovered.assetId; } - TagCoveredAssetInner(covered, beCovered, setNormalStatus, res, errCode); + TagAssetInfo tagAssetInfo = {covered, beCovered, tagAssetsInfo.setNormalStatus, tagAssetsInfo.isFrocePullAssets}; + TagCoveredAssetInner(tagAssetInfo, res, errCode); return res; } @@ -328,18 +359,17 @@ void TagAssetForUpload(const std::string &filedName, bool isInsert, VBucket &cov } } // namespace -Assets TagAssetsInSingleCol( - VBucket &coveredData, VBucket &beCoveredData, const Field &assetField, bool setNormalStatus, int &errCode) +Assets TagAssetsInSingleCol(TagAssetsInfo &tagAssetsInfo, const Field &assetField, int &errCode) { // Define a list to store the tagged result Assets assets = {}; switch (assetField.type) { case TYPE_INDEX: { - assets = TagAssets(assetField.colName, coveredData, beCoveredData, setNormalStatus, errCode); + assets = TagAssets(assetField.colName, tagAssetsInfo, errCode); break; } case TYPE_INDEX: { - assets = TagAsset(assetField.colName, coveredData, beCoveredData, setNormalStatus, errCode); + assets = TagAsset(assetField.colName, tagAssetsInfo, errCode); break; } default: diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_tag_assets.h b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_tag_assets.h index 0db944fa7c883d3f215188fadf014fc0b0b15ac3..75fd6c8ac780bcdc85b0eab625f5f658f8ecf6d4 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_tag_assets.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_tag_assets.h @@ -29,8 +29,21 @@ namespace DistributedDB { -Assets TagAssetsInSingleCol( - VBucket &coveredData, VBucket &beCoveredData, const Field &assetField, bool setNormalStatus, int &errCode); +struct TagAssetsInfo { + VBucket &coveredData; + VBucket &beCoveredData; + bool setNormalStatus = false; + bool isFrocePullAssets = false; +}; + +struct TagAssetInfo { + Asset &covered; + Asset &beCovered; + bool setNormalStatus = false; + bool isFrocePullAssets = false; +}; + +Assets TagAssetsInSingleCol(TagAssetsInfo &tagAssetsInfo, const Field &assetField, int &errCode); Type &GetAssetsCaseInsensitive(const std::string &assetFieldName, VBucket &vBucket); void TagAssetsInSingleCol(const Field &assetField, bool isInsert, VBucket &coveredData); } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_utils.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_utils.cpp index 82397022719bd84ecc14726e0e3ab5248b2ce796..46878a2a5eb8d90d1e831d8d5c5daaf6fe6cb06a 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_utils.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_utils.cpp @@ -12,13 +12,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "cloud/cloud_sync_utils.h" + #include "cloud/asset_operation_utils.h" #include "cloud/cloud_db_constant.h" #include "cloud/cloud_storage_utils.h" #include "db_common.h" +#include "db_dfx_adapter.h" #include "db_errno.h" #include "log_print.h" -#include "cloud/cloud_sync_utils.h" namespace DistributedDB { int CloudSyncUtils::GetCloudPkVals(const VBucket &datum, const std::vector &pkColNames, int64_t dataKey, @@ -617,6 +619,7 @@ CloudSyncer::CloudTaskInfo CloudSyncUtils::InitCompensatedSyncTaskInfo() { CloudSyncer::CloudTaskInfo taskInfo; taskInfo.priorityTask = true; + taskInfo.priorityLevel = CloudDbConstant::COMMON_TASK_PRIORITY_LEVEL; taskInfo.timeout = CloudDbConstant::CLOUD_DEFAULT_TIMEOUT; taskInfo.mode = SyncMode::SYNC_MODE_CLOUD_MERGE; taskInfo.callback = nullptr; @@ -650,4 +653,317 @@ CloudSyncer::CloudTaskInfo CloudSyncUtils::InitCompensatedSyncTaskInfo(const Clo taskInfo.prepareTraceId = oriTaskInfo.prepareTraceId; return taskInfo; } + +void CloudSyncUtils::CheckQueryCloudData(std::string &traceId, DownloadData &downloadData, + std::vector &pkColNames) +{ + for (auto &data : downloadData.data) { + bool isVersionExist = data.count(CloudDbConstant::VERSION_FIELD) != 0; + bool isContainAllPk = true; + for (auto &pkColName : pkColNames) { + if (data.count(pkColName) == 0) { + isContainAllPk = false; + break; + } + } + std::string gid; + (void)CloudStorageUtils::GetValueFromVBucket(CloudDbConstant::GID_FIELD, data, gid); + if (!isVersionExist || !isContainAllPk) { + LOGE("[CloudSyncer] Invalid data from cloud, no version[%d], lost primary key[%d], gid[%s], traceId[%s]", + static_cast(!isVersionExist), static_cast(!isContainAllPk), gid.c_str(), traceId.c_str()); + } + } +} + +bool CloudSyncUtils::IsNeedUpdateAsset(const VBucket &data) +{ + for (const auto &item : data) { + const Asset *asset = std::get_if>(&item.second); + if (asset != nullptr) { + uint32_t lowBitStatus = AssetOperationUtils::EraseBitMask(asset->status); + if (lowBitStatus == static_cast(AssetStatus::ABNORMAL) || + lowBitStatus == static_cast(AssetStatus::DOWNLOADING)) { + return true; + } + continue; + } + const Assets *assets = std::get_if>(&item.second); + if (assets == nullptr) { + continue; + } + for (const auto &oneAsset : *assets) { + uint32_t lowBitStatus = AssetOperationUtils::EraseBitMask(oneAsset.status); + if (lowBitStatus == static_cast(AssetStatus::ABNORMAL) || + lowBitStatus == static_cast(AssetStatus::DOWNLOADING)) { + return true; + } + } + } + return false; +} + +std::tuple CloudSyncUtils::GetDownloadListByGid( + const std::shared_ptr &proxy, const std::vector &data, const std::string &table) +{ + std::tuple res; + std::vector pkColNames; + std::vector assetFields; + auto &[errCode, downloadList, changeData] = res; + errCode = proxy->GetPrimaryColNamesWithAssetsFields(table, pkColNames, assetFields); + if (errCode != E_OK) { + LOGE("[CloudSyncUtils] Get %s pk names by failed %d", DBCommon::StringMiddleMasking(table).c_str(), errCode); + return res; + } + changeData.tableName = table; + changeData.type = ChangedDataType::ASSET; + changeData.field = pkColNames; + for (const auto &gid : data) { + VBucket assetInfo; + VBucket record; + record[CloudDbConstant::GID_FIELD] = gid; + DataInfoWithLog dataInfo; + errCode = proxy->GetInfoByPrimaryKeyOrGid(table, record, false, dataInfo, assetInfo); + if (errCode != E_OK) { + LOGE("[CloudSyncUtils] Get download list by gid failed %s %d", gid.c_str(), errCode); + break; + } + Type prefix; + std::vector pkVal; + OpType strategy = OpType::UPDATE; + errCode = CloudSyncUtils::GetCloudPkVals(dataInfo.primaryKeys, pkColNames, dataInfo.logInfo.dataKey, pkVal); + if (errCode != E_OK) { + LOGE("[CloudSyncUtils] HandleTagAssets cannot get primary key value list. %d", errCode); + break; + } + if (IsSinglePrimaryKey(pkColNames) && !pkVal.empty()) { + prefix = pkVal[0]; + } + auto assetsMap = AssetOperationUtils::FilterNeedDownloadAsset(assetInfo); + downloadList.push_back( + std::make_tuple(dataInfo.logInfo.cloudGid, prefix, strategy, assetsMap, dataInfo.logInfo.hashKey, + pkVal, dataInfo.logInfo.timestamp)); + } + return res; +} + +void CloudSyncUtils::UpdateMaxTimeWithDownloadList(const DownloadList &downloadList, const std::string &table, + std::map &downloadBeginTime) +{ + auto origin = downloadBeginTime[table]; + for (const auto &item : downloadList) { + auto timestamp = std::get(item); + downloadBeginTime[table] = std::max(static_cast(timestamp), downloadBeginTime[table]); + } + if (downloadBeginTime[table] == origin) { + downloadBeginTime[table]++; + } +} + +bool CloudSyncUtils::IsContainDownloading(const DownloadAssetUnit &downloadAssetUnit) +{ + auto &assets = std::get(downloadAssetUnit); + for (const auto &item : assets) { + for (const auto &asset : item.second) { + if ((AssetOperationUtils::EraseBitMask(asset.status) & static_cast(AssetStatus::DOWNLOADING)) + != 0) { + return true; + } + } + } + return false; +} + +int CloudSyncUtils::GetDownloadAssetsOnlyMapFromDownLoadData( + size_t idx, ICloudSyncer::SyncParam ¶m, std::map &downloadAssetsMap) +{ + std::string gid; + int errCode = CloudStorageUtils::GetValueFromVBucket( + CloudDbConstant::GID_FIELD, param.downloadData.data[idx], gid); + if (errCode != E_OK) { + LOGE("Get gid from bucket fail when get download assets only map from download data, error code %d", errCode); + return errCode; + } + + auto assetsMap = param.gidAssetsMap[gid]; + for (auto &item : param.downloadData.data[idx]) { + auto findAssetList = assetsMap.find(item.first); + if (findAssetList == assetsMap.end()) { + continue; + } + Asset *asset = std::get_if(&item.second); + if (asset != nullptr) { + auto matchName = std::find_if(findAssetList->second.begin(), + findAssetList->second.end(), + [&asset](const std::string &a) { return a == asset->name; }); + if (matchName != findAssetList->second.end()) { + Asset tmpAsset = *asset; + tmpAsset.status = static_cast(AssetStatus::UPDATE); + tmpAsset.flag = static_cast(AssetOpType::UPDATE); + downloadAssetsMap[item.first].push_back(tmpAsset); + } + continue; + } + Assets *assets = std::get_if(&item.second); + if (assets == nullptr) { + continue; + } + for (const auto &assetItem : (*assets)) { + auto matchName = std::find_if(findAssetList->second.begin(), + findAssetList->second.end(), + [&assetItem](const std::string &a) { return a == assetItem.name; }); + if (matchName != findAssetList->second.end()) { + Asset tmpAsset = assetItem; + tmpAsset.status = static_cast(AssetStatus::UPDATE); + tmpAsset.flag = static_cast(AssetOpType::UPDATE); + downloadAssetsMap[item.first].push_back(tmpAsset); + } + } + } + return E_OK; +} + +int CloudSyncUtils::NotifyChangeData(const std::string &dev, const std::shared_ptr &proxy, + ChangedData &&changedData) +{ + int ret = proxy->NotifyChangedData(dev, std::move(changedData)); + if (ret != E_OK) { + DBDfxAdapter::ReportBehavior( + {__func__, Scene::CLOUD_SYNC, State::END, Stage::CLOUD_NOTIFY, StageResult::FAIL, ret}); + LOGE("[CloudSyncer] Cannot notify changed data while downloading, %d.", ret); + } else { + DBDfxAdapter::ReportBehavior( + {__func__, Scene::CLOUD_SYNC, State::END, Stage::CLOUD_NOTIFY, StageResult::SUCC, ret}); + } + return ret; +} + +int CloudSyncUtils::GetQueryAndUsersForCompensatedSync(bool isQueryDownloadRecords, + std::shared_ptr &storageProxy, std::vector &users, + std::vector &syncQuery) +{ + int errCode = storageProxy->GetCompensatedSyncQuery(syncQuery, users, isQueryDownloadRecords); + if (errCode != E_OK) { + LOGW("[CloudSyncer] get query for compensated sync failed! errCode = %d", errCode); + return errCode; + } + if (syncQuery.empty()) { + LOGD("[CloudSyncer] Not need generate compensated sync"); + } + return E_OK; +} + +void CloudSyncUtils::GetUserListForCompensatedSync( + CloudDBProxy &cloudDB, const std::vector &users, std::vector &userList) +{ + auto cloudDBs = cloudDB.GetCloudDB(); + if (cloudDBs.empty()) { + LOGW("[CloudSyncer][GetUserListForCompensatedSync] not set cloud db"); + return; + } + for (auto &[user, cloudDb] : cloudDBs) { + auto it = std::find(users.begin(), users.end(), user); + if (it != users.end()) { + userList.push_back(user); + } + } +} + +bool CloudSyncUtils::SetAssetsMapByCloudGid( + std::vector &cloudGid, const AssetsMap &groupAssetsMap, std::map &gidAssetsMap) +{ + bool isFindOneRecord = false; + for (auto &iter : cloudGid) { + auto gidIter = gidAssetsMap.find(iter); + if (gidIter == gidAssetsMap.end()) { + continue; + } + for (const auto &pair : groupAssetsMap) { + if (gidIter->second.find(pair.first) == gidIter->second.end()) { + gidIter->second[pair.first] = pair.second; + } else { + // merge assets + gidIter->second[pair.first].insert(pair.second.begin(), pair.second.end()); + } + } + isFindOneRecord = true; + } + return isFindOneRecord; +} + +bool CloudSyncUtils::CheckAssetsOnlyIsEmptyInGroup( + const std::map &gidAssetsMap, const AssetsMap &assetsMap) +{ + if (gidAssetsMap.empty()) { + return true; + } + for (const auto &item : gidAssetsMap) { + const auto &gidAssets = item.second; + if (gidAssets.empty()) { + return true; + } + bool isMatch = true; + for (const auto &assets : assetsMap) { + auto iter = gidAssets.find(assets.first); + if (iter == gidAssets.end()) { + isMatch = false; + break; + } + if (!std::includes(iter->second.begin(), iter->second.end(), assets.second.begin(), assets.second.end())) { + isMatch = false; + break; + } + } + if (isMatch) { + // find one match, so group is not empty. + return false; + } + } + return true; +} + +bool CloudSyncUtils::IsAssetOnlyData(VBucket &queryData, AssetsMap &assetsMap, bool isDownloading) +{ + if (assetsMap.empty()) { + return false; + } + for (auto &item : assetsMap) { + auto &assetNameList = item.second; + auto findAssetField = queryData.find(item.first); + if (findAssetField == queryData.end() || assetNameList.empty()) { + // if not find asset field or assetNameList is empty, mean this is not asset only data. + return false; + } + + Asset *asset = std::get_if(&(findAssetField->second)); + if (asset != nullptr) { + // if is Asset type, assetNameList size must be 1. + if (assetNameList.size() != 1u || *(assetNameList.begin()) != asset->name || + asset->status == AssetStatus::DELETE) { + // if data is delele, also not asset only data. + return false; + } + if (isDownloading) { + asset->status = static_cast(AssetStatus::DOWNLOADING); + } + continue; + } + + Assets *assets = std::get_if(&(findAssetField->second)); + if (assets == nullptr) { + return false; + } + for (auto &assetName : assetNameList) { + auto findAsset = std::find_if( + assets->begin(), assets->end(), [&assetName](const Asset &a) { return a.name == assetName; }); + if (findAsset == assets->end() || (*findAsset).status == AssetStatus::DELETE) { + // if data is delele, also not asset only data. + return false; + } + if (isDownloading) { + (*findAsset).status = AssetStatus::DOWNLOADING; + } + } + } + return true; +} } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_utils.h b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_utils.h index b175c74c5813362e00973729412852d4e5ed1187..dd5cd76e2477e186abe2cb677f1a8a88380da1f2 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_utils.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_sync_utils.h @@ -103,6 +103,40 @@ public: const SyncProcessCallback &onProcess); static CloudSyncer::CloudTaskInfo InitCompensatedSyncTaskInfo(const CloudSyncer::CloudTaskInfo &oriTaskInfo); + + static void CheckQueryCloudData(std::string &traceId, DownloadData &downloadData, + std::vector &pkColNames); + + static bool IsNeedUpdateAsset(const VBucket &data); + + static std::tuple GetDownloadListByGid(const std::shared_ptr &proxy, + const std::vector &data, const std::string &table); + + static void UpdateMaxTimeWithDownloadList(const DownloadList &downloadList, const std::string &table, + std::map &downloadBeginTime); + + static bool IsContainDownloading(const DownloadAssetUnit &downloadAssetUnit); + + static int GetDownloadAssetsOnlyMapFromDownLoadData( + size_t idx, ICloudSyncer::SyncParam ¶m, std::map &downloadAssetsMap); + + static int NotifyChangeData(const std::string &dev, const std::shared_ptr &proxy, + ChangedData &&changedData); + + static int GetQueryAndUsersForCompensatedSync(bool isQueryDownloadRecords, + std::shared_ptr &storageProxy, std::vector &users, + std::vector &syncQuery); + + static void GetUserListForCompensatedSync( + CloudDBProxy &cloudDB, const std::vector &users, std::vector &userList); + + static bool SetAssetsMapByCloudGid(std::vector &cloudGid, const AssetsMap &groupAssetsMap, + std::map &gidAssetsMap); + + static bool CheckAssetsOnlyIsEmptyInGroup( + const std::map &gidAssetsMap, const AssetsMap &assetsMap); + + static bool IsAssetOnlyData(VBucket &queryData, AssetsMap &assetsMap, bool isDownloading); private: static void InsertOrReplaceChangedDataByType(ChangeType type, std::vector &pkVal, ChangedData &changedData); diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.cpp index bcd5d5d681e5bf697cd75d79ec60eae41050ff12..6344da0d4ee3919bc965116b71d5c28d1f8f9c69 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.cpp @@ -43,7 +43,10 @@ CloudSyncer::CloudSyncer( hasKvRemoveTask(false), timerId_(0u), isKvScene_(isKvScene), - policy_(policy) + policy_(policy), + asyncTaskId_(INVALID_TASK_ID), + cancelAsyncTask_(false), + waitDownloadListener_(nullptr) { if (storageProxy_ != nullptr) { id_ = storageProxy_->GetIdentify(); @@ -92,9 +95,6 @@ int CloudSyncer::Sync(const CloudTaskInfo &taskInfo) if (errCode != E_OK) { return errCode; } - if (taskInfo.priorityTask) { - MarkCurrentTaskPausedIfNeed(); - } return TriggerSync(); } @@ -181,6 +181,12 @@ void CloudSyncer::DoSyncIfNeed() if (PrepareSync(triggerTaskId) != E_OK) { break; } + // if the task is compensated task, we should get the query data and user list. + if (IsCompensatedTask(triggerTaskId) && !TryToInitQueryAndUserListForCompensatedSync(triggerTaskId)) { + // try to init query fail, we finish the compensated task. + continue; + } + CancelBackgroundDownloadAssetsTaskIfNeed(); // do sync logic std::vector usersList; { @@ -290,9 +296,10 @@ int CloudSyncer::PrepareAndUpload(const CloudTaskInfo &taskInfo, size_t index) int CloudSyncer::DoUploadInNeed(const CloudTaskInfo &taskInfo, const bool needUpload) { - if (!needUpload) { + if (!needUpload || taskInfo.isAssetsOnly) { return E_OK; } + storageProxy_->BeforeUploadTransaction(); int errCode = storageProxy_->StartTransaction(); if (errCode != E_OK) { LOGE("[CloudSyncer] start transaction failed before doing upload."); @@ -466,8 +473,7 @@ void CloudSyncer::DoFinished(TaskId taskId, int errCode) } { std::lock_guard autoLock(dataLock_); - taskQueue_.remove(taskId); - priorityTaskQueue_.remove(taskId); + RemoveTaskFromQueue(cloudTaskInfos_[taskId].priorityLevel, taskId); } ClearContextAndNotify(taskId, errCode); } @@ -522,6 +528,9 @@ int CloudSyncer::UpdateChangedData(SyncParam ¶m, DownloadList &assetsDownloa bool CloudSyncer::IsDataContainDuplicateAsset(const std::vector &assetFields, VBucket &data) { for (const auto &assetField : assetFields) { + if (data.find(assetField.colName) == data.end()) { + return false; + } if (assetField.type == TYPE_INDEX && data[assetField.colName].index() == TYPE_INDEX) { if (CloudStorageUtils::IsAssetsContainDuplicateAsset(std::get(data[assetField.colName]))) { return true; @@ -547,7 +556,7 @@ bool CloudSyncer::IsDataContainAssets() } std::map CloudSyncer::TagAssetsInSingleRecord(VBucket &coveredData, VBucket &beCoveredData, - bool setNormalStatus, int &errCode) + bool setNormalStatus, bool isForcePullAseets, int &errCode) { // Define a map to store the result std::map res = {}; @@ -557,8 +566,9 @@ std::map CloudSyncer::TagAssetsInSingleRecord(VBucket &cove assetFields = currentContext_.assetFields[currentContext_.tableName]; } // For every column contain asset or assets, assetFields are in context + TagAssetsInfo tagAssetsInfo = {coveredData, beCoveredData, setNormalStatus, isForcePullAseets}; for (const Field &assetField : assetFields) { - Assets assets = TagAssetsInSingleCol(coveredData, beCoveredData, assetField, setNormalStatus, errCode); + Assets assets = TagAssetsInSingleCol(tagAssetsInfo, assetField, errCode); if (!assets.empty()) { res[assetField.colName] = assets; } @@ -569,28 +579,37 @@ std::map CloudSyncer::TagAssetsInSingleRecord(VBucket &cove return res; } -int CloudSyncer::FillCloudAssets(const std::string &tableName, VBucket &normalAssets, - VBucket &failedAssets) +int CloudSyncer::FillCloudAssets(InnerProcessInfo &info, VBucket &normalAssets, VBucket &failedAssets) { int ret = E_OK; if (normalAssets.size() > 1) { - ret = storageProxy_->FillCloudAssetForDownload(tableName, normalAssets, true); + if (info.isAsyncDownload) { + ret = storageProxy_->FillCloudAssetForAsyncDownload(info.tableName, normalAssets, true); + } else { + ret = storageProxy_->FillCloudAssetForDownload(info.tableName, normalAssets, true); + } if (ret != E_OK) { - LOGE("[CloudSyncer] Can not fill normal cloud assets for download"); + LOGE("[CloudSyncer]%s download: Can not fill normal assets for download", + info.isAsyncDownload ? "Async" : "Sync"); return ret; } } if (failedAssets.size() > 1) { - ret = storageProxy_->FillCloudAssetForDownload(tableName, failedAssets, false); + if (info.isAsyncDownload) { + ret = storageProxy_->FillCloudAssetForAsyncDownload(info.tableName, failedAssets, false); + } else { + ret = storageProxy_->FillCloudAssetForDownload(info.tableName, failedAssets, false); + } if (ret != E_OK) { - LOGE("[CloudSyncer] Can not fill abnormal assets for download"); + LOGE("[CloudSyncer]%s download: Can not fill abnormal assets for download", + info.isAsyncDownload ? "Async" : "Sync"); return ret; } } return E_OK; } -int CloudSyncer::HandleDownloadResult(const DownloadItem &downloadItem, const std::string &tableName, +int CloudSyncer::HandleDownloadResult(const DownloadItem &downloadItem, InnerProcessInfo &info, DownloadCommitList &commitList, uint32_t &successCount) { successCount = 0; @@ -599,7 +618,7 @@ int CloudSyncer::HandleDownloadResult(const DownloadItem &downloadItem, const st LOGE("[CloudSyncer] start transaction Failed before handle download."); return errCode; } - errCode = CommitDownloadAssets(downloadItem, tableName, commitList, successCount); + errCode = CommitDownloadAssets(downloadItem, info, commitList, successCount); if (errCode != E_OK) { successCount = 0; int ret = E_OK; @@ -714,7 +733,8 @@ int CloudSyncer::TagDownloadAssets(const Key &hashKey, size_t idx, SyncParam &pa case OpType::NOT_HANDLE: case OpType::ONLY_UPDATE_GID: case OpType::SET_CLOUD_FORCE_PUSH_FLAG_ZERO: { // means upload need this data - (void)TagAssetsInSingleRecord(localAssetInfo, param.downloadData.data[idx], true, ret); + (void)TagAssetsInSingleRecord( + localAssetInfo, param.downloadData.data[idx], true, param.isForcePullAseets, ret); for (const auto &[col, value]: localAssetInfo) { param.downloadData.data[idx].insert_or_assign(col, value); } @@ -746,7 +766,7 @@ int CloudSyncer::HandleTagAssets(const Key &hashKey, const DataInfo &dataInfo, s } AssetOperationUtils::FilterDeleteAsset(param.downloadData.data[idx]); std::map assetsMap = TagAssetsInSingleRecord(param.downloadData.data[idx], localAssetInfo, - false, ret); + false, param.isForcePullAseets, ret); if (ret != E_OK) { LOGE("[CloudSyncer] TagAssetsInSingleRecord report ERROR in download data"); return ret; @@ -762,7 +782,7 @@ int CloudSyncer::HandleTagAssets(const Key &hashKey, const DataInfo &dataInfo, s } int CloudSyncer::SaveDatum(SyncParam ¶m, size_t idx, std::vector> &deletedList, - std::map &localLogInfoCache) + std::map &localLogInfoCache, std::vector &localInfo) { int ret = PreHandleData(param.downloadData.data[idx], param.pkColNames); if (ret != E_OK) { @@ -790,6 +810,20 @@ int CloudSyncer::SaveDatum(SyncParam ¶m, size_t idx, std::vectorsecond; + localAssetInfo[CloudDbConstant::HASH_KEY_FIELD] = dataInfo.localInfo.logInfo.hashKey; + localInfo.push_back(localAssetInfo); + return ret; // assets only not need to save changed data without assets. + } + ret = CloudSyncUtils::SaveChangedData(param, idx, dataInfo, deletedList); if (ret != E_OK) { LOGE("[CloudSyncer] Cannot save changed data: %d.", ret); @@ -816,8 +850,9 @@ int CloudSyncer::SaveData(CloudSyncer::TaskId taskId, SyncParam ¶m) std::vector> deletedList; // use for record local delete status std::map localLogInfoCache; + std::vector localInfo; for (size_t i = 0; i < param.downloadData.data.size(); i++) { - ret = SaveDatum(param, i, deletedList, localLogInfoCache); + ret = SaveDatum(param, i, deletedList, localLogInfoCache, localInfo); if (ret != E_OK) { param.info.downLoadInfo.failCount += param.downloadData.data.size(); LOGE("[CloudSyncer] Cannot save datum due to error code %d", ret); @@ -829,13 +864,12 @@ int CloudSyncer::SaveData(CloudSyncer::TaskId taskId, SyncParam ¶m) std::lock_guard autoLock(dataLock_); currentContext_.assetDownloadList = param.assetsDownloadList; } - // save the data to the database by batch, downloadData will return rowid when insert data. - ret = storageProxy_->PutCloudSyncData(param.tableName, param.downloadData); + + ret = PutCloudSyncDataOrUpdateStatusForAssetOnly(param, localInfo); if (ret != E_OK) { - param.info.downLoadInfo.failCount += param.downloadData.data.size(); - LOGE("[CloudSyncer] Cannot save the data to database with error code: %d.", ret); return ret; } + ret = UpdateChangedData(param, currentContext_.assetDownloadList); if (ret != E_OK) { param.info.downLoadInfo.failCount += param.downloadData.data.size(); @@ -852,7 +886,7 @@ int CloudSyncer::SaveData(CloudSyncer::TaskId taskId, SyncParam ¶m) } else { param.cloudWaterMark = std::get(lastData[CloudDbConstant::CURSOR_FIELD]); } - return UpdateFlagForSavedRecord(param); + return param.isAssetsOnly ? E_OK : UpdateFlagForSavedRecord(param); } int CloudSyncer::PreCheck(CloudSyncer::TaskId &taskId, const TableName &tableName) @@ -899,7 +933,7 @@ bool CloudSyncer::NeedNotifyChangedData(const ChangedData &changedData) return true; } -int CloudSyncer::NotifyChangedData(ChangedData &&changedData) +int CloudSyncer::NotifyChangedDataInCurrentTask(ChangedData &&changedData) { if (!NeedNotifyChangedData(changedData)) { return E_OK; @@ -917,15 +951,7 @@ int CloudSyncer::NotifyChangedData(ChangedData &&changedData) // We use first device name as the target of NotifyChangedData deviceName = devices[0]; } - int ret = storageProxy_->NotifyChangedData(deviceName, std::move(changedData)); - if (ret != E_OK) { - DBDfxAdapter::ReportBehavior( - {__func__, Scene::CLOUD_SYNC, State::END, Stage::CLOUD_NOTIFY, StageResult::FAIL, ret}); - LOGE("[CloudSyncer] Cannot notify changed data while downloading, %d.", ret); - } - DBDfxAdapter::ReportBehavior( - {__func__, Scene::CLOUD_SYNC, State::END, Stage::CLOUD_NOTIFY, StageResult::FAIL, ret}); - return ret; + return CloudSyncUtils::NotifyChangeData(deviceName, storageProxy_, std::move(changedData)); } void CloudSyncer::NotifyInDownload(CloudSyncer::TaskId taskId, SyncParam ¶m, bool isFirstDownload) @@ -993,7 +1019,7 @@ int CloudSyncer::SaveDataInTransaction(CloudSyncer::TaskId taskId, SyncParam &pa return ret; } -int CloudSyncer::DoDownloadAssets(bool skipSave, SyncParam ¶m) +int CloudSyncer::DoDownloadAssets(SyncParam ¶m) { // Begin downloading assets ChangedData changedAssets; @@ -1005,16 +1031,7 @@ int CloudSyncer::DoDownloadAssets(bool skipSave, SyncParam ¶m) return errCode; } if (!isSharedTable) { - (void)NotifyChangedData(std::move(changedAssets)); - } - if (ret == -E_TASK_PAUSED) { - LOGD("[CloudSyncer] current task was paused, abort download asset"); - std::lock_guard autoLock(dataLock_); - resumeTaskInfos_[currentContext_.currentTaskId].skipQuery = true; - return ret; - } else if (skipSave) { - std::lock_guard autoLock(dataLock_); - resumeTaskInfos_[currentContext_.currentTaskId].skipQuery = false; + (void)NotifyChangedDataInCurrentTask(std::move(changedAssets)); } if (ret != E_OK) { LOGE("[CloudSyncer] Cannot notify downloadAssets due to error %d", ret); @@ -1025,32 +1042,30 @@ int CloudSyncer::DoDownloadAssets(bool skipSave, SyncParam ¶m) int CloudSyncer::SaveDataNotifyProcess(CloudSyncer::TaskId taskId, SyncParam ¶m) { ChangedData changedData; - bool skipSave = false; - { - bool currentTableResume = IsCurrentTableResume(taskId, false); - std::lock_guard autoLock(dataLock_); - if (currentTableResume && resumeTaskInfos_[currentContext_.currentTaskId].skipQuery) { - skipSave = true; - } + InnerProcessInfo tmpInfo = param.info; + param.changedData = changedData; + param.downloadData.opType.resize(param.downloadData.data.size()); + param.downloadData.existDataKey.resize(param.downloadData.data.size()); + param.downloadData.existDataHashKey.resize(param.downloadData.data.size()); + int ret = SaveDataInTransaction(taskId, param); + if (ret != E_OK) { + return ret; } - int ret; - if (!skipSave) { - param.changedData = changedData; - param.downloadData.opType.resize(param.downloadData.data.size()); - param.downloadData.existDataKey.resize(param.downloadData.data.size()); - param.downloadData.existDataHashKey.resize(param.downloadData.data.size()); - ret = SaveDataInTransaction(taskId, param); - if (ret != E_OK) { - return ret; - } - // call OnChange to notify changedData object first time (without Assets) - ret = NotifyChangedData(std::move(param.changedData)); - if (ret != E_OK) { - LOGE("[CloudSyncer] Cannot notify changed data due to error %d", ret); - return ret; + // call OnChange to notify changedData object first time (without Assets) + ret = NotifyChangedDataInCurrentTask(std::move(param.changedData)); + if (ret != E_OK) { + LOGE("[CloudSyncer] Cannot notify changed data due to error %d", ret); + return ret; + } + + ret = DoDownloadAssets(param); + if (ret == -E_TASK_PAUSED) { + param.info = tmpInfo; + if (IsAsyncDownloadAssets(taskId)) { + UpdateCloudWaterMark(taskId, param); + (void)SaveCloudWaterMark(param.tableName, taskId); } } - ret = DoDownloadAssets(skipSave, param); if (ret != E_OK) { return ret; } @@ -1298,6 +1313,13 @@ int CloudSyncer::PreProcessBatchUpload(UploadParam &uploadParam, const InnerProc int CloudSyncer::SaveCloudWaterMark(const TableName &tableName, const TaskId taskId) { + { + std::lock_guard autoLock(dataLock_); + if (cloudTaskInfos_[taskId].isAssetsOnly) { + // assset only task does not need to save water mark. + return E_OK; + } + } std::string cloudWaterMark; bool isUpdateCloudCursor = true; { @@ -1445,14 +1467,26 @@ int CloudSyncer::GetCurrentTableName(std::string &tableName) return E_OK; } +size_t CloudSyncer::GetCurrentCommonTaskNum() +{ + size_t queuedTaskNum = taskQueue_.count(CloudDbConstant::COMMON_TASK_PRIORITY_LEVEL); + auto rang = taskQueue_.equal_range(CloudDbConstant::COMMON_TASK_PRIORITY_LEVEL); + size_t compensatedTaskNum = 0; + for (auto it = rang.first; it != rang.second; ++it) { + compensatedTaskNum += cloudTaskInfos_[it->second].compensatedTask ? 1 : 0; + } + return queuedTaskNum - compensatedTaskNum; +} + int CloudSyncer::CheckQueueSizeWithNoLock(bool priorityTask) { int32_t limit = queuedManualSyncLimit_; - if (!priorityTask && taskQueue_.size() >= static_cast(limit)) { - LOGW("[CloudSyncer] too much sync task"); - return -E_BUSY; - } else if (priorityTask && priorityTaskQueue_.size() >= static_cast(limit)) { - LOGW("[CloudSyncer] too much priority sync task"); + size_t totalTaskNum = taskQueue_.size(); + size_t commonTaskNum = GetCurrentCommonTaskNum(); + size_t queuedTaskNum = priorityTask ? totalTaskNum - commonTaskNum : commonTaskNum; + if (queuedTaskNum >= static_cast(limit)) { + std::string priorityName = priorityTask ? CLOUD_PRIORITY_TASK_STRING : CLOUD_COMMON_TASK_STRING; + LOGW("[CloudSyncer] too much %s sync task", priorityName.c_str()); return -E_BUSY; } return E_OK; @@ -1620,7 +1654,7 @@ void CloudSyncer::SetTaskFailed(TaskId taskId, int errCode) int32_t CloudSyncer::GetCloudSyncTaskCount() { std::lock_guard autoLock(dataLock_); - return static_cast(taskQueue_.size() + priorityTaskQueue_.size()); + return static_cast(taskQueue_.size()); } int CloudSyncer::CleanCloudData(ClearMode mode, const std::vector &tableNameList, @@ -1650,7 +1684,7 @@ int CloudSyncer::CleanCloudData(ClearMode mode, const std::vector & storageProxy_->Rollback(); return errCode; } - + LOGI("[CloudSyncer] Clean cloud data success, mode=%d", mode); if (!assets.empty() && mode == FLAG_AND_DATA) { errCode = cloudDB_.RemoveLocalAssets(assets); if (errCode != E_OK) { @@ -1658,6 +1692,7 @@ int CloudSyncer::CleanCloudData(ClearMode mode, const std::vector & storageProxy_->Rollback(); return errCode; } + LOGI("[CloudSyncer] Remove local asset success, size=%zu", assets.size()); } storageProxy_->Commit(); @@ -1683,6 +1718,10 @@ void CloudSyncer::UpdateCloudWaterMark(TaskId taskId, const SyncParam ¶m) DBCommon::StringMiddleMasking(param.tableName).c_str(), param.tableName.length()); { std::lock_guard autoLock(dataLock_); + if (cloudTaskInfos_[taskId].isAssetsOnly) { + LOGI("[CloudSyncer] assets only task not save water mark."); + return; + } currentContext_.cloudWaterMarks[currentContext_.currentUserIndex][param.info.tableName] = param.cloudWaterMark; } } @@ -1694,7 +1733,12 @@ int CloudSyncer::CommitDownloadResult(const DownloadItem &downloadItem, InnerPro return E_OK; } uint32_t successCount = 0u; - int ret = HandleDownloadResult(downloadItem, info.tableName, commitList, successCount); + int ret = E_OK; + if (info.isAsyncDownload) { + ret = CommitDownloadAssetsForAsyncDownload(downloadItem, info, commitList, successCount); + } else { + ret = HandleDownloadResult(downloadItem, info, commitList, successCount); + } if (errCode == E_OK) { info.downLoadInfo.failCount += (commitList.size() - successCount); info.downLoadInfo.successCount -= (commitList.size() - successCount); @@ -1740,7 +1784,7 @@ int CloudSyncer::TagStatusByStrategy(bool isExist, SyncParam ¶m, DataInfo &d int CloudSyncer::GetLocalInfo(size_t index, SyncParam ¶m, DataInfoWithLog &logInfo, std::map &localLogInfoCache, VBucket &localAssetInfo) { - int errCode = storageProxy_->GetInfoByPrimaryKeyOrGid(param.tableName, param.downloadData.data[index], + int errCode = storageProxy_->GetInfoByPrimaryKeyOrGid(param.tableName, param.downloadData.data[index], true, logInfo, localAssetInfo); if (errCode != E_OK && errCode != -E_NOT_FOUND) { return errCode; @@ -1749,6 +1793,13 @@ int CloudSyncer::GetLocalInfo(size_t index, SyncParam ¶m, DataInfoWithLog &l if (hashKey.empty()) { return errCode; } + + int ret = CheckLocalQueryAssetsOnlyIfNeed(localAssetInfo, param, logInfo); + if (ret != E_OK) { + LOGE("[CloudSyncer] check local assets failed, error code: %d", ret); + return ret; + } + param.downloadData.existDataKey[index] = logInfo.logInfo.dataKey; param.downloadData.existDataHashKey[index] = logInfo.logInfo.hashKey; if (localLogInfoCache.find(hashKey) != localLogInfoCache.end()) { @@ -1767,32 +1818,29 @@ int CloudSyncer::GetLocalInfo(size_t index, SyncParam ¶m, DataInfoWithLog &l } errCode = E_OK; } - logInfo.logInfo.isNeedUpdateAsset = IsNeedUpdateAsset(localAssetInfo); + logInfo.logInfo.isNeedUpdateAsset = CloudSyncUtils::IsNeedUpdateAsset(localAssetInfo); return errCode; } TaskId CloudSyncer::GetNextTaskId() { std::lock_guard autoLock(dataLock_); - if (!priorityTaskQueue_.empty()) { - return priorityTaskQueue_.front(); - } if (!taskQueue_.empty()) { - return taskQueue_.front(); + return taskQueue_.begin()->second; } return INVALID_TASK_ID; } -void CloudSyncer::MarkCurrentTaskPausedIfNeed() +void CloudSyncer::MarkCurrentTaskPausedIfNeed(const CloudTaskInfo &taskInfo) { - std::lock_guard autoLock(dataLock_); + // must sure have dataLock_ before call this function. if (currentContext_.currentTaskId == INVALID_TASK_ID) { return; } if (cloudTaskInfos_.find(currentContext_.currentTaskId) == cloudTaskInfos_.end()) { return; } - if (!cloudTaskInfos_[currentContext_.currentTaskId].priorityTask) { + if (cloudTaskInfos_[currentContext_.currentTaskId].priorityLevel < taskInfo.priorityLevel) { cloudTaskInfos_[currentContext_.currentTaskId].pause = true; LOGD("[CloudSyncer] Mark taskId %" PRIu64 " paused success", currentContext_.currentTaskId); } @@ -1836,9 +1884,6 @@ void CloudSyncer::UnlockIfNeed() std::shared_ptr cacheLocker; { std::lock_guard autoLock(dataLock_); - if (currentContext_.locker == nullptr) { - LOGW("[CloudSyncer] locker is nullptr when unlock it"); // should not happen - } cacheLocker = currentContext_.locker; currentContext_.locker = nullptr; } @@ -1864,6 +1909,18 @@ void CloudSyncer::ClearCurrentContextWithoutLock() currentContext_.repeatCount = 0; } +bool CloudSyncer::IsAlreadyHaveCompensatedSyncTask() +{ + std::lock_guard autoLock(dataLock_); + for (const auto &item : cloudTaskInfos_) { + const auto &taskInfo = item.second; + if (taskInfo.compensatedTask) { + return true; + } + } + return false; +} + void CloudSyncer::ClearContextAndNotify(TaskId taskId, int errCode) { std::shared_ptr notifier = nullptr; @@ -1899,7 +1956,8 @@ void CloudSyncer::ClearContextAndNotify(TaskId taskId, int errCode) notifier->NotifyProcess(info, {}, true); } // generate compensated sync - if (!info.compensatedTask) { + // if already have compensated sync task in queue, no need to generate new compensated sync task + if (!info.compensatedTask && !IsAlreadyHaveCompensatedSyncTask()) { CloudTaskInfo taskInfo = CloudSyncUtils::InitCompensatedSyncTaskInfo(info); GenerateCompensatedSync(taskInfo); } @@ -1957,18 +2015,15 @@ int CloudSyncer::DownloadOneAssetRecord(const std::set &dupHashKeySet, cons } } } - if (errorCode != E_OK) { - info.downLoadInfo.failCount += 1; - if (info.downLoadInfo.successCount == 0) { - LOGW("[CloudSyncer] Invalid successCount"); - } else { - info.downLoadInfo.successCount -= 1; - } - } + ModifyDownLoadInfoCount(errorCode, info); if (!downloadItem.assets.empty()) { if (dupHashKeySet.find(downloadItem.hashKey) == dupHashKeySet.end()) { - changedAssets.primaryData[CloudSyncUtils::OpTypeToChangeType(downloadItem.strategy)].push_back( - downloadItem.primaryKeyValList); + if (CloudSyncUtils::OpTypeToChangeType(downloadItem.strategy) == OP_BUTT) { + LOGW("[CloudSyncer] [DownloadOneAssetRecord] strategy is invalid."); + } else { + changedAssets.primaryData[CloudSyncUtils::OpTypeToChangeType(downloadItem.strategy)].push_back( + downloadItem.primaryKeyValList); + } } else if (downloadItem.strategy == OpType::INSERT) { changedAssets.primaryData[ChangeType::OP_UPDATE].push_back(downloadItem.primaryKeyValList); } @@ -2020,6 +2075,12 @@ int CloudSyncer::GetSyncParamForDownload(TaskId taskId, SyncParam ¶m) } } currentContext_.notifier->GetDownloadInfoByTableName(param.info); + auto queryObject = GetQuerySyncObject(param.tableName); + param.isAssetsOnly = queryObject.IsAssetsOnly(); + param.groupNum = queryObject.GetGroupNum(); + param.assetsGroupMap = queryObject.GetAssetsOnlyGroupMap(); + param.isVaildForAssetsOnly = queryObject.IsValidForAssetsOnly(); + param.isForcePullAseets = IsModeForcePull(taskId) && queryObject.IsContainQueryNodes(); return ret; } @@ -2047,8 +2108,11 @@ int CloudSyncer::DownloadDataFromCloud(TaskId taskId, SyncParam ¶m, bool &ab // Get cloud data after cloud water mark param.info.tableStatus = ProcessStatus::PROCESSING; param.downloadData = {}; + if (param.isAssetsOnly) { + param.cloudWaterMarkForAssetsOnly = param.cloudWaterMark; + } int ret = QueryCloudData(taskId, param.info.tableName, param.cloudWaterMark, param.downloadData); - CheckQueryCloudData(cloudTaskInfos_[taskId].prepareTraceId, param.downloadData, param.pkColNames); + CloudSyncUtils::CheckQueryCloudData(cloudTaskInfos_[taskId].prepareTraceId, param.downloadData, param.pkColNames); if (ret == -E_QUERY_END) { // Won't break here since downloadData may not be null param.isLastBatch = true; @@ -2059,6 +2123,17 @@ int CloudSyncer::DownloadDataFromCloud(TaskId taskId, SyncParam ¶m, bool &ab abort = true; return ret; } + + ret = CheckCloudQueryAssetsOnlyIfNeed(taskId, param); + if (ret != E_OK) { + LOGE("[CloudSyncer] query assets failed, error code: %d", ret); + std::lock_guard autoLock(dataLock_); + param.info.tableStatus = ProcessStatus::FINISHED; + currentContext_.notifier->UpdateProcess(param.info); + abort = true; + return ret; + } + if (param.downloadData.data.empty()) { if (ret == E_OK || isFirstDownload) { LOGD("[CloudSyncer] try to query cloud data use increment water mark"); @@ -2074,77 +2149,16 @@ int CloudSyncer::DownloadDataFromCloud(TaskId taskId, SyncParam ¶m, bool &ab return E_OK; } -size_t CloudSyncer::GetDownloadAssetIndex(TaskId taskId) +void CloudSyncer::ModifyDownLoadInfoCount(const int errorCode, InnerProcessInfo &info) { - size_t index = 0u; - std::lock_guard autoLock(dataLock_); - if (resumeTaskInfos_[taskId].lastDownloadIndex != 0u) { - index = resumeTaskInfos_[taskId].lastDownloadIndex; - resumeTaskInfos_[taskId].lastDownloadIndex = 0u; + if (errorCode == E_OK) { + return; } - return index; -} - -uint32_t CloudSyncer::GetCurrentTableUploadBatchIndex() -{ - std::lock_guard autoLock(dataLock_); - return currentContext_.notifier->GetUploadBatchIndex(currentContext_.tableName); -} - -void CloudSyncer::ResetCurrentTableUploadBatchIndex() -{ - std::lock_guard autoLock(dataLock_); - currentContext_.notifier->ResetUploadBatchIndex(currentContext_.tableName); -} - -void CloudSyncer::RecordWaterMark(TaskId taskId, Timestamp waterMark) -{ - std::lock_guard autoLock(dataLock_); - resumeTaskInfos_[taskId].lastLocalWatermark = waterMark; -} - -Timestamp CloudSyncer::GetResumeWaterMark(TaskId taskId) -{ - std::lock_guard autoLock(dataLock_); - return resumeTaskInfos_[taskId].lastLocalWatermark; -} - -CloudSyncer::InnerProcessInfo CloudSyncer::GetInnerProcessInfo(const std::string &tableName, UploadParam &uploadParam) -{ - InnerProcessInfo info; - info.tableName = tableName; - info.tableStatus = ProcessStatus::PROCESSING; - ReloadUploadInfoIfNeed(uploadParam, info); - return info; -} - -void CloudSyncer::SetGenCloudVersionCallback(const GenerateCloudVersionCallback &callback) -{ - cloudDB_.SetGenCloudVersionCallback(callback); -} - -std::vector CloudSyncer::CopyAndClearTaskInfos() -{ - std::vector infoList; - std::lock_guard autoLock(dataLock_); - for (const auto &item: cloudTaskInfos_) { - infoList.push_back(item.second); + info.downLoadInfo.failCount += 1; + if (info.downLoadInfo.successCount == 0) { + LOGW("[CloudSyncer] Invalid successCount"); + } else { + info.downLoadInfo.successCount -= 1; } - taskQueue_.clear(); - priorityTaskQueue_.clear(); - cloudTaskInfos_.clear(); - resumeTaskInfos_.clear(); - currentContext_.notifier = nullptr; - return infoList; -} - -void CloudSyncer::WaitCurTaskFinished() -{ - LOGD("[CloudSyncer] begin wait current task finished"); - std::unique_lock uniqueLock(dataLock_); - contextCv_.wait(uniqueLock, [this]() { - return currentContext_.currentTaskId == INVALID_TASK_ID; - }); - LOGD("[CloudSyncer] current task has been finished"); } } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.h b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.h index eeb07ddc29e917ecb5a7b391989ae5197e5cb3ff..59dcae016492cb8723baccc0cfea3edd266738c6 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer.h @@ -38,6 +38,8 @@ namespace DistributedDB { using DownloadCommitList = std::vector, bool>>; +const std::string CLOUD_PRIORITY_TASK_STRING = "priority"; +const std::string CLOUD_COMMON_TASK_STRING = "common"; class CloudSyncer : public ICloudSyncer { public: explicit CloudSyncer(std::shared_ptr storageProxy, bool isKvScene = false, @@ -132,7 +134,6 @@ protected: TaskContext context; SyncParam syncParam; bool upload = false; // task pause when upload - bool skipQuery = false; // task should skip query now size_t lastDownloadIndex = 0u; Timestamp lastLocalWatermark = 0u; int downloadStatus = E_OK; @@ -208,6 +209,8 @@ protected: int QueryCloudData(TaskId taskId, const std::string &tableName, std::string &cloudWaterMark, DownloadData &downloadData); + size_t GetCurrentCommonTaskNum(); + int CheckTaskIdValid(TaskId taskId); int GetCurrentTableName(std::string &tableName); @@ -233,7 +236,7 @@ protected: void SetTaskFailed(TaskId taskId, int errCode); int SaveDatum(SyncParam ¶m, size_t idx, std::vector> &deletedList, - std::map &localLogInfoCache); + std::map &localLogInfoCache, std::vector &localInfo); int SaveData(CloudSyncer::TaskId taskId, SyncParam ¶m); @@ -241,10 +244,7 @@ protected: int SaveDataInTransaction(CloudSyncer::TaskId taskId, SyncParam ¶m); - int SaveChangedData(SyncParam ¶m, size_t dataIndex, const DataInfo &dataInfo, - std::vector> &deletedList); - - int DoDownloadAssets(bool skipSave, SyncParam ¶m); + int DoDownloadAssets(SyncParam ¶m); int SaveDataNotifyProcess(CloudSyncer::TaskId taskId, SyncParam ¶m); @@ -252,10 +252,10 @@ protected: bool NeedNotifyChangedData(const ChangedData &changedData); - int NotifyChangedData(ChangedData &&changedData); + int NotifyChangedDataInCurrentTask(ChangedData &&changedData); std::map TagAssetsInSingleRecord(VBucket &coveredData, VBucket &beCoveredData, - bool setNormalStatus, int &errCode); + bool setNormalStatus, bool isForcePullAseets, int &errCode); int TagStatus(bool isExist, SyncParam ¶m, size_t idx, DataInfo &dataInfo, VBucket &localAssetInfo); @@ -265,12 +265,14 @@ protected: int TagDownloadAssets(const Key &hashKey, size_t idx, SyncParam ¶m, const DataInfo &dataInfo, VBucket &localAssetInfo); + int TagDownloadAssetsForAssetOnly( + const Key &hashKey, size_t idx, SyncParam ¶m, const DataInfo &dataInfo, VBucket &localAssetInfo); + void TagUploadAssets(CloudSyncData &uploadData); - int FillCloudAssets(const std::string &tableName, VBucket &normalAssets, - VBucket &failedAssets); + int FillCloudAssets(InnerProcessInfo &info, VBucket &normalAssets, VBucket &failedAssets); - int HandleDownloadResult(const DownloadItem &downloadItem, const std::string &tableName, + int HandleDownloadResult(const DownloadItem &downloadItem, InnerProcessInfo &info, DownloadCommitList &commitList, uint32_t &successCount); int FillDownloadExtend(TaskId taskId, const std::string &tableName, const std::string &cloudWaterMark, @@ -278,6 +280,9 @@ protected: int GetCloudGid(TaskId taskId, const std::string &tableName, QuerySyncObject &obj); + int GetCloudGid( + TaskId taskId, const std::string &tableName, QuerySyncObject &obj, std::vector &cloudGid); + int DownloadAssets(InnerProcessInfo &info, const std::vector &pKColNames, const std::set &dupHashKeySet, ChangedData &changedAssets); @@ -306,7 +311,7 @@ protected: TaskId GetNextTaskId(); - void MarkCurrentTaskPausedIfNeed(); + void MarkCurrentTaskPausedIfNeed(const CloudTaskInfo &taskInfo); void SetCurrentTaskFailedWithoutLock(int errCode); @@ -361,6 +366,11 @@ protected: int BatchUpdate(Info &updateInfo, CloudSyncData &uploadData, InnerProcessInfo &innerProcessInfo); + int BatchInsertOrUpdate(Info &uploadInfo, CloudSyncData &uploadData, InnerProcessInfo &innerProcessInfo, + bool isInsert); + + int BackFillAfterBatchUpload(CloudSyncData &uploadData, bool isInsert, int batchUploadResult); + int BatchDelete(Info &deleteInfo, CloudSyncData &uploadData, InnerProcessInfo &innerProcessInfo); int DownloadAssetsOneByOne(const InnerProcessInfo &info, DownloadItem &downloadItem, @@ -381,7 +391,10 @@ protected: int DownloadAssetsOneByOneInner(bool isSharedTable, const InnerProcessInfo &info, DownloadItem &downloadItem, std::map &downloadAssets); - int CommitDownloadAssets(const DownloadItem &downloadItem, const std::string &tableName, + int CommitDownloadAssets(const DownloadItem &downloadItem, InnerProcessInfo &info, + DownloadCommitList &commitList, uint32_t &successCount); + + int CommitDownloadAssetsForAsyncDownload(const DownloadItem &downloadItem, InnerProcessInfo &info, DownloadCommitList &commitList, uint32_t &successCount); void SeparateNormalAndFailAssets(const std::map &assetsMap, VBucket &normalAssets, @@ -401,6 +414,8 @@ protected: bool MergeTaskInfo(const std::shared_ptr &cloudSchema, TaskId taskId); + void RemoveTaskFromQueue(int32_t priorityLevel, TaskId taskId); + std::pair TryMergeTask(const std::shared_ptr &cloudSchema, TaskId tryTaskId); bool IsTaskCanMerge(const CloudTaskInfo &taskInfo); @@ -440,8 +455,6 @@ protected: void MarkUploadFinishIfNeed(const std::string &table); - bool IsNeedUpdateAsset(const VBucket &data); - int GenerateTaskIdIfNeed(CloudTaskInfo &taskInfo); void ProcessVersionConflictInfo(InnerProcessInfo &innerProcessInfo, uint32_t retryCount); @@ -459,7 +472,7 @@ protected: using DownloadAssetsRecords = std::vector; using DownloadAssetDetail = std::tuple; DownloadAssetDetail GetDownloadRecords(const DownloadList &downloadList, const std::set &dupHashKeySet, - bool isSharedTable, const InnerProcessInfo &info); + bool isSharedTable, bool isAsyncDownloadAssets, const InnerProcessInfo &info); int BatchDownloadAndCommitRes(const DownloadList &downloadList, const std::set &dupHashKeySet, InnerProcessInfo &info, ChangedData &changedAssets, @@ -473,12 +486,62 @@ protected: void CheckDataAfterDownload(const std::string &tableName); - void CheckQueryCloudData(std::string &traceId, DownloadData &downloadData, std::vector &pkColNames); + bool IsAsyncDownloadAssets(TaskId taskId); + + void TriggerAsyncDownloadAssetsInTaskIfNeed(bool isFirstDownload); + + void TriggerAsyncDownloadAssetsIfNeed(); + + void BackgroundDownloadAssetsTask(); + + void CancelDownloadListener(); + + void DoBackgroundDownloadAssets(); + + void CancelBackgroundDownloadAssetsTaskIfNeed(); + + void CancelBackgroundDownloadAssetsTask(bool cancelDownload = true); + + int BackgroundDownloadAssetsByTable(const std::string &table, std::map &downloadBeginTime); + + int CheckCloudQueryAssetsOnlyIfNeed(TaskId taskId, SyncParam ¶m); + + int CheckLocalQueryAssetsOnlyIfNeed(VBucket &localAssetInfo, SyncParam ¶m, DataInfoWithLog &logInfo); + + int PutCloudSyncDataOrUpdateStatusForAssetOnly(SyncParam ¶m, std::vector &localInfo); + + bool IsCurrentAsyncDownloadTask(); + + bool CanStartAsyncDownload() const; + + int GetCloudGidAndFillExtend(TaskId taskId, const std::string &tableName, QuerySyncObject &obj, VBucket &extend); + + int QueryCloudGidForAssetsOnly( + TaskId taskId, SyncParam ¶m, int64_t groupIdx, std::vector &cloudGid); + + int GetEmptyGidAssetsMapFromDownloadData( + const std::vector &data, std::map &gidAssetsMap); + + int SetAssetsMapAndEraseDataForAssetsOnly(TaskId taskId, SyncParam ¶m, std::vector &downloadData, + std::map &gidAssetsMap); + + void NotifyChangedDataWithDefaultDev(ChangedData &&changedData); + + bool IsAlreadyHaveCompensatedSyncTask(); + + bool TryToInitQueryAndUserListForCompensatedSync(TaskId triggerTaskId); + + int FillCloudAssetsForOneRecord(const std::string &gid, const std::map &assetsMap, + InnerProcessInfo &info, bool setAllNormal, bool &isExistAssetDownloadFail); + + int UpdateRecordFlagForOneRecord(const std::string &gid, const DownloadItem &downloadItem, InnerProcessInfo &info, + bool isExistAssetDownloadFail); + + static void ModifyDownLoadInfoCount(const int errorCode, InnerProcessInfo &info); mutable std::mutex dataLock_; TaskId lastTaskId_; - std::list taskQueue_; - std::list priorityTaskQueue_; + std::multimap> taskQueue_; std::map cloudTaskInfos_; std::map resumeTaskInfos_; @@ -506,6 +569,11 @@ protected: // 2. Whether the local data need update for different flag when the local time is larger. bool isKvScene_; std::atomic policy_; + std::condition_variable asyncTaskCv_; + TaskId asyncTaskId_; + std::atomic cancelAsyncTask_; + std::mutex listenerMutex_; + NotificationChain::Listener *waitDownloadListener_; static constexpr const TaskId INVALID_TASK_ID = 0u; static constexpr const int MAX_HEARTBEAT_FAILED_LIMIT = 2; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer_extend.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer_extend.cpp index 9af87b83e03ae974cf030b56d90720de15a4417f..99c32f2710e3f64b08a7bf3a4e0d569c194bda6f 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer_extend.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/cloud_syncer_extend.cpp @@ -27,7 +27,6 @@ #include "kv_store_errno.h" #include "log_print.h" #include "runtime_context.h" -#include "storage_proxy.h" #include "store_types.h" #include "strategy_factory.h" #include "version.h" @@ -70,6 +69,17 @@ void CloudSyncer::GetLastUploadInfo(const std::string &tableName, Info &lastUplo return currentContext_.notifier->GetLastUploadInfo(tableName, lastUploadInfo, retryInfo); } +int CloudSyncer::GetCloudGidAndFillExtend(TaskId taskId, const std::string &tableName, QuerySyncObject &obj, + VBucket &extend) +{ + int errCode = GetCloudGid(taskId, tableName, obj); + if (errCode != E_OK) { + LOGE("[CloudSyncer] Failed to get cloud gid when fill extend, %d.", errCode); + return errCode; + } + return CloudStorageUtils::FillCloudQueryToExtend(obj, extend); +} + int CloudSyncer::FillDownloadExtend(TaskId taskId, const std::string &tableName, const std::string &cloudWaterMark, VBucket &extend) { @@ -79,24 +89,18 @@ int CloudSyncer::FillDownloadExtend(TaskId taskId, const std::string &tableName, QuerySyncObject obj = GetQuerySyncObject(tableName); if (obj.IsContainQueryNodes()) { + return GetCloudGidAndFillExtend(taskId, tableName, obj, extend); + } + if (IsCompensatedTask(taskId)) { int errCode = GetCloudGid(taskId, tableName, obj); if (errCode != E_OK) { - LOGE("[CloudSyncer] Failed to get cloud gid when fill extend, %d.", errCode); return errCode; } - Bytes bytes; - bytes.resize(obj.CalculateParcelLen(SOFTWARE_VERSION_CURRENT)); - Parcel parcel(bytes.data(), bytes.size()); - errCode = obj.SerializeData(parcel, SOFTWARE_VERSION_CURRENT); - if (errCode != E_OK) { - LOGE("[CloudSyncer] Query serialize failed %d", errCode); - return errCode; + if (obj.IsContainQueryNodes()) { + return CloudStorageUtils::FillCloudQueryToExtend(obj, extend); } - extend[CloudDbConstant::TYPE_FIELD] = static_cast(CloudQueryType::QUERY_FIELD); - extend[CloudDbConstant::QUERY_FIELD] = bytes; - } else { - extend[CloudDbConstant::TYPE_FIELD] = static_cast(CloudQueryType::FULL_TABLE); } + extend[CloudDbConstant::TYPE_FIELD] = static_cast(CloudQueryType::FULL_TABLE); return E_OK; } @@ -114,6 +118,18 @@ int CloudSyncer::GetCloudGid(TaskId taskId, const std::string &tableName, QueryS return errCode; } +int CloudSyncer::GetCloudGid( + TaskId taskId, const std::string &tableName, QuerySyncObject &obj, std::vector &cloudGid) +{ + bool isCloudForcePush = cloudTaskInfos_[taskId].mode == SYNC_MODE_CLOUD_FORCE_PUSH; + int errCode = storageProxy_->GetCloudGid(obj, isCloudForcePush, IsCompensatedTask(taskId), cloudGid); + if (errCode != E_OK) { + LOGE("[CloudSyncer] Failed to get cloud gid, taskid:%" PRIu64 ", table name: %s, length: %zu, %d.", + taskId, DBCommon::StringMiddleMasking(tableName).c_str(), tableName.length(), errCode); + } + return errCode; +} + QuerySyncObject CloudSyncer::GetQuerySyncObject(const std::string &tableName) { std::lock_guard autoLock(dataLock_); @@ -149,96 +165,76 @@ void CloudSyncer::NotifyUploadFailed(int errCode, InnerProcessInfo &info) int CloudSyncer::BatchInsert(Info &insertInfo, CloudSyncData &uploadData, InnerProcessInfo &innerProcessInfo) { - uint32_t retryCount = 0; - int errCode = cloudDB_.BatchInsert(uploadData.tableName, uploadData.insData.record, - uploadData.insData.extend, insertInfo, retryCount); - innerProcessInfo.upLoadInfo.successCount += insertInfo.successCount; - innerProcessInfo.upLoadInfo.failCount += insertInfo.failCount; - innerProcessInfo.upLoadInfo.insertCount += insertInfo.successCount; - if (errCode == -E_CLOUD_VERSION_CONFLICT) { - ProcessVersionConflictInfo(innerProcessInfo, retryCount); - } - if (errCode != E_OK) { - LOGE("[CloudSyncer][BatchInsert] BatchInsert with error, ret is %d.", errCode); - } - if (uploadData.isCloudVersionRecord) { - return errCode; - } - bool isSharedTable = false; - int ret = storageProxy_->IsSharedTable(uploadData.tableName, isSharedTable); - if (ret != E_OK) { - LOGE("[CloudSyncer] DoBatchUpload cannot judge the table is shared table. %d", ret); - return ret; - } - if (!isSharedTable) { - ret = CloudSyncUtils::FillAssetIdToAssets(uploadData.insData, errCode, CloudWaterType::INSERT); - if (ret != E_OK) { - LOGW("[CloudSyncer][BatchInsert] FillAssetIdToAssets with error, ret is %d.", ret); - } - } - if (errCode != E_OK) { - storageProxy_->FillCloudGidIfSuccess(OpType::INSERT, uploadData); - bool isSkip = CloudSyncUtils::IsSkipAssetsMissingRecord(uploadData.insData.extend); - if (isSkip) { - LOGI("[CloudSyncer][BatchInsert] Try to FillCloudLogAndAsset when assets missing. errCode: %d", errCode); - return E_OK; - } else { - LOGE("[CloudSyncer][BatchInsert] errCode: %d, can not skip assets missing record.", errCode); - return errCode; - } - } - // we need to fill back gid after insert data to cloud. - int errorCode = storageProxy_->FillCloudLogAndAsset(OpType::INSERT, uploadData); - if ((errorCode != E_OK) || (ret != E_OK)) { - LOGE("[CloudSyncer] Failed to fill back when doing upload insData, %d.", errorCode); - return ret == E_OK ? errorCode : ret; - } - return E_OK; + return BatchInsertOrUpdate(insertInfo, uploadData, innerProcessInfo, true); } int CloudSyncer::BatchUpdate(Info &updateInfo, CloudSyncData &uploadData, InnerProcessInfo &innerProcessInfo) +{ + return BatchInsertOrUpdate(updateInfo, uploadData, innerProcessInfo, false); +} + +int CloudSyncer::BatchInsertOrUpdate(Info &uploadInfo, CloudSyncData &uploadData, InnerProcessInfo &innerProcessInfo, + bool isInsert) { uint32_t retryCount = 0; - int errCode = cloudDB_.BatchUpdate(uploadData.tableName, uploadData.updData.record, - uploadData.updData.extend, updateInfo, retryCount); - innerProcessInfo.upLoadInfo.successCount += updateInfo.successCount; - innerProcessInfo.upLoadInfo.failCount += updateInfo.failCount; - innerProcessInfo.upLoadInfo.updateCount += updateInfo.successCount; + int errCode = E_OK; + if (isInsert) { + errCode = cloudDB_.BatchInsert(uploadData.tableName, uploadData.insData.record, + uploadData.insData.extend, uploadInfo, retryCount); + innerProcessInfo.upLoadInfo.insertCount += uploadInfo.successCount; + } else { + errCode = cloudDB_.BatchUpdate(uploadData.tableName, uploadData.updData.record, + uploadData.updData.extend, uploadInfo, retryCount); + innerProcessInfo.upLoadInfo.updateCount += uploadInfo.successCount; + } + innerProcessInfo.upLoadInfo.successCount += uploadInfo.successCount; + innerProcessInfo.upLoadInfo.failCount += uploadInfo.failCount; if (errCode == -E_CLOUD_VERSION_CONFLICT) { ProcessVersionConflictInfo(innerProcessInfo, retryCount); } if (errCode != E_OK) { - LOGE("[CloudSyncer][BatchUpdate] BatchUpdate with error, ret is %d.", errCode); + LOGE("[CloudSyncer][BatchInsertOrUpdate] BatchInsertOrUpdate with error, ret is %d.", errCode); } if (uploadData.isCloudVersionRecord) { return errCode; } + return BackFillAfterBatchUpload(uploadData, isInsert, errCode); +} + +int CloudSyncer::BackFillAfterBatchUpload(CloudSyncData &uploadData, bool isInsert, int batchUploadResult) +{ bool isSharedTable = false; int ret = storageProxy_->IsSharedTable(uploadData.tableName, isSharedTable); if (ret != E_OK) { - LOGE("[CloudSyncer] DoBatchUpload cannot judge the table is shared table. %d", ret); + LOGE("[CloudSyncer] BackFillAfterBatchUpload cannot judge the table is shared table. %d", ret); return ret; } + int errCode = batchUploadResult; if (!isSharedTable) { - ret = CloudSyncUtils::FillAssetIdToAssets(uploadData.updData, errCode, CloudWaterType::UPDATE); + CloudWaterType type = isInsert ? CloudWaterType::INSERT : CloudWaterType::UPDATE; + CloudSyncBatch &data = isInsert ? uploadData.insData : uploadData.updData; + ret = CloudSyncUtils::FillAssetIdToAssets(data, errCode, type); if (ret != E_OK) { - LOGW("[CloudSyncer][BatchUpdate] FillAssetIdToAssets with error, ret is %d.", ret); + LOGW("[CloudSyncer][BackFillAfterBatchUpload] FillAssetIdToAssets with error, ret is %d.", ret); } } + OpType opType = isInsert ? OpType::INSERT : OpType::UPDATE; if (errCode != E_OK) { - storageProxy_->FillCloudGidIfSuccess(OpType::UPDATE, uploadData); - bool isSkip = CloudSyncUtils::IsSkipAssetsMissingRecord(uploadData.updData.extend); + storageProxy_->FillCloudGidIfSuccess(opType, uploadData); + CloudSyncBatch &data = isInsert ? uploadData.insData : uploadData.updData; + bool isSkip = CloudSyncUtils::IsSkipAssetsMissingRecord(data.extend); if (isSkip) { - LOGI("[CloudSyncer][BatchUpdate] Try to FillCloudLogAndAsset when assets missing. errCode: %d", errCode); + LOGI("[CloudSyncer][BackFillAfterBatchUpload] Try to FillCloudLogAndAsset when assets missing: %d", + errCode); return E_OK; } else { - LOGE("[CloudSyncer][BatchUpdate] errCode: %d, can not skip assets missing record.", errCode); + LOGE("[CloudSyncer][BackFillAfterBatchUpload] errCode: %d, can not skip assets missing record.", errCode); return errCode; } } - int errorCode = storageProxy_->FillCloudLogAndAsset(OpType::UPDATE, uploadData); + int errorCode = storageProxy_->FillCloudLogAndAsset(opType, uploadData); if ((errorCode != E_OK) || (ret != E_OK)) { - LOGE("[CloudSyncer] Failed to fill back when doing upload updData, %d.", errorCode); + LOGE("[CloudSyncer] Failed to fill back when doing upload insData or updData, %d.", errorCode); return ret == E_OK ? errorCode : ret; } return E_OK; @@ -284,7 +280,7 @@ std::pair CloudSyncer::GetDBAssets(bool isSharedTable, const Inne LOGE("[CloudSyncer] begin transaction before download failed %d", errCode); return res; } - res = storageProxy_->GetAssetsByGidOrHashKey(info.tableName, downloadItem.gid, + res = storageProxy_->GetAssetsByGidOrHashKey(info.tableName, info.isAsyncDownload, downloadItem.gid, downloadItem.hashKey, dbAssets); if (errCode != E_OK && errCode != -E_NOT_FOUND) { if (errCode != -E_CLOUD_GID_MISMATCH) { @@ -340,8 +336,16 @@ std::map& CloudSyncer::BackFillAssetsAfterDownload(int down int CloudSyncer::IsNeedSkipDownload(bool isSharedTable, int &errCode, const InnerProcessInfo &info, const DownloadItem &downloadItem, VBucket &dbAssets) { - auto [tmpCode, status] = GetDBAssets(isSharedTable, info, downloadItem, dbAssets); - if (tmpCode == -E_CLOUD_GID_MISMATCH) { + std::pair res = { E_OK, static_cast(LockStatus::UNLOCK)}; + auto &ret = res.first; + auto &status = res.second; + if (info.isAsyncDownload) { + res = storageProxy_->GetAssetsByGidOrHashKey(info.tableName, info.isAsyncDownload, downloadItem.gid, + downloadItem.hashKey, dbAssets); + } else { + res = GetDBAssets(isSharedTable, info, downloadItem, dbAssets); + } + if (ret == -E_CLOUD_GID_MISMATCH) { LOGW("[CloudSyncer] skip download asset because gid mismatch"); errCode = E_OK; return true; @@ -351,9 +355,10 @@ int CloudSyncer::IsNeedSkipDownload(bool isSharedTable, int &errCode, const Inne errCode = E_OK; return true; } - if (tmpCode != E_OK) { - LOGE("[CloudSyncer] Get assets from DB failed: %d, return errCode: %d", tmpCode, errCode); - errCode = (errCode != E_OK) ? errCode : tmpCode; + if (ret != E_OK) { + LOGE("[CloudSyncer]%s download get assets from DB failed: %d, return errCode: %d", + info.isAsyncDownload ? "Async" : "Sync", ret, errCode); + errCode = (errCode != E_OK) ? errCode : ret; return true; } return false; @@ -434,7 +439,7 @@ int CloudSyncer::DownloadAssetsOneByOneInner(bool isSharedTable, const InnerProc GetAssetsToDownload(downloadAssets, dbAssets, isSharedTable, tmpAssetsToDownload, tmpFlags); } auto downloadCode = cloudDB_.Download(info.tableName, downloadItem.gid, downloadItem.prefix, tmpAssetsToDownload); - if (!CheckDownloadOrDeleteCode(errCode, downloadCode, deleteCode, downloadItem)) { + if (downloadCode != SKIP_ASSET && !CheckDownloadOrDeleteCode(errCode, downloadCode, deleteCode, downloadItem)) { return errCode; } @@ -472,7 +477,7 @@ void CloudSyncer::SeparateNormalAndFailAssets(const std::mapSetLogTriggerStatus(false); @@ -496,7 +501,7 @@ int CloudSyncer::CommitDownloadAssets(const DownloadItem &downloadItem, const st SeparateNormalAndFailAssets(assetsMap, normalAssets, failedAssets); } if (!downloadItem.recordConflict) { - errCode = FillCloudAssets(tableName, normalAssets, failedAssets); + errCode = FillCloudAssets(info, normalAssets, failedAssets); if (errCode != E_OK) { break; } @@ -512,7 +517,8 @@ int CloudSyncer::CommitDownloadAssets(const DownloadItem &downloadItem, const st logInfo.timestamp = 0u; } - errCode = storageProxy_->UpdateRecordFlag(tableName, downloadItem.recordConflict, logInfo); + errCode = storageProxy_->UpdateRecordFlag( + info.tableName, info.isAsyncDownload, downloadItem.recordConflict, logInfo); if (errCode != E_OK) { break; } @@ -522,33 +528,97 @@ int CloudSyncer::CommitDownloadAssets(const DownloadItem &downloadItem, const st return errCode == E_OK ? ret : errCode; } +int CloudSyncer::FillCloudAssetsForOneRecord(const std::string &gid, const std::map &assetsMap, + InnerProcessInfo &info, bool setAllNormal, bool &isExistAssetDownloadFail) +{ + VBucket normalAssets; + VBucket failedAssets; + normalAssets[CloudDbConstant::GID_FIELD] = gid; + failedAssets[CloudDbConstant::GID_FIELD] = gid; + if (setAllNormal) { + for (auto &[key, asset] : assetsMap) { + normalAssets[key] = std::move(asset); + } + } else { + SeparateNormalAndFailAssets(assetsMap, normalAssets, failedAssets); + } + isExistAssetDownloadFail = failedAssets.size() > 1; // There is initially one element present + return FillCloudAssets(info, normalAssets, failedAssets); +} + +int CloudSyncer::UpdateRecordFlagForOneRecord(const std::string &gid, const DownloadItem &downloadItem, + InnerProcessInfo &info, bool isExistAssetDownloadFail) +{ + LogInfo logInfo; + logInfo.cloudGid = gid; + // download must contain gid, just set the default value here. + logInfo.dataKey = DBConstant::DEFAULT_ROW_ID; + logInfo.hashKey = downloadItem.hashKey; + logInfo.timestamp = downloadItem.timestamp; + // there are failed assets, reset the timestamp to prevent the flag from being marked as consistent. + if (isExistAssetDownloadFail) { + logInfo.timestamp = 0u; + } + return storageProxy_->UpdateRecordFlag(info.tableName, info.isAsyncDownload, downloadItem.recordConflict, logInfo); +} + +int CloudSyncer::CommitDownloadAssetsForAsyncDownload(const DownloadItem &downloadItem, InnerProcessInfo &info, + DownloadCommitList &commitList, uint32_t &successCount) +{ + int errCode = storageProxy_->SetLogTriggerStatus(false, true); + if (errCode != E_OK) { + return errCode; + } + for (auto &item : commitList) { + std::string gid = std::get<0>(item); // 0 means gid is the first element in assetsInfo + // 1 means assetsMap info [colName, assets] is the forth element in downloadList[i] + std::map assetsMap = std::get<1>(item); + bool setAllNormal = std::get<2>(item); // 2 means whether the download return is E_OK + LockStatus status = LockStatus::BUTT; + errCode = storageProxy_->GetLockStatusByGid(info.tableName, gid, status); + if (errCode == E_OK && status != LockStatus::UNLOCK) { + continue; + } + + bool isExistAssetDownloadFail = false; + if (!downloadItem.recordConflict) { + errCode = FillCloudAssetsForOneRecord(gid, assetsMap, info, setAllNormal, isExistAssetDownloadFail); + if (errCode != E_OK) { + break; + } + } + + errCode = UpdateRecordFlagForOneRecord(gid, downloadItem, info, isExistAssetDownloadFail); + if (errCode != E_OK) { + break; + } + successCount++; + } + int ret = storageProxy_->SetLogTriggerStatus(true, true); + return errCode == E_OK ? ret : errCode; +} + void CloudSyncer::GenerateCompensatedSync(CloudTaskInfo &taskInfo) { std::vector syncQuery; std::vector users; - int errCode = storageProxy_->GetCompensatedSyncQuery(syncQuery, users); + int errCode = + CloudSyncUtils::GetQueryAndUsersForCompensatedSync(CanStartAsyncDownload(), storageProxy_, users, syncQuery); if (errCode != E_OK) { - LOGW("[CloudSyncer] Generate compensated sync failed by get query! errCode = %d", errCode); + LOGW("[CloudSyncer] get query for compensated sync failed! errCode = %d", errCode); return; } if (syncQuery.empty()) { LOGD("[CloudSyncer] Not need generate compensated sync"); return; } - taskInfo.users.clear(); - auto cloudDBs = cloudDB_.GetCloudDB(); - for (auto &[user, cloudDb] : cloudDBs) { - auto it = std::find(users.begin(), users.end(), user); - if (it != users.end()) { - taskInfo.users.push_back(user); - } - } - for (const auto &query : syncQuery) { - taskInfo.table.push_back(query.GetRelationTableName()); - taskInfo.queryList.push_back(query); + for (const auto &it : syncQuery) { + CloudTaskInfo compensatedTaskInfo = taskInfo; + compensatedTaskInfo.queryList.push_back(it); + Sync(compensatedTaskInfo); + taskInfo.callback = nullptr; + LOGI("[CloudSyncer] Generate compensated sync finished"); } - Sync(taskInfo); - LOGI("[CloudSyncer] Generate compensated sync finished"); } void CloudSyncer::ChkIgnoredProcess(InnerProcessInfo &info, const CloudSyncData &uploadData, UploadParam &uploadParam) @@ -631,11 +701,22 @@ int CloudSyncer::UpdateFlagForSavedRecord(const SyncParam ¶m) std::lock_guard autoLock(dataLock_); downloadList = currentContext_.assetDownloadList; } - std::set gidFilters; - for (const auto &tuple: downloadList) { - gidFilters.insert(std::get(tuple)); + std::set downloadGid; + std::set consistentGid; + for (const auto &tuple : downloadList) { + if (CloudSyncUtils::IsContainDownloading(tuple)) { + downloadGid.insert(std::get(tuple)); + } + consistentGid.insert(std::get(tuple)); } - return storageProxy_->MarkFlagAsConsistent(param.tableName, param.downloadData, gidFilters); + if (IsCurrentAsyncDownloadTask()) { + int errCode = storageProxy_->MarkFlagAsAssetAsyncDownload(param.tableName, param.downloadData, downloadGid); + if (errCode != E_OK) { + LOGE("[CloudSyncer] Failed to mark flag consistent errCode %d", errCode); + return errCode; + } + } + return storageProxy_->MarkFlagAsConsistent(param.tableName, param.downloadData, consistentGid); } int CloudSyncer::BatchDelete(Info &deleteInfo, CloudSyncData &uploadData, InnerProcessInfo &innerProcessInfo) @@ -797,6 +878,7 @@ int CloudSyncer::DoDownloadInNeed(const CloudTaskInfo &taskInfo, const bool need } } DoNotifyInNeed(taskInfo.taskId, needNotifyTables, isFirstDownload); + TriggerAsyncDownloadAssetsInTaskIfNeed(isFirstDownload); return E_OK; } @@ -819,6 +901,9 @@ int CloudSyncer::TryToAddSyncTask(CloudTaskInfo &&taskInfo) return errCode; } std::lock_guard autoLock(dataLock_); + taskInfo.priorityLevel = (!taskInfo.priorityTask || taskInfo.compensatedTask) + ? CloudDbConstant::COMMON_TASK_PRIORITY_LEVEL + : taskInfo.priorityLevel; errCode = CheckQueueSizeWithNoLock(taskInfo.priorityTask); if (errCode != E_OK) { return errCode; @@ -830,15 +915,23 @@ int CloudSyncer::TryToAddSyncTask(CloudTaskInfo &&taskInfo) auto taskId = taskInfo.taskId; cloudTaskInfos_[taskId] = std::move(taskInfo); if (cloudTaskInfos_[taskId].priorityTask) { - priorityTaskQueue_.push_back(taskId); - LOGI("[CloudSyncer] Add priority task ok, storeId %.3s, taskId %" PRIu64, - cloudTaskInfos_[taskId].storeId.c_str(), cloudTaskInfos_[taskId].taskId); + taskQueue_.insert({cloudTaskInfos_[taskId].priorityLevel, taskId}); + LOGI("[CloudSyncer] Add priority task ok, storeId %.3s, priorityLevel %" PRId32 ", taskId %" PRIu64 " async %d", + cloudTaskInfos_[taskId].storeId.c_str(), + cloudTaskInfos_[taskId].priorityLevel, + cloudTaskInfos_[taskId].taskId, + static_cast(cloudTaskInfos_[taskId].asyncDownloadAssets)); + MarkCurrentTaskPausedIfNeed(taskInfo); return E_OK; } if (!MergeTaskInfo(cloudSchema, taskId)) { - taskQueue_.push_back(taskId); - LOGI("[CloudSyncer] Add task ok, storeId %.3s, taskId %" PRIu64, cloudTaskInfos_[taskId].storeId.c_str(), - cloudTaskInfos_[taskId].taskId); + taskQueue_.insert({cloudTaskInfos_[taskId].priorityLevel, taskId}); + LOGI("[CloudSyncer] Add task ok, storeId %.3s, priorityLevel %" PRId32 ", taskId %" PRIu64 " async %d", + cloudTaskInfos_[taskId].storeId.c_str(), + cloudTaskInfos_[taskId].priorityLevel, + cloudTaskInfos_[taskId].taskId, + static_cast(cloudTaskInfos_[taskId].asyncDownloadAssets)); + MarkCurrentTaskPausedIfNeed(taskInfo); } return E_OK; } @@ -858,14 +951,26 @@ bool CloudSyncer::MergeTaskInfo(const std::shared_ptr &cloudSche return mergeHappen; } +void CloudSyncer::RemoveTaskFromQueue(int32_t priorityLevel, TaskId taskId) +{ + for (auto it = taskQueue_.find(priorityLevel); it != taskQueue_.end(); ++it) { + if (it->second == taskId) { + taskQueue_.erase(it); + return; + } + } +} + std::pair CloudSyncer::TryMergeTask(const std::shared_ptr &cloudSchema, TaskId tryTaskId) { std::pair res; auto &[merge, nextTryTask] = res; TaskId beMergeTask = INVALID_TASK_ID; TaskId runningTask = currentContext_.currentTaskId; - for (const auto &taskId : taskQueue_) { - if (taskId == runningTask || taskId == tryTaskId) { // LCOV_EXCL_BR_LINE + auto commonLevelTask = taskQueue_.equal_range(CloudDbConstant::COMMON_TASK_PRIORITY_LEVEL); + for (auto it = commonLevelTask.first; it != commonLevelTask.second; ++it) { + TaskId taskId = it->second; + if (taskId == runningTask || taskId == tryTaskId) { // LCOV_EXCL_BR_LINE continue; } if (!IsTasksCanMerge(taskId, tryTaskId)) { // LCOV_EXCL_BR_LINE @@ -898,8 +1003,8 @@ std::pair CloudSyncer::TryMergeTask(const std::shared_ptrSetAllTableFinish(); processNotifier->NotifyProcess(cloudTaskInfos_[beMergeTask], {}, true); + RemoveTaskFromQueue(cloudTaskInfos_[beMergeTask].priorityLevel, beMergeTask); cloudTaskInfos_.erase(beMergeTask); - taskQueue_.remove(beMergeTask); LOGW("[CloudSyncer] TaskId %" PRIu64 " has been merged", beMergeTask); return res; } @@ -915,7 +1020,8 @@ bool CloudSyncer::IsTasksCanMerge(TaskId taskId, TaskId tryMergeTaskId) const auto &taskInfo = cloudTaskInfos_[taskId]; const auto &tryMergeTaskInfo = cloudTaskInfos_[tryMergeTaskId]; return IsTaskCanMerge(taskInfo) && IsTaskCanMerge(tryMergeTaskInfo) && - taskInfo.devices == tryMergeTaskInfo.devices; + taskInfo.devices == tryMergeTaskInfo.devices && + taskInfo.asyncDownloadAssets == tryMergeTaskInfo.asyncDownloadAssets; } bool CloudSyncer::MergeTaskTablesIfConsistent(TaskId sourceId, TaskId targetId) @@ -1232,33 +1338,6 @@ void CloudSyncer::MarkUploadFinishIfNeed(const std::string &table) currentContext_.processRecorder->MarkUploadFinish(currentContext_.currentUserIndex, table, true); } -bool CloudSyncer::IsNeedUpdateAsset(const VBucket &data) -{ - for (const auto &item : data) { - const Asset *asset = std::get_if>(&item.second); - if (asset != nullptr) { - uint32_t lowBitStatus = AssetOperationUtils::EraseBitMask(asset->status); - if (lowBitStatus == static_cast(AssetStatus::ABNORMAL) || - lowBitStatus == static_cast(AssetStatus::DOWNLOADING)) { - return true; - } - continue; - } - const Assets *assets = std::get_if>(&item.second); - if (assets == nullptr) { - continue; - } - for (const auto &oneAsset : *assets) { - uint32_t lowBitStatus = AssetOperationUtils::EraseBitMask(oneAsset.status); - if (lowBitStatus == static_cast(AssetStatus::ABNORMAL) || - lowBitStatus == static_cast(AssetStatus::DOWNLOADING)) { - return true; - } - } - } - return false; -} - SyncProcess CloudSyncer::GetCloudTaskStatus(uint64_t taskId) const { std::lock_guard autoLock(dataLock_); @@ -1388,6 +1467,10 @@ int CloudSyncer::TagStatus(bool isExist, SyncParam ¶m, size_t idx, DataInfo if (isExist) { hashKey = dataInfo.localInfo.logInfo.hashKey; } + if (param.isAssetsOnly) { + return strategyOpResult == OpType::LOCKED_NOT_HANDLE ? + E_OK : TagDownloadAssetsForAssetOnly(hashKey, idx, param, dataInfo, localAssetInfo); + } return TagDownloadAssets(hashKey, idx, param, dataInfo, localAssetInfo); } @@ -1406,7 +1489,7 @@ int CloudSyncer::CloudDbBatchDownloadAssets(TaskId taskId, const DownloadList &d } // prepare download data auto [downloadRecord, removeAssets, downloadAssets] = - GetDownloadRecords(downloadList, dupHashKeySet, isSharedTable, info); + GetDownloadRecords(downloadList, dupHashKeySet, isSharedTable, IsAsyncDownloadAssets(taskId), info); std::tuple detail = { std::move(downloadRecord), std::move(removeAssets), std::move(downloadAssets), isSharedTable }; @@ -1438,7 +1521,7 @@ void CloudSyncer::FillDownloadItem(const std::set &dupHashKeySet, const Dow } CloudSyncer::DownloadAssetDetail CloudSyncer::GetDownloadRecords(const DownloadList &downloadList, - const std::set &dupHashKeySet, bool isSharedTable, const InnerProcessInfo &info) + const std::set &dupHashKeySet, bool isSharedTable, bool isAsyncDownloadAssets, const InnerProcessInfo &info) { DownloadItemRecords downloadRecord; RemoveAssetsRecords removeAssets; @@ -1452,6 +1535,9 @@ CloudSyncer::DownloadAssetDetail CloudSyncer::GetDownloadRecords(const DownloadL record.downloadItem.gid, record.downloadItem.prefix, std::move(record.assetsToRemove) }; removeAssets.push_back(std::move(removeAsset)); + if (isAsyncDownloadAssets) { + record.assetsToDownload.clear(); + } IAssetLoader::AssetRecord downloadAsset = { record.downloadItem.gid, record.downloadItem.prefix, std::move(record.assetsToDownload) }; @@ -1491,6 +1577,7 @@ int CloudSyncer::BatchDownloadAndCommitRes(const DownloadList &downloadList, con // commit download res DownloadCommitList commitList; // Process result of each asset + downloadCode = downloadAssets[index].status == SKIP_ASSET ? E_OK : downloadCode; commitList.push_back(std::make_tuple(item.downloadItem.gid, std::move(item.downloadItem.assets), deleteCode == E_OK && downloadCode == E_OK)); errorCode = (errorCode != E_OK) ? errorCode : deleteCode; @@ -1502,13 +1589,14 @@ int CloudSyncer::BatchDownloadAndCommitRes(const DownloadList &downloadList, con } index++; } + storageProxy_->PrintCursorChange(info.tableName); return errorCode; } void CloudSyncer::StatisticDownloadRes(const IAssetLoader::AssetRecord &downloadRecord, const IAssetLoader::AssetRecord &removeRecord, InnerProcessInfo &info, DownloadItem &downloadItem) { - if ((downloadRecord.status == OK) && (removeRecord.status == OK)) { + if ((downloadRecord.status == OK || downloadRecord.status == SKIP_ASSET) && (removeRecord.status == OK)) { return; } if ((downloadRecord.status == CLOUD_RECORD_EXIST_CONFLICT) || @@ -1531,8 +1619,12 @@ void CloudSyncer::AddNotifyDataFromDownloadAssets(const std::set &dupHashKe return; } if (dupHashKeySet.find(downloadItem.hashKey) == dupHashKeySet.end()) { - changedAssets.primaryData[CloudSyncUtils::OpTypeToChangeType(downloadItem.strategy)].push_back( - downloadItem.primaryKeyValList); + if (CloudSyncUtils::OpTypeToChangeType(downloadItem.strategy) == OP_BUTT) { + LOGW("[CloudSyncer] [AddNotifyDataFromDownloadAssets] strategy is invalid."); + } else { + changedAssets.primaryData[CloudSyncUtils::OpTypeToChangeType(downloadItem.strategy)].push_back( + downloadItem.primaryKeyValList); + } } else if (downloadItem.strategy == OpType::INSERT) { changedAssets.primaryData[ChangeType::OP_UPDATE].push_back(downloadItem.primaryKeyValList); } @@ -1551,24 +1643,535 @@ void CloudSyncer::CheckDataAfterDownload(const std::string &tableName) } } -void CloudSyncer::CheckQueryCloudData(std::string &traceId, DownloadData &downloadData, - std::vector &pkColNames) +void CloudSyncer::WaitCurTaskFinished() { - for (auto &data : downloadData.data) { - bool isVersionExist = data.count(CloudDbConstant::VERSION_FIELD) != 0; - bool isContainAllPk = true; - for (auto &pkColName : pkColNames) { - if (data.count(pkColName) == 0) { - isContainAllPk = false; - break; + CancelBackgroundDownloadAssetsTask(); + std::unique_lock uniqueLock(dataLock_); + if (currentContext_.currentTaskId != INVALID_TASK_ID) { + LOGI("[CloudSyncer] begin wait current task %" PRIu64 " finished", currentContext_.currentTaskId); + contextCv_.wait(uniqueLock, [this]() { + return currentContext_.currentTaskId == INVALID_TASK_ID; + }); + LOGI("[CloudSyncer] current task has been finished"); + } +} + +bool CloudSyncer::IsAsyncDownloadAssets(TaskId taskId) +{ + std::lock_guard autoLock(dataLock_); + return cloudTaskInfos_[taskId].asyncDownloadAssets; +} + +void CloudSyncer::TriggerAsyncDownloadAssetsInTaskIfNeed(bool isFirstDownload) +{ + { + std::lock_guard autoLock(dataLock_); + if (!cloudTaskInfos_[currentContext_.currentTaskId].asyncDownloadAssets) { + return; + } + } + if (isFirstDownload) { + std::lock_guard autoLock(dataLock_); + if (currentContext_.isNeedUpload) { + return; + } + } + TriggerAsyncDownloadAssetsIfNeed(); +} + +void CloudSyncer::TriggerAsyncDownloadAssetsIfNeed() +{ + if (!storageProxy_->IsContainAssetsTable()) { + LOGD("[CloudSyncer] No exist table contain assets, skip async download asset check"); + return; + } + TaskId taskId = INVALID_TASK_ID; + { + std::lock_guard autoLock(dataLock_); + if (asyncTaskId_ != INVALID_TASK_ID || closed_) { + LOGI("[CloudSyncer] No need generate async task now asyncTaskId %" PRIu64 " closed %d", + static_cast(asyncTaskId_), static_cast(closed_)); + return; + } + lastTaskId_++; + asyncTaskId_ = lastTaskId_; + taskId = asyncTaskId_; + IncObjRef(this); + } + int errCode = RuntimeContext::GetInstance()->ScheduleTask([taskId, this]() { + LOGI("[CloudSyncer] Exec asyncTaskId %" PRIu64 " begin", taskId); + BackgroundDownloadAssetsTask(); + LOGI("[CloudSyncer] Exec asyncTaskId %" PRIu64 " finished", taskId); + { + std::lock_guard autoLock(dataLock_); + asyncTaskId_ = INVALID_TASK_ID; + } + asyncTaskCv_.notify_all(); + DecObjRef(this); + }); + if (errCode == E_OK) { + LOGI("[CloudSyncer] Schedule asyncTaskId %" PRIu64 " success", taskId); + } else { + LOGW("[CloudSyncer] Schedule BackgroundDownloadAssetsTask failed %d", errCode); + DecObjRef(this); + } +} + +void CloudSyncer::BackgroundDownloadAssetsTask() +{ + // remove listener first + CancelDownloadListener(); + // add download count and register listener if failed + auto manager = RuntimeContext::GetInstance()->GetAssetsDownloadManager(); + IncObjRef(this); + auto [errCode, listener] = manager->BeginDownloadWithListener([this](void *) { + TriggerAsyncDownloadAssetsIfNeed(); + }, [this]() { + DecObjRef(this); + }); + if (errCode == E_OK) { + // increase download count success + DecObjRef(this); + CancelDownloadListener(); + DoBackgroundDownloadAssets(); + RuntimeContext::GetInstance()->GetAssetsDownloadManager()->FinishDownload(); + return; + } + if (listener != nullptr) { + std::lock_guard autoLock(listenerMutex_); + waitDownloadListener_ = listener; + return; + } + LOGW("[CloudSyncer] BeginDownloadWithListener failed %d", errCode); + DecObjRef(this); +} + +void CloudSyncer::CancelDownloadListener() +{ + NotificationChain::Listener *waitDownloadListener = nullptr; + { + std::lock_guard autoLock(listenerMutex_); + if (waitDownloadListener_ != nullptr) { + waitDownloadListener = waitDownloadListener_; + waitDownloadListener_ = nullptr; + } + } + if (waitDownloadListener != nullptr) { + waitDownloadListener->Drop(true); + waitDownloadListener = nullptr; + } +} + +void CloudSyncer::DoBackgroundDownloadAssets() +{ + bool allDownloadFinish = true; + std::map downloadBeginTime; + do { + auto [errCode, tables] = storageProxy_->GetDownloadAssetTable(); + if (errCode != E_OK) { + LOGE("[CloudSyncer] Get download asset table failed %d", errCode); + return; + } + allDownloadFinish = true; + std::list tableQueue(tables.begin(), tables.end()); + while (!tableQueue.empty()) { + if (cancelAsyncTask_ || closed_) { + LOGW("[CloudSyncer] exit task by cancel %d closed %d", static_cast(cancelAsyncTask_), + static_cast(closed_)); + return; + } + errCode = BackgroundDownloadAssetsByTable(tableQueue.front(), downloadBeginTime); + if (errCode == E_OK) { + allDownloadFinish = false; + } else if (errCode == -E_FINISHED) { + tableQueue.pop_front(); + errCode = E_OK; + } else { + LOGW("[CloudSyncer] BackgroundDownloadAssetsByTable table %s failed %d", + DBCommon::StringMiddleMasking(tableQueue.front()).c_str(), errCode); + tableQueue.pop_front(); } } - std::string gid; - (void)CloudStorageUtils::GetValueFromVBucket(CloudDbConstant::GID_FIELD, data, gid); - if (!isVersionExist || !isContainAllPk) { - LOGE("[CloudSyncer] Invalid data from cloud, no version[%d], lost primary key[%d], gid[%s], traceId[%s]", - static_cast(!isVersionExist), static_cast(!isContainAllPk), gid.c_str(), traceId.c_str()); + } while (!allDownloadFinish); +} + +void CloudSyncer::CancelBackgroundDownloadAssetsTaskIfNeed() +{ + bool cancelDownload = true; + { + std::unique_lock uniqueLock(dataLock_); + if (cloudTaskInfos_[currentContext_.currentTaskId].asyncDownloadAssets || asyncTaskId_ == INVALID_TASK_ID) { + return; + } + if (cloudTaskInfos_[currentContext_.currentTaskId].compensatedTask) { + cancelDownload = false; + } + } + CancelBackgroundDownloadAssetsTask(cancelDownload); +} + +void CloudSyncer::CancelBackgroundDownloadAssetsTask(bool cancelDownload) +{ + cancelAsyncTask_ = true; + if (cancelDownload) { + cloudDB_.CancelDownload(); + } + std::unique_lock uniqueLock(dataLock_); + if (asyncTaskId_ != INVALID_TASK_ID) { + LOGI("[CloudSyncer] begin wait async download task % " PRIu64 " finished", asyncTaskId_); + asyncTaskCv_.wait(uniqueLock, [this]() { + return asyncTaskId_ == INVALID_TASK_ID; + }); + LOGI("[CloudSyncer] async download task has been finished"); + } + cancelAsyncTask_ = false; +} + +int CloudSyncer::BackgroundDownloadAssetsByTable(const std::string &table, + std::map &downloadBeginTime) +{ + auto [errCode, downloadData] = storageProxy_->GetDownloadAssetRecords(table, downloadBeginTime[table]); + if (errCode != E_OK) { + return errCode; + } + if (downloadData.empty()) { + LOGD("[CloudSyncer] table %s async download finished", DBCommon::StringMiddleMasking(table).c_str()); + return -E_FINISHED; + } + + bool isSharedTable = false; + errCode = storageProxy_->IsSharedTable(table, isSharedTable); + if (errCode != E_OK) { + LOGE("[CloudSyncer] check is shared table failed %d", errCode); + return errCode; + } + DownloadList downloadList; + ChangedData changedAssets; + std::tie(errCode, downloadList, changedAssets) = CloudSyncUtils::GetDownloadListByGid(storageProxy_, downloadData, + table); + if (errCode != E_OK) { + return errCode; + } + CloudSyncUtils::UpdateMaxTimeWithDownloadList(downloadList, table, downloadBeginTime); + std::set dupHashKeySet; + InnerProcessInfo info; + info.tableName = table; + info.isAsyncDownload = true; + + // prepare download data + auto [downloadRecord, removeAssets, downloadAssets] = + GetDownloadRecords(downloadList, dupHashKeySet, isSharedTable, false, info); + std::tuple detail = { + std::move(downloadRecord), std::move(removeAssets), std::move(downloadAssets), isSharedTable + }; + errCode = BatchDownloadAndCommitRes(downloadList, dupHashKeySet, info, changedAssets, detail); + NotifyChangedDataWithDefaultDev(std::move(changedAssets)); + return errCode; +} + +int CloudSyncer::TagDownloadAssetsForAssetOnly( + const Key &hashKey, size_t idx, SyncParam ¶m, const DataInfo &dataInfo, VBucket &localAssetInfo) +{ + Type prefix; + std::vector pkVals; + int ret = CloudSyncUtils::GetCloudPkVals( + param.downloadData.data[idx], param.pkColNames, dataInfo.localInfo.logInfo.dataKey, pkVals); + if (ret != E_OK) { + // if get pk vals failed, mean cloud data is deteled. + LOGE("[CloudSyncer] TagDownloadAssetsForAssetOnly cannot get primary key value list. %d", + -E_ASSET_NOT_FOUND_FOR_DOWN_ONLY); + return -E_ASSET_NOT_FOUND_FOR_DOWN_ONLY; + } + prefix = param.isSinglePrimaryKey ? pkVals[0] : prefix; + if (param.isSinglePrimaryKey && prefix.index() == TYPE_INDEX) { + LOGE("[CloudSyncer] Invalid primary key type in TagStatus, it's Nil."); + return -E_INTERNAL_ERROR; + } + + std::map downloadAssetsMap{}; + ret = CloudSyncUtils::GetDownloadAssetsOnlyMapFromDownLoadData(idx, param, downloadAssetsMap); + if (ret != E_OK) { + return ret; + } + param.assetsDownloadList.push_back( + std::make_tuple(dataInfo.cloudLogInfo.cloudGid, prefix, OpType::UPDATE, downloadAssetsMap, hashKey, + pkVals, dataInfo.cloudLogInfo.timestamp)); + return ret; +} + +int CloudSyncer::PutCloudSyncDataOrUpdateStatusForAssetOnly(SyncParam ¶m, std::vector &localInfo) +{ + int ret = E_OK; + if (param.isAssetsOnly) { + // download and save only asset, ignore other data. + for (auto &item : localInfo) { + ret = storageProxy_->UpdateAssetStatusForAssetOnly(param.tableName, item); + if (ret != E_OK) { + LOGE("[CloudSyncer] Cannot save asset data due to error code %d", ret); + return ret; + } + } + } else { + ret = storageProxy_->PutCloudSyncData(param.tableName, param.downloadData); + if (ret != E_OK) { + param.info.downLoadInfo.failCount += param.downloadData.data.size(); + LOGE("[CloudSyncer] Cannot save the data to database with error code: %d.", ret); + } + } + return ret; +} + +int CloudSyncer::QueryCloudGidForAssetsOnly( + TaskId taskId, SyncParam ¶m, int64_t groupIdx, std::vector &cloudGid) +{ + auto tableName = param.info.tableName; + QuerySyncObject syncObj = GetQuerySyncObject(tableName); + VBucket extend = {{CloudDbConstant::CURSOR_FIELD, param.cloudWaterMarkForAssetsOnly}}; + QuerySyncObject obj; + int ret = syncObj.GetQuerySyncObjectFromGroup(groupIdx, obj); + if (ret != E_OK) { + LOGE("Get query obj from group fail, errCode = %d", ret); + return ret; + } + ret = GetCloudGid(taskId, tableName, obj, cloudGid); + if (ret != E_OK) { + LOGE("Get cloud gid fail, errCode = %d", ret); + } + return ret; +} + +int CloudSyncer::GetEmptyGidAssetsMapFromDownloadData( + const std::vector &data, std::map &gidAssetsMap) +{ + for (uint32_t i = 0; i < data.size(); i++) { + std::string gidStr; + int errCode = CloudStorageUtils::GetValueFromVBucket(CloudDbConstant::GID_FIELD, data[i], gidStr); + if (errCode != E_OK) { + LOGE("Get gid from bucket fail when mark flag as consistent, errCode = %d", errCode); + return errCode; + } + gidAssetsMap[gidStr] = AssetsMap{}; + } + return E_OK; +} + +int CloudSyncer::SetAssetsMapAndEraseDataForAssetsOnly( + TaskId taskId, SyncParam ¶m, std::vector &downloadData, std::map &gidAssetsMap) +{ + for (uint32_t i = 0; i < param.groupNum; i++) { + std::vector cloudGid; + int ret = QueryCloudGidForAssetsOnly(taskId, param, i, cloudGid); + if ((ret != E_OK && ret != -E_QUERY_END) || cloudGid.empty()) { + LOGE("[CloudSyncer] Cannot get the %u group data, error code: %d.", i, -E_ASSET_NOT_FOUND_FOR_DOWN_ONLY); + return -E_ASSET_NOT_FOUND_FOR_DOWN_ONLY; + } + if (!CloudSyncUtils::SetAssetsMapByCloudGid(cloudGid, param.assetsGroupMap[i], gidAssetsMap)) { + // if group no match data, return error code. + LOGE("[CloudSyncer] Cannot get the %u group data, error code: %d.", i, -E_ASSET_NOT_FOUND_FOR_DOWN_ONLY); + return -E_ASSET_NOT_FOUND_FOR_DOWN_ONLY; + } + } + + for (auto iter = downloadData.begin(); iter != downloadData.end();) { + std::string gidStr; + int ret = CloudStorageUtils::GetValueFromVBucket(CloudDbConstant::GID_FIELD, *iter, gidStr); + if (ret != E_OK) { + LOGE("Get gid from bucket fail when mark flag as consistent, errCode = %d", ret); + return ret; + } + + if (DBCommon::IsRecordDelete(*iter)) { + iter = downloadData.erase(iter); + gidAssetsMap.erase(gidStr); + continue; + } + + auto assetsMap = gidAssetsMap[gidStr]; + if (!CloudSyncUtils::IsAssetOnlyData(*iter, assetsMap, false)) { + iter = downloadData.erase(iter); + gidAssetsMap.erase(gidStr); + continue; + } + ++iter; + } + return E_OK; +} + +int CloudSyncer::CheckCloudQueryAssetsOnlyIfNeed(TaskId taskId, SyncParam ¶m) +{ + { + std::lock_guard autoLock(dataLock_); + if (!param.isAssetsOnly || cloudTaskInfos_[taskId].compensatedTask) { + return E_OK; + } + if (!param.isVaildForAssetsOnly) { + param.downloadData.data.clear(); + return E_OK; } + cloudTaskInfos_[taskId].isAssetsOnly = param.isAssetsOnly; + cloudTaskInfos_[taskId].groupNum = param.groupNum; + cloudTaskInfos_[taskId].assetsGroupMap = param.assetsGroupMap; + } + + std::vector &downloadData = param.downloadData.data; + auto &gidAssetsMap = param.gidAssetsMap; + gidAssetsMap.clear(); + int ret = GetEmptyGidAssetsMapFromDownloadData(downloadData, gidAssetsMap); + if (ret != E_OK) { + return ret; + } + + // set assets map for every record and erase not match data. + ret = SetAssetsMapAndEraseDataForAssetsOnly(taskId, param, downloadData, gidAssetsMap); + if (ret != E_OK) { + return ret; + } + + for (uint32_t i = 0; i < param.groupNum; i++) { + bool isEmpty = CloudSyncUtils::CheckAssetsOnlyIsEmptyInGroup(gidAssetsMap, param.assetsGroupMap[i]); + if (isEmpty) { + LOGE("[CloudSyncer] query assets failed, error code: %d", -E_ASSET_NOT_FOUND_FOR_DOWN_ONLY); + return -E_ASSET_NOT_FOUND_FOR_DOWN_ONLY; + } + } + return E_OK; +} + +int CloudSyncer::CheckLocalQueryAssetsOnlyIfNeed(VBucket &localAssetInfo, SyncParam ¶m, DataInfoWithLog &logInfo) +{ + if (!param.isAssetsOnly) { + return E_OK; + } + std::string gid = logInfo.logInfo.cloudGid; + auto iter = param.gidAssetsMap.find(gid); + if (iter == param.gidAssetsMap.end()) { + LOGE("query assets failed, error code:%d", -E_ASSET_NOT_FOUND_FOR_DOWN_ONLY); + return -E_ASSET_NOT_FOUND_FOR_DOWN_ONLY; + } + + auto assetsMap = iter->second; + if (!CloudSyncUtils::IsAssetOnlyData(localAssetInfo, assetsMap, true)) { + LOGE("[CloudSyncer] query assets failed, error code: %d", -E_ASSET_NOT_FOUND_FOR_DOWN_ONLY); + return -E_ASSET_NOT_FOUND_FOR_DOWN_ONLY; + } + return E_OK; +} + +bool CloudSyncer::IsCurrentAsyncDownloadTask() +{ + std::lock_guard autoLock(dataLock_); + return cloudTaskInfos_[currentContext_.currentTaskId].asyncDownloadAssets; +} + +bool CloudSyncer::CanStartAsyncDownload() const +{ + if (!RuntimeContext::GetInstance()->GetAssetsDownloadManager()->CanStartNewTask()) { + LOGW("[CloudSyncer] Too many download tasks"); + return false; + } + return asyncTaskId_ == INVALID_TASK_ID; +} + +void CloudSyncer::NotifyChangedDataWithDefaultDev(ChangedData &&changedData) +{ + auto table = changedData.tableName; + int ret = CloudSyncUtils::NotifyChangeData(CloudDbConstant::DEFAULT_CLOUD_DEV, storageProxy_, + std::move(changedData)); + if (ret != E_OK) { + LOGW("[CloudSyncer] Notify %s change data failed %d", DBCommon::StringMiddleMasking(table).c_str(), ret); + } +} + +void CloudSyncer::SetGenCloudVersionCallback(const GenerateCloudVersionCallback &callback) +{ + cloudDB_.SetGenCloudVersionCallback(callback); +} + +size_t CloudSyncer::GetDownloadAssetIndex(TaskId taskId) +{ + size_t index = 0u; + std::lock_guard autoLock(dataLock_); + if (resumeTaskInfos_[taskId].lastDownloadIndex != 0u) { + index = resumeTaskInfos_[taskId].lastDownloadIndex; + resumeTaskInfos_[taskId].lastDownloadIndex = 0u; } + return index; +} + +uint32_t CloudSyncer::GetCurrentTableUploadBatchIndex() +{ + std::lock_guard autoLock(dataLock_); + return currentContext_.notifier->GetUploadBatchIndex(currentContext_.tableName); +} + +void CloudSyncer::ResetCurrentTableUploadBatchIndex() +{ + std::lock_guard autoLock(dataLock_); + currentContext_.notifier->ResetUploadBatchIndex(currentContext_.tableName); +} + +void CloudSyncer::RecordWaterMark(TaskId taskId, Timestamp waterMark) +{ + std::lock_guard autoLock(dataLock_); + resumeTaskInfos_[taskId].lastLocalWatermark = waterMark; +} + +Timestamp CloudSyncer::GetResumeWaterMark(TaskId taskId) +{ + std::lock_guard autoLock(dataLock_); + return resumeTaskInfos_[taskId].lastLocalWatermark; } + +CloudSyncer::InnerProcessInfo CloudSyncer::GetInnerProcessInfo(const std::string &tableName, UploadParam &uploadParam) +{ + InnerProcessInfo info; + info.tableName = tableName; + info.tableStatus = ProcessStatus::PROCESSING; + ReloadUploadInfoIfNeed(uploadParam, info); + return info; +} + +std::vector CloudSyncer::CopyAndClearTaskInfos() +{ + std::vector infoList; + std::lock_guard autoLock(dataLock_); + for (const auto &item: cloudTaskInfos_) { + infoList.push_back(item.second); + } + taskQueue_.clear(); + cloudTaskInfos_.clear(); + resumeTaskInfos_.clear(); + currentContext_.notifier = nullptr; + return infoList; +} + +bool CloudSyncer::TryToInitQueryAndUserListForCompensatedSync(TaskId triggerTaskId) +{ + std::vector syncQuery; + std::vector users; + int errCode = + CloudSyncUtils::GetQueryAndUsersForCompensatedSync(CanStartAsyncDownload(), storageProxy_, users, syncQuery); + if (errCode != E_OK) { + LOGW("[CloudSyncer] get query for compensated sync failed! errCode = %d", errCode); + // if failed, finshed the task directly. + DoFinished(triggerTaskId, errCode); + return false; + } + if (syncQuery.empty()) { + // if quey is empty, finshed the task directly. + DoFinished(triggerTaskId, E_OK); + return false; + } + std::vector userList; + CloudSyncUtils::GetUserListForCompensatedSync(cloudDB_, users, userList); + { + std::lock_guard autoLock(dataLock_); + cloudTaskInfos_[triggerTaskId].users = userList; + cloudTaskInfos_[triggerTaskId].table.clear(); + cloudTaskInfos_[triggerTaskId].queryList.clear(); + cloudTaskInfos_[triggerTaskId].table.push_back(syncQuery[0].GetRelationTableName()); + cloudTaskInfos_[triggerTaskId].queryList.push_back(syncQuery[0]); + } + return true; } +} \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/icloud_syncer.h b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/icloud_syncer.h index 56ec607e73230c00b2a66d6aa41c065b7ff180f6..92faf8133c3e1277e3a714b2043382c4afd8c977 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/icloud_syncer.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/cloud/icloud_syncer.h @@ -21,19 +21,25 @@ #include "query_sync_object.h" #include "ref_object.h" namespace DistributedDB { -using DownloadList = std::vector, Key, - std::vector, Timestamp>>; +using DownloadAssetUnit = std::tuple, Key, + std::vector, Timestamp>; +using DownloadList = std::vector; class ICloudSyncer : public virtual RefObject { public: using TaskId = uint64_t; struct CloudTaskInfo { bool priorityTask = false; + int32_t priorityLevel = 0; bool compensatedTask = false; + bool isAssetsOnly = false; bool pause = false; bool resume = false; + bool merge = false; + bool asyncDownloadAssets = false; + int errCode = 0; SyncMode mode = SyncMode::SYNC_MODE_PUSH_ONLY; ProcessStatus status = ProcessStatus::PREPARED; - int errCode = 0; + LockAction lockAction = LockAction::INSERT; TaskId taskId = 0u; int64_t timeout = 0; SyncProcessCallback callback; @@ -41,10 +47,10 @@ public: std::vector devices; std::vector queryList; std::vector users; - LockAction lockAction = LockAction::INSERT; - bool merge = false; std::string storeId; std::string prepareTraceId; + uint32_t groupNum = 0; + AssetsGroupMap assetsGroupMap; }; struct UploadRetryInfo { @@ -58,6 +64,7 @@ public: Info downLoadInfo; Info upLoadInfo; UploadRetryInfo retryInfo; + bool isAsyncDownload = false; }; struct WithoutRowIdData { @@ -80,6 +87,13 @@ public: bool isLastBatch = false; WithoutRowIdData withoutRowIdData; std::vector> insertPk; + bool isAssetsOnly = false; + bool isVaildForAssetsOnly = false; + uint32_t groupNum = 0; + AssetsGroupMap assetsGroupMap; + std::string cloudWaterMarkForAssetsOnly; + std::map gidAssetsMap; // only used for assets only. + bool isForcePullAseets = false; }; struct DataInfo { diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/ability_sync.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/device/ability_sync.cpp index 3e75eefdc6cd32aa7d09f2fcb2edc65bad6cb53f..efcbb30d2ba868d2baa2bd96833a117a33ddf019 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/ability_sync.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/ability_sync.cpp @@ -423,6 +423,7 @@ int AbilitySync::AckRecv(const Message *message, ISyncTaskContext *context) } uint32_t remoteSoftwareVersion = packet->GetSoftwareVersion(); context->SetRemoteSoftwareVersion(remoteSoftwareVersion); + metadata_->SetRemoteSchemaVersion(context->GetDeviceId(), remoteSoftwareVersion); if (remoteSoftwareVersion > SOFTWARE_VERSION_RELEASE_2_0) { errCode = AckRecvWithHighVersion(message, context, packet); } else { @@ -523,10 +524,36 @@ void AbilitySync::SetAbilitySyncFinishedStatus(bool syncFinished, ISyncTaskConte } } +bool AbilitySync::SecLabelCheckInner(int32_t remoteSecLabel, int errCode, SecurityOption option, + const AbilitySyncRequestPacket *packet) const +{ + if (remoteSecLabel == NOT_SUPPORT_SEC_CLASSIFICATION || remoteSecLabel == SecurityLabel::NOT_SET) { + return true; + } + if (errCode == -E_NOT_SUPPORT || (errCode == E_OK && option.securityLabel == SecurityLabel::NOT_SET)) { + return true; + } + if (remoteSecLabel == FAILED_GET_SEC_CLASSIFICATION || errCode != E_OK) { + LOGE("[AbilitySync][RequestRecv] check error remoteL:%d, errCode:%d", remoteSecLabel, errCode); + return false; + } + if (remoteSecLabel == option.securityLabel) { + return true; + } + LOGE("[AbilitySync][RequestRecv] check error remote:%d , %d local:%d , %d", + remoteSecLabel, packet->GetSecFlag(), option.securityLabel, option.securityFlag); + return false; +} + bool AbilitySync::SecLabelCheck(const AbilitySyncRequestPacket *packet) const { SecurityOption option; - int errCode = (static_cast(storageInterface_))->GetSecurityOption(option); + auto *syncInterface = static_cast(storageInterface_); + if (syncInterface == nullptr) { + LOGE("[AbilitySync][RequestRecv] get sync interface wrong"); + return false; + } + int errCode = syncInterface->GetSecurityOption(option); int32_t remoteSecLabel = TransformSecLabelIfNeed(packet->GetSecLabel(), option.securityLabel); LOGI("[AbilitySync][RequestRecv] remote label:%d local l:%d, f:%d, errCode:%d", remoteSecLabel, option.securityLabel, option.securityFlag, errCode); @@ -542,22 +569,7 @@ bool AbilitySync::SecLabelCheck(const AbilitySyncRequestPacket *packet) const LOGE("[AbilitySync][RequestRecv] remote security label not set!"); return false; } - if (remoteSecLabel == NOT_SUPPORT_SEC_CLASSIFICATION || remoteSecLabel == SecurityLabel::NOT_SET) { - return true; - } - if (errCode == -E_NOT_SUPPORT || (errCode == E_OK && option.securityLabel == SecurityLabel::NOT_SET)) { - return true; - } - if (remoteSecLabel == FAILED_GET_SEC_CLASSIFICATION || errCode != E_OK) { - LOGE("[AbilitySync][RequestRecv] check error remoteL:%d, errCode:%d", remoteSecLabel, errCode); - return false; - } - if (remoteSecLabel == option.securityLabel) { - return true; - } - LOGE("[AbilitySync][RequestRecv] check error remote:%d , %d local:%d , %d", - remoteSecLabel, packet->GetSecFlag(), option.securityLabel, option.securityFlag); - return false; + return SecLabelCheckInner(remoteSecLabel, errCode, option, packet); } void AbilitySync::HandleVersionV3RequestParam(const AbilitySyncRequestPacket *packet, ISyncTaskContext *context) @@ -957,12 +969,29 @@ ERROR_OUT: return errCode; } +void AbilitySync::SetAbilityRequestBodyInfoInner(uint16_t remoteCommunicatorVersion, AbilitySyncRequestPacket &packet, + std::string &schemaStr, uint32_t schemaType) const +{ + // 102 version is forbidden to sync with 103 json-schema or flatbuffer-schema + // so schema should put null string while remote is 102 version to avoid this bug. + if (remoteCommunicatorVersion == 1) { + packet.SetSchema(""); + packet.SetSchemaType(0); + } else { + packet.SetSchema(schemaStr); + packet.SetSchemaType(schemaType); + } +} + int AbilitySync::SetAbilityRequestBodyInfo(uint16_t remoteCommunicatorVersion, const ISyncTaskContext *context, AbilitySyncRequestPacket &packet) const { + if (storageInterface_ == nullptr) { + LOGE("[AbilitySync][FillAbilityRequest] storageInterface is nullptr"); + return -E_INVALID_ARGS; + } uint64_t dbCreateTime; - int errCode = - (static_cast(storageInterface_))->GetDatabaseCreateTimestamp(dbCreateTime); + int errCode = (static_cast(storageInterface_))->GetDatabaseCreateTimestamp(dbCreateTime); if (errCode != E_OK) { LOGE("[AbilitySync][FillAbilityRequest] GetDatabaseCreateTimestamp failed, err %d", errCode); return errCode; @@ -991,15 +1020,7 @@ int AbilitySync::SetAbilityRequestBodyInfo(uint16_t remoteCommunicatorVersion, c LOGE("[AbilitySync][FillAbilityRequest] GetLocalSchemaVersion failed, err %d", err); return err; } - // 102 version is forbidden to sync with 103 json-schema or flatbuffer-schema - // so schema should put null string while remote is 102 version to avoid this bug. - if (remoteCommunicatorVersion == 1) { - packet.SetSchema(""); - packet.SetSchemaType(0); - } else { - packet.SetSchema(schemaStr); - packet.SetSchemaType(schemaType); - } + SetAbilityRequestBodyInfoInner(remoteCommunicatorVersion, packet, schemaStr, schemaType); packet.SetProtocolVersion(ABILITY_SYNC_VERSION_V1); packet.SetSoftwareVersion(SOFTWARE_VERSION_CURRENT); packet.SetSecLabel(option.securityLabel); @@ -1375,6 +1396,10 @@ void AbilitySync::InitRemoteDBAbility(ISyncTaskContext &context) return; } context.SetDbAbility(ability); + auto version = static_cast(metadata_->GetRemoteSoftwareVersion(context.GetDeviceId())); + if (version > 0) { + context.SetRemoteSoftwareVersion(version); + } } void AbilitySync::RecordAbilitySyncFinish(uint64_t remoteSchemaVersion, ISyncTaskContext &context) diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/ability_sync.h b/kv_store/frameworks/libs/distributeddb/syncer/src/device/ability_sync.h index 0e9535adac2b96723e06a2926d19adb3dc4edcdc..cba09fb3d7156755bba50c425751a5b6d660c572 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/ability_sync.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/ability_sync.h @@ -219,6 +219,9 @@ private: void GetPacketSecOption(const ISyncTaskContext *context, SecurityOption &option) const; + void SetAbilityRequestBodyInfoInner(uint16_t remoteCommunicatorVersion, AbilitySyncRequestPacket &packet, + std::string &schemaStr, uint32_t schemaType) const; + int SetAbilityRequestBodyInfo(uint16_t remoteCommunicatorVersion, const ISyncTaskContext *context, AbilitySyncRequestPacket &packet) const; @@ -237,6 +240,9 @@ private: bool IsSingleRelationalVer() const; + bool SecLabelCheckInner(int32_t remoteSecLabel, int errCode, SecurityOption option, + const AbilitySyncRequestPacket *packet) const; + int SendAck(const ISyncTaskContext *context, const Message *message, int ackCode, bool isAckNotify, AbilitySyncAckPacket &ackPacket); diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/communicator_proxy.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/device/communicator_proxy.cpp index 6e1f0b290e537b6bc72535b993a106c9d3ef7c83..15327f2541210458e16587e8943b889329a9c46a 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/communicator_proxy.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/communicator_proxy.cpp @@ -78,10 +78,10 @@ int CommunicatorProxy::RegOnSendableCallback(const std::function &on return E_OK; } -void CommunicatorProxy::Activate() +void CommunicatorProxy::Activate(const std::string &userId) { if (mainComm_ != nullptr) { - mainComm_->Activate(); + mainComm_->Activate(userId); } // use temp map to avoid active in lock @@ -95,7 +95,7 @@ void CommunicatorProxy::Activate() } for (const auto &iter : tempMap) { - tempMap[iter.first]->Activate(); + tempMap[iter.first]->Activate(userId); RefObject::DecObjRef(tempMap[iter.first]); } } diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/communicator_proxy.h b/kv_store/frameworks/libs/distributeddb/syncer/src/device/communicator_proxy.h index 47f7fc19a0ab814a7511f56c6da9e4d55734df22..fafd852f7067b42c670d8f67eec8b3c98c217884 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/communicator_proxy.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/communicator_proxy.h @@ -34,7 +34,7 @@ public: int RegOnMessageCallback(const OnMessageCallback &onMessage, const Finalizer &inOper) override; int RegOnConnectCallback(const OnConnectCallback &onConnect, const Finalizer &inOper) override; int RegOnSendableCallback(const std::function &onSendable, const Finalizer &inOper) override; - void Activate() override; + void Activate(const std::string &userId = "") override; uint32_t GetCommunicatorMtuSize() const override; uint32_t GetCommunicatorMtuSize(const std::string &target) const override; uint32_t GetTimeout() const override; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/generic_syncer.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/device/generic_syncer.cpp index c56316b66fa170c92211561e7cf00396eb4587c7..90b771be2790505ced51d14d68474d136136bed0 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/generic_syncer.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/generic_syncer.cpp @@ -296,6 +296,7 @@ int GenericSyncer::RemoveSyncOperation(int syncId) syncIdMap_.erase(syncId); return E_OK; } + LOGE("[Syncer] RemoveSyncOperation, id %d not found", syncId); return -E_INVALID_ARGS; } @@ -387,13 +388,22 @@ void GenericSyncer::AddSyncOperation(ISyncEngine *engine, SyncOperation *operati return; } - LOGD("[Syncer] AddSyncOperation."); + LOGD("[Syncer] AddSyncOperation, sync id: %d.", operation->GetSyncId()); engine->AddSyncOperation(operation); if (operation->CheckIsAllFinished()) { + LOGD("[Syncer] AddSyncOperation, sync id: %d, but all finished.", operation->GetSyncId()); return; } + { + std::lock_guard lock(syncerLock_); + if (closing_ || !initialized_) { + LOGE("[Syncer] Syncer has been closed, return"); + operation->SetUnfinishedDevStatus(SyncOperation::OP_FAILED); + return; + } + } std::lock_guard lock(operationMapLock_); syncOperationMap_.insert(std::pair(operation->GetSyncId(), operation)); // To make sure operation alive before WaitIfNeed out @@ -537,6 +547,7 @@ bool GenericSyncer::IsValidDevices(const std::vector &devices) cons void GenericSyncer::ClearSyncOperations(bool isClosedOperation) { + LOGD("[Syncer] begin clear sync operations"); std::vector syncOperation; { std::lock_guard lock(operationMapLock_); @@ -563,6 +574,7 @@ void GenericSyncer::ClearSyncOperations(bool isClosedOperation) RefObject::DecObjRef(operation); } ClearInnerResource(isClosedOperation); + LOGD("[Syncer] clear sync operations done"); } void GenericSyncer::ClearInnerResource(bool isClosedOperation) @@ -570,6 +582,9 @@ void GenericSyncer::ClearInnerResource(bool isClosedOperation) { std::lock_guard lock(operationMapLock_); for (auto &iter : syncOperationMap_) { + if (iter.second->IsBlockSync()) { + iter.second->NotifyIfNeed(); + } RefObject::KillAndDecObjRef(iter.second); iter.second = nullptr; } diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/meta_data.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/device/meta_data.cpp index 8ddd8894caaf9fda47c72e944fb451b8ab77abef..a812917ed10b14e668989489e4b6932a7f021bff 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/meta_data.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/meta_data.cpp @@ -125,7 +125,7 @@ int Metadata::SavePeerWaterMark(const DeviceID &deviceId, uint64_t inValue, bool return SaveMetaDataValue(deviceId, metadata, isNeedHash); } -int Metadata::SaveLocalTimeOffset(TimeOffset timeOffset) +int Metadata::SaveLocalTimeOffset(TimeOffset timeOffset, bool saveIntoDb) { std::string timeOffsetString = std::to_string(timeOffset); std::vector timeOffsetValue(timeOffsetString.begin(), timeOffsetString.end()); @@ -134,7 +134,10 @@ int Metadata::SaveLocalTimeOffset(TimeOffset timeOffset) std::lock_guard lockGuard(localTimeOffsetLock_); localTimeOffset_ = timeOffset; - LOGD("Metadata::SaveLocalTimeOffset offset = %" PRId64, timeOffset); + LOGI("Metadata::SaveLocalTimeOffset offset = %" PRId64 " save db %d", timeOffset, static_cast(saveIntoDb)); + if (!saveIntoDb) { + return E_OK; + } int errCode = SetMetadataToDb(localTimeOffsetValue, timeOffsetValue); if (errCode != E_OK) { LOGE("Metadata::SaveLocalTimeOffset SetMetadataToDb failed errCode:%d", errCode); @@ -265,6 +268,10 @@ int64_t Metadata::StringToLong(const std::vector &value) const { std::string valueString(value.begin(), value.end()); int64_t longData = std::strtoll(valueString.c_str(), nullptr, DBConstant::STR_TO_LL_BY_DEVALUE); + if (errno == ERANGE && (longData == LLONG_MAX || longData == LLONG_MIN)) { + LOGW("[Metadata][StringToLong] convert string '%s' to number failed, longData = %" PRId64, + valueString.c_str(), longData); + } LOGD("Metadata::StringToLong longData = %" PRId64, longData); return longData; } @@ -951,4 +958,22 @@ int Metadata::GetMetaDataValueFromDB(const Key &key, MetaDataValue &metaDataValu } return DeSerializeMetaData(value, metaDataValue); } + +uint64_t Metadata::GetRemoteSoftwareVersion(const std::string &deviceId) +{ + MetaDataValue metadata; + std::lock_guard lockGuard(metadataLock_); + GetMetaDataValue(deviceId, metadata, true); + return metadata.remoteSoftwareVersion; +} + +int Metadata::SetRemoteSoftwareVersion(const std::string &deviceId, uint64_t version) +{ + MetaDataValue metadata; + std::lock_guard lockGuard(metadataLock_); + GetMetaDataValue(deviceId, metadata, true); + metadata.remoteSoftwareVersion = version; + LOGI("[Metadata] Set %.3s version %" PRId64, deviceId.c_str(), version); + return SaveMetaDataValue(deviceId, metadata); +} } // namespace DistributedDB \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/meta_data.h b/kv_store/frameworks/libs/distributeddb/syncer/src/device/meta_data.h index be6478456bbb9aaa6e4af7a44b738fde92a9a4c1..c483b86aba330662afa7594d915a13c5b9a671cf 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/meta_data.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/meta_data.h @@ -37,6 +37,7 @@ struct MetaDataValue { uint64_t syncMark = 0; // 0x1 ability sync finish 0x2 time sync finish uint64_t remoteSchemaVersion = 0; // reset zero when local schema change int64_t systemTimeOffset = 0; // record dev time offset + uint64_t remoteSoftwareVersion = 0; // record remote version }; struct LocalMetaData { @@ -78,7 +79,7 @@ public: int SavePeerWaterMark(const DeviceID &deviceId, uint64_t inValue, bool isNeedHash); - int SaveLocalTimeOffset(TimeOffset timeOffset); + int SaveLocalTimeOffset(TimeOffset timeOffset, bool saveIntoDb = true); TimeOffset GetLocalTimeOffset() const; @@ -173,6 +174,10 @@ public: std::pair GetLocalSchemaVersion(); int SetLocalSchemaVersion(uint64_t schemaVersion); + + uint64_t GetRemoteSoftwareVersion(const std::string &deviceId); + + int SetRemoteSoftwareVersion(const std::string &deviceId, uint64_t version); private: int SaveMetaDataValue(const DeviceID &deviceId, const MetaDataValue &inValue, bool isNeedHash = true); diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/remote_executor.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/device/remote_executor.cpp index eb30ebfd91427364a72778cec1c7e91abd548367..3d69bcf1bfe3dc8f7b2f628b56fd363fde8a298f 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/remote_executor.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/remote_executor.cpp @@ -34,10 +34,14 @@ namespace { void ReleaseMessageAndPacket(Message *message, ISyncPacket *packet) { - delete message; - message = nullptr; - delete packet; - packet = nullptr; + if (message != nullptr) { + delete message; + message = nullptr; + } + if (packet != nullptr) { + delete packet; + packet = nullptr; + } } } @@ -225,9 +229,10 @@ int RemoteExecutor::CheckPermissions(const std::string &device, Message *inMsg) std::string appId = storage->GetDbProperties().GetStringProp(DBProperties::APP_ID, ""); std::string userId = storage->GetDbProperties().GetStringProp(DBProperties::USER_ID, ""); std::string storeId = storage->GetDbProperties().GetStringProp(DBProperties::STORE_ID, ""); + std::string subUseId = storage->GetDbProperties().GetStringProp(DBProperties::SUB_USER, ""); int32_t instanceId = syncInterface_->GetDbProperties().GetIntProp(DBProperties::INSTANCE_ID, 0); int errCode = RuntimeContext::GetInstance()->RunPermissionCheck( - { userId, appId, storeId, device, instanceId }, CHECK_FLAG_SEND); + { userId, appId, storeId, device, subUseId, instanceId }, CHECK_FLAG_SEND); if (errCode != E_OK) { LOGE("[RemoteExecutor][CheckPermissions] check permission errCode = %d.", errCode); storage->DecRefCount(); diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_packet.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_packet.cpp index c2a7f12bf259ec269362a3280f15d5b6c56e075b..e776e310985a57ec4bfad81d546845d72667b2c4 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_packet.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_packet.cpp @@ -29,7 +29,6 @@ DataRequestPacket::~DataRequestPacket() { for (auto &entry : data_) { delete entry; - entry = nullptr; } } diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_sync.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_sync.cpp index d5543bfdfd919849d0a2486f7e0863c80e7d1544..167d671d64e7a006b714f4f178e48d636dbbe903 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_sync.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_sync.cpp @@ -40,9 +40,6 @@ SingleVerDataSync::SingleVerDataSync() SingleVerDataSync::~SingleVerDataSync() { - storage_ = nullptr; - communicateHandle_ = nullptr; - metadata_ = nullptr; } int SingleVerDataSync::Initialize(ISyncInterface *inStorage, ICommunicator *inCommunicateHandle, @@ -984,14 +981,14 @@ int SingleVerDataSync::DataRequestRecvPre(SingleVerSyncTaskContext *context, con return errCode; } -int SingleVerDataSync::DataRequestRecv(SingleVerSyncTaskContext *context, const Message *message, +int SingleVerDataSync::DataRequestRecvInner(SingleVerSyncTaskContext *context, const Message *message, WaterMark &pullEndWatermark) { - int errCode = DataRequestRecvPre(context, message); - if (errCode != E_OK) { - return errCode; - } const DataRequestPacket *packet = message->GetObject(); + if (packet == nullptr) { + LOGE("[DataSync][DataRequestRecv] get packet object failed"); + return -E_INVALID_ARGS; + } const std::vector &data = packet->GetData(); SyncType curType = SyncOperation::GetSyncType(packet->GetMode()); LOGI("[DataSync][DataRequestRecv] curType=%d, remote ver=%" PRIu32 ", size=%zu, errCode=%d, queryId=%s," @@ -1000,7 +997,7 @@ int SingleVerDataSync::DataRequestRecv(SingleVerSyncTaskContext *context, const context->SetReceiveWaterMarkErr(false); UpdateWaterMark isUpdateWaterMark; SyncTimeRange dataTime = SingleVerDataSyncUtils::GetRecvDataTimeRange(curType, data, isUpdateWaterMark); - errCode = RemoveDeviceDataHandle(context, message, dataTime.endTime); + int errCode = RemoveDeviceDataHandle(context, message, dataTime.endTime); if (errCode != E_OK) { return errCode; } @@ -1010,7 +1007,8 @@ int SingleVerDataSync::DataRequestRecv(SingleVerSyncTaskContext *context, const } GetPullEndWatermark(context, packet, pullEndWatermark); // save data first - errCode = SaveData(context, data, curType, packet->GetQuery()); + errCode = SaveData(context, data, curType, + SingleVerDataSyncUtils::GetQueryFromDataRequest(*packet, *context, message->GetSessionId())); if (errCode != E_OK) { (void)SendDataAck(context, message, errCode, dataTime.endTime); return errCode; @@ -1026,11 +1024,8 @@ int SingleVerDataSync::DataRequestRecv(SingleVerSyncTaskContext *context, const } RemotePushFinished(packet->GetSendCode(), packet->GetMode(), message->GetSessionId(), context->GetRequestSessionId()); - if (curType != SyncType::QUERY_SYNC_TYPE && isUpdateWaterMark.normalUpdateMark) { - UpdatePeerWaterMark(curType, "", context, dataTime.endTime + 1, 0); - } else if (curType == SyncType::QUERY_SYNC_TYPE && packet->IsNeedUpdateWaterMark()) { - UpdateQueryPeerWaterMark(curType, packet->GetQueryId(), dataTime, context, isUpdateWaterMark); - } + UpdatePeerWaterMarkInner(*packet, dataTime, isUpdateWaterMark, context); + if (errCode != E_OK) { return errCode; } @@ -1040,6 +1035,16 @@ int SingleVerDataSync::DataRequestRecv(SingleVerSyncTaskContext *context, const return errCode; } +int SingleVerDataSync::DataRequestRecv(SingleVerSyncTaskContext *context, const Message *message, + WaterMark &pullEndWatermark) +{ + int errCode = DataRequestRecvPre(context, message); + if (errCode != E_OK) { + return errCode; + } + return DataRequestRecvInner(context, message, pullEndWatermark); +} + int SingleVerDataSync::SendDataPacket(SyncType syncType, DataRequestPacket *packet, SingleVerSyncTaskContext *context) { @@ -1589,6 +1594,10 @@ void SingleVerDataSync::RemotePushFinished(int sendCode, int inMode, uint32_t ms (mode != SyncModeType::QUERY_PUSH_PULL)) { return; } + if (storage_ == nullptr) { + LOGE("RemotePushFinished fail, storage is nullptr."); + return; + } if ((sendCode == E_OK) && (msgSessionId != 0) && (msgSessionId != contextSessionId)) { storage_->NotifyRemotePushFinished(deviceId_); @@ -1686,6 +1695,10 @@ int SingleVerDataSync::GetReSendData(SyncEntry &syncData, SingleVerSyncTaskConte int SingleVerDataSync::RemoveDeviceDataIfNeed(SingleVerSyncTaskContext *context) { + if (context == nullptr) { + LOGE("[SingleVerDataSync][RemoveDeviceDataIfNeed] context is nullptr."); + return -E_INVALID_ARGS; + } if (context->GetRemoteSoftwareVersion() <= SOFTWARE_VERSION_RELEASE_3_0) { return E_OK; } @@ -1855,4 +1868,15 @@ int SingleVerDataSync::ControlCmdRequestRecv(SingleVerSyncTaskContext *context, } return errCode; } + +void SingleVerDataSync::UpdatePeerWaterMarkInner(const DataRequestPacket &packet, const SyncTimeRange &dataTime, + const UpdateWaterMark &isUpdateWaterMark, const SingleVerSyncTaskContext *context) +{ + SyncType curType = SyncOperation::GetSyncType(packet.GetMode()); + if (curType != SyncType::QUERY_SYNC_TYPE && isUpdateWaterMark.normalUpdateMark) { + UpdatePeerWaterMark(curType, "", context, dataTime.endTime + 1, 0); + } else if (curType == SyncType::QUERY_SYNC_TYPE && packet.IsNeedUpdateWaterMark()) { + UpdateQueryPeerWaterMark(curType, packet.GetQueryId(), dataTime, context, isUpdateWaterMark); + } +} } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_sync.h b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_sync.h index 4a34bf9fa24ba5ca781837ea1da8afb127fe07de..5c1a758c55d9f4d0720d51f8509ef74ad2865903 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_sync.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_sync.h @@ -253,6 +253,11 @@ protected: void RemoveSubscribeIfNeed(const std::string &queryId, const std::shared_ptr &subscribeManager); + int DataRequestRecvInner(SingleVerSyncTaskContext *context, const Message *message, WaterMark &pullEndWatermark); + + void UpdatePeerWaterMarkInner(const DataRequestPacket &packet, const SyncTimeRange &dataTime, + const UpdateWaterMark &isUpdateWaterMark, const SingleVerSyncTaskContext *context); + uint32_t mtuSize_; SyncGenericInterface* storage_; ICommunicator* communicateHandle_; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_sync_utils.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_sync_utils.cpp index ee31265048802341fef98287170dac43c0ca8f7e..f9eb3b7602393cac76acc14736b396469a6baef8 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_sync_utils.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_sync_utils.cpp @@ -646,4 +646,13 @@ void SingleVerDataSyncUtils::CacheInitWaterMark(SingleVerSyncTaskContext *contex context->SetInitDeletedMark(deletedMark); LOGI("[SingleVerDataSync][CacheInitWaterMark] startMark %" PRIu64 " deletedMark %" PRIu64, startMark, deletedMark); } + +QuerySyncObject SingleVerDataSyncUtils::GetQueryFromDataRequest(const DataRequestPacket &packet, + const SingleVerSyncTaskContext &context, uint32_t sessionId) +{ + auto query = packet.GetQuery(); + query.SetRemoteDev(context.GetDeviceId()); + query.SetUseLocalSchema(sessionId == context.GetRequestSessionId()); + return query; +} } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_sync_utils.h b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_sync_utils.h index f01eb4de42b6fd5c917fd087dabaaeb6f09f68b3..1fa99eaf162dc840cc7eec940157aa04c1f7a99d 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_sync_utils.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_data_sync_utils.h @@ -114,6 +114,9 @@ public: static void UpdateSyncProcess(SingleVerSyncTaskContext *context, const DataRequestPacket *packet); static void CacheInitWaterMark(SingleVerSyncTaskContext *context, SingleVerDataSync *dataSync); + + static QuerySyncObject GetQueryFromDataRequest(const DataRequestPacket &packet, + const SingleVerSyncTaskContext &context, uint32_t sessionId); private: static int RunPermissionCheckInner(const SingleVerSyncTaskContext *context, const SyncGenericInterface* storage, const std::string &label, const DataRequestPacket *packet, int mode); diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_kv_syncer.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_kv_syncer.cpp index d52e36d0a6cae232b36397c11257f84b4109e928..31ac7c4b1ceaee17fc1e62a38fe67b4cf80d7df3 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_kv_syncer.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_kv_syncer.cpp @@ -127,7 +127,8 @@ void SingleVerKVSyncer::RemoteDataChanged(const std::string &device) std::string userId = syncInterface_->GetDbProperties().GetStringProp(KvDBProperties::USER_ID, ""); std::string appId = syncInterface_->GetDbProperties().GetStringProp(KvDBProperties::APP_ID, ""); std::string storeId = syncInterface_->GetDbProperties().GetStringProp(KvDBProperties::STORE_ID, ""); - RuntimeContext::GetInstance()->NotifyDatabaseStatusChange(userId, appId, storeId, device, true); + std::string subUserId = syncInterface_->GetDbProperties().GetStringProp(KvDBProperties::SUB_USER, ""); + RuntimeContext::GetInstance()->NotifyDatabaseStatusChange({userId, appId, storeId, subUserId, device}, true); SingleVerSyncer::RemoteDataChanged(device); if (autoSyncEnable_) { RefObject::IncObjRef(syncEngine_); diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_relational_sync_task_context.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_relational_sync_task_context.cpp index 607d2999148bf646d5a795833666bdb42016b0a1..e1f536963e27fea9b874303c1804b045b64cb7bf 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_relational_sync_task_context.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_relational_sync_task_context.cpp @@ -15,6 +15,7 @@ #include "single_ver_relational_sync_task_context.h" #include "db_common.h" +#include "relational_db_sync_interface.h" #ifdef RELATIONAL_STORE namespace DistributedDB { @@ -28,8 +29,26 @@ SingleVerRelationalSyncTaskContext::~SingleVerRelationalSyncTaskContext() std::string SingleVerRelationalSyncTaskContext::GetQuerySyncId() const { + RelationalSchemaObject schemaObj; + if (!IsRemoteSupportFieldSync() || GetDistributedSchema(schemaObj) != E_OK) { + std::lock_guard autoLock(querySyncIdMutex_); + return querySyncId_; + } + + std::string tableName = GetQuery().GetRelationTableName(); + std::vector fieldsInfo = schemaObj.GetSyncFieldInfo(tableName); + std::vector strFields(fieldsInfo.size()); + for (const auto &field : fieldsInfo) { + strFields.push_back(field.GetFieldName()); + } + std::sort(strFields.begin(), strFields.end()); + std::string splitFields; + for (const auto &strField : strFields) { + splitFields += strField; + } + std::string queryFieldsSyncId = DBCommon::TransferHashString(splitFields); std::lock_guard autoLock(querySyncIdMutex_); - return querySyncId_; + return querySyncId_ + DBCommon::TransferStringToHex(queryFieldsSyncId); } std::string SingleVerRelationalSyncTaskContext::GetDeleteSyncId() const @@ -107,5 +126,20 @@ bool SingleVerRelationalSyncTaskContext::IsSchemaCompatible() const } return true; } + +bool SingleVerRelationalSyncTaskContext::IsRemoteSupportFieldSync() const +{ + return GetRemoteSoftwareVersion() > SOFTWARE_VERSION_RELEASE_10_0; +} + +int SingleVerRelationalSyncTaskContext::GetDistributedSchema(RelationalSchemaObject &schemaObj) const +{ + auto *relationalDbSyncInterface = static_cast(syncInterface_); + if (SyncTaskContext::GetMode() == SyncModeType::RESPONSE_PULL) { + return relationalDbSyncInterface->GetRemoteDeviceSchema(GetDeviceId(), schemaObj); + } + schemaObj = relationalDbSyncInterface->GetSchemaInfo(); + return E_OK; +} } #endif \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_relational_sync_task_context.h b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_relational_sync_task_context.h index b22d4837360a839128e59efe511f189e1680a2c3..b07d7c3e9e27a65b3f0a1b14c571c1b50f9851b9 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_relational_sync_task_context.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_relational_sync_task_context.h @@ -37,6 +37,10 @@ public: void SchemaChange() override; bool IsSchemaCompatible() const override; + + bool IsRemoteSupportFieldSync() const; + + int GetDistributedSchema(RelationalSchemaObject &schemaObj) const; protected: ~SingleVerRelationalSyncTaskContext() override; void CopyTargetData(const ISyncTarget *target, const TaskParam &taskParam) override; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_relational_syncer.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_relational_syncer.cpp index 85eb16788d8834ed997683a566b35ce18fbcd66e..106797beac702f8c924035d5a0aa64a683519625 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_relational_syncer.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_relational_syncer.cpp @@ -184,6 +184,21 @@ int SingleVerRelationalSyncer::SyncConditionCheck(const SyncParma ¶m, const LOGE("[SingleVerRelationalSyncer] QuerySyncObject check failed"); return errCode; } + const RelationalSchemaObject &schemaObj = static_cast(storage)->GetSchemaInfo(); + if (schemaObj.GetTableMode() == DistributedTableMode::COLLABORATION) { + const std::vector &sTable = schemaObj.GetDistributedSchema().tables; + if (sTable.empty()) { + LOGE("[SingleVerRelationalSyncer] Distributed schema not set in COLLABORATION mode"); + return -E_SCHEMA_MISMATCH; + } + auto iter = std::find_if(sTable.begin(), sTable.end(), [¶m](const DistributedTable &table) { + return table.tableName == param.syncQuery.GetTableName(); + }); + if (iter == sTable.end()) { + LOGE("[SingleVerRelationalSyncer] table name mismatch"); + return -E_SCHEMA_MISMATCH; + } + } if (param.mode == SUBSCRIBE_QUERY) { return -E_NOT_SUPPORT; } diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_serialize_manager.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_serialize_manager.cpp index 186c9f779e5ceff0262c5208e5596faa408d5c1f..9be5cdaa36c6ea8b20d1ba86415dabb944546561 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_serialize_manager.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_serialize_manager.cpp @@ -31,7 +31,7 @@ std::mutex SingleVerSerializeManager::handlesLock_; std::map SingleVerSerializeManager::messageHandles_; int SingleVerSerializeManager::Serialization(uint8_t *buffer, uint32_t length, const Message *inMsg) { - if ((buffer == nullptr) || !(IsPacketValid(inMsg))) { + if ((buffer == nullptr) || length == 0u || !(IsPacketValid(inMsg))) { return -E_MESSAGE_ID_ERROR; } SerializeFunc serializeFunc = nullptr; @@ -78,7 +78,7 @@ int SingleVerSerializeManager::ControlSerialization(uint8_t *buffer, uint32_t le int SingleVerSerializeManager::DeSerialization(const uint8_t *buffer, uint32_t length, Message *inMsg) { - if ((buffer == nullptr) || !(IsPacketValid(inMsg))) { + if ((buffer == nullptr) || length == 0u || !(IsPacketValid(inMsg))) { return -E_MESSAGE_ID_ERROR; } DeserializeFunc deserializeFunc = nullptr; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_sync_task_context.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_sync_task_context.cpp index 995fa508055c9510667c0a6b23b49be6f284b4ae..3183a48654e3a0a26be95e563c34e452e8aa0b60 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_sync_task_context.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_sync_task_context.cpp @@ -200,10 +200,7 @@ void SingleVerSyncTaskContext::CopyTargetData(const ISyncTarget *target, const T if (mode_ == SyncModeType::RESPONSE_PULL) { responseSessionId_ = targetTmp->GetResponseSessionId(); } - { - std::lock_guard autoLock(queryMutex_); - query_ = targetTmp->GetQuery(); - } + SetQuery(targetTmp->GetQuery()); isQuerySync_ = targetTmp->IsQuerySync(); } @@ -293,7 +290,7 @@ void SingleVerSyncTaskContext::ClearAllSyncTask() if (GetTaskExecStatus() == SyncTaskContext::RUNNING) { // clear syncing task. stateMachine_->CommErrAbort(); - SetCommFailErrCode(static_cast(COMM_FAILURE)); + SetCommFailErrCode(static_cast(SyncOperation::OP_COMM_ABNORMAL)); } // reset last push status for sync merge ResetLastPushTaskStatus(); @@ -388,6 +385,8 @@ void SingleVerSyncTaskContext::SetQuery(const QuerySyncObject &query) { std::lock_guard autoLock(queryMutex_); query_ = query; + query_.SetUseLocalSchema(mode_ != SyncModeType::RESPONSE_PULL); + query_.SetRemoteDev(deviceId_); } QuerySyncObject SingleVerSyncTaskContext::GetQuery() const diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_syncer.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_syncer.cpp index 4512687ef4c8ec1bf8a82816cc846ba2e9250a13..322f2dca6ba8f76176759e699476546f4d65b382 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_syncer.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/singlever/single_ver_syncer.cpp @@ -29,7 +29,8 @@ void SingleVerSyncer::RemoteDeviceOffline(const std::string &device) std::string userId = syncInterface_->GetDbProperties().GetStringProp(KvDBProperties::USER_ID, ""); std::string appId = syncInterface_->GetDbProperties().GetStringProp(KvDBProperties::APP_ID, ""); std::string storeId = syncInterface_->GetDbProperties().GetStringProp(KvDBProperties::STORE_ID, ""); - RuntimeContext::GetInstance()->NotifyDatabaseStatusChange(userId, appId, storeId, device, false); + std::string subUserId = syncInterface_->GetDbProperties().GetStringProp(KvDBProperties::SUB_USER, ""); + RuntimeContext::GetInstance()->NotifyDatabaseStatusChange({userId, appId, storeId, subUserId, device}, false); RefObject::IncObjRef(syncEngine_); ISyncEngine *engine = syncEngine_; ISyncInterface *storage = syncInterface_; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/sync_engine.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/device/sync_engine.cpp index 0a784b1a55d3675d1616f1946738da44b677d9f1..b64cd1e60b63b6ee90abd1877cf83fef4f95a0a7 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/sync_engine.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/sync_engine.cpp @@ -218,7 +218,7 @@ void SyncEngine::StartCommunicator() LOGE("[SyncEngine][StartCommunicator] register failed, auto sync can not use! err %d", errCode); return; } - communicator_->Activate(); + communicator_->Activate(GetUserId()); } void SyncEngine::GetOnlineDevices(std::vector &devices) const @@ -286,9 +286,9 @@ int SyncEngine::InitComunicator(const ISyncInterface *syncInterface) std::vector dualTuplelabel = syncInterface->GetDualTupleIdentifier(); LOGI("[SyncEngine] dual tuple mode, original identifier=%.3s, target identifier=%.3s", VEC_TO_STR(label), VEC_TO_STR(dualTuplelabel)); - communicator_ = communicatorAggregator->AllocCommunicator(dualTuplelabel, errCode); + communicator_ = communicatorAggregator->AllocCommunicator(dualTuplelabel, errCode, GetUserId(syncInterface)); } else { - communicator_ = communicatorAggregator->AllocCommunicator(label, errCode); + communicator_ = communicatorAggregator->AllocCommunicator(label, errCode, GetUserId(syncInterface)); } if (communicator_ == nullptr) { LOGE("[SyncEngine] AllocCommunicator error when init the sync engine! err = %d", errCode); @@ -299,7 +299,7 @@ int SyncEngine::InitComunicator(const ISyncInterface *syncInterface) [this](const std::string &targetDev, Message *inMsg) { MessageReciveCallback(targetDev, inMsg); }, []() {}); if (errCode != E_OK) { LOGE("[SyncEngine] SyncRequestCallback register failed! err = %d", errCode); - communicatorAggregator->ReleaseCommunicator(communicator_); + communicatorAggregator->ReleaseCommunicator(communicator_, GetUserId(syncInterface)); communicator_ = nullptr; return errCode; } @@ -307,7 +307,7 @@ int SyncEngine::InitComunicator(const ISyncInterface *syncInterface) std::lock_guard lock(communicatorProxyLock_); communicatorProxy_ = new (std::nothrow) CommunicatorProxy(); if (communicatorProxy_ == nullptr) { - communicatorAggregator->ReleaseCommunicator(communicator_); + communicatorAggregator->ReleaseCommunicator(communicator_, GetUserId(syncInterface)); communicator_ = nullptr; return -E_OUT_OF_MEMORY; } @@ -494,8 +494,10 @@ void SyncEngine::MessageReciveCallback(const std::string &targetDev, Message *in IncExecTaskCount(); int errCode = MessageReciveCallbackInner(targetDev, inMsg); if (errCode != E_OK) { - delete inMsg; - inMsg = nullptr; + if (inMsg != nullptr) { + delete inMsg; + inMsg = nullptr; + } DecExecTaskCount(); LOGE("[SyncEngine] MessageReciveCallback failed!"); } @@ -703,16 +705,33 @@ int SyncEngine::GetQueueCacheSize() const return queueCacheSize_; } +void SyncEngine::SetQueueCacheSize(int size) +{ + std::lock_guard lock(queueLock_); + queueCacheSize_ = size; +} + unsigned int SyncEngine::GetDiscardMsgNum() const { return discardMsgNum_; } +void SyncEngine::SetDiscardMsgNum(unsigned int num) +{ + std::lock_guard lock(queueLock_); + discardMsgNum_ = num; +} + unsigned int SyncEngine::GetMaxExecNum() const { return MAX_EXEC_NUM; } +int SyncEngine::GetMaxQueueCacheSize() const +{ + return maxQueueCacheSize_; +} + void SyncEngine::SetMaxQueueCacheSize(int value) { maxQueueCacheSize_ = value; @@ -758,7 +777,7 @@ int SyncEngine::SetEqualIdentifier(const std::string &identifier, const std::vec communicator = equalCommunicators_[identifier]; } else { int errCode = E_OK; - communicator = AllocCommunicator(identifier, errCode); + communicator = AllocCommunicator(identifier, errCode, GetUserId()); if (communicator == nullptr) { return errCode; } @@ -779,7 +798,7 @@ int SyncEngine::SetEqualIdentifier(const std::string &identifier, const std::vec } communicatorProxy_->SetEqualCommunicator(communicator, identifier, targets); } - communicator->Activate(); + communicator->Activate(GetUserId()); return E_OK; } @@ -894,7 +913,7 @@ void SyncEngine::GetAllUnFinishSubQueries(std::mapGetAllUnFinishSubQueries(allSyncQueries); } -ICommunicator *SyncEngine::AllocCommunicator(const std::string &identifier, int &errCode) +ICommunicator *SyncEngine::AllocCommunicator(const std::string &identifier, int &errCode, std::string userId) { ICommunicatorAggregator *communicatorAggregator = nullptr; errCode = RuntimeContext::GetInstance()->GetCommunicatorAggregator(communicatorAggregator); @@ -903,7 +922,7 @@ ICommunicator *SyncEngine::AllocCommunicator(const std::string &identifier, int return nullptr; } std::vector identifierVect(identifier.begin(), identifier.end()); - auto communicator = communicatorAggregator->AllocCommunicator(identifierVect, errCode); + auto communicator = communicatorAggregator->AllocCommunicator(identifierVect, errCode, userId); if (communicator == nullptr) { LOGE("[SyncEngine] AllocCommunicator error when SetEqualIdentifier! err = %d", errCode); return communicator; @@ -913,7 +932,7 @@ ICommunicator *SyncEngine::AllocCommunicator(const std::string &identifier, int [this](const std::string &targetDev, Message *inMsg) { MessageReciveCallback(targetDev, inMsg); }, []() {}); if (errCode != E_OK) { LOGE("[SyncEngine] SyncRequestCallback register failed in SetEqualIdentifier! err = %d", errCode); - communicatorAggregator->ReleaseCommunicator(communicator); + communicatorAggregator->ReleaseCommunicator(communicator, userId); return nullptr; } @@ -924,7 +943,7 @@ ICommunicator *SyncEngine::AllocCommunicator(const std::string &identifier, int if (errCode != E_OK) { LOGE("[SyncEngine][RegConnCB] register failed in SetEqualIdentifier! err %d", errCode); communicator->RegOnMessageCallback(nullptr, nullptr); - communicatorAggregator->ReleaseCommunicator(communicator); + communicatorAggregator->ReleaseCommunicator(communicator, userId); return nullptr; } @@ -961,13 +980,13 @@ void SyncEngine::ReleaseCommunicators() } if (communicator_ != nullptr) { - communicatorAggregator->ReleaseCommunicator(communicator_); + communicatorAggregator->ReleaseCommunicator(communicator_, GetUserId()); communicator_ = nullptr; } std::lock_guard lock(equalCommunicatorsLock_); for (auto &iter : equalCommunicators_) { - communicatorAggregator->ReleaseCommunicator(iter.second); + communicatorAggregator->ReleaseCommunicator(iter.second, GetUserId()); } equalCommunicators_.clear(); } @@ -1318,6 +1337,26 @@ void SyncEngine::SetSyncInterface(ISyncInterface *syncInterface) syncInterface_ = syncInterface; } +std::string SyncEngine::GetUserId(const ISyncInterface *syncInterface) +{ + if (syncInterface == nullptr) { + LOGW("[SyncEngine][GetUserId] sync interface has not initialized"); + return ""; + } + std::string userId = syncInterface->GetDbProperties().GetStringProp(DBProperties::USER_ID, ""); + std::string subUserId = syncInterface->GetDbProperties().GetStringProp(DBProperties::SUB_USER, ""); + if (!subUserId.empty()) { + userId += "-" + subUserId; + } + return userId; +} + +std::string SyncEngine::GetUserId() +{ + std::lock_guard autoLock(storageMutex_); + return GetUserId(syncInterface_); +} + uint32_t SyncEngine::GetTimeout(const std::string &dev) { ICommunicator *communicator = nullptr; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/sync_engine.h b/kv_store/frameworks/libs/distributeddb/syncer/src/device/sync_engine.h index 4b0cc7379a0c7efdd42e23966f6c2f169710d3b1..78c93192234325c4bf43ef4c157617084054d2a3 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/sync_engine.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/sync_engine.h @@ -63,12 +63,21 @@ public: // Get the queue cache memory size int GetQueueCacheSize() const; + // Set the queue cache memory size + void SetQueueCacheSize(int size); + // Get the number of message which is discarded unsigned int GetDiscardMsgNum() const; + // Set the number of message which is discarded + void SetDiscardMsgNum(unsigned int num); + // Get the maximum of executing message number unsigned int GetMaxExecNum() const; + // Get the maximum of queue cache memory size + int GetMaxQueueCacheSize() const; + // Set the maximum of queue cache memory size void SetMaxQueueCacheSize(int value); @@ -194,7 +203,7 @@ private: ISyncTaskContext *GetContextForMsg(const std::string &targetDev, int &errCode); - ICommunicator *AllocCommunicator(const std::string &identifier, int &errCode); + ICommunicator *AllocCommunicator(const std::string &identifier, int &errCode, std::string userId = ""); void UnRegCommunicatorsCallback(); @@ -222,6 +231,10 @@ private: void AddQuerySubscribe(SyncGenericInterface *storage, const std::string &device, const QuerySyncObject &query); + std::string GetUserId(); + + std::string GetUserId(const ISyncInterface *syncInterface); + uint32_t GetTimeout(const std::string &dev); ICommunicator *communicator_; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/device/sync_task_context.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/device/sync_task_context.cpp index 8a38d34e36c5bf3e6670d9a439a8ef1a76ce38c8..4fd93de50f11932d034806f7f0b20e29309c2b8e 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/device/sync_task_context.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/device/sync_task_context.cpp @@ -178,7 +178,6 @@ int SyncTaskContext::RemoveSyncOperation(int syncId) if (iter != requestTargetQueue_.end()) { if (*iter != nullptr) { delete *iter; - *iter = nullptr; } requestTargetQueue_.erase(iter); return E_OK; @@ -192,7 +191,6 @@ void SyncTaskContext::ClearSyncTarget() for (auto &requestTarget : requestTargetQueue_) { if (requestTarget != nullptr) { delete requestTarget; - requestTarget = nullptr; } } requestTargetQueue_.clear(); @@ -200,7 +198,6 @@ void SyncTaskContext::ClearSyncTarget() for (auto &responseTarget : responseTargetQueue_) { if (responseTarget != nullptr) { // LCOV_EXCL_BR_LINE delete responseTarget; - responseTarget = nullptr; } } responseTargetQueue_.clear(); @@ -549,7 +546,7 @@ void SyncTaskContext::CommErrHandlerFuncInner(int errCode, uint32_t sessionId, b return; } if (errCode > 0) { - SetCommFailErrCode(static_cast(COMM_FAILURE)); + SetCommFailErrCode(static_cast(SyncOperation::OP_COMM_ABNORMAL)); } else { SetCommFailErrCode(errCode); } @@ -764,9 +761,10 @@ int SyncTaskContext::RunPermissionCheck(uint8_t flag) const std::string appId = syncInterface_->GetDbProperties().GetStringProp(DBProperties::APP_ID, ""); std::string userId = syncInterface_->GetDbProperties().GetStringProp(DBProperties::USER_ID, ""); std::string storeId = syncInterface_->GetDbProperties().GetStringProp(DBProperties::STORE_ID, ""); + std::string subUserId = syncInterface_->GetDbProperties().GetStringProp(DBProperties::SUB_USER, ""); int32_t instanceId = syncInterface_->GetDbProperties().GetIntProp(DBProperties::INSTANCE_ID, 0); int errCode = RuntimeContext::GetInstance()->RunPermissionCheck( - { userId, appId, storeId, deviceId_, instanceId }, flag); + { userId, appId, storeId, deviceId_, subUserId, instanceId }, flag); if (errCode != E_OK) { LOGE("[SyncTaskContext] RunPermissionCheck not pass errCode:%d, flag:%d, %s{private}", errCode, flag, deviceId_.c_str()); @@ -867,7 +865,7 @@ void SyncTaskContext::SetCommFailErrCode(int errCode) void SyncTaskContext::SetErrCodeWhenWaitTimeOut(int errCode) { if (errCode > 0) { - SetCommFailErrCode(static_cast(TIME_OUT)); + SetCommFailErrCode(static_cast(SyncOperation::OP_TIMEOUT)); } else { SetCommFailErrCode(errCode); } diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/time_helper.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/time_helper.cpp index 68ff51740da33327efacf1a90daea1076b6e469c..c0369a08132e0ab9bcd17b2a7ce01908a6a169e6 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/time_helper.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/time_helper.cpp @@ -89,7 +89,8 @@ int TimeHelper::Initialize(const ISyncInterface *inStorage, const std::shared_pt Timestamp virtualSysTime = static_cast(currentSysTime + localTimeOffset); if (virtualSysTime <= maxItemTime || virtualSysTime > BUFFER_VALID_TIME) { localTimeOffset = static_cast(maxItemTime - currentSysTime + MS_TO_100_NS); // 1ms - int errCode = SaveLocalTimeOffset(localTimeOffset); + // cal timeOffset without time tick, should not be written into db + int errCode = metadata_->SaveLocalTimeOffset(localTimeOffset, false); if (errCode != E_OK) { LOGE("[TimeHelper] save local time offset failed,err=%d", errCode); return errCode; @@ -134,11 +135,6 @@ TimeOffset TimeHelper::GetLocalTimeOffset() const return metadata_->GetLocalTimeOffset(); } -int TimeHelper::SaveLocalTimeOffset(TimeOffset offset) -{ - return metadata_->SaveLocalTimeOffset(offset); -} - void TimeHelper::SetSendConfig(const std::string &dstTarget, bool nonBlock, uint32_t timeout, SendConfig &sendConf) { SetSendConfigParam(storage_->GetDbProperties(), dstTarget, false, SEND_TIME_OUT, sendConf); @@ -153,4 +149,11 @@ Timestamp TimeHelper::GetMonotonicTime() } return time; } + +Timestamp TimeHelper::GetCurrentLocalTime(int64_t &curTimeOffset, int64_t &localTimeOffset) +{ + Timestamp currentSysTime = GetSysCurrentTime(); + Timestamp currentLocalTime = currentSysTime + curTimeOffset + localTimeOffset; + return currentLocalTime; +} } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/time_helper.h b/kv_store/frameworks/libs/distributeddb/syncer/src/time_helper.h index c0163d9f8fbeb143b6c25120c4359d9622b368d1..f06ac32ea6847994194853f4d9ccc4d6e7211c8e 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/time_helper.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/time_helper.h @@ -56,13 +56,12 @@ public: // Get local time offset TimeOffset GetLocalTimeOffset() const; - // Get local time - int SaveLocalTimeOffset(TimeOffset offset); - void SetSendConfig(const std::string &dstTarget, bool nonBlock, uint32_t timeout, SendConfig &sendConf); static Timestamp GetMonotonicTime(); + static Timestamp GetCurrentLocalTime(int64_t &curTimeOffset, int64_t &localTimeOffset); + private: static std::mutex systemTimeLock_; static Timestamp lastSystemTimeUs_; diff --git a/kv_store/frameworks/libs/distributeddb/test/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/BUILD.gn index d564778816d2f15b4710e35da6e1f707a1761bd3..8c83c045ae553e2f0f684c9b273c522b60bfd26d 100644 --- a/kv_store/frameworks/libs/distributeddb/test/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/BUILD.gn @@ -88,7 +88,6 @@ config("module_private_config") { "../syncer/src/device", "../syncer/src/device/multiver", "../syncer/src/device/singlever", - "//third_party/openssl/include/", "../gaussdb_rd/include", "../gaussdb_rd/include/grd_base", "../gaussdb_rd/include/grd_document", @@ -114,6 +113,7 @@ config("module_private_config") { "TRACE_SQLITE_EXECUTE", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "USE_DISTRIBUTEDDB_CLOUD", ] if (is_ohos) { defines += [ "USE_FFRT" ] @@ -125,37 +125,12 @@ ohos_source_set("src_file") { testonly = true sources = distributeddb_src + sources += distributeddb_cloud_src sources += [ - "../gaussdb_rd/src/common/src/collection_option.cpp", - "../gaussdb_rd/src/common/src/db_config.cpp", - "../gaussdb_rd/src/common/src/grd_api_manager.cpp", - "../gaussdb_rd/src/common/src/json_common.cpp", - "../gaussdb_rd/src/common/src/os_api.cpp", - "../gaussdb_rd/src/common/src/rd_log_print.cpp", - "../gaussdb_rd/src/executor/base/grd_db_api.cpp", - "../gaussdb_rd/src/executor/base/grd_db_api_inner.cpp", - "../gaussdb_rd/src/executor/document/check_common.cpp", - "../gaussdb_rd/src/executor/document/grd_document_api.cpp", - "../gaussdb_rd/src/executor/document/grd_document_api_inner.cpp", - "../gaussdb_rd/src/executor/document/grd_resultset_api.cpp", - "../gaussdb_rd/src/executor/document/grd_resultset_api_inner.cpp", - "../gaussdb_rd/src/executor/kv/grd_kv_api.cpp", - "../gaussdb_rd/src/executor/kv/grd_kv_api_inner.cpp", - "../gaussdb_rd/src/interface/src/collection.cpp", - "../gaussdb_rd/src/interface/src/doc_errno.cpp", - "../gaussdb_rd/src/interface/src/document_key.cpp", - "../gaussdb_rd/src/interface/src/document_store.cpp", - "../gaussdb_rd/src/interface/src/document_store_manager.cpp", - "../gaussdb_rd/src/interface/src/projection_tree.cpp", - "../gaussdb_rd/src/interface/src/result_set.cpp", - "../gaussdb_rd/src/interface/src/result_set_common.cpp", - "../gaussdb_rd/src/oh_adapter/src/kv_store_manager.cpp", - "../gaussdb_rd/src/oh_adapter/src/rd_json_object.cpp", - "../gaussdb_rd/src/oh_adapter/src/rd_sqlite_utils.cpp", - "../gaussdb_rd/src/oh_adapter/src/sqlite_store_executor_impl.cpp", "unittest/common/common/distributeddb_data_generate_unit_test.cpp", "unittest/common/common/distributeddb_tools_unit_test.cpp", "unittest/common/common/native_sqlite.cpp", + "unittest/common/common/rdb_data_generator.cpp", "unittest/common/common/system_time.cpp", "unittest/common/common/thread_pool_test_stub.cpp", "unittest/common/interfaces/process_system_api_adapter_impl.cpp", @@ -185,27 +160,24 @@ ohos_source_set("src_file") { cfi_cross_dso = true debug = false } - deps = [ - "//third_party/googletest:gtest_main", - "//third_party/sqlite:sqlite", - ] - configs += [ "//third_party/jsoncpp:jsoncpp_config" ] ldflags = [ "-Wl,--exclude-libs,ALL" ] - deps += [ - "//third_party/jsoncpp:jsoncpp", - "//third_party/openssl:libcrypto_shared", - ] + deps = [ "../gaussdb_rd:gaussdb_rd" ] configs += [ ":gaussdb_rd_config" ] public_configs = [ ":gaussdb_rd_public_config" ] - configs += [ "//third_party/cJSON:cJSON_config" ] - deps += [ "//third_party/cJSON:cjson" ] + external_deps = [ + "cJSON:cjson", "c_utils:utils", "ffrt:libffrt", + "googletest:gmock_main", + "googletest:gtest_main", "hilog:libhilog", "hisysevent:libhisysevent", "hitrace:hitrace_meter", + "jsoncpp:jsoncpp", + "openssl:libcrypto_shared", + "sqlite:sqlite", "zlib:libz", ] part_name = "kv_store" @@ -224,22 +196,22 @@ template("distributeddb_unittest") { configs = [ ":module_private_config" ] deps += [ ":src_file", - "//third_party/googletest:gmock_main", - "//third_party/googletest:gtest_main", - "//third_party/sqlite:sqlite", + "../gaussdb_rd:gaussdb_rd", ] - configs += [ "//third_party/jsoncpp:jsoncpp_config" ] + ldflags = [ "-Wl,--exclude-libs,ALL" ] - deps += [ - "//third_party/jsoncpp:jsoncpp", - "//third_party/openssl:libcrypto_shared", - ] + external_deps = [ "c_utils:utils", "ffrt:libffrt", + "googletest:gmock_main", + "googletest:gtest_main", "hilog:libhilog", "hisysevent:libhisysevent", "hitrace:hitrace_meter", + "jsoncpp:jsoncpp", + "openssl:libcrypto_shared", + "sqlite:sqlite", "zlib:libz", ] } @@ -729,6 +701,10 @@ distributeddb_unittest("DistributedDBCloudSyncerDownloadAssetsTest") { sources = [ "unittest/common/syncer/cloud/distributeddb_cloud_syncer_download_assets_test.cpp" ] } +distributeddb_unittest("DistributedDBCloudSyncerDownloadAssetsOnlyTest") { + sources = [ "unittest/common/syncer/cloud/distributeddb_cloud_syncer_download_assets_only_test.cpp" ] +} + distributeddb_unittest("DistributedDBCloudSyncerLockTest") { sources = [ "unittest/common/syncer/cloud/distributeddb_cloud_syncer_lock_test.cpp", @@ -877,16 +853,31 @@ distributeddb_unittest("DistributedDBCloudKvStoreTest") { [ "unittest/common/syncer/cloud/distributeddb_cloud_kvstore_test.cpp" ] } +distributeddb_unittest("DistributedDBRDBCollaborationTest") { + sources = + [ "unittest/common/storage/distributeddb_rdb_collaboration_test.cpp" ] +} + +distributeddb_unittest("DistributedDBCloudAsyncDownloadAssetsTest") { + sources = [ "unittest/common/syncer/cloud/distributeddb_cloud_async_download_assets_test.cpp" ] +} + +distributeddb_unittest("DistributedDBCloudSimpleAssetTest") { + sources = [ + "unittest/common/syncer/cloud/distributeddb_cloud_simple_asset_test.cpp", + ] +} + ############################################################################### group("unittest") { testonly = true - deps = [ "//third_party/googletest:gmock" ] - + deps = [] deps += [ ":DistributedDBAbilitySyncTest", ":DistributedDBAutoLaunchUnitTest", ":DistributedDBCloudAssetCompareTest", ":DistributedDBCloudAssetsOperationSyncTest", + ":DistributedDBCloudAsyncDownloadAssetsTest", ":DistributedDBCloudCheckSyncTest", ":DistributedDBCloudDBProxyTest", ":DistributedDBCloudInterfacesReferenceTest", @@ -900,7 +891,9 @@ group("unittest") { ":DistributedDBCloudReferenceSyncTest", ":DistributedDBCloudSaveCloudDataTest", ":DistributedDBCloudSchemaMgrTest", + ":DistributedDBCloudSimpleAssetTest", ":DistributedDBCloudStrategyTest", + ":DistributedDBCloudSyncerDownloadAssetsOnlyTest", ":DistributedDBCloudSyncerDownloadAssetsTest", ":DistributedDBCloudSyncerDownloadTest", ":DistributedDBCloudSyncerLockTest", @@ -955,6 +948,7 @@ group("unittest") { ":DistributedDBMultiVerVacuumTest", ":DistributedDBNotificationChainTest", ":DistributedDBParcelTest", + ":DistributedDBRDBCollaborationTest", ":DistributedDBRelationalCloudSyncableStorageTest", ":DistributedDBRelationalEncryptedDbTest", ":DistributedDBRelationalGetDataTest", diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/cloudsync_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/cloudsync_fuzzer/BUILD.gn index 2dc2423435815a560c2253e9f0d310929523377c..40519259b1e22c6caa5b3b7ad69dc033b66613ea 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/cloudsync_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/cloudsync_fuzzer/BUILD.gn @@ -74,6 +74,7 @@ ohos_fuzztest("CloudsyncFuzzTest") { fuzz_config_file = "../cloudsync_fuzzer" sources = distributeddb_src + sources += distributeddb_cloud_src sources += [ "../../../test/fuzztest/cloudsync_fuzzer/cloudsync_fuzzer.cpp", "../../../test/fuzztest/common/distributeddb_tools_test.cpp", @@ -102,6 +103,7 @@ ohos_fuzztest("CloudsyncFuzzTest") { "SQLITE_EXPORT_SYMBOLS", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "USE_DISTRIBUTEDDB_CLOUD", ] deps = [ @@ -109,12 +111,12 @@ ohos_fuzztest("CloudsyncFuzzTest") { "//third_party/jsoncpp:jsoncpp", "//third_party/openssl:libcrypto_shared", "//third_party/sqlite:sqlite", - "//third_party/zlib:shared_libz", ] external_deps = [ "c_utils:utils", "hilog:libhilog", + "zlib:shared_libz", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/delegate_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/delegate_fuzzer/BUILD.gn index 8e8f9b74d56f4ef15a445f0981d7301d0495c64a..d47439104b21d6da6a48a905d6e4d232bdaecb9c 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/delegate_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/delegate_fuzzer/BUILD.gn @@ -80,6 +80,7 @@ ohos_fuzztest("DelegateFuzzTest") { fuzz_config_file = "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/delegate_fuzzer" sources = distributeddb_src + sources += distributeddb_cloud_src sources += [ "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/common/distributeddb_tools_test.cpp", "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_data_generate_unit_test.cpp", @@ -103,6 +104,7 @@ ohos_fuzztest("DelegateFuzzTest") { "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "USE_DISTRIBUTEDDB_CLOUD", ] deps = [ @@ -110,12 +112,12 @@ ohos_fuzztest("DelegateFuzzTest") { "//third_party/jsoncpp:jsoncpp", "//third_party/openssl:libcrypto_shared", "//third_party/sqlite:sqlite", - "//third_party/zlib:shared_libz", ] external_deps = [ "c_utils:utils", "hilog:libhilog", + "zlib:shared_libz", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/fileoper_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/fileoper_fuzzer/BUILD.gn index c7fb71d3e660b6a7233d1b0ad3c3be7934e73307..2b4a6b6cf7ed45db9194aca031f89cc99013e879 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/fileoper_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/fileoper_fuzzer/BUILD.gn @@ -81,6 +81,7 @@ ohos_fuzztest("FileOperFuzzTest") { fuzz_config_file = "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/fileoper_fuzzer" sources = distributeddb_src + sources += distributeddb_cloud_src sources += [ "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/common/distributeddb_tools_test.cpp", "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_data_generate_unit_test.cpp", @@ -92,7 +93,6 @@ ohos_fuzztest("FileOperFuzzTest") { "//third_party/jsoncpp:jsoncpp", "//third_party/openssl:libcrypto_shared", "//third_party/sqlite:sqlite", - "//third_party/zlib:shared_libz", ] defines = [ @@ -112,11 +112,13 @@ ohos_fuzztest("FileOperFuzzTest") { "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "USE_DISTRIBUTEDDB_CLOUD", ] external_deps = [ "c_utils:utils", "hilog:libhilog", + "zlib:shared_libz", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/importfile_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/importfile_fuzzer/BUILD.gn index 85fee558ba3455d71784e92b5d8f9cda32fd0fb8..4c14ac1557c77bcd00855673319b904d254237f3 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/importfile_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/importfile_fuzzer/BUILD.gn @@ -81,6 +81,7 @@ ohos_fuzztest("ImportFileFuzzTest") { fuzz_config_file = "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/importfile_fuzzer" sources = distributeddb_src + sources += distributeddb_cloud_src sources += [ "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/common/distributeddb_tools_test.cpp", "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_data_generate_unit_test.cpp", @@ -104,6 +105,7 @@ ohos_fuzztest("ImportFileFuzzTest") { "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "USE_DISTRIBUTEDDB_CLOUD", ] deps = [ @@ -111,12 +113,12 @@ ohos_fuzztest("ImportFileFuzzTest") { "//third_party/jsoncpp:jsoncpp", "//third_party/openssl:libcrypto_shared", "//third_party/sqlite:sqlite", - "//third_party/zlib:shared_libz", ] external_deps = [ "c_utils:utils", "hilog:libhilog", + "zlib:shared_libz", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/iprocesscommunicator_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/iprocesscommunicator_fuzzer/BUILD.gn index c2683478394fb58d5ba8f54a148bfd15868ad56c..b7dd82377f24da3483156f05c5ef60ae5ab94f83 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/iprocesscommunicator_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/iprocesscommunicator_fuzzer/BUILD.gn @@ -81,6 +81,7 @@ ohos_fuzztest("IProcessCommunicatorFuzzTest") { fuzz_config_file = "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/iprocesscommunicator_fuzzer" sources = distributeddb_src + sources += distributeddb_cloud_src sources += [ "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/common/distributeddb_tools_test.cpp", "iprocesscommunicator_fuzzer.cpp", @@ -103,6 +104,7 @@ ohos_fuzztest("IProcessCommunicatorFuzzTest") { "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "USE_DISTRIBUTEDDB_CLOUD", ] deps = [ @@ -110,12 +112,12 @@ ohos_fuzztest("IProcessCommunicatorFuzzTest") { "//third_party/jsoncpp:jsoncpp", "//third_party/openssl:libcrypto_shared", "//third_party/sqlite:sqlite", - "//third_party/zlib:shared_libz", ] external_deps = [ "c_utils:utils", "hilog:libhilog", + "zlib:shared_libz", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/json_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/json_fuzzer/BUILD.gn index 48bf2bc8c10201dadda477f5c58b0e4511e5ab6d..cffe3bff406ee4209dae5201c7520362e0a0586f 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/json_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/json_fuzzer/BUILD.gn @@ -37,6 +37,7 @@ config("module_private_config") { "USING_HILOG_LOGGER", "USE_SQLITE_SYMBOLS", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "USE_DISTRIBUTEDDB_CLOUD", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/json_fuzzer/json_fuzzer.cpp b/kv_store/frameworks/libs/distributeddb/test/fuzztest/json_fuzzer/json_fuzzer.cpp index 778d346e94de4ff01584ce9acd90cc5503f9057d..a1d345b8d19f843ec3c244f41d59fcdf36f2e3b7 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/json_fuzzer/json_fuzzer.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/json_fuzzer/json_fuzzer.cpp @@ -1565,9 +1565,12 @@ void DropCollectionFuzz(const uint8_t *data, size_t size) void DbFlushFuzz(const uint8_t *data, size_t size) { + if (data == nullptr) { + return; + } GRD_DB *db = nullptr; GRD_DB *db2 = nullptr; - const uint32_t flags = *reinterpret_cast(data); + const uint32_t flags = *data; int ret = GRD_DBOpen(TEST_DB_FILE, CONFIG_STR, GRD_DB_OPEN_CREATE, &db); if (ret == GRD_OK) { GRD_Flush(db, flags); diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/jsoninner_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/jsoninner_fuzzer/BUILD.gn index d3823c7e39afbae6409eb6aa3de3cb128376a7f8..e1df9821a52c162a0ae2784fe640f94b0e2a5409 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/jsoninner_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/jsoninner_fuzzer/BUILD.gn @@ -37,6 +37,7 @@ config("module_private_config") { "USING_HILOG_LOGGER", "USE_SQLITE_SYMBOLS", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "USE_DISTRIBUTEDDB_CLOUD", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/jsoninner_fuzzer/jsoninner_fuzzer.cpp b/kv_store/frameworks/libs/distributeddb/test/fuzztest/jsoninner_fuzzer/jsoninner_fuzzer.cpp index 7abfdeec0238cb2515868c50de266d5e5a4458e8..3f6262e96d3a026c802a9364eb1da473a7ae9cda 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/jsoninner_fuzzer/jsoninner_fuzzer.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/jsoninner_fuzzer/jsoninner_fuzzer.cpp @@ -1574,9 +1574,12 @@ void DropCollectionFuzz(const uint8_t *data, size_t size) void DbFlushFuzz(const uint8_t *data, size_t size) { + if (data == nullptr) { + return; + } GRD_DB *db = nullptr; GRD_DB *db2 = nullptr; - const uint32_t flags = *reinterpret_cast(data); + const uint32_t flags = *data; int ret = GRD_DBOpenInner(TEST_DB_FILE, CONFIG_STR, GRD_DB_OPEN_CREATE, &db); if (ret == GRD_OK) { GRD_FlushInner(db, flags); diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvdelegatemanager_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvdelegatemanager_fuzzer/BUILD.gn index d66696d028fbc48c25b2592d1f1341d5ebe141f3..327c65931de4576e5bcbb9bfe3501f42ffd67ee8 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvdelegatemanager_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvdelegatemanager_fuzzer/BUILD.gn @@ -81,6 +81,7 @@ ohos_fuzztest("KvDelegateManagerFuzzTest") { fuzz_config_file = "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvdelegatemanager_fuzzer" sources = distributeddb_src + sources += distributeddb_cloud_src sources += [ "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/common/distributeddb_tools_test.cpp", "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_data_generate_unit_test.cpp", @@ -104,6 +105,7 @@ ohos_fuzztest("KvDelegateManagerFuzzTest") { "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "USE_DISTRIBUTEDDB_CLOUD", ] deps = [ @@ -111,12 +113,12 @@ ohos_fuzztest("KvDelegateManagerFuzzTest") { "//third_party/jsoncpp:jsoncpp", "//third_party/openssl:libcrypto_shared", "//third_party/sqlite:sqlite", - "//third_party/zlib:shared_libz", ] external_deps = [ "c_utils:utils", "hilog:libhilog", + "zlib:shared_libz", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvstoreresultset_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvstoreresultset_fuzzer/BUILD.gn index b8f8e53f1def2e394926e871847351c13c0be03d..9e2b842361bf3d9ada9f5ae4f6fb94aae142aa6c 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvstoreresultset_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvstoreresultset_fuzzer/BUILD.gn @@ -81,6 +81,7 @@ ohos_fuzztest("KvStoreResultSetFuzzTest") { fuzz_config_file = "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvstoreresultset_fuzzer" sources = distributeddb_src + sources += distributeddb_cloud_src sources += [ "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/common/distributeddb_tools_test.cpp", "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_data_generate_unit_test.cpp", @@ -104,6 +105,7 @@ ohos_fuzztest("KvStoreResultSetFuzzTest") { "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "USE_DISTRIBUTEDDB_CLOUD", ] deps = [ @@ -111,12 +113,12 @@ ohos_fuzztest("KvStoreResultSetFuzzTest") { "//third_party/jsoncpp:jsoncpp", "//third_party/openssl:libcrypto_shared", "//third_party/sqlite:sqlite", - "//third_party/zlib:shared_libz", ] external_deps = [ "c_utils:utils", "hilog:libhilog", + "zlib:shared_libz", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/nbdelegate_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/nbdelegate_fuzzer/BUILD.gn index 75dc50ad39aa4c0f59fca75e7684f98f523fa57a..7244809252639a9c8253940c93d968dc1e20aaae 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/nbdelegate_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/nbdelegate_fuzzer/BUILD.gn @@ -81,6 +81,7 @@ ohos_fuzztest("NbDelegateFuzzTest") { fuzz_config_file = "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/nbdelegate_fuzzer" sources = distributeddb_src + sources += distributeddb_cloud_src sources += [ "../common/fuzzer_data.cpp", "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/common/distributeddb_tools_test.cpp", @@ -104,6 +105,7 @@ ohos_fuzztest("NbDelegateFuzzTest") { "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "USE_DISTRIBUTEDDB_CLOUD", ] deps = [ @@ -111,12 +113,12 @@ ohos_fuzztest("NbDelegateFuzzTest") { "//third_party/jsoncpp:jsoncpp", "//third_party/openssl:libcrypto_shared", "//third_party/sqlite:sqlite", - "//third_party/zlib:shared_libz", ] external_deps = [ "c_utils:utils", "hilog:libhilog", + "zlib:shared_libz", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/parseckeck_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/parseckeck_fuzzer/BUILD.gn index 35e065f45cbe7d71d09f9773960cf1441e4c5531..cdb448f9ee7a6a5d0182f7e2b8163d5f10d09a59 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/parseckeck_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/parseckeck_fuzzer/BUILD.gn @@ -81,6 +81,7 @@ ohos_fuzztest("ParseCkeckFuzzTest") { fuzz_config_file = "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/parseckeck_fuzzer" sources = distributeddb_src + sources += distributeddb_cloud_src sources += [ "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/common/distributeddb_tools_test.cpp", "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_data_generate_unit_test.cpp", @@ -104,6 +105,7 @@ ohos_fuzztest("ParseCkeckFuzzTest") { "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "USE_DISTRIBUTEDDB_CLOUD", ] deps = [ @@ -111,12 +113,12 @@ ohos_fuzztest("ParseCkeckFuzzTest") { "//third_party/jsoncpp:jsoncpp", "//third_party/openssl:libcrypto_shared", "//third_party/sqlite:sqlite", - "//third_party/zlib:shared_libz", ] external_deps = [ "c_utils:utils", "hilog:libhilog", + "zlib:shared_libz", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/query_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/query_fuzzer/BUILD.gn index dc37b3eee719fdd46dbb3203e5e4d629c662b1b7..0cbf9a210f7a5b3bec114c67924ea5e06abae29a 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/query_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/query_fuzzer/BUILD.gn @@ -81,6 +81,7 @@ ohos_fuzztest("QueryFuzzTest") { fuzz_config_file = "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/query_fuzzer" sources = distributeddb_src + sources += distributeddb_cloud_src sources += [ "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_data_generate_unit_test.cpp", "query_fuzzer.cpp", @@ -103,6 +104,7 @@ ohos_fuzztest("QueryFuzzTest") { "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "USE_DISTRIBUTEDDB_CLOUD", ] deps = [ @@ -110,12 +112,12 @@ ohos_fuzztest("QueryFuzzTest") { "//third_party/jsoncpp:jsoncpp", "//third_party/openssl:libcrypto_shared", "//third_party/sqlite:sqlite", - "//third_party/zlib:shared_libz", ] external_deps = [ "c_utils:utils", "hilog:libhilog", + "zlib:shared_libz", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/rekey_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/rekey_fuzzer/BUILD.gn index 34128d2f3ad3bda197cfef909d673ed7d3c6d254..97f3b495bf077fc1ddb5d3e5458b2789d32e5acf 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/rekey_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/rekey_fuzzer/BUILD.gn @@ -81,6 +81,7 @@ ohos_fuzztest("ReKeyFuzzTest") { fuzz_config_file = "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/rekey_fuzzer" sources = distributeddb_src + sources += distributeddb_cloud_src sources += [ "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/common/distributeddb_tools_test.cpp", "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_data_generate_unit_test.cpp", @@ -104,6 +105,7 @@ ohos_fuzztest("ReKeyFuzzTest") { "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "USE_DISTRIBUTEDDB_CLOUD", ] deps = [ @@ -111,12 +113,12 @@ ohos_fuzztest("ReKeyFuzzTest") { "//third_party/jsoncpp:jsoncpp", "//third_party/openssl:libcrypto_shared", "//third_party/sqlite:sqlite", - "//third_party/zlib:shared_libz", ] external_deps = [ "c_utils:utils", "hilog:libhilog", + "zlib:shared_libz", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/BUILD.gn index c683d4a92311441ff221d0d4b59ea124ddd4fb83..7b09db2daeb0f41f0161349df4fc8e12496ad935 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/BUILD.gn @@ -81,6 +81,7 @@ ohos_fuzztest("RelationalstoredelegateFuzzTest") { fuzz_config_file = "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer" sources = distributeddb_src + sources += distributeddb_cloud_src sources += [ "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/common/distributeddb_tools_test.cpp", "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/common/fuzzer_data.cpp", @@ -108,6 +109,7 @@ ohos_fuzztest("RelationalstoredelegateFuzzTest") { "SQLITE_EXPORT_SYMBOLS", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "USE_DISTRIBUTEDDB_CLOUD", ] deps = [ @@ -115,12 +117,12 @@ ohos_fuzztest("RelationalstoredelegateFuzzTest") { "//third_party/jsoncpp:jsoncpp", "//third_party/openssl:libcrypto_shared", "//third_party/sqlite:sqlite", - "//third_party/zlib:shared_libz", ] external_deps = [ "c_utils:utils", "hilog:libhilog", + "zlib:shared_libz", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/relationalstoredelegate_fuzzer.cpp b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/relationalstoredelegate_fuzzer.cpp index 78c2971af70419dd5b64400656dc7b70fc4a5064..e9f6f19174ecb56911a450c533043e7fb0f73bcd 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/relationalstoredelegate_fuzzer.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/relationalstoredelegate_fuzzer.cpp @@ -19,6 +19,7 @@ #include "distributeddb/result_set.h" #include "distributeddb_tools_test.h" #include "fuzzer_data.h" +#include "fuzzer/FuzzedDataProvider.h" #include "log_print.h" #include "query.h" #include "relational_store_delegate.h" @@ -97,8 +98,8 @@ void TearDown() DistributedDBToolsTest::RemoveTestDbFiles(g_testDir); } -void MultiCombineTest(const uint8_t *data, const std::string &tableName, const std::set &extendColNames, - const std::set &trackerColNames, const bool isDeleted) +void MultiCombineTest(FuzzedDataProvider *fdp, const std::string &tableName, + const std::set &extendColNames, const std::set &trackerColNames, const bool isDeleted) { TrackerSchema schema; schema.tableName = tableName; @@ -109,17 +110,38 @@ void MultiCombineTest(const uint8_t *data, const std::string &tableName, const s g_delegate->CleanTrackerData(tableName, 0); bool logicDelete = isDeleted; auto pragmaData = static_cast(&logicDelete); - auto pragmaCmd = static_cast(data[0]); + size_t pragmaCmdLen = sizeof(PragmaCmd); + auto pragmaCmd = static_cast(fdp->ConsumeIntegral() % pragmaCmdLen); g_delegate->Pragma(pragmaCmd, pragmaData); VBucket records; records[*extendColNames.begin()] = *extendColNames.begin(); - auto recordStatus = static_cast(data[0]); + size_t recordStatusLen = sizeof(RecordStatus); + auto recordStatus = static_cast(fdp->ConsumeIntegral() % recordStatusLen); g_delegate->UpsertData(tableName, { records }, recordStatus); DistributedDB::SqlCondition sqlCondition; std::vector sqlRecords; g_delegate->ExecuteSql(sqlCondition, sqlRecords); } +void TestDistributedSchema(FuzzedDataProvider *fdp) +{ + DistributedSchema schema; + schema.version = fdp->ConsumeIntegral(); + auto fieldSize = fdp->ConsumeIntegral() % 30; // 30 is mod for field size + auto tableSize = fdp->ConsumeIntegral() % 30; // 30 is mod for table size + for (uint32_t i = 0; i < tableSize; ++i) { + DistributedTable table; + table.tableName = fdp->ConsumeRandomLengthString(); + for (uint32_t j = 0; j < fieldSize; j++) { + DistributedField field; + field.colName = fdp->ConsumeRandomLengthString(); + table.fields.push_back(field); + } + schema.tables.push_back(table); + } + g_delegate->SetDistributedSchema(schema); +} + void CombineTest(const uint8_t *data, size_t size) { auto observer = new (std::nothrow) DistributedDB::StoreObserver; @@ -154,7 +176,8 @@ void CombineTest(const uint8_t *data, size_t size) std::set extendColNames = {fuzzerData.GetString(len % lenMod)}; std::set trackerColNames = fuzzerData.GetStringSet(len % lenMod); bool isLogicDeleted = static_cast(*data); - MultiCombineTest(data, tableName, extendColNames, trackerColNames, isLogicDeleted); + FuzzedDataProvider fdp(data, size); + MultiCombineTest(&fdp, tableName, extendColNames, trackerColNames, isLogicDeleted); std::string deviceId = device.size() > 0 ? device[0] : tableName; g_delegate->RemoveDeviceData(); g_delegate->RemoveDeviceData(deviceId); @@ -169,6 +192,8 @@ void CombineTest(const uint8_t *data, size_t size) g_delegate->UnRegisterObserver(); delete observer; observer = nullptr; + + TestDistributedSchema(&fdp); } } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/BUILD.gn index 5269b5d77f51bb23df917cb43b0e430a174a9dba..6087cf010f52354c519e3f0f5eaa44babc35fabd 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/BUILD.gn @@ -81,6 +81,7 @@ ohos_fuzztest("RelationalstoremanagerFuzzTest") { fuzz_config_file = "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer" sources = distributeddb_src + sources += distributeddb_cloud_src sources += [ "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/common/distributeddb_tools_test.cpp", "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/common/fuzzer_data.cpp", @@ -108,6 +109,7 @@ ohos_fuzztest("RelationalstoremanagerFuzzTest") { "SQLITE_EXPORT_SYMBOLS", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "USE_DISTRIBUTEDDB_CLOUD", ] deps = [ @@ -115,12 +117,12 @@ ohos_fuzztest("RelationalstoremanagerFuzzTest") { "//third_party/jsoncpp:jsoncpp", "//third_party/openssl:libcrypto_shared", "//third_party/sqlite:sqlite", - "//third_party/zlib:shared_libz", ] external_deps = [ "c_utils:utils", "hilog:libhilog", + "zlib:shared_libz", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/relationalstoremanager_fuzzer.cpp b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/relationalstoremanager_fuzzer.cpp index 877a5e90e5be6a40fe05a3fba8c949ab21837513..a1941bb5bb54b188c0af70791d9a3d31c443c8de 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/relationalstoremanager_fuzzer.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/relationalstoremanager_fuzzer.cpp @@ -16,7 +16,7 @@ #include "relationalstoremanager_fuzzer.h" #include "distributeddb_data_generate_unit_test.h" #include "distributeddb_tools_test.h" -#include "fuzzer_data.h" +#include "fuzzer/FuzzedDataProvider.h" #include "relational_store_manager.h" #include "runtime_config.h" #include "store_changed_data.h" @@ -66,9 +66,9 @@ void TearDown() DistributedDBToolsTest::RemoveTestDbFiles(g_testDir); } -void RuntimeConfigTest(const uint8_t *data, size_t size) +void RuntimeConfigTest(FuzzedDataProvider *fdp) { - bool isPermissionCheck = static_cast(*data); + bool isPermissionCheck = fdp->ConsumeBool(); auto permissionCheckCallbackV2 = [isPermissionCheck](const std::string &userId, const std::string &appId, const std::string &storeId, const std::string &deviceId, uint8_t flag) -> bool { return isPermissionCheck; }; RuntimeConfig::SetPermissionCheckCallback(permissionCheckCallbackV2); @@ -76,7 +76,7 @@ void RuntimeConfigTest(const uint8_t *data, size_t size) return isPermissionCheck; }; RuntimeConfig::SetPermissionCheckCallback(permissionCheckCallbackV3); - bool isSyncActivationCheck = static_cast(*data); + bool isSyncActivationCheck = fdp->ConsumeBool(); auto syncActivationCheck = [isSyncActivationCheck](const std::string &userId, const std::string &appId, const std::string &storeId) -> bool { return isSyncActivationCheck; }; RuntimeConfig::SetSyncActivationCheckCallback(syncActivationCheck); @@ -84,25 +84,23 @@ void RuntimeConfigTest(const uint8_t *data, size_t size) return isSyncActivationCheck; }; RuntimeConfig::SetSyncActivationCheckCallback(syncActivationCheckV2); - FuzzerData fuzzerData(data, size); - uint32_t instanceId = fuzzerData.GetUInt32(); - const int lenMod = 30; // 30 is mod for string vector size - std::string userId = fuzzerData.GetString(instanceId % lenMod); - std::string subUserId = fuzzerData.GetString(instanceId % lenMod); + std::string userId = fdp->ConsumeRandomLengthString(); + std::string subUserId = fdp->ConsumeRandomLengthString(); RuntimeConfig::SetPermissionConditionCallback([userId, subUserId](const PermissionConditionParam ¶m) { std::map res; res.emplace(userId, subUserId); return res; }); RuntimeConfig::IsProcessSystemApiAdapterValid(); - bool isAutoLaunch = static_cast(*data); + bool isAutoLaunch = fdp->ConsumeBool(); auto autoLaunchRequestCallback = [isAutoLaunch](const std::string &identifier, AutoLaunchParam ¶m) -> bool { return isAutoLaunch; }; - auto dbType = static_cast(data[0]); + size_t dbTypeLen = sizeof(DBType); + auto dbType = static_cast(fdp->ConsumeIntegral() % dbTypeLen); RuntimeConfig::SetAutoLaunchRequestCallback(autoLaunchRequestCallback, dbType); - std::string appId = fuzzerData.GetString(instanceId % lenMod); - std::string storeId = fuzzerData.GetString(instanceId % lenMod); + std::string appId = fdp->ConsumeRandomLengthString(); + std::string storeId = fdp->ConsumeRandomLengthString(); RuntimeConfig::ReleaseAutoLaunch(userId, appId, storeId, dbType); std::vector dbInfos; DBInfo dbInfo = { @@ -113,48 +111,48 @@ void RuntimeConfigTest(const uint8_t *data, size_t size) true }; dbInfos.push_back(dbInfo); - std::string device = fuzzerData.GetString(instanceId % lenMod); + std::string device = fdp->ConsumeRandomLengthString(); RuntimeConfig::NotifyDBInfos({ device }, dbInfos); RuntimeConfig::NotifyUserChanged(); } -void CombineTest(const uint8_t *data, size_t size) +void CombineTest(FuzzedDataProvider *fdp) { - FuzzerData fuzzerData(data, size); - uint32_t instanceId = fuzzerData.GetUInt32(); - const int lenMod = 30; // 30 is mod for string vector size - std::string appId = fuzzerData.GetString(instanceId % lenMod); - std::string userId = fuzzerData.GetString(instanceId % lenMod); - std::string storeId = fuzzerData.GetString(instanceId % lenMod); + uint32_t instanceId = fdp->ConsumeIntegral(); + std::string appId = fdp->ConsumeRandomLengthString(); + std::string userId = fdp->ConsumeRandomLengthString(); + std::string storeId = fdp->ConsumeRandomLengthString(); RelationalStoreManager::GetDistributedTableName(appId, userId); RelationalStoreManager mgr(appId, userId, instanceId); g_mgr.GetDistributedTableName(appId, userId); g_mgr.GetDistributedLogTableName(userId); g_mgr.OpenStore(g_dbDir + appId + DB_SUFFIX, storeId, {}, g_delegate); g_mgr.GetRelationalStoreIdentifier(userId, appId, storeId, instanceId % 2); // 2 is mod num for last parameter - int type = fuzzerData.GetInt(); + int type = fdp->ConsumeIntegral(); Bytes bytes = { type, type, type }; - auto status = static_cast(data[0]); + size_t statusLen = sizeof(DBStatus); + auto status = static_cast(fdp->ConsumeIntegral() % statusLen); g_mgr.ParserQueryNodes(bytes, status); - std::string key = fuzzerData.GetString(instanceId % lenMod); + std::string key = fdp->ConsumeRandomLengthString(); std::map primaryKey = {{ key, key }}; - auto collateType = static_cast(data[0]); + size_t collateTypeLen = sizeof(CollateType); + auto collateType = static_cast(fdp->ConsumeIntegral() % collateTypeLen); std::map collateTypeMap = {{ key, collateType }}; g_mgr.CalcPrimaryKeyHash(primaryKey, collateTypeMap); RuntimeConfig::SetProcessLabel(appId, userId); RuntimeConfig::SetTranslateToDeviceIdCallback([](const std::string &oriDevId, const StoreInfo &info) { return oriDevId + "_" + info.appId; }); - RuntimeConfigTest(data, size); + RuntimeConfigTest(fdp); } } - /* Fuzzer entry point */ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { OHOS::Setup(); - OHOS::CombineTest(data, size); + FuzzedDataProvider fdp(data, size); + OHOS::CombineTest(&fdp); OHOS::TearDown(); return 0; } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/schemadelegate_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/schemadelegate_fuzzer/BUILD.gn index 26c13bcf8630a960047d6f4a61e1277755ce14b8..9d39da2d7f3a7f6b5de86edbd806b84cca9e8451 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/schemadelegate_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/schemadelegate_fuzzer/BUILD.gn @@ -80,6 +80,7 @@ ohos_fuzztest("SchemaDelegateFuzzTest") { fuzz_config_file = "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/schemadelegate_fuzzer" sources = distributeddb_src + sources += distributeddb_cloud_src sources += [ "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/common/distributeddb_tools_test.cpp", "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/common/fuzzer_data.cpp", @@ -104,6 +105,7 @@ ohos_fuzztest("SchemaDelegateFuzzTest") { "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "USE_DISTRIBUTEDDB_CLOUD", ] deps = [ @@ -111,12 +113,12 @@ ohos_fuzztest("SchemaDelegateFuzzTest") { "//third_party/jsoncpp:jsoncpp", "//third_party/openssl:libcrypto_shared", "//third_party/sqlite:sqlite", - "//third_party/zlib:shared_libz", ] external_deps = [ "c_utils:utils", "hilog:libhilog", + "zlib:shared_libz", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/storage_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/storage_fuzzer/BUILD.gn index aa498b9a29bba17c70ecb10b990471701b0b5614..40b2edce3a3439ef8a946c09486a2862da4b55e7 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/storage_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/storage_fuzzer/BUILD.gn @@ -73,6 +73,7 @@ ohos_fuzztest("StorageFuzzTest") { fuzz_config_file = "../storage_fuzzer" sources = distributeddb_src + sources += distributeddb_cloud_src sources += [ "../../../test/fuzztest/common/distributeddb_tools_test.cpp", "../../../test/fuzztest/common/fuzzer_data.cpp", @@ -98,6 +99,7 @@ ohos_fuzztest("StorageFuzzTest") { "SQLITE_EXPORT_SYMBOLS", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "USE_DISTRIBUTEDDB_CLOUD", ] deps = [ @@ -105,12 +107,12 @@ ohos_fuzztest("StorageFuzzTest") { "//third_party/jsoncpp:jsoncpp", "//third_party/openssl:libcrypto_shared", "//third_party/sqlite:sqlite", - "//third_party/zlib:shared_libz", ] external_deps = [ "c_utils:utils", "hilog:libhilog", + "zlib:shared_libz", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/sync_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/sync_fuzzer/BUILD.gn index 02d0af3fd9b0a30a3681718711c4ffbbd67ae916..29eaa19893429edfd55414517ce5002afb130545 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/sync_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/sync_fuzzer/BUILD.gn @@ -81,6 +81,7 @@ ohos_fuzztest("SyncFuzzTest") { fuzz_config_file = "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/sync_fuzzer" sources = distributeddb_src + sources += distributeddb_cloud_src sources += [ "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/fuzztest/common/distributeddb_tools_test.cpp", "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/generic_virtual_device.cpp", @@ -108,6 +109,7 @@ ohos_fuzztest("SyncFuzzTest") { "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "USE_DISTRIBUTEDDB_CLOUD", ] deps = [ @@ -115,12 +117,12 @@ ohos_fuzztest("SyncFuzzTest") { "//third_party/jsoncpp:jsoncpp", "//third_party/openssl:libcrypto_shared", "//third_party/sqlite:sqlite", - "//third_party/zlib:shared_libz", ] external_deps = [ "c_utils:utils", "hilog:libhilog", + "zlib:shared_libz", ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_auto_launch_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_auto_launch_test.cpp index 5411d323e1efad6ec29c3968bff8a09851067f05..080be5722a06306c8198850f1755a0dd749048b2 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_auto_launch_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_auto_launch_test.cpp @@ -1108,4 +1108,47 @@ HWTEST_F(DistributedDBAutoLaunchUnitTest, AutoLaunch015, TestSize.Level3) th.join(); delete observer; -} \ No newline at end of file +} + +/** + * @tc.name: AutoLaunchRelational001 + * @tc.desc: test GetAutoLaunchProperties will give back the correct tableMode + * @tc.type: FUNC + * @tc.author: liuhongyang + */ +HWTEST_F(DistributedDBAutoLaunchUnitTest, AutoLaunchRelational001, TestSize.Level3) +{ + AutoLaunchOption defaultOption; + AutoLaunchOption splitOption; + AutoLaunchOption collaborateOption; + splitOption.tableMode = DistributedTableMode::SPLIT_BY_DEVICE; + collaborateOption.tableMode = DistributedTableMode::COLLABORATION; + /** + * @tc.steps: step1. call GetAutoLaunchProperties with default param + * @tc.expected: step1. property pointer has SPLIT_BY_DEVICE mode + */ + AutoLaunchParam param = {USER_ID, APP_ID, STORE_ID_0, defaultOption, nullptr, "", ""}; + std::shared_ptr ptr; + int errCode = AutoLaunch::GetAutoLaunchProperties(param, DBTypeInner::DB_RELATION, false, ptr); + ASSERT_EQ(errCode, E_OK); + DistributedTableMode mode = std::static_pointer_cast(ptr)->GetDistributedTableMode(); + EXPECT_EQ(mode, DistributedTableMode::SPLIT_BY_DEVICE); + /** + * @tc.steps: step2. call GetAutoLaunchProperties with split param + * @tc.expected: step2. property pointer has SPLIT_BY_DEVICE mode + */ + param.option = splitOption; + errCode = AutoLaunch::GetAutoLaunchProperties(param, DBTypeInner::DB_RELATION, false, ptr); + ASSERT_EQ(errCode, E_OK); + mode = std::static_pointer_cast(ptr)->GetDistributedTableMode(); + EXPECT_EQ(mode, DistributedTableMode::SPLIT_BY_DEVICE); + /** + * @tc.steps: step3. call GetAutoLaunchProperties with collaboration param + * @tc.expected: step3. property pointer has COLLABORATION mode + */ + param.option = collaborateOption; + errCode = AutoLaunch::GetAutoLaunchProperties(param, DBTypeInner::DB_RELATION, false, ptr); + ASSERT_EQ(errCode, E_OK); + mode = std::static_pointer_cast(ptr)->GetDistributedTableMode(); + EXPECT_EQ(mode, DistributedTableMode::COLLABORATION); +} diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_data_generate_unit_test.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_data_generate_unit_test.h index 6857e05caa89c6bad9ddb015aed8f5078cb6a3ca..259d7a481c0f39130f3a28d895132852e248a67f 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_data_generate_unit_test.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_data_generate_unit_test.h @@ -115,6 +115,11 @@ void GenerateRecords(int recordNum, std::vector &entries, int keySize = DEFAULT_NB_KEY_VALUE_SIZE, int valSize = DEFAULT_NB_KEY_VALUE_SIZE); void GenerateNumberEntryVector(int entryNum, std::vector &entries); + +class UnitTestCommonConstant { +public: + static constexpr const char *DEVICE_B = "DEVICE_B"; +}; } // namespace DistributedDBUnitTest #endif // DISTRIBUTEDDB_DATA_GENERATE_UNIT_H diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_parcel_unit_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_parcel_unit_test.cpp index d3c1b8cede626867a4aab3f3e73786930501b470..4a95864e05c01053d6c4920d7df72cea59a56033 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_parcel_unit_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_parcel_unit_test.cpp @@ -745,12 +745,13 @@ HWTEST_F(DistributedDBParcelTest, ParcelErrTest, TestSize.Level1) EXPECT_EQ(parcel.ReadBlob(nullptr, 0), expectedVal); /** - * @tc.steps: step3. WriteDouble when Parcel para is null; + * @tc.steps: step3. WriteBlob when Parcel para is null string; * @tc.expected: step3. return -E_PARSE_FAIL; */ - ret = parcel.WriteBlob("", 1); + char para[] = ""; + ret = parcel.WriteBlob(para, 1); EXPECT_EQ(ret, -E_PARSE_FAIL); - EXPECT_EQ(parcel.ReadBlob("", 1), expectedVal); + EXPECT_EQ(parcel.ReadBlob(para, 1), expectedVal); } #endif \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_tools_unit_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_tools_unit_test.cpp index 48999d1c75f2fceb418f33fcbf43e4e8ee4a0cc9..fc4fbb9869a222beb9d2dc32dcc7f74c95d6f014 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_tools_unit_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_tools_unit_test.cpp @@ -28,11 +28,14 @@ #include #include "cloud/cloud_db_constant.h" +#include "cloud/cloud_db_sync_utils_test.h" #include "cloud/cloud_db_types.h" +#include "cloud/virtual_cloud_data_translate.h" #include "db_common.h" #include "db_constant.h" #include "generic_single_ver_kv_entry.h" #include "platform_specific.h" +#include "res_finalizer.h" #include "runtime_config.h" #include "single_ver_data_packet.h" #include "sqlite_relational_utils.h" @@ -700,6 +703,24 @@ std::string DistributedDBToolsUnitTest::GetKvNbStoreDirectory(const std::string return dbDir + "/" + identifierName + "/" + dbFilePath; } +void DistributedDBToolsUnitTest::BlockSync(RelationalStoreDelegate &delegate, const Query &query, + DistributedDB::SyncMode syncMode, DistributedDB::DBStatus exceptStatus, + const std::vector &devices) +{ + std::map> statusMap; + SyncStatusCallback callBack = [&statusMap]( + const std::map> &devicesMap) { + statusMap = devicesMap; + }; + DBStatus callStatus = delegate.Sync(devices, syncMode, query, callBack, true); + EXPECT_EQ(callStatus, OK); + for (const auto &tablesRes : statusMap) { + for (const auto &tableStatus : tablesRes.second) { + EXPECT_EQ(tableStatus.status, exceptStatus); + } + } +} + KvStoreObserverUnitTest::KvStoreObserverUnitTest() : callCount_(0), isCleared_(false) {} @@ -797,6 +818,7 @@ void RelationalStoreObserverUnitTest::OnChange( { cloudCallCount_++; savedChangedData_[data.tableName] = data; + lastOrigin_ = origin; LOGD("cloud sync Onchangedata, tableName = %s", data.tableName.c_str()); } @@ -942,6 +964,11 @@ DistributedDB::StoreProperty RelationalStoreObserverUnitTest::GetStoreProperty() return storeProperty_; } +std::unordered_map RelationalStoreObserverUnitTest::GetSavedChangedData() const +{ + return savedChangedData_; +} + DBStatus DistributedDBToolsUnitTest::SyncTest(KvStoreNbDelegate* delegate, const std::vector& devices, SyncMode mode, std::map& statuses, const Query &query) @@ -1303,6 +1330,18 @@ END: void RelationalTestUtils::CloudBlockSync(const DistributedDB::Query &query, DistributedDB::RelationalStoreDelegate *delegate, DistributedDB::DBStatus expect, DistributedDB::DBStatus callbackExpect) +{ + DistributedDB::CloudSyncOption option; + option.devices = { "CLOUD" }; + option.mode = SYNC_MODE_CLOUD_MERGE; + option.query = query; + option.waitTime = DBConstant::MAX_TIMEOUT; + CloudBlockSync(option, delegate, expect, callbackExpect); +} + +void RelationalTestUtils::CloudBlockSync(const DistributedDB::CloudSyncOption &option, + DistributedDB::RelationalStoreDelegate *delegate, + DistributedDB::DBStatus expect, DistributedDB::DBStatus callbackExpect) { ASSERT_NE(delegate, nullptr); std::mutex dataMutex; @@ -1320,7 +1359,7 @@ void RelationalTestUtils::CloudBlockSync(const DistributedDB::Query &query, } } }; - ASSERT_EQ(delegate->Sync({ "CLOUD" }, SYNC_MODE_CLOUD_MERGE, query, callback, DBConstant::MAX_TIMEOUT), expect); + ASSERT_EQ(delegate->Sync(option, callback), expect); if (expect != DistributedDB::DBStatus::OK) { return; } @@ -1510,6 +1549,62 @@ int RelationalTestUtils::DeleteRecord(sqlite3 *db, const std::string &tableName, return errCode; } +bool RelationalTestUtils::IsExistEmptyHashAsset(sqlite3 *db, const DistributedDB::TableSchema &schema) +{ + if (db == nullptr) { + return false; + } + std::vector assetCol; + for (const auto &field : schema.fields) { + if (field.type == TYPE_INDEX || field.type == TYPE_INDEX) { + assetCol.push_back(field); + } + } + if (assetCol.empty()) { + return false; + } + std::string sql = "SELECT "; + for (const auto &field : assetCol) { + sql += field.colName + ","; + } + sql.pop_back(); + sql += " FROM " + schema.name; + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(db, sql, stmt); + if (errCode != E_OK) { + return false; + } + ResFinalizer finalizer([stmt]() { + sqlite3_stmt *statement = stmt; + int ret = E_OK; + SQLiteUtils::ResetStatement(statement, true, ret); + }); + VirtualCloudDataTranslate translate; + while (sqlite3_step(stmt) == SQLITE_ROW) { + for (int index = 0; index < static_cast(assetCol.size()); index++) { + Value value; + (void)SQLiteUtils::GetColumnBlobValue(stmt, index, value); + Assets assets; + if (assetCol[index].type == TYPE_INDEX) { + assets.push_back(translate.BlobToAsset(value)); + } else { + assets = translate.BlobToAssets(value); + } + if (IsExistEmptyHashAsset(assets)) { + return true; + } + } + } + return false; +} + +bool RelationalTestUtils::IsExistEmptyHashAsset(const DistributedDB::Assets &assets) +{ + return std::any_of(assets.begin(), assets.end(), [](const Asset &asset) { + return asset.hash.empty(); + }); +} + bool DBInfoHandleTest::IsSupport() { std::lock_guard autoLock(supportMutex_); @@ -1534,4 +1629,32 @@ void DBInfoHandleTest::SetNeedAutoSync(bool needAutoSync) std::lock_guard autoLock(autoSyncMutex_); isNeedAutoSync_ = needAutoSync; } + +DistributedDB::ICloudSyncStorageHook *RelationalTestUtils::GetRDBStorageHook(const std::string &userId, + const std::string &appId, const std::string &storeId, const std::string &dbPath) +{ + RelationalDBProperties properties; + CloudDBSyncUtilsTest::InitStoreProp(dbPath, appId, userId, storeId, properties); + int errCode = E_OK; + auto store = RelationalStoreInstance::GetDataBase(properties, errCode); + if (store == nullptr) { + return nullptr; + } + auto engine = static_cast(store)->GetStorageEngine(); + return static_cast(engine); +} + +bool RelationalStoreObserverUnitTest::IsAssetChange(const std::string &table) const +{ + auto changeData = savedChangedData_.find(table); + if (changeData == savedChangedData_.end()) { + return false; + } + return changeData->second.type == ChangedDataType::ASSET; +} + +DistributedDB::Origin RelationalStoreObserverUnitTest::GetLastOrigin() const +{ + return lastOrigin_; +} } // namespace DistributedDBUnitTest diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_tools_unit_test.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_tools_unit_test.h index ccc1cf1e1a09f80770e239c9a49d84d85cdea076..a076b2c2d543a0dc0ea4ff4cc327baf105d1ba30 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_tools_unit_test.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/distributeddb_tools_unit_test.h @@ -39,6 +39,7 @@ #include "log_print.h" #include "message.h" #include "query.h" +#include "relational_store_delegate.h" #include "relational_store_sqlite_ext.h" #include "store_observer.h" #include "store_changed_data.h" @@ -231,6 +232,9 @@ public: static std::string GetKvNbStoreDirectory(const std::string &identifier, const std::string &dbFilePath, const std::string &dbDir); + static void BlockSync(DistributedDB::RelationalStoreDelegate &delegate, const DistributedDB::Query &query, + DistributedDB::SyncMode syncMode, DistributedDB::DBStatus exceptStatus, + const std::vector &devices); private: static int OpenMockMultiDb(DatabaseInfo &dbInfo, DistributedDB::OpenDbProperties &properties); @@ -308,6 +312,11 @@ public: unsigned long GetCloudCallCount() const; const std::string GetDataChangeDevice() const; DistributedDB::StoreProperty GetStoreProperty() const; + std::unordered_map GetSavedChangedData() const; + + bool IsAssetChange(const std::string &table) const; + + DistributedDB::Origin GetLastOrigin() const; private: unsigned long callCount_; unsigned long cloudCallCount_ = 0; @@ -316,6 +325,7 @@ private: std::unordered_map expectedChangedData_; std::unordered_map savedChangedData_; uint32_t detailsType_ = static_cast(DistributedDB::CallbackDetailsType::DEFAULT); + DistributedDB::Origin lastOrigin_ = DistributedDB::ORIGIN_REMOTE; }; class KvStoreCorruptInfo { @@ -362,6 +372,14 @@ public: static int GetRecordLog(sqlite3 *db, const std::string &tableName, std::vector &records); static int DeleteRecord(sqlite3 *db, const std::string &tableName, const std::vector> &conditions); + static void CloudBlockSync(const DistributedDB::CloudSyncOption &option, + DistributedDB::RelationalStoreDelegate *delegate, + DistributedDB::DBStatus expect = DistributedDB::DBStatus::OK, + DistributedDB::DBStatus callbackExpect = DistributedDB::DBStatus::OK); + static bool IsExistEmptyHashAsset(sqlite3 *db, const DistributedDB::TableSchema &schema); + static bool IsExistEmptyHashAsset(const DistributedDB::Assets &assets); + static DistributedDB::ICloudSyncStorageHook *GetRDBStorageHook(const std::string &userId, + const std::string &appId, const std::string &storeId, const std::string &dbPath); }; class DBInfoHandleTest : public DistributedDB::DBInfoHandle { diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/evloop_timer_unit_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/evloop_timer_unit_test.cpp index 549298daef18e8ce91660471f6a572dd46450a68..ea7ab4c62a192a7f6947392320732f2b2a34bcba 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/evloop_timer_unit_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/evloop_timer_unit_test.cpp @@ -122,7 +122,7 @@ HWTEST_F(DistributedDBEventLoopTimerTest, EventLoopTimerTest001, TestSize.Level0 */ bool finalized = false; loop->OnLastRef([&finalized]() { finalized = true; }); - loop->DecObjRef(loop); + RefObject::DecObjRef(loop); loop = nullptr; EXPECT_EQ(finalized, true); } @@ -247,7 +247,7 @@ HWTEST_F(DistributedDBEventLoopTimerTest, EventLoopTimerTest004, TestSize.Level1 EXPECT_EQ(counter > 0, true); g_loop->KillObj(); loopThread.join(); - timer->DecObjRef(timer); + RefObject::DecObjRef(timer); } /** @@ -361,7 +361,7 @@ HWTEST_F(DistributedDBEventLoopTimerTest, EventLoopTimerTest006, TestSize.Level1 std::this_thread::sleep_for(std::chrono::milliseconds(TIME_PIECE_100)); g_loop->KillObj(); loopThread.join(); - timer->DecObjRef(timer); + RefObject::DecObjRef(timer); timer = nullptr; EXPECT_EQ(finalize, true); EXPECT_EQ(counter > 0, true); @@ -428,7 +428,7 @@ HWTEST_F(DistributedDBEventLoopTimerTest, EventLoopTimerTest007, TestSize.Level2 std::this_thread::sleep_for(std::chrono::milliseconds(TIME_PIECE_10000)); g_loop->KillObj(); loopThread.join(); - timer->DecObjRef(timer); + RefObject::DecObjRef(timer); } /** @@ -444,6 +444,7 @@ HWTEST_F(DistributedDBEventLoopTimerTest, EventLoopTest001, TestSize.Level0) EXPECT_EQ(loop->Initialize(), E_OK); EXPECT_EQ(loop->Initialize(), -E_INVALID_ARGS); + DistributedDB::RefObject::KillAndDecObjRef(loop); } /** @@ -528,6 +529,7 @@ HWTEST_F(DistributedDBEventLoopTimerTest, EventTest001, TestSize.Level0) event = IEvent::CreateEvent(eventFd, events, eventTime, errCode); ASSERT_NE(event, nullptr); EXPECT_EQ(errCode, E_OK); + DistributedDB::RefObject::KillAndDecObjRef(event); } /** @@ -554,6 +556,7 @@ HWTEST_F(DistributedDBEventLoopTimerTest, EventTest002, TestSize.Level0) * @tc.expected: step2. return INVALID_ARGS */ EXPECT_EQ(event->SetAction(nullptr), -E_INVALID_ARGS); + DistributedDB::RefObject::KillAndDecObjRef(event); } /** @@ -590,6 +593,7 @@ HWTEST_F(DistributedDBEventLoopTimerTest, EventTest003, TestSize.Level0) events |= ET_READ; EXPECT_EQ(event->AddEvents(events), -E_INVALID_ARGS); EXPECT_EQ(event->RemoveEvents(events), -E_INVALID_ARGS); + DistributedDB::RefObject::KillAndDecObjRef(event); } /** @@ -632,6 +636,7 @@ HWTEST_F(DistributedDBEventLoopTimerTest, EventTest004, TestSize.Level0) ASSERT_EQ(g_loop->Add(event), E_OK); EXPECT_EQ(event->AddEvents(events), E_OK); EXPECT_EQ(event->RemoveEvents(events), E_OK); + DistributedDB::RefObject::KillAndDecObjRef(event); } /** @@ -650,6 +655,7 @@ HWTEST_F(DistributedDBEventLoopTimerTest, EventTest005, TestSize.Level0) EventTime eventTime = -1; // -1 is invalid arg IEvent *event = new (std::nothrow) EventImpl(eventTime); ASSERT_NE(event, nullptr); + DistributedDB::RefObject::KillAndDecObjRef(event); /** * @tc.steps:step2. instantiation event with eventFd, events, eventTime @@ -659,6 +665,7 @@ HWTEST_F(DistributedDBEventLoopTimerTest, EventTest005, TestSize.Level0) EventsMask events = 1u; // 1 means ET_READ EventImpl *eventImpl = new (std::nothrow) EventImpl(eventFd, events, eventTime); ASSERT_NE(eventImpl, nullptr); + DistributedDB::RefObject::KillAndDecObjRef(eventImpl); } /** @@ -688,6 +695,7 @@ HWTEST_F(DistributedDBEventLoopTimerTest, EventTest006, TestSize.Level0) EXPECT_EQ(event->SetTimeout(eventTime), E_OK); eventTime = -1; // -1 is invalid args EXPECT_EQ(event->SetTimeout(eventTime), -E_INVALID_ARGS); + DistributedDB::RefObject::KillAndDecObjRef(event); } /** @@ -725,6 +733,7 @@ HWTEST_F(DistributedDBEventLoopTimerTest, EventTest007, TestSize.Level0) eventImpl->SetEvents(false, events); EXPECT_EQ(eventImpl->GetEvents(), 1u); // 1 means ET_READ EXPECT_FALSE(eventImpl->GetTimeoutPoint(eventTime)); + DistributedDB::RefObject::KillAndDecObjRef(eventImpl); } /** @@ -760,5 +769,6 @@ HWTEST_F(DistributedDBEventLoopTimerTest, EventTest008, TestSize.Level0) * @tc.expected: step3. return INVALID_ARGS */ EXPECT_EQ(eventImpl->Dispatch(), -E_INVALID_ARGS); + DistributedDB::RefObject::KillAndDecObjRef(eventImpl); } } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/rdb_data_generator.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/rdb_data_generator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b770a478fb8383f1c38f8755cfe0d20acb9bd3ad --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/rdb_data_generator.cpp @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2024 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 "rdb_data_generator.h" + +#include "distributeddb_tools_unit_test.h" +#include "log_print.h" +#include "res_finalizer.h" +namespace DistributedDBUnitTest { +using namespace DistributedDB; +int RDBDataGenerator::InitDatabase(const DataBaseSchema &schema, sqlite3 &db) +{ + int errCode = RelationalTestUtils::ExecSql(&db, "PRAGMA journal_mode=WAL;"); + if (errCode != SQLITE_OK) { + return errCode; + } + for (const auto &table : schema.tables) { + errCode = InitTable(table, false, db); + if (errCode != SQLITE_OK) { + break; + } + } + return errCode; +} + +int RDBDataGenerator::InitTable(const DistributedDB::TableSchema &table, bool notNullWithStr, sqlite3 &db) +{ + return InitTable(table, notNullWithStr, false, db); +} + +int RDBDataGenerator::InitTable(const TableSchema &table, bool notNullWithStr, bool isAutoIncrement, sqlite3 &db) +{ + std::string sql = "CREATE TABLE IF NOT EXISTS " + table.name + "("; + for (const auto &field : table.fields) { + sql += "'" + field.colName + "' " + GetTypeText(field.type); + if (field.primary) { + sql += " PRIMARY KEY"; + if (isAutoIncrement) { + sql += " AUTOINCREMENT"; + } + } + if (notNullWithStr && field.type == TYPE_INDEX) { + sql += " NOT NULL ON CONFLICT IGNORE"; + } + sql += ","; + } + sql.pop_back(); + sql += ");"; + int errCode = RelationalTestUtils::ExecSql(&db, sql); + if (errCode != SQLITE_OK) { + LOGE("execute sql failed %d, sql is %s", errCode, sql.c_str()); + } + return errCode; +} + +std::string RDBDataGenerator::GetTypeText(int type) +{ + switch (type) { + case DistributedDB::TYPE_INDEX: + return "INTEGER"; + case DistributedDB::TYPE_INDEX: + return "TEXT"; + case DistributedDB::TYPE_INDEX: + return "ASSETS"; + case DistributedDB::TYPE_INDEX: + return "ASSET"; + default: + return ""; + } +} + +DistributedDB::DBStatus RDBDataGenerator::InsertCloudDBData(int64_t begin, int64_t count, int64_t gidStart, + const DistributedDB::DataBaseSchema &schema, + const std::shared_ptr &virtualCloudDb) +{ + for (const auto &table : schema.tables) { + auto [record, extend] = GenerateDataRecords(begin, count, gidStart, table.fields); + DBStatus res = virtualCloudDb->BatchInsertWithGid(table.name, std::move(record), extend); + if (res != DBStatus::OK) { + return res; + } + } + return DBStatus::OK; +} + +std::pair, std::vector> RDBDataGenerator::GenerateDataRecords(int64_t begin, + int64_t count, int64_t gidStart, const std::vector &fields) +{ + std::vector record; + std::vector extend; + Timestamp now = TimeHelper::GetSysCurrentTime(); + auto time = static_cast(now / CloudDbConstant::TEN_THOUSAND); + for (int64_t i = begin; i < begin + count; i++) { + VBucket data; + for (const auto &field : fields) { + FillColValueByType(i, field, data); + } + record.push_back(data); + + VBucket log; + log.insert_or_assign(CloudDbConstant::CREATE_FIELD, time); + log.insert_or_assign(CloudDbConstant::MODIFY_FIELD, time); + log.insert_or_assign(CloudDbConstant::DELETE_FIELD, false); + log.insert_or_assign(CloudDbConstant::GID_FIELD, std::to_string(i + gidStart)); + extend.push_back(log); + time++; + } + return {record, extend}; +} + +void RDBDataGenerator::FillColValueByType(int64_t index, const Field &field, VBucket &vBucket) +{ + vBucket[field.colName] = GetColValueByType(index, field); +} + +DistributedDB::Type RDBDataGenerator::GetColValueByType(int64_t index, const DistributedDB::Field &field) +{ + Type value = Nil(); + switch (field.type) { + case DistributedDB::TYPE_INDEX: + value = index; + break; + case DistributedDB::TYPE_INDEX: + value = field.colName + "_" + std::to_string(index); + break; + case DistributedDB::TYPE_INDEX: + value = GenerateAssets(index, field); + break; + case DistributedDB::TYPE_INDEX: + value = GenerateAsset(index, field); + break; + } + return value; +} + +Asset RDBDataGenerator::GenerateAsset(int64_t index, const DistributedDB::Field &field) +{ + Asset asset; + asset.name = field.colName + "_" + std::to_string(index); + asset.hash = "default_hash"; + return asset; +} + +Assets RDBDataGenerator::GenerateAssets(int64_t index, const Field &field) +{ + Assets assets; + assets.push_back(GenerateAsset(index, field)); + return assets; +} + +int RDBDataGenerator::InsertLocalDBData(int64_t begin, int64_t count, sqlite3 *db, + const DistributedDB::DataBaseSchema &schema) +{ + for (const auto &table : schema.tables) { + int errCode = InsertLocalDBData(begin, count, db, table); + if (errCode != E_OK) { + return errCode; + } + } + return E_OK; +} + +int RDBDataGenerator::InsertLocalDBData(int64_t begin, int64_t count, sqlite3 *db, + const DistributedDB::TableSchema &schema) +{ + if (schema.fields.empty()) { + return -E_INTERNAL_ERROR; + } + std::string sql = "INSERT OR REPLACE INTO " + schema.name + " VALUES("; + for (size_t i = 0; i < schema.fields.size(); ++i) { + sql += "?,"; + } + sql.pop_back(); + sql += ");"; + for (int64_t i = begin; i < begin + count; i++) { + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(db, sql, stmt); + if (errCode != E_OK) { + return errCode; + } + ResFinalizer resFinalizer([stmt]() { + sqlite3_stmt *sqlite3Stmt = stmt; + int ret = E_OK; + SQLiteUtils::ResetStatement(sqlite3Stmt, true, ret); + }); + errCode = BindOneRowStmt(i, stmt, 0, false, schema.fields); + if (errCode != E_OK) { + return errCode; + } + errCode = SQLiteUtils::StepNext(stmt); + if (errCode != -E_FINISHED) { + return errCode; + } + } + return E_OK; +} + +int RDBDataGenerator::UpsertLocalDBData(int64_t begin, int64_t count, sqlite3 *db, + const DistributedDB::TableSchema &schema) +{ + if (schema.fields.empty()) { + return -E_INTERNAL_ERROR; + } + std::string sql = GetUpsertSQL(schema); + for (int64_t i = begin; i < begin + count; i++) { + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(db, sql, stmt); + if (errCode != E_OK) { + return errCode; + } + ResFinalizer resFinalizer([stmt]() { + sqlite3_stmt *sqlite3Stmt = stmt; + int ret = E_OK; + SQLiteUtils::ResetStatement(sqlite3Stmt, true, ret); + }); + errCode = BindOneRowStmt(i, stmt, 0, false, schema.fields); + if (errCode != E_OK) { + return errCode; + } + errCode = BindOneRowStmt(i, stmt, static_cast(schema.fields.size()), true, schema.fields); + if (errCode != E_OK) { + return errCode; + } + errCode = SQLiteUtils::StepNext(stmt); + if (errCode != -E_FINISHED) { + return errCode; + } + } + return E_OK; +} + +int RDBDataGenerator::UpdateLocalDBData(int64_t begin, int64_t count, sqlite3 *db, const TableSchema &schema) +{ + if (schema.fields.empty()) { + return -E_INTERNAL_ERROR; + } + std::string sql = GetUpdateSQL(schema); + for (int64_t i = begin; i < begin + count; i++) { + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(db, sql, stmt); + if (errCode != E_OK) { + return errCode; + } + ResFinalizer resFinalizer([stmt]() { + sqlite3_stmt *sqlite3Stmt = stmt; + int ret = E_OK; + SQLiteUtils::ResetStatement(sqlite3Stmt, true, ret); + }); + errCode = BindOneRowUpdateStmt(i, stmt, 0, schema.fields); + if (errCode != E_OK) { + return errCode; + } + errCode = SQLiteUtils::StepNext(stmt); + if (errCode != -E_FINISHED) { + return errCode; + } + } + return E_OK; +} + +int RDBDataGenerator::BindOneRowStmt(int64_t index, sqlite3_stmt *stmt, int cid, bool withoutPk, + const std::vector &fields) +{ + for (const auto &field : fields) { + if (withoutPk && field.primary) { + continue; + } + cid++; + auto type = GetColValueByType(index, field); + int errCode = BindOneColStmt(cid, stmt, type); + if (errCode != E_OK) { + return errCode; + } + } + return E_OK; +} + +int RDBDataGenerator::BindOneRowUpdateStmt(int64_t index, sqlite3_stmt *stmt, int cid, + const std::vector &fields) +{ + std::vector pkFields; + for (const auto &field : fields) { + if (field.primary) { + pkFields.push_back(field); + continue; + } + cid++; + auto type = GetColValueByType(index, field); + int errCode = BindOneColStmt(cid, stmt, type); + if (errCode != E_OK) { + return errCode; + } + } + return BindOneRowStmt(index, stmt, cid, false, pkFields); +} + +int RDBDataGenerator::BindOneColStmt(int cid, sqlite3_stmt *stmt, const DistributedDB::Type &type) +{ + switch (type.index()) { + case DistributedDB::TYPE_INDEX: + return SQLiteUtils::BindInt64ToStatement(stmt, cid, std::get(type)); + case DistributedDB::TYPE_INDEX: + return SQLiteUtils::BindTextToStatement(stmt, cid, std::get(type)); + case DistributedDB::TYPE_INDEX: { + auto assets = std::get(type); + std::vector blob; + int errCode = RuntimeContext::GetInstance()->AssetsToBlob(assets, blob); + if (errCode != E_OK) { + return errCode; + } + return SQLiteUtils::BindBlobToStatement(stmt, cid, blob); + } + case DistributedDB::TYPE_INDEX: { + auto assets = std::get(type); + std::vector blob; + int errCode = RuntimeContext::GetInstance()->AssetToBlob(assets, blob); + if (errCode != E_OK) { + return errCode; + } + return SQLiteUtils::BindBlobToStatement(stmt, cid, blob); + } + } + return E_OK; +} + +std::string RDBDataGenerator::GetUpsertSQL(const DistributedDB::TableSchema &schema) +{ + std::string sql = "INSERT INTO " + schema.name + "("; + for (const auto &field : schema.fields) { + sql += field.colName + ","; + } + sql.pop_back(); + sql += ") VALUES("; + std::string pkFields; + std::string noPkFields; + for (const auto &field : schema.fields) { + sql += "?,"; + if (field.primary) { + pkFields += field.colName + ","; + } else { + noPkFields += field.colName + "=?,"; + } + } + pkFields.pop_back(); + noPkFields.pop_back(); + sql.pop_back(); + sql += ") ON CONFLICT(" + pkFields + ") DO UPDATE SET " + noPkFields; + LOGI("upsert sql is %s", sql.c_str()); + return sql; +} + +std::string RDBDataGenerator::GetUpdateSQL(const TableSchema &schema) +{ + std::string pkFields; + std::string noPkFields; + for (const auto &field : schema.fields) { + if (field.primary) { + pkFields += "'" + field.colName + "'=?,"; + } else { + noPkFields += "'" + field.colName + "'=?,"; + } + } + pkFields.pop_back(); + noPkFields.pop_back(); + std::string sql = "UPDATE " + schema.name + " SET "; + sql += noPkFields + " WHERE " + pkFields; + LOGI("upsert sql is %s", sql.c_str()); + return sql; +} + +int RDBDataGenerator::InsertVirtualLocalDBData(int64_t begin, int64_t count, + DistributedDB::RelationalVirtualDevice *device, const DistributedDB::TableSchema &schema) +{ + if (device == nullptr) { + return -E_INVALID_ARGS; + } + std::vector rows; + for (int64_t index = begin; index < count; ++index) { + VirtualRowData virtualRowData; + for (const auto &field : schema.fields) { + auto type = GetColValueByType(index, field); + FillTypeIntoDataValue(field, type, virtualRowData); + } + virtualRowData.logInfo.timestamp = TimeHelper::GetSysCurrentTime() + TimeHelper::BASE_OFFSET; + rows.push_back(virtualRowData); + } + return device->PutData(schema.name, rows); +} + +DistributedDB::DistributedSchema RDBDataGenerator::ParseSchema(const DistributedDB::DataBaseSchema &schema, + bool syncOnlyPk) +{ + DistributedDB::DistributedSchema res; + for (const auto &item : schema.tables) { + DistributedTable table; + for (const auto &field : item.fields) { + DistributedField distributedField; + distributedField.isP2pSync = syncOnlyPk ? field.primary : true; + distributedField.colName = field.colName; + distributedField.isSpecified = field.primary; + table.fields.push_back(distributedField); + } + table.tableName = item.name; + res.tables.push_back(table); + } + return res; +} + +void RDBDataGenerator::FillTypeIntoDataValue(const DistributedDB::Field &field, const DistributedDB::Type &type, + DistributedDB::VirtualRowData &virtualRow) +{ + DataValue dataValue; + std::string hash; + switch (type.index()) { + case DistributedDB::TYPE_INDEX: + if (field.primary) { + hash = std::to_string(std::get(type)); + } + dataValue = std::get(type); + break; + case DistributedDB::TYPE_INDEX: + if (field.primary) { + hash = std::get(type); + } + dataValue = std::get(type); + break; + default: + return; + } + if (field.primary) { + std::vector blob; + DBCommon::StringToVector(hash, blob); + DBCommon::CalcValueHash(blob, virtualRow.logInfo.hashKey); + } + virtualRow.objectData.PutDataValue(field.colName, dataValue); +} + +int RDBDataGenerator::PrepareVirtualDeviceEnv(const std::string &tableName, sqlite3 *db, + DistributedDB::RelationalVirtualDevice *device) +{ + return PrepareVirtualDeviceEnv(tableName, tableName, db, device); +} + +int RDBDataGenerator::PrepareVirtualDeviceEnv(const std::string &scanTable, const std::string &expectTable, sqlite3 *db, + DistributedDB::RelationalVirtualDevice *device) +{ + TableInfo tableInfo; + int errCode = SQLiteUtils::AnalysisSchema(db, scanTable, tableInfo); + if (errCode != E_OK) { + return errCode; + } + tableInfo.SetTableName(expectTable); + device->SetLocalFieldInfo(tableInfo.GetFieldInfos()); + device->SetTableInfo(tableInfo); + return E_OK; +} + +DistributedDB::TableSchema RDBDataGenerator::FlipTableSchema(const DistributedDB::TableSchema &origin) +{ + DistributedDB::TableSchema res; + res.name = origin.name; + for (const auto &item : origin.fields) { + res.fields.insert(res.fields.begin(), item); + } + return res; +} +} \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/rdb_data_generator.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/rdb_data_generator.h new file mode 100644 index 0000000000000000000000000000000000000000..6cd34c8a4d9e990b73b0be5753597cc303e58593 --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/common/rdb_data_generator.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2024 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 RDB_DATA_GENERATE_H +#define RDB_DATA_GENERATE_H + +#include "cloud/cloud_store_types.h" +#include "relational_virtual_device.h" +#include "sqlite_utils.h" +#include "virtual_cloud_db.h" +namespace DistributedDBUnitTest { +class RDBDataGenerator { +public: + static int InitDatabase(const DistributedDB::DataBaseSchema &schema, sqlite3 &db); + + static int InitTable(const DistributedDB::TableSchema &table, bool notNullWithStr, sqlite3 &db); + + static int InitTable(const DistributedDB::TableSchema &table, bool notNullWithStr, bool isAutoIncrement, + sqlite3 &db); + + static DistributedDB::DBStatus InsertCloudDBData(int64_t begin, int64_t count, int64_t gidStart, + const DistributedDB::DataBaseSchema &schema, + const std::shared_ptr &virtualCloudDb); + + static std::pair, std::vector> GenerateDataRecords( + int64_t begin, int64_t count, int64_t gidStart, const std::vector &fields); + + static int InsertLocalDBData(int64_t begin, int64_t count, sqlite3 *db, + const DistributedDB::DataBaseSchema &schema); + + static int InsertLocalDBData(int64_t begin, int64_t count, sqlite3 *db, + const DistributedDB::TableSchema &schema); + + static int UpsertLocalDBData(int64_t begin, int64_t count, sqlite3 *db, + const DistributedDB::TableSchema &schema); + + static int UpdateLocalDBData(int64_t begin, int64_t count, sqlite3 *db, + const DistributedDB::TableSchema &schema); + + static int InsertVirtualLocalDBData(int64_t begin, int64_t count, DistributedDB::RelationalVirtualDevice *device, + const DistributedDB::TableSchema &schema); + + static DistributedDB::DistributedSchema ParseSchema(const DistributedDB::DataBaseSchema &schema, + bool syncOnlyPk = false); + + static int PrepareVirtualDeviceEnv(const std::string &tableName, sqlite3 *db, + DistributedDB::RelationalVirtualDevice *device); + + static int PrepareVirtualDeviceEnv(const std::string &scanTable, const std::string &expectTable, sqlite3 *db, + DistributedDB::RelationalVirtualDevice *device); + + static DistributedDB::TableSchema FlipTableSchema(const DistributedDB::TableSchema &origin); +private: + static std::string GetTypeText(int type); + + static void FillColValueByType(int64_t index, const DistributedDB::Field &field, DistributedDB::VBucket &vBucket); + + static DistributedDB::Type GetColValueByType(int64_t index, const DistributedDB::Field &field); + + static DistributedDB::Asset GenerateAsset(int64_t index, const DistributedDB::Field &field); + + static DistributedDB::Assets GenerateAssets(int64_t index, const DistributedDB::Field &field); + + static int BindOneRowStmt(int64_t index, sqlite3_stmt *stmt, int cid, bool withoutPk, + const std::vector &fields); + + static int BindOneRowUpdateStmt(int64_t index, sqlite3_stmt *stmt, int cid, + const std::vector &fields); + + static int BindOneColStmt(int cid, sqlite3_stmt *stmt, const DistributedDB::Type &type); + + static std::string GetUpsertSQL(const DistributedDB::TableSchema &schema); + + static std::string GetUpdateSQL(const DistributedDB::TableSchema &schema); + + static void FillTypeIntoDataValue(const DistributedDB::Field &field, const DistributedDB::Type &type, + DistributedDB::VirtualRowData &virtualRow); +}; +} +#endif // RDB_DATA_GENERATE_H diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/adapter_stub.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/adapter_stub.cpp index 1ce3148bd9d7e54e560db8954e11a8654b0f0e4f..6c874be3eb8353e25add1a63641691eed028b9ce 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/adapter_stub.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/adapter_stub.cpp @@ -221,11 +221,13 @@ void AdapterStub::CheckAndGetDataHeadInfo(const uint8_t *data, uint32_t totalLen NetToHost(info->length); NetToHost(info->version); headLength = info->length; - std::string tmpUserId(BUFF_LEN, 0); + userId = ""; for (uint8_t i = 0; i < BUFF_LEN; i++) { - tmpUserId[i] = info->userId[i]; + if (info->userId[i] == 0) { + return; + } + userId.push_back(info->userId[i]); } - userId = tmpUserId; } else { headLength = 0; } @@ -254,7 +256,7 @@ void AdapterStub::SimulateSendRetry(const std::string &dstTarget) targetRetrySet_.insert(dstTarget); } -void AdapterStub::SimulateSendRetryClear(const std::string &dstTarget, int softBusErrCode) +void AdapterStub::SimulateSendRetryClear(const std::string &dstTarget, int deviceCommErrCode) { { std::lock_guard retryLockGuard(retryMutex_); @@ -265,15 +267,15 @@ void AdapterStub::SimulateSendRetryClear(const std::string &dstTarget, int softB } std::lock_guard onSendableLockGuard(onSendableMutex_); if (onSendableHandle_) { - onSendableHandle_(dstTarget, softBusErrCode); + onSendableHandle_(dstTarget, deviceCommErrCode); } } -void AdapterStub::SimulateTriggerSendableCallback(const std::string &dstTarget, int softBusErrCode) +void AdapterStub::SimulateTriggerSendableCallback(const std::string &dstTarget, int deviceCommErrCode) { std::lock_guard onSendableLockGuard(onSendableMutex_); if (onSendableHandle_) { - onSendableHandle_(dstTarget, softBusErrCode); + onSendableHandle_(dstTarget, deviceCommErrCode); } } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/adapter_stub.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/adapter_stub.h index 2040a210d5df7c45438ad26716cb90708829f17f..88b773a90ae6ef964e947f634977e50dd86666ee 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/adapter_stub.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/adapter_stub.h @@ -67,8 +67,8 @@ public: void SimulateSendBlockClear(); void SimulateSendRetry(const std::string &dstTarget); - void SimulateSendRetryClear(const std::string &dstTarget, int softBusErrCode = E_OK); - void SimulateTriggerSendableCallback(const std::string &dstTarget, int softBusErrCode = E_OK); + void SimulateSendRetryClear(const std::string &dstTarget, int deviceCommErrCode = E_OK); + void SimulateTriggerSendableCallback(const std::string &dstTarget, int deviceCommErrCode = E_OK); void SimulateSendPartialLoss(); void SimulateSendPartialLossClear(); diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_common.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_common.cpp index bb885604b02c0a8fc3e981a54a71d87c4f3b2888..cf2bb2e0458e76773fcbdd47da257026842f2ce3 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_common.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_common.cpp @@ -60,7 +60,7 @@ void TearDownEnv(EnvHandle &inEnv) { if (inEnv.commAggrHandle != nullptr) { inEnv.commAggrHandle->Finalize(); - inEnv.commAggrHandle->DecObjRef(inEnv.commAggrHandle); + RefObject::DecObjRef(inEnv.commAggrHandle); inEnv.commAggrHandle = nullptr; } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_common.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_common.h index 1aeeaf71f8f3206c1735fb447100f71ba8d7a9b0..dbf2a0641ba7f5dd00bc5d166468887123dfc473 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_common.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_common.h @@ -118,6 +118,8 @@ private: const std::string DEVICE_NAME_A = "DeviceA"; const std::string DEVICE_NAME_B = "DeviceB"; const std::string DEVICE_NAME_C = "DeviceC"; +const std::string USER_ID_1 = "user_1"; +const std::string USER_ID_2 = "user_2"; constexpr uint64_t LABEL_A = 1234; constexpr uint64_t LABEL_B = 2345; constexpr uint64_t LABEL_C = 3456; @@ -143,10 +145,10 @@ DistributedDB::Message *BuildRegedGiantMessage(uint32_t length); DistributedDB::Message *BuildRegedOverSizeMessage(); DistributedDB::Message *BuildUnRegedTinyMessage(); -#define ASSERT_NOT_NULL_AND_ACTIVATE(communicator) \ +#define ASSERT_NOT_NULL_AND_ACTIVATE(communicator, userId) \ { \ ASSERT_NE(communicator, nullptr); \ - (communicator)->Activate(); \ + (communicator)->Activate(userId); \ } #endif // DISTRIBUTEDDB_COMMUNICATOR_COMMON_H \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_deep_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_deep_test.cpp index 3e27785c08cc78ef486bb8f97921c413b4b42574..03522eb78e47c56211526883939961d4e9bdadde 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_deep_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_deep_test.cpp @@ -84,17 +84,17 @@ void AllocAllCommunicator() { int errorNo = E_OK; g_commAA = g_envDeviceA.commAggrHandle->AllocCommunicator(LABEL_A, errorNo); - ASSERT_NOT_NULL_AND_ACTIVATE(g_commAA); + ASSERT_NOT_NULL_AND_ACTIVATE(g_commAA, ""); g_commAB = g_envDeviceA.commAggrHandle->AllocCommunicator(LABEL_B, errorNo); - ASSERT_NOT_NULL_AND_ACTIVATE(g_commAB); + ASSERT_NOT_NULL_AND_ACTIVATE(g_commAB, ""); g_commBB = g_envDeviceB.commAggrHandle->AllocCommunicator(LABEL_B, errorNo); - ASSERT_NOT_NULL_AND_ACTIVATE(g_commBB); + ASSERT_NOT_NULL_AND_ACTIVATE(g_commBB, ""); g_commBC = g_envDeviceB.commAggrHandle->AllocCommunicator(LABEL_C, errorNo); - ASSERT_NOT_NULL_AND_ACTIVATE(g_commBC); + ASSERT_NOT_NULL_AND_ACTIVATE(g_commBC, ""); g_commCC = g_envDeviceC.commAggrHandle->AllocCommunicator(LABEL_C, errorNo); - ASSERT_NOT_NULL_AND_ACTIVATE(g_commCC); + ASSERT_NOT_NULL_AND_ACTIVATE(g_commCC, ""); g_commCA = g_envDeviceC.commAggrHandle->AllocCommunicator(LABEL_A, errorNo); - ASSERT_NOT_NULL_AND_ACTIVATE(g_commCA); + ASSERT_NOT_NULL_AND_ACTIVATE(g_commCA, ""); } void ReleaseAllCommunicator() diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_send_receive_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_send_receive_test.cpp index 5b0661529335f4f7c077bbf231ac2b99a18b0e68..b3f7e8ff09af6c45eb94641bdd8c2314b9b56930 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_send_receive_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_send_receive_test.cpp @@ -72,26 +72,23 @@ void DistributedDBCommunicatorSendReceiveTest::TearDownTestCase(void) CommunicatorAggregator::EnableCommunicatorNotFoundFeedback(true); } +static void GetCommunicator(uint64_t label, const std::string &userId, EnvHandle &device, ICommunicator **comm) +{ + int errorNo = E_OK; + *comm = device.commAggrHandle->AllocCommunicator(label, errorNo, userId); + ASSERT_EQ(errorNo, E_OK); + ASSERT_NOT_NULL_AND_ACTIVATE(*comm, userId); +} + void DistributedDBCommunicatorSendReceiveTest::SetUp() { DistributedDBUnitTest::DistributedDBToolsUnitTest::PrintTestCaseInfo(); /** * @tc.setup: Alloc communicator AA, BA, BB */ - int errorNo = E_OK; - g_commAA = g_envDeviceA.commAggrHandle->AllocCommunicator(LABEL_A, errorNo); - ASSERT_EQ(errorNo, E_OK); - ASSERT_NOT_NULL_AND_ACTIVATE(g_commAA); - - errorNo = E_OK; - g_commBA = g_envDeviceB.commAggrHandle->AllocCommunicator(LABEL_A, errorNo); - ASSERT_EQ(errorNo, E_OK); - ASSERT_NOT_NULL_AND_ACTIVATE(g_commBA); - - errorNo = E_OK; - g_commBB = g_envDeviceB.commAggrHandle->AllocCommunicator(LABEL_B, errorNo); - ASSERT_EQ(errorNo, E_OK); - ASSERT_NOT_NULL_AND_ACTIVATE(g_commBB); + GetCommunicator(LABEL_A, "", g_envDeviceA, &g_commAA); + GetCommunicator(LABEL_A, "", g_envDeviceB, &g_commBA); + GetCommunicator(LABEL_B, "", g_envDeviceB, &g_commBB); } void DistributedDBCommunicatorSendReceiveTest::TearDown() @@ -118,6 +115,31 @@ static Message *BuildAppLayerFrameMessage() return message; } +static void CheckRecvMessage(Message *recvMsg, bool isEmpty, uint32_t msgId, uint32_t msgType) +{ + if (isEmpty) { + EXPECT_EQ(recvMsg, nullptr); + } else { + ASSERT_NE(recvMsg, nullptr); + EXPECT_EQ(recvMsg->GetMessageId(), msgId); + EXPECT_EQ(recvMsg->GetMessageType(), msgType); + EXPECT_EQ(recvMsg->GetSessionId(), FIXED_SESSIONID); + EXPECT_EQ(recvMsg->GetSequenceId(), FIXED_SEQUENCEID); + EXPECT_EQ(recvMsg->GetErrorNo(), NO_ERROR); + delete recvMsg; + recvMsg = nullptr; + } +} + +#define REG_MESSAGE_CALLBACK(src, label) \ + string srcTargetFor##src##label; \ + Message *recvMsgFor##src##label = nullptr; \ + g_comm##src##label->RegOnMessageCallback( \ + [&srcTargetFor##src##label, &recvMsgFor##src##label](const std::string &srcTarget, Message *inMsg) { \ + srcTargetFor##src##label = srcTarget; \ + recvMsgFor##src##label = inMsg; \ + }, nullptr); + /** * @tc.name: Send And Receive 001 * @tc.desc: Test send and receive based on equipment communicator @@ -128,24 +150,9 @@ static Message *BuildAppLayerFrameMessage() HWTEST_F(DistributedDBCommunicatorSendReceiveTest, SendAndReceive001, TestSize.Level1) { // Preset - string srcTargetForAA; - Message *recvMsgForAA = nullptr; - string srcTargetForBA; - Message *recvMsgForBA = nullptr; - string srcTargetForBB; - Message *recvMsgForBB = nullptr; - g_commAA->RegOnMessageCallback([&srcTargetForAA, &recvMsgForAA](const std::string &srcTarget, Message *inMsg) { - srcTargetForAA = srcTarget; - recvMsgForAA = inMsg; - }, nullptr); - g_commBA->RegOnMessageCallback([&srcTargetForBA, &recvMsgForBA](const std::string &srcTarget, Message *inMsg) { - srcTargetForBA = srcTarget; - recvMsgForBA = inMsg; - }, nullptr); - g_commBB->RegOnMessageCallback([&srcTargetForBB, &recvMsgForBB](const std::string &srcTarget, Message *inMsg) { - srcTargetForBB = srcTarget; - recvMsgForBB = inMsg; - }, nullptr); + REG_MESSAGE_CALLBACK(A, A); + REG_MESSAGE_CALLBACK(B, A); + REG_MESSAGE_CALLBACK(B, B); /** * @tc.steps: step1. connect device A with device B @@ -162,16 +169,9 @@ HWTEST_F(DistributedDBCommunicatorSendReceiveTest, SendAndReceive001, TestSize.L int errCode = g_commAA->SendMessage(DEVICE_NAME_B, msgForAA, conf); EXPECT_EQ(errCode, E_OK); std::this_thread::sleep_for(std::chrono::milliseconds(200)); // sleep 200 ms - EXPECT_EQ(recvMsgForBB, nullptr); + CheckRecvMessage(recvMsgForBB, true, 0, 0); EXPECT_EQ(srcTargetForBA, DEVICE_NAME_A); - ASSERT_NE(recvMsgForBA, nullptr); - EXPECT_EQ(recvMsgForBA->GetMessageId(), REGED_TINY_MSG_ID); - EXPECT_EQ(recvMsgForBA->GetMessageType(), TYPE_REQUEST); - EXPECT_EQ(recvMsgForBA->GetSessionId(), FIXED_SESSIONID); - EXPECT_EQ(recvMsgForBA->GetSequenceId(), FIXED_SEQUENCEID); - EXPECT_EQ(recvMsgForBA->GetErrorNo(), NO_ERROR); - delete recvMsgForBA; - recvMsgForBA = nullptr; + CheckRecvMessage(recvMsgForBA, false, REGED_TINY_MSG_ID, TYPE_REQUEST); /** * @tc.steps: step3. device B send message(registered and tiny) to device A using communicator BB @@ -249,6 +249,77 @@ HWTEST_F(DistributedDBCommunicatorSendReceiveTest, SendAndReceive003, TestSize.L AdapterStub::DisconnectAdapterStub(g_envDeviceA.adapterHandle, g_envDeviceB.adapterHandle); } +/** + * @tc.name: Send And Receive 004 + * @tc.desc: Test send and receive with different users. + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBCommunicatorSendReceiveTest, SendAndReceive004, TestSize.Level1) +{ + /** + * @tc.steps: step1. Get communicators for users {"", "user_1", "user_2"} + * @tc.expected: step1. ok + */ + ICommunicator *g_commAAUser1 = nullptr; + GetCommunicator(LABEL_A, USER_ID_1, g_envDeviceA, &g_commAAUser1); + ICommunicator *g_commBAUser1 = nullptr; + GetCommunicator(LABEL_A, USER_ID_1, g_envDeviceB, &g_commBAUser1); + + ICommunicator *g_commAAUser2 = nullptr; + GetCommunicator(LABEL_A, USER_ID_2, g_envDeviceA, &g_commAAUser2); + ICommunicator *g_commBAUser2 = nullptr; + GetCommunicator(LABEL_A, USER_ID_2, g_envDeviceB, &g_commBAUser2); + + /** + * @tc.steps: step2. Set callback on B, save all message from A + * @tc.expected: step2. ok + */ + REG_MESSAGE_CALLBACK(B, A) + REG_MESSAGE_CALLBACK(B, AUser1) + REG_MESSAGE_CALLBACK(B, AUser2) + + /** + * @tc.steps: step3. Connect and send message from A to B. + * @tc.expected: step3. ok + */ + AdapterStub::ConnectAdapterStub(g_envDeviceA.adapterHandle, g_envDeviceB.adapterHandle); + + Message *msgForAA = BuildRegedTinyMessage(); + ASSERT_NE(msgForAA, nullptr); + Message *msgForAAUser1 = BuildRegedHugeMessage(); + ASSERT_NE(msgForAAUser1, nullptr); + Message *msgForAAUser2 = BuildRegedGiantMessage(HUGE_SIZE + HUGE_SIZE); + ASSERT_NE(msgForAAUser2, nullptr); + SendConfig conf = {false, false, 0}; + int errCode = g_commAA->SendMessage(DEVICE_NAME_B, msgForAA, conf); + EXPECT_EQ(errCode, E_OK); + SendConfig confUser1 = {false, true, 0, {"appId", "storeId", USER_ID_1, "DeviceB", ""}}; + errCode = g_commAA->SendMessage(DEVICE_NAME_B, msgForAAUser1, confUser1); + EXPECT_EQ(errCode, E_OK); + SendConfig confUser2 = {false, true, 0, {"appId", "storeId", USER_ID_2, "DeviceB", ""}}; + errCode = g_commAA->SendMessage(DEVICE_NAME_B, msgForAAUser2, confUser2); + EXPECT_EQ(errCode, E_OK); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + /** + * @tc.steps: step4. Check message. + * @tc.expected: step4. ok + */ + EXPECT_EQ(srcTargetForBA, DEVICE_NAME_A); + EXPECT_EQ(srcTargetForBAUser1, DEVICE_NAME_A); + EXPECT_EQ(srcTargetForBAUser2, DEVICE_NAME_A); + CheckRecvMessage(recvMsgForBA, false, REGED_TINY_MSG_ID, TYPE_REQUEST); + CheckRecvMessage(recvMsgForBAUser1, false, REGED_HUGE_MSG_ID, TYPE_RESPONSE); + CheckRecvMessage(recvMsgForBAUser2, false, REGED_GIANT_MSG_ID, TYPE_NOTIFY); + // CleanUp + AdapterStub::DisconnectAdapterStub(g_envDeviceA.adapterHandle, g_envDeviceB.adapterHandle); + g_envDeviceA.commAggrHandle->ReleaseCommunicator(g_commAAUser1, USER_ID_1); + g_envDeviceB.commAggrHandle->ReleaseCommunicator(g_commBAUser1, USER_ID_1); + g_envDeviceA.commAggrHandle->ReleaseCommunicator(g_commAAUser2, USER_ID_2); + g_envDeviceB.commAggrHandle->ReleaseCommunicator(g_commBAUser2, USER_ID_2); +} + /** * @tc.name: Send Flow Control 001 * @tc.desc: Test send in nonblock way @@ -618,15 +689,6 @@ HWTEST_F(DistributedDBCommunicatorSendReceiveTest, SendResultNotify001, TestSize EXPECT_NE(sendResult[1], E_OK); // 1 for second element } -#define REG_MESSAGE_CALLBACK(src, label) \ - string srcTargetFor##src##label; \ - Message *recvMsgFor##src##label = nullptr; \ - g_comm##src##label->RegOnMessageCallback( \ - [&srcTargetFor##src##label, &recvMsgFor##src##label](const std::string &srcTarget, Message *inMsg) { \ - srcTargetFor##src##label = srcTarget; \ - recvMsgFor##src##label = inMsg; \ - }, nullptr); - /** * @tc.name: Message Feedback 001 * @tc.desc: Test feedback not support messageid and communicator not found @@ -709,19 +771,9 @@ HWTEST_F(DistributedDBCommunicatorSendReceiveTest, MessageFeedback001, TestSize. HWTEST_F(DistributedDBCommunicatorSendReceiveTest, SendAndReceiveWithExtendHead001, TestSize.Level1) { // Preset - string srcTargetForAA; - Message *recvMsgForAA = nullptr; - string srcTargetForBA; - Message *recvMsgForBA = nullptr; TimeSync::RegisterTransformFunc(); - g_commAA->RegOnMessageCallback([&srcTargetForAA, &recvMsgForAA](const std::string &srcTarget, Message *inMsg) { - srcTargetForAA = srcTarget; - recvMsgForAA = inMsg; - }, nullptr); - g_commBA->RegOnMessageCallback([&srcTargetForBA, &recvMsgForBA](const std::string &srcTarget, Message *inMsg) { - srcTargetForBA = srcTarget; - recvMsgForBA = inMsg; - }, nullptr); + REG_MESSAGE_CALLBACK(A, A); + REG_MESSAGE_CALLBACK(B, A); /** * @tc.steps: step1. connect device A with device B @@ -734,7 +786,7 @@ HWTEST_F(DistributedDBCommunicatorSendReceiveTest, SendAndReceiveWithExtendHead0 */ Message *msgForAA = BuildAppLayerFrameMessage(); ASSERT_NE(msgForAA, nullptr); - SendConfig conf = {false, true, 0, {"appId", "storeId", "userId", "deviceB"}}; + SendConfig conf = {false, true, 0, {"appId", "storeId", "", "DeviceB"}}; int errCode = g_commAA->SendMessage(DEVICE_NAME_B, msgForAA, conf); EXPECT_EQ(errCode, E_OK); std::this_thread::sleep_for(std::chrono::milliseconds(200)); // sleep 200 ms diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_test.cpp index 1d8f1aac9136c8111a28f6851fc8a57f54674a71..8cda98e645ef16d4e08deefd4cfb42ae963dba9d 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_test.cpp @@ -156,6 +156,54 @@ HWTEST_F(DistributedDBCommunicatorTest, CommunicatorManagement001, TestSize.Leve commD = nullptr; } +/** + * @tc.name: Communicator Management 002 + * @tc.desc: Test alloc and release communicator with different userId + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBCommunicatorTest, CommunicatorManagement002, TestSize.Level1) +{ + /** + * @tc.steps: step1. alloc communicator A using label A with USER_ID_1 + * @tc.expected: step1. alloc return OK. + */ + int errorNo = E_OK; + ICommunicator *commA = g_envDeviceA.commAggrHandle->AllocCommunicator(LABEL_A, errorNo, USER_ID_1); + commA->Activate(USER_ID_1); + EXPECT_EQ(errorNo, E_OK); + EXPECT_NE(commA, nullptr); + + /** + * @tc.steps: step2. alloc communicator B using label A with USER_ID_2 + * @tc.expected: step2. alloc return OK, and commA == commB is TRUE + */ + errorNo = E_OK; + ICommunicator *commB = g_envDeviceA.commAggrHandle->AllocCommunicator(LABEL_A, errorNo, USER_ID_2); + commB->Activate(USER_ID_2); + EXPECT_EQ(errorNo, E_OK); + EXPECT_NE(commA, nullptr); + + /** + * @tc.steps: step3. alloc communicator C using label A with USER_ID_1 + * @tc.expected: step3. alloc return not OK. + */ + errorNo = E_OK; + ICommunicator *commC = g_envDeviceA.commAggrHandle->AllocCommunicator(LABEL_A, errorNo, USER_ID_1); + EXPECT_NE(errorNo, E_OK); + EXPECT_EQ(commC, nullptr); + + /** + * @tc.steps: step4. release communicator A and communicator B + * @tc.expected: step4. OK. + */ + g_envDeviceA.commAggrHandle->ReleaseCommunicator(commA, USER_ID_1); + commA = nullptr; + g_envDeviceA.commAggrHandle->ReleaseCommunicator(commB, USER_ID_2); + commB = nullptr; +} + static void ConnectWaitDisconnect() { AdapterStub::ConnectAdapterStub(g_envDeviceA.adapterHandle, g_envDeviceB.adapterHandle); @@ -178,7 +226,7 @@ HWTEST_F(DistributedDBCommunicatorTest, OnlineAndOffline001, TestSize.Level1) */ int errorNo = E_OK; ICommunicator *commAA = g_envDeviceA.commAggrHandle->AllocCommunicator(LABEL_A, errorNo); - ASSERT_NOT_NULL_AND_ACTIVATE(commAA); + ASSERT_NOT_NULL_AND_ACTIVATE(commAA, ""); OnOfflineDevice onlineForAA; commAA->RegOnConnectCallback([&onlineForAA](const std::string &target, bool isConnect) { HandleConnectChange(onlineForAA, target, isConnect);}, nullptr); @@ -196,7 +244,7 @@ HWTEST_F(DistributedDBCommunicatorTest, OnlineAndOffline001, TestSize.Level1) * @tc.expected: step3. no callback. */ ICommunicator *commBB = g_envDeviceB.commAggrHandle->AllocCommunicator(LABEL_B, errorNo); - ASSERT_NOT_NULL_AND_ACTIVATE(commBB); + ASSERT_NOT_NULL_AND_ACTIVATE(commBB, ""); OnOfflineDevice onlineForBB; commBB->RegOnConnectCallback([&onlineForBB](const std::string &target, bool isConnect) { HandleConnectChange(onlineForBB, target, isConnect);}, nullptr); @@ -216,7 +264,7 @@ HWTEST_F(DistributedDBCommunicatorTest, OnlineAndOffline001, TestSize.Level1) * @tc.expected: step5. no callback. */ ICommunicator *commBA = g_envDeviceB.commAggrHandle->AllocCommunicator(LABEL_A, errorNo); - ASSERT_NOT_NULL_AND_ACTIVATE(commBA); + ASSERT_NOT_NULL_AND_ACTIVATE(commBA, ""); OnOfflineDevice onlineForBA; commBA->RegOnConnectCallback([&onlineForBA](const std::string &target, bool isConnect) { HandleConnectChange(onlineForBA, target, isConnect);}, nullptr); @@ -291,7 +339,7 @@ HWTEST_F(DistributedDBCommunicatorTest, OnlineAndOffline002, TestSize.Level1) */ int errorNo = E_OK; ICommunicator *commAA = g_envDeviceA.commAggrHandle->AllocCommunicator(LABEL_A, errorNo); - ASSERT_NOT_NULL_AND_ACTIVATE(commAA); + ASSERT_NOT_NULL_AND_ACTIVATE(commAA, ""); OnOfflineDevice onlineForAA; REG_CONNECT_CALLBACK(commAA, onlineForAA); EXPECT_EQ(onlineForAA.onlineDevices.size(), static_cast(0)); @@ -301,7 +349,7 @@ HWTEST_F(DistributedDBCommunicatorTest, OnlineAndOffline002, TestSize.Level1) * @tc.expected: step3. no callback. */ ICommunicator *commBB = g_envDeviceB.commAggrHandle->AllocCommunicator(LABEL_B, errorNo); - ASSERT_NOT_NULL_AND_ACTIVATE(commBB); + ASSERT_NOT_NULL_AND_ACTIVATE(commBB, ""); OnOfflineDevice onlineForBB; REG_CONNECT_CALLBACK(commBB, onlineForBB); EXPECT_EQ(onlineForAA.onlineDevices.size(), static_cast(0)); @@ -314,7 +362,7 @@ HWTEST_F(DistributedDBCommunicatorTest, OnlineAndOffline002, TestSize.Level1) * communicator BB no callback. */ ICommunicator *commBA = g_envDeviceB.commAggrHandle->AllocCommunicator(LABEL_A, errorNo); - ASSERT_NOT_NULL_AND_ACTIVATE(commBA); + ASSERT_NOT_NULL_AND_ACTIVATE(commBA, ""); OnOfflineDevice onlineForBA; REG_CONNECT_CALLBACK(commBA, onlineForBA); std::this_thread::sleep_for(std::chrono::milliseconds(100)); @@ -330,7 +378,7 @@ HWTEST_F(DistributedDBCommunicatorTest, OnlineAndOffline002, TestSize.Level1) * communicator BB has callback of device A online; */ ICommunicator *commAB = g_envDeviceA.commAggrHandle->AllocCommunicator(LABEL_B, errorNo); - ASSERT_NOT_NULL_AND_ACTIVATE(commAB); + ASSERT_NOT_NULL_AND_ACTIVATE(commAB, ""); OnOfflineDevice onlineForAB; REG_CONNECT_CALLBACK(commAB, onlineForAB); std::this_thread::sleep_for(std::chrono::milliseconds(100)); @@ -388,7 +436,7 @@ void TestRemoteRestart() */ int errorNo = E_OK; ICommunicator *commDD = envDeviceD.commAggrHandle->AllocCommunicator(LABEL_A, errorNo); - ASSERT_NOT_NULL_AND_ACTIVATE(commDD); + ASSERT_NOT_NULL_AND_ACTIVATE(commDD, ""); OnOfflineDevice onlineForDD; REG_CONNECT_CALLBACK(commDD, onlineForDD); @@ -396,7 +444,7 @@ void TestRemoteRestart() * @tc.steps: step3. device E alloc communicator EE using label A and register callback */ ICommunicator *commEE = envDeviceE.commAggrHandle->AllocCommunicator(LABEL_A, errorNo); - ASSERT_NOT_NULL_AND_ACTIVATE(commEE); + ASSERT_NOT_NULL_AND_ACTIVATE(commEE, ""); OnOfflineDevice onlineForEE; REG_CONNECT_CALLBACK(commEE, onlineForEE); /** @@ -417,7 +465,7 @@ void TestRemoteRestart() SetUpEnv(envDeviceE, "DEVICE_E"); commEE = envDeviceE.commAggrHandle->AllocCommunicator(LABEL_A, errorNo); - ASSERT_NOT_NULL_AND_ACTIVATE(commEE); + ASSERT_NOT_NULL_AND_ACTIVATE(commEE, ""); REG_CONNECT_CALLBACK(commEE, onlineForEE); onlineForEE.onlineDevices.clear(); /** @@ -563,7 +611,7 @@ HWTEST_F(DistributedDBCommunicatorTest, ReportCommunicatorNotFound001, TestSize. * @tc.expected: step3. device B callback that label A not found. */ ICommunicator *commAA = g_envDeviceA.commAggrHandle->AllocCommunicator(LABEL_A, errCode); - ASSERT_NOT_NULL_AND_ACTIVATE(commAA); + ASSERT_NOT_NULL_AND_ACTIVATE(commAA, ""); Message *msgForAA = BuildRegedTinyMessage(); ASSERT_NE(msgForAA, nullptr); SendConfig conf = {true, false, 0}; @@ -583,7 +631,7 @@ HWTEST_F(DistributedDBCommunicatorTest, ReportCommunicatorNotFound001, TestSize. commBA->RegOnMessageCallback([&recvMsgForBA](const std::string &srcTarget, Message *inMsg) { recvMsgForBA = inMsg; }, nullptr); - commBA->Activate(); + commBA->Activate(USER_ID_1); std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Sleep 100 ms EXPECT_EQ(recvMsgForBA, nullptr); @@ -615,7 +663,7 @@ HWTEST_F(DistributedDBCommunicatorTest, ReportCommunicatorNotFound001, TestSize. #define ALLOC_AND_SEND_MESSAGE(src, dst, label, session) \ ICommunicator *comm##src##label = g_envDevice##src.commAggrHandle->AllocCommunicator(LABEL_##label, errCode); \ - ASSERT_NOT_NULL_AND_ACTIVATE(comm##src##label); \ + ASSERT_NOT_NULL_AND_ACTIVATE(comm##src##label, ""); \ DO_SEND_MESSAGE(src, dst, label, session) #define REG_MESSAGE_CALLBACK(src, label) \ @@ -818,11 +866,11 @@ HWTEST_F(DistributedDBCommunicatorTest, ReDeliverMessage003, TestSize.Level2) * @tc.steps: step3. device A alloc communicator AA,AB,AC using label A,B,C */ ICommunicator *commAA = g_envDeviceA.commAggrHandle->AllocCommunicator(LABEL_A, errCode); - ASSERT_NOT_NULL_AND_ACTIVATE(commAA); + ASSERT_NOT_NULL_AND_ACTIVATE(commAA, ""); ICommunicator *commAB = g_envDeviceA.commAggrHandle->AllocCommunicator(LABEL_B, errCode); - ASSERT_NOT_NULL_AND_ACTIVATE(commAB); + ASSERT_NOT_NULL_AND_ACTIVATE(commAB, ""); ICommunicator *commAC = g_envDeviceA.commAggrHandle->AllocCommunicator(LABEL_C, errCode); - ASSERT_NOT_NULL_AND_ACTIVATE(commAC); + ASSERT_NOT_NULL_AND_ACTIVATE(commAC, ""); std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Sleep 100 ms /** @@ -883,7 +931,7 @@ namespace { std::vector commLabel(label.begin(), label.end()); int errorNo = E_OK; comm = envDevice.commAggrHandle->AllocCommunicator(commLabel, errorNo); - ASSERT_NOT_NULL_AND_ACTIVATE(comm); + ASSERT_NOT_NULL_AND_ACTIVATE(comm, ""); REG_CONNECT_CALLBACK(comm, onlineCallback); } } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_cloud_interfaces_relational_ext_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_cloud_interfaces_relational_ext_test.cpp index 7e7d1af7c670b6bfefb1f627537f70051e083266..8c3aa97573dd9f7e99b61d1a77c996bf7b6e6dee 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_cloud_interfaces_relational_ext_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_cloud_interfaces_relational_ext_test.cpp @@ -1236,7 +1236,7 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalExtTest, FfrtTest003, TestSize.Le * @tc.expected: step2. return ok. */ #ifdef USE_FFRT - EXPECT_NE(count, num * num); + EXPECT_LE(count, num * num); #else EXPECT_EQ(count, num * num); #endif @@ -1459,6 +1459,7 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalExtTest, LockDataTest003, TestSiz sql = "delete from " + tableName + " where id in (2,12,22,32)"; EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK); CheckDataStatus(tableName, " status = 1 and data_key = -1 ", db, 3); // 3 is changed count + EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK); } DistributedDB::StoreObserver::StoreChangedInfo g_changedData; @@ -1734,6 +1735,7 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalExtTest, RegisterStoreObserverTes auto storeObserver = std::make_shared(); EXPECT_EQ(RegisterStoreObserver(db, storeObserver), OK); EXPECT_EQ(RegisterStoreObserver(db, storeObserver), INVALID_ARGS); + EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK); } /** diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_cloud_interfaces_relational_remove_device_data_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_cloud_interfaces_relational_remove_device_data_test.cpp index 1637a5887a88cad2536eb33db199e5b2d527917c..03c7fda7b91dca2a4f81453e090e247b66a5730f 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_cloud_interfaces_relational_remove_device_data_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_cloud_interfaces_relational_remove_device_data_test.cpp @@ -1884,6 +1884,124 @@ HWTEST_F(DistributedDBCloudInterfacesRelationalRemoveDeviceDataTest, CleanCloudD " where flag & 0x02 == 0x02;"; EXPECT_EQ(sqlite3_exec(db, sql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, reinterpret_cast(cloudCount), nullptr), SQLITE_OK); + EXPECT_EQ(g_observer->GetLastOrigin(), Origin::ORIGIN_CLOUD); + CloseDb(); +} + +/* + * @tc.name: CleanCloudDataTest028 + * @tc.desc: Test flag_only and logic delete. + * @tc.type: FUNC + * @tc.require: + * @tc.author: wangxiangdong + */ +HWTEST_F(DistributedDBCloudInterfacesRelationalRemoveDeviceDataTest, CleanCloudDataTest028, TestSize.Level0) +{ + /** + * @tc.steps: step1. Set data is logicDelete + * @tc.expected: OK. + */ + bool logicDelete = true; + auto data = static_cast(&logicDelete); + g_delegate->Pragma(LOGIC_DELETE_SYNC_DATA, data); + /** + * @tc.steps: step2. make data: 20 records on cloud + * @tc.expected: OK. + */ + int64_t paddingSize = 20; + int cloudCount = 20; + InsertCloudTableRecord(0, cloudCount, paddingSize, false); + /** + * @tc.steps: step3. call Sync with cloud merge strategy. + * @tc.expected: OK. + */ + CloudDBSyncUtilsTest::callSync(g_tables, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, g_delegate); + /** + * @tc.steps: step4. after remove device data and check log num. + * @tc.expected: OK. + */ + std::string device; + ASSERT_EQ(g_delegate->RemoveDeviceData(device, DistributedDB::FLAG_ONLY), DBStatus::OK); + std::string sql = "select count(*) from " + DBCommon::GetLogTableName(g_tables[0]) + + " where flag & 0x02 == 0x02;"; + EXPECT_EQ(sqlite3_exec(db, sql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(0), nullptr), SQLITE_OK); + /** + * @tc.steps: step5. call Sync with cloud merge strategy after delete by cloud. + * @tc.expected: OK. + */ + DeleteCloudTableRecordByGid(0, 2); + CloudDBSyncUtilsTest::callSync(g_tables, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, g_delegate); + + /** + * @tc.steps: step6. call Sync with cloud merge strategy. + * @tc.expected: OK. + */ + DeleteCloudTableRecordByGid(4, 2); + CloudDBSyncUtilsTest::callSync(g_tables, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, g_delegate); + sql = "select count(*) from " + DBCommon::GetLogTableName(g_tables[0]) + + " where cloud_gid = '';"; + EXPECT_EQ(sqlite3_exec(db, sql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(2), nullptr), SQLITE_OK); + CheckCloudTotalCount(g_tables, {18, 20}); + CloseDb(); +} + +/* + * @tc.name: CleanCloudDataTest029 + * @tc.desc: Test flag_and_data and logic delete to remove cloud and inconsistency data. + * @tc.type: FUNC + * @tc.require: + * @tc.author: wangxiangdong + */ +HWTEST_F(DistributedDBCloudInterfacesRelationalRemoveDeviceDataTest, CleanCloudDataTest029, TestSize.Level0) +{ + /** + * @tc.steps: step1. Set data is logicDelete + * @tc.expected: OK. + */ + bool logicDelete = true; + auto data = static_cast(&logicDelete); + g_delegate->Pragma(LOGIC_DELETE_SYNC_DATA, data); + /** + * @tc.steps: step2. make data: 20 records on cloud + * @tc.expected: OK. + */ + int64_t paddingSize = 20; + int cloudCount = 20; + InsertCloudTableRecord(0, cloudCount, paddingSize, false); + /** + * @tc.steps: step3. call Sync with cloud merge strategy. + * @tc.expected: OK. + */ + g_virtualAssetLoader->SetDownloadStatus(CLOUD_ASSET_SPACE_INSUFFICIENT); + CloudDBSyncUtilsTest::callSync(g_tables, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, g_delegate); + /** + * @tc.steps: step4. remove device data and check log num. + * @tc.expected: OK. + */ + std::string device; + ASSERT_EQ(g_delegate->RemoveDeviceData(device, DistributedDB::FLAG_AND_DATA), DBStatus::OK); + std::string sql = "select count(*) from " + DBCommon::GetLogTableName(g_tables[0]) + + " where flag & 0x82B == 0x82B;"; + EXPECT_EQ(sqlite3_exec(db, sql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(20), nullptr), SQLITE_OK); + DropLogicDeletedData(db, g_tables[0], 0); + /** + * @tc.steps: step5. call Sync with cloud merge strategy after set asset download ok. + * @tc.expected: OK. + */ + g_virtualAssetLoader->SetDownloadStatus(DBStatus::OK); + CloudDBSyncUtilsTest::callSync(g_tables, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, g_delegate); + /** + * @tc.steps: step6. check data is consistence. + * @tc.expected: OK. + */ + sql = "select count(*) from " + DBCommon::GetLogTableName(g_tables[0]) + + " where flag & 0x20 = 0;"; + EXPECT_EQ(sqlite3_exec(db, sql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(20), nullptr), SQLITE_OK); + CheckCloudTotalCount(g_tables, {20, 20}); CloseDb(); } } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_cloud_interfaces_set_cloud_schema_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_cloud_interfaces_set_cloud_schema_test.cpp index 0498181882743a2fb44ab2064d2aa741320f7548..1853d15780ce0bf8456ed839da41e697796c4fba 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_cloud_interfaces_set_cloud_schema_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_cloud_interfaces_set_cloud_schema_test.cpp @@ -181,6 +181,10 @@ namespace { RuntimeContext::GetInstance()->SetCommunicatorAggregator(nullptr); communicatorAggregator_ = nullptr; RuntimeContext::GetInstance()->SetProcessSystemApiAdapter(nullptr); + if (g_observer != nullptr) { + delete g_observer; + g_observer = nullptr; + } } void DistributedDBCloudInterfacesSetCloudSchemaTest::CreateUserDBAndTable() diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_auto_launch_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_auto_launch_test.cpp index 52f057a45713c0e87e3b1b05844c3a865e1ed99a..49a7fc40c3dcc7babf84524f01806ff0cc484091 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_auto_launch_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_auto_launch_test.cpp @@ -74,18 +74,19 @@ namespace { {} // If not success, return nullptr and set outErrorNo - ICommunicator *AllocCommunicator(uint64_t commLabel, int &outErrorNo) override + ICommunicator *AllocCommunicator(uint64_t commLabel, int &outErrorNo, const std::string &userId) override { outErrorNo = -E_OUT_OF_MEMORY; return nullptr; } - ICommunicator *AllocCommunicator(const LabelType &commLabel, int &outErrorNo) override + ICommunicator *AllocCommunicator(const LabelType &commLabel, int &outErrorNo, + const std::string &userId) override { outErrorNo = -E_OUT_OF_MEMORY; return nullptr; } - void ReleaseCommunicator(ICommunicator *inCommunicator) override + void ReleaseCommunicator(ICommunicator *inCommunicator, const std::string &userId) override {} int RegCommunicatorLackCallback(const CommunicatorLackCallback &onCommLack, const Finalizer &inOper) override diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_device_identifier_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_device_identifier_test.cpp index 4b35596fc207528147d6c901bd5a1abf67d9ea12..d3e1b8216daad5d4b1b9a5cadeb25b5a8d0b3943 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_device_identifier_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_device_identifier_test.cpp @@ -99,7 +99,7 @@ void DistributedDBDeviceIdentifierTest::SetUp(void) int erroCode = E_OK; g_connection = static_cast(g_store->GetDBConnection(erroCode)); ASSERT_NE(g_connection, nullptr); - g_store->DecObjRef(g_store); + RefObject::DecObjRef(g_store); EXPECT_EQ(erroCode, E_OK); } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_nb_delegate_extend_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_nb_delegate_extend_test.cpp index bb9678ad83751e52d38eb108919bd2ac6c75d74b..998ccacaa1843d4da88cde672bb89f10187bba2b 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_nb_delegate_extend_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_nb_delegate_extend_test.cpp @@ -1161,7 +1161,7 @@ HWTEST_F(DistributedDBInterfacesNBDelegateExtendTest, AbnormalKvStoreTest003, Te EXPECT_EQ(kvStoreObj.ReleaseCloudDataToken(continueStmtToken), E_OK); std::vector syncQuery; std::vector users; - EXPECT_EQ(kvStoreObj.GetCompensatedSyncQuery(syncQuery, users), E_OK); + EXPECT_EQ(kvStoreObj.GetCompensatedSyncQuery(syncQuery, users, true), E_OK); /** * @tc.steps: step2. Call interfaces when class para is null. diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_nb_delegate_rd_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_nb_delegate_rd_test.cpp index 0534b91dd9d3f16d5e7e55fcfd9998afa476d221..75071421dac4493b5290ccf0dc00b7c53d05726a 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_nb_delegate_rd_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_nb_delegate_rd_test.cpp @@ -2309,6 +2309,7 @@ HWTEST_F(DistributedDBInterfacesNBDelegateRdTest, RdGetWaterMarkInfo001, TestSiz g_kvNbDelegatePtr = nullptr; } +#ifdef USE_DISTRIBUTEDDB_CLOUD /** * @tc.name: RdSync001 * @tc.desc:Test sync func with rd. @@ -2428,5 +2429,6 @@ HWTEST_F(DistributedDBInterfacesNBDelegateRdTest, RdGetCloudVersion001, TestSize EXPECT_EQ(g_mgr.DeleteKvStore("RdGetCloudVersion001"), OK); g_kvNbDelegatePtr = nullptr; } +#endif } #endif // USE_RD_KERNEL diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_nb_delegate_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_nb_delegate_test.cpp index 57af4088434f7ba71d803771fa03ba66148a7072..eec05b15a17439c2ff92e48c0466d97367506e0b 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_nb_delegate_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_nb_delegate_test.cpp @@ -1355,6 +1355,80 @@ HWTEST_F(DistributedDBInterfacesNBDelegateTest, SingleVerPutBatch008, TestSize.L EXPECT_EQ(g_mgr.DeleteKvStore("SingleVerPutBatch008"), OK); g_kvNbDelegatePtr = nullptr; } + +/** + * @tc.name: SingleVerPutBatch009 + * @tc.desc: Check for illegal parameters + * @tc.type: FUNC + * @tc.require: + * @tc.author: wangxiangdong + */ +HWTEST_F(DistributedDBInterfacesNBDelegateTest, SingleVerPutBatch009, TestSize.Level1) +{ + /** + * @tc.steps: step1. + * Create and construct three sets of vector , each set of three data contains records: + * (K4, V4) are legal. + * (K5, V5) are not legal. + */ + uint32_t maxValueSize = 64 * 1024 * 1024; + Key legalKey; + DistributedDBToolsUnitTest::GetRandomKeyValue(legalKey, DBConstant::MAX_KEY_SIZE); // 1K + Value legalValue; + DistributedDBToolsUnitTest::GetRandomKeyValue(legalValue, maxValueSize); // 64M + Value illegalValue; + DistributedDBToolsUnitTest::GetRandomKeyValue(illegalValue, maxValueSize + 1); // 64M + 1 + vector entrysl = {KV_ENTRY_1, KV_ENTRY_2, {KEY_3, VALUE_3}}; + vector entrys2 = {{KEY_4, legalValue}}; + vector entrysIllegal = {{KEY_5, illegalValue}}; + /** + * @tc.steps: step2. + * pragrma SET_MAX_VALUE_SIZE of legal and illegal value + */ + const KvStoreNbDelegate::Option option = {true, false}; + g_mgr.SetKvStoreConfig(g_config); + g_mgr.GetKvStore("distributed_SingleVerPutBatch_001", option, g_kvNbDelegateCallback); + ASSERT_TRUE(g_kvNbDelegatePtr != nullptr); + EXPECT_TRUE(g_kvDelegateStatus == OK); + EXPECT_EQ(g_kvNbDelegatePtr->PutLocalBatch(entrys2), INVALID_ARGS); + EXPECT_EQ(g_kvNbDelegatePtr->PutLocal(KEY_4, legalValue), INVALID_ARGS); + uint32_t illegalValueSize = 64 * 1024 * 1024 + 1; + PragmaData input = static_cast(&illegalValueSize); + DBStatus status = g_kvNbDelegatePtr->Pragma(SET_MAX_VALUE_SIZE, input); + EXPECT_TRUE(status == INVALID_ARGS); + input = static_cast(&maxValueSize); + status = g_kvNbDelegatePtr->Pragma(SET_MAX_VALUE_SIZE, input); + EXPECT_TRUE(status == OK); + /** + * @tc.steps: step3. PutBatch/PutLocalBatch/PublishLocal operates on three sets of data. + * @tc.expected: step3. Three operations return OK or INVALID_ARGS. + */ + EXPECT_EQ(g_kvNbDelegatePtr->PutBatch(entrysl), OK); + EXPECT_EQ(g_kvNbDelegatePtr->PutLocalBatch(entrys2), OK); + EXPECT_EQ(g_kvNbDelegatePtr->PutLocal(KEY_4, legalValue), OK); + EXPECT_EQ(g_kvNbDelegatePtr->PutBatch(entrys2), OK); + EXPECT_EQ(g_kvNbDelegatePtr->PutBatch(entrysIllegal), INVALID_ARGS); + EXPECT_EQ(g_kvNbDelegatePtr->PutBatch(entrysIllegal), INVALID_ARGS); + EXPECT_EQ(g_kvNbDelegatePtr->PutLocalBatch(entrysIllegal), INVALID_ARGS); + EXPECT_EQ(g_kvNbDelegatePtr->PutLocal(KEY_5, illegalValue), INVALID_ARGS); + EXPECT_EQ(g_kvNbDelegatePtr->PutLocal(KEY_6, legalValue), OK); + EXPECT_EQ(g_kvNbDelegatePtr->PublishLocal(KEY_6, true, false, nullptr), OK); + + /** + * @tc.steps: step4. Use Get to check data in database. + * @tc.expected: step4. Get value by key successfully. + */ + Value valueReadLocal; + EXPECT_EQ(g_kvNbDelegatePtr->Get(KEY_4, valueReadLocal), OK); + Value valueRead; + EXPECT_EQ(g_kvNbDelegatePtr->GetLocal(KEY_4, valueRead), OK); + EXPECT_EQ(valueRead, valueReadLocal); + EXPECT_EQ(valueRead, legalValue); + + EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK); + EXPECT_EQ(g_mgr.DeleteKvStore("distributed_SingleVerPutBatch_001"), OK); + g_kvNbDelegatePtr = nullptr; +} #endif // LOW_LEVEL_MEM_DEV /** diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_relational_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_relational_test.cpp index 77b8e9fbdfa29f13d209fb36cb03e2609dca4be7..b208abee2874bee66e4415d4c53bdf29f71d531f 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_relational_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_relational_test.cpp @@ -1937,58 +1937,6 @@ HWTEST_F(DistributedDBInterfacesRelationalTest, CreateDistributedTableTest004, T delegate = nullptr; } -/** - * @tc.name: CreateDistributedTableTest005 - * @tc.desc: Test create distributed table again will return ok when rebuild table(miss one field) - * @tc.type: FUNC - * @tc.require: - * @tc.author: zhangshijie - */ -HWTEST_F(DistributedDBInterfacesRelationalTest, CreateDistributedTableTest005, TestSize.Level1) -{ - /** - * @tc.steps:step1. Prepare db and table - * @tc.expected: step1. Return OK. - */ - sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX); - ASSERT_NE(db, nullptr); - EXPECT_EQ(RelationalTestUtils::ExecSql(db, "PRAGMA journal_mode=WAL;"), SQLITE_OK); - std::string t1 = "t1"; - std::string sql = "create table " + t1 + "(key int, value text);"; - EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK); - - /** - * @tc.steps:step2. open relational store, create distributed table with default mode - * @tc.expected: step2. Return OK. - */ - RelationalStoreDelegate *delegate = nullptr; - EXPECT_EQ(g_mgr.OpenStore(g_dbDir + STORE_ID + DB_SUFFIX, STORE_ID, {}, delegate), OK); - ASSERT_NE(delegate, nullptr); - EXPECT_EQ(delegate->CreateDistributedTable("t1"), OK); - - /** - * @tc.steps:step3. drop t1, rebuild t1(miss one column), then reopen store, create distributed table - * @tc.expected: step3. Return OK. - */ - sql = "drop table " + t1; - EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK); - sql = "create table " + t1 + "(key int);"; - EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK); - EXPECT_EQ(g_mgr.CloseStore(delegate), OK); - delegate = nullptr; - EXPECT_EQ(g_mgr.OpenStore(g_dbDir + STORE_ID + DB_SUFFIX, STORE_ID, {}, delegate), OK); - ASSERT_NE(delegate, nullptr); - EXPECT_EQ(delegate->CreateDistributedTable("t1"), OK); - - /** - * @tc.steps:step4. close store - * @tc.expected: step4. Return OK. - */ - EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK); - EXPECT_EQ(g_mgr.CloseStore(delegate), OK); - delegate = nullptr; -} - /** * @tc.name: CloudRelationalStoreTest006 * @tc.desc: Test create distributed table and execute transaction concurrently diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_relational_tracker_table_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_relational_tracker_table_test.cpp index 6028fabbd2529a126d2f4aca83ea077678689c9f..ec16703f44142a2da825075707cc6269e805f935 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_relational_tracker_table_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_relational_tracker_table_test.cpp @@ -143,8 +143,8 @@ namespace { { int index = 0; string querySql = "select json_extract(extend_field, '$.name'), cursor from " + - std::string(DBConstant::RELATIONAL_PREFIX) + tableName + - "_log" + " where data_key <= " + std::to_string(num); + std::string(DBConstant::RELATIONAL_PREFIX) + tableName + "_log" + " where data_key <= " + + std::to_string(num); sqlite3_stmt *stmt = nullptr; EXPECT_EQ(SQLiteUtils::GetStatement(g_db, querySql, stmt), E_OK); while (SQLiteUtils::StepWithRetry(stmt) == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { @@ -344,7 +344,7 @@ HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, TrackerTableTest002, * @tc.expected: step2. Return OK. */ schema.extendColNames = {EXTEND_COL_NAME1}; - SetTrackerTableTest(schema, OK); + SetTrackerTableTest(schema, SCHEMA_MISMATCH); /** * @tc.steps:step1. param valid but extend name is empty @@ -387,6 +387,14 @@ HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, TrackerTableTest003, schema.trackerColNames = LOCAL_TABLE_TRACKER_NAME_SET2; schema.extendColNames = {EXTEND_COL_NAME1}; SetTrackerTableTest(schema, SCHEMA_MISMATCH); + + /** + * @tc.steps:step4. extend name is no exist when tracker col name is enpty + * @tc.expected: step4. Return SCHEMA_MISMATCH. + */ + schema.trackerColNames.clear(); + schema.extendColNames = {EXTEND_COL_NAME1}; + SetTrackerTableTest(schema, SCHEMA_MISMATCH); } /** @@ -966,7 +974,7 @@ HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, TrackerTableTest017, * @tc.steps:step2. Create DEVICE_COOPERATION DistributedTable * @tc.expected: step2. Return NOT_SUPPORT. */ - EXPECT_EQ(g_delegate->CreateDistributedTable(TABLE_NAME2, DEVICE_COOPERATION), DBStatus::NOT_SUPPORT); + EXPECT_EQ(g_delegate->CreateDistributedTable(TABLE_NAME2, DEVICE_COOPERATION), DBStatus::OK); /** * @tc.steps:step3. operator data on table2 @@ -1022,10 +1030,10 @@ HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, TrackerTableTest018, /** * @tc.steps:step2. SetTrackerTable on table2 - * @tc.expected: step2. Return NOT_SUPPORT. + * @tc.expected: step2. Return OK. */ TrackerSchema schema = g_normalSchema1; - EXPECT_EQ(g_delegate->SetTrackerTable(schema), NOT_SUPPORT); + EXPECT_EQ(g_delegate->SetTrackerTable(schema), OK); /** * @tc.steps:step3. operator data on table2 @@ -1036,10 +1044,10 @@ HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, TrackerTableTest018, /** * @tc.steps:step4. unSetTrackerTable - * @tc.expected: step4. Return NOT_SUPPORT. + * @tc.expected: step4. Return OK. */ schema.trackerColNames = {}; - EXPECT_EQ(g_delegate->SetTrackerTable(schema), NOT_SUPPORT); + EXPECT_EQ(g_delegate->SetTrackerTable(schema), OK); /** * @tc.steps:step5. operator data on table2 @@ -1724,6 +1732,35 @@ HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, ExecuteSql008, TestS CloseStore(); } +/** + * @tc.name: ExecuteSql009 + * @tc.desc: Test ExecuteSql update using the parameter "readOnly" + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, ExecuteSql009, TestSize.Level0) +{ + /** + * @tc.steps:step1. init db data + * @tc.expected: step1. Return OK. + */ + uint64_t num = 10; + CreateMultiTable(); + BatchInsertTableName2Data(num); + OpenStore(); + /** + * @tc.steps:step2. ExecuteSql update using the parameter "readOnly" + * @tc.expected: step2. Return OK. + */ + SqlCondition condition; + std::vector records; + condition.readOnly = true; + condition.sql = "update " + TABLE_NAME2 + " set name = 'new_name' where age = 18"; + EXPECT_EQ(g_delegate->ExecuteSql(condition, records), OK); + CloseStore(); +} + /** * @tc.name: ExecuteSql010 * @tc.desc: Test ExecuteSql with temp table @@ -1765,6 +1802,55 @@ HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, ExecuteSql010, TestS CloseStore(); } +/** + * @tc.name: ExecuteSql011 + * @tc.desc: Test ExecuteSql concurrently + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ + +HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, ExecuteSql011, TestSize.Level1) +{ + /** + * @tc.steps:step1. init db data + * @tc.expected: step1. Return OK. + */ + uint64_t num = 10; + CreateMultiTable(); + BatchInsertTableName2Data(num); + OpenStore(); + /** + * @tc.steps:step2. ExecuteSql concurrently + * @tc.expected: step2. Return OK. + */ + std::thread readThread([&]() { + SqlCondition condition; + std::vector records; + condition.readOnly = true; + condition.sql = "select * from " + TABLE_NAME2; + for (int i = 0; i < 100; i++) { + EXPECT_EQ(g_delegate->ExecuteSql(condition, records), OK); + } + }); + std::thread transactionThread([&]() { + SqlCondition condition; + condition.readOnly = true; + std::vector records; + for (int i = 0; i < 100; i++) { + condition.sql = "BEGIN;"; + EXPECT_EQ(g_delegate->ExecuteSql(condition, records), OK); + condition.sql = "select * from " + TABLE_NAME2; + EXPECT_EQ(g_delegate->ExecuteSql(condition, records), OK); + condition.sql = "COMMIT;"; + EXPECT_EQ(g_delegate->ExecuteSql(condition, records), OK); + } + }); + readThread.join(); + transactionThread.join(); + CloseStore(); +} + /** * @tc.name: TrackerTableTest026 * @tc.desc: Test tracker table with case sensitive table name @@ -2188,10 +2274,10 @@ HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, TrackerTableTest035, CloseStore(); } -void SetLowVersionSchema(sqlite3 *db) +void SetLowVersionSchema(sqlite3 *db, const std::string &extendColName) { std::string sql = "update naturalbase_rdb_aux_metadata set value = " - "json_insert(value,'$.TABLES[0].EXTEND_NAME', 'age')" + "json_insert(value,'$.TABLES[0].EXTEND_NAME', '" + extendColName + "')" "where json_valid(value)=1 and json_extract(value, '$.TABLES[0].EXTEND_NAMES') is not null"; EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK); sql = "update naturalbase_rdb_aux_metadata set value = json_remove(value,'$.TABLES[0].EXTEND_NAMES')" @@ -2224,7 +2310,7 @@ HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, TrackerTableTest036, EXPECT_EQ(RelationalTestUtils::ExecSql(g_db, sql), SQLITE_OK); sql = "update " + DBCommon::GetLogTableName(TABLE_NAME2) + " set extend_field = 'old_age'"; EXPECT_EQ(RelationalTestUtils::ExecSql(g_db, sql), SQLITE_OK); - SetLowVersionSchema(g_db); + SetLowVersionSchema(g_db, "age"); CloseStore(); OpenStore(); /** @@ -2265,6 +2351,226 @@ HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, TrackerTableTest036, CloseStore(); } +/** + * @tc.name: TrackerTableTest037 + * @tc.desc: Test open low version db which extend name is empty + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, TrackerTableTest037, TestSize.Level0) +{ + /** + * @tc.steps:step1. Init db + * @tc.expected: step1. Return OK. + */ + CreateMultiTable(); + OpenStore(); + EXPECT_EQ(g_delegate->CreateDistributedTable(TABLE_NAME2, CLOUD_COOPERATION), OK); + TrackerSchema schema = g_normalSchema1; + schema.extendColNames = {EXTEND_COL_NAME3}; + EXPECT_EQ(g_delegate->SetTrackerTable(schema), OK); + /** + * @tc.steps:step2. Set schema as low version which extend name is empty + * @tc.expected: step2. Return E_OK. + */ + SetLowVersionSchema(g_db, ""); + /** + * @tc.steps:step3. close and open DB + * @tc.expected: step3. Return E_OK. + */ + CloseStore(); + OpenStore(); + CloseStore(); +} + +/** + * @tc.name: TrackerTableTest038 + * @tc.desc: Test create distributed table with DEVICE_COOPERATION mode then set tracker table + * @tc.type: FUNC + * @tc.require: + * @tc.author: tankaisheng + */ +HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, TrackerTableTest038, TestSize.Level0) +{ + /** + * @tc.steps:step1. Create DEVICE_COOPERATION DistributedTable + * @tc.expected: step1. Return OK. + */ + CreateMultiTable(); + OpenStore(); + EXPECT_EQ(g_delegate->CreateDistributedTable(TABLE_NAME2, DEVICE_COOPERATION), DBStatus::OK); + + /** + * @tc.steps:step2. SetTrackerTable on table2 + * @tc.expected: step2. Return OK. + */ + TrackerSchema schema = g_normalSchema1; + EXPECT_EQ(g_delegate->SetTrackerTable(schema), OK); + + /** + * @tc.steps:step3. Insert data to table2 then check tracker table data + * @tc.expected: step3. Return E_OK. + */ + uint64_t num = 10; + BatchInsertTableName2Data(num); + std::string checkInsertSql = "select count(*) from " + DBCommon::GetLogTableName(TABLE_NAME2) + + " where cursor='10';"; + ASSERT_EQ(sqlite3_exec(g_db, checkInsertSql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(1), nullptr), SQLITE_OK); + + /** + * @tc.steps:step4. Update data to table2 then check tracker table data + * @tc.expected: step4. Return E_OK. + */ + uint64_t updateNum = 2; + BatchUpdateTableName2Data(updateNum, LOCAL_TABLE_TRACKER_NAME_SET2); + int index = 0; + string checkUpdateSql = "select json_extract(extend_field, '$.name'), cursor from " + + DBCommon::GetLogTableName(TABLE_NAME2) + " where data_key <= " + std::to_string(updateNum); + sqlite3_stmt *stmt = nullptr; + EXPECT_EQ(SQLiteUtils::GetStatement(g_db, checkUpdateSql, stmt), E_OK); + while (SQLiteUtils::StepWithRetry(stmt) == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + std::string extendVal; + EXPECT_EQ(SQLiteUtils::GetColumnTextValue(stmt, 0, extendVal), E_OK); + EXPECT_EQ(extendVal, "1"); + std::string cursorVal; + EXPECT_EQ(SQLiteUtils::GetColumnTextValue(stmt, 1, cursorVal), E_OK); + EXPECT_EQ(cursorVal, std::to_string(num + (++index))); + } + int errCode; + SQLiteUtils::ResetStatement(stmt, true, errCode); + + /** + * @tc.steps:step5. Delete data to table2 then check tracker table data + * @tc.expected: step5. Return E_OK. + */ + BatchDeleteTableName2Data(num / HALF); + std::string checkDeleteSql = "select count(*) from " + DBCommon::GetLogTableName(TABLE_NAME2) + + " where cursor='17';"; + ASSERT_EQ(sqlite3_exec(g_db, checkDeleteSql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(1), nullptr), SQLITE_OK); + CloseStore(); +} + +/** + * @tc.name: TrackerTableTest039 + * @tc.desc: Test SetTrackerTable repeatedly and delete trigger + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, TrackerTableTest039, TestSize.Level0) +{ + /** + * @tc.steps:step1. Init db + * @tc.expected: step1. Return OK. + */ + CreateMultiTable(); + OpenStore(); + EXPECT_EQ(g_delegate->CreateDistributedTable(TABLE_NAME2, CLOUD_COOPERATION), OK); + TrackerSchema schema = g_normalSchema1; + EXPECT_EQ(g_delegate->SetTrackerTable(schema), OK); + /** + * @tc.steps:step2. delete triggers + * @tc.expected: step2. Return OK. + */ + std::vector triggerTypes = {"INSERT", "UPDATE", "DELETE"}; + for (const auto &triggerType : triggerTypes) { + std::string sql = "DROP TRIGGER IF EXISTS naturalbase_rdb_" + TABLE_NAME2 + "_ON_" + triggerType; + SQLiteUtils::ExecuteRawSQL(g_db, sql); + } + /** + * @tc.steps:step3. SetTrackerTable repeatedly + * @tc.expected: step3. Return OK. + */ + EXPECT_EQ(g_delegate->SetTrackerTable(schema), OK); + /** + * @tc.steps:step4. Check if the trigger exists + * @tc.expected: step4. Check OK. + */ + for (const auto &triggerType : triggerTypes) { + std::string sql = "select count(*) from sqlite_master where type = 'trigger' and tbl_name = '" + TABLE_NAME2 + + "' and name = 'naturalbase_rdb_" + TABLE_NAME2 + "_ON_" + triggerType + "';"; + EXPECT_EQ(sqlite3_exec(g_db, sql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(1), nullptr), SQLITE_OK); + } + CloseStore(); +} + +/** + * @tc.name: TrackerTableTest040 + * @tc.desc: Test set tracker table with invalid col name + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, TrackerTableTest040, TestSize.Level0) +{ + /** + * @tc.steps:step1. Init db and init extend field to old version data + * @tc.expected: step1. Return OK. + */ + CreateMultiTable(); + OpenStore(); + EXPECT_EQ(g_delegate->CreateDistributedTable(TABLE_NAME2, CLOUD_COOPERATION), OK); + /** + * @tc.steps:step2. Set tracker table with invalid col name + * @tc.expected: step2. Return E_OK. + */ + TrackerSchema schema = g_normalSchema1; + schema.extendColNames = {EXTEND_COL_NAME1}; + EXPECT_EQ(g_delegate->SetTrackerTable(schema), SCHEMA_MISMATCH); + CloseStore(); +} + +/** + * @tc.name: TrackerTableTest042 + * @tc.desc: tracker table update timestamp + * @tc.type: FUNC + * @tc.require: + * @tc.author: tankaisheng + */ +HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, TrackerTableTest042, TestSize.Level0) +{ + /** + * @tc.steps:step1. SetTrackerTable + * @tc.expected: step1. Return OK. + */ + TrackerSchema schema = g_normalSchema1; + CreateMultiTable(); + OpenStore(); + EXPECT_EQ(g_delegate->SetTrackerTable(schema), OK); + + /** + * @tc.steps:step2. Insert data to table2 + * @tc.expected: step2. Return E_OK. + */ + uint64_t num = 10; + BatchInsertTableName2Data(num); + sqlite3_stmt *stmt = nullptr; + EXPECT_EQ(SQLiteUtils::GetStatement( + g_db, "select timestamp from naturalbase_rdb_aux_worKer2_log where data_key = 1", stmt), E_OK); + ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)); + int64_t beforTime = static_cast(sqlite3_column_int64(stmt, 0)); + int errCode; + SQLiteUtils::ResetStatement(stmt, true, errCode); + + /** + * @tc.steps:step3. CreateDistributedTable then checkout data + * @tc.expected: step3. Return E_OK. + */ + EXPECT_EQ(g_delegate->CreateDistributedTable(TABLE_NAME2, DEVICE_COOPERATION), OK); + stmt = nullptr; + EXPECT_EQ(SQLiteUtils::GetStatement( + g_db, "select timestamp from naturalbase_rdb_aux_worKer2_log where data_key = 1", stmt), E_OK); + ASSERT_EQ(SQLiteUtils::StepWithRetry(stmt, false), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)); + int64_t afterTime = static_cast(sqlite3_column_int64(stmt, 0)); + SQLiteUtils::ResetStatement(stmt, true, errCode); + EXPECT_NE(beforTime, afterTime); + CloseStore(); +} + /** * @tc.name: SchemaStrTest001 * @tc.desc: Test open reOpen stroe when schemaStr is empty @@ -2333,4 +2639,52 @@ HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, SchemaStrTest001, Te EXPECT_EQ(g_delegate->SetTrackerTable(schema), OK); CloseStore(); } + +/** + * @tc.name: TrackerTableTest041 + * @tc.desc: Test cursor increases when set tracker table after create distributed table by DEVICE_COOPERATION type + * @tc.type: FUNC + * @tc.require: + * @tc.author: suyue + */ +HWTEST_F(DistributedDBInterfacesRelationalTrackerTableTest, TrackerTableTest041, TestSize.Level0) +{ + CreateMultiTable(); + OpenStore(); + + /** + * @tc.steps:step1. create distributed table by DEVICE_COOPERATION type and insert data + * @tc.expected: step1. return OK + */ + EXPECT_EQ(g_delegate->CreateDistributedTable(TABLE_NAME2, DEVICE_COOPERATION), DBStatus::OK); + BatchInsertTableName2Data(10); // insert 10 data + + /** + * @tc.steps:step2. set tracker table on table2 and check cursor + * @tc.expected: step2. cursor increases + */ + string querySql = "select cursor from " + std::string(DBConstant::RELATIONAL_PREFIX) + TABLE_NAME2 + "_log"; + sqlite3_stmt *stmt = nullptr; + EXPECT_EQ(SQLiteUtils::GetStatement(g_db, querySql, stmt), E_OK); + while (SQLiteUtils::StepWithRetry(stmt) == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + std::string cursorVal; + EXPECT_EQ(SQLiteUtils::GetColumnTextValue(stmt, 0, cursorVal), E_OK); + EXPECT_EQ(cursorVal, "0"); + } + int errCode; + SQLiteUtils::ResetStatement(stmt, true, errCode); + + TrackerSchema schema = g_normalSchema1; + EXPECT_EQ(g_delegate->SetTrackerTable(schema), WITH_INVENTORY_DATA); + int index = 0; + stmt = nullptr; + EXPECT_EQ(SQLiteUtils::GetStatement(g_db, querySql, stmt), E_OK); + while (SQLiteUtils::StepWithRetry(stmt) == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + std::string cursorVal; + EXPECT_EQ(SQLiteUtils::GetColumnTextValue(stmt, 0, cursorVal), E_OK); + EXPECT_EQ(cursorVal, std::to_string(++index)); + } + SQLiteUtils::ResetStatement(stmt, true, errCode); + CloseStore(); +} } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_single_version_result_set_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_single_version_result_set_test.cpp index 1f222b69182a36e465f1a4e61fcd5f0ec9c46a0e..f1706163806deebe3958b055d8ce258bce789d25 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_single_version_result_set_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_single_version_result_set_test.cpp @@ -113,7 +113,7 @@ void DistributedDBInterfacesSingleVersionResultSetTest::SetUp(void) int errCode = E_OK; g_connection = static_cast(g_store->GetDBConnection(errCode)); ASSERT_NE(g_connection, nullptr); - g_store->DecObjRef(g_store); + RefObject::DecObjRef(g_store); EXPECT_EQ(errCode, E_OK); /** diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_space_management_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_space_management_test.cpp index d362c78de6d26c5fc01c928d19948e61b86fc0f7..86edf5fc43e01b1aa209bf507c60f71c1b3c958a 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_space_management_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_space_management_test.cpp @@ -348,11 +348,11 @@ HWTEST_F(DistributedDBInterfacesSpaceManagementTest, GetKvStoreDiskSize003, Test std::string exceptStoreId; exceptStoreId.clear(); EXPECT_EQ(g_mgr.GetKvStoreDiskSize(exceptStoreId, dbSize), INVALID_ARGS); - EXPECT_EQ(dbSize, 0ull); + EXPECT_EQ(dbSize, 0uLL); exceptStoreId.resize(129, 'X'); EXPECT_EQ(g_mgr.GetKvStoreDiskSize(exceptStoreId, dbSize), INVALID_ARGS); - EXPECT_EQ(dbSize, 0ull); + EXPECT_EQ(dbSize, 0uLL); /** * @tc.steps: step2. Use a valid but not exist storeId to GetKvStoreDiskSize. @@ -360,7 +360,7 @@ HWTEST_F(DistributedDBInterfacesSpaceManagementTest, GetKvStoreDiskSize003, Test */ exceptStoreId.resize(128, 'X'); EXPECT_EQ(g_mgr.GetKvStoreDiskSize(exceptStoreId, dbSize), NOT_FOUND); - EXPECT_EQ(dbSize, 0ull); + EXPECT_EQ(dbSize, 0uLL); /** * @tc.steps: step3/4. Use right storeId to GetKvStoreDiskSize. @@ -432,7 +432,7 @@ HWTEST_F(DistributedDBInterfacesSpaceManagementTest, GetKvStoreDiskSize004, Test */ singleVerDbSize = 0; EXPECT_EQ(g_mgr.GetKvStoreDiskSize(g_storeId, singleVerDbSize), OK); - EXPECT_EQ(singleVerDbSize, 0ull); + EXPECT_EQ(singleVerDbSize, 0uLL); /** * @tc.steps: step6. Close memoryDb. @@ -497,9 +497,9 @@ HWTEST_F(DistributedDBInterfacesSpaceManagementTest, DeleteDbByStoreId001, TestS uint64_t store1DbSize = 0; EXPECT_EQ(g_mgr.GetKvStoreDiskSize(storeId1, store1DbSize), OK); - EXPECT_NE(store1DbSize, 0ull); + EXPECT_NE(store1DbSize, 0uLL); EXPECT_EQ(g_mgr.GetKvStoreDiskSize(storeId2, store1DbSize), OK); - EXPECT_NE(store1DbSize, 0ull); + EXPECT_NE(store1DbSize, 0uLL); /** * @tc.steps: step1. Delete database by storeId 1. @@ -512,14 +512,14 @@ HWTEST_F(DistributedDBInterfacesSpaceManagementTest, DeleteDbByStoreId001, TestS */ store1DbSize = 0; EXPECT_EQ(g_mgr.GetKvStoreDiskSize(storeId1, store1DbSize), NOT_FOUND); - EXPECT_EQ(store1DbSize, 0ull); + EXPECT_EQ(store1DbSize, 0uLL); /** * @tc.steps: step3. Use storeId 2 to get Db size by GetKvStoreDiskSize. * @tc.expected: step3. Return right size and ok. */ EXPECT_EQ(g_mgr.GetKvStoreDiskSize(storeId2, store1DbSize), OK); - EXPECT_NE(store1DbSize, 0ull); + EXPECT_NE(store1DbSize, 0uLL); } /** @@ -535,7 +535,7 @@ HWTEST_F(DistributedDBInterfacesSpaceManagementTest, DeleteDbByStoreId002, TestS uint64_t store1DbSize = 0; EXPECT_EQ(g_mgr.GetKvStoreDiskSize(storeId1, store1DbSize), NOT_FOUND); - EXPECT_EQ(store1DbSize, 0ull); + EXPECT_EQ(store1DbSize, 0uLL); /** * @tc.steps: step1. Delete database by not exist storeId 1. diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_assets_operation_sync_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_assets_operation_sync_test.cpp index 2de7c1e36118e5d05e6d65171b771be6e0abf585..99562a4130e2b3b1ca94789884ff7974a2f9864f 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_assets_operation_sync_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_assets_operation_sync_test.cpp @@ -390,7 +390,8 @@ void DistributedDBCloudAssetsOperationSyncTest::CheckAssetsCount(const std::vect void DistributedDBCloudAssetsOperationSyncTest::ForkDownloadAndRemoveAsset(DBStatus removeStatus, int &downLoadCount, int &removeCount) { - virtualAssetLoader_->ForkDownload([this, &downLoadCount](std::map &assets) { + virtualAssetLoader_->ForkDownload([this, &downLoadCount](const std::string &tableName, + std::map &assets) { downLoadCount++; if (downLoadCount == 1) { std::string sql = "UPDATE " + tableName_ + " SET assets = NULL WHERE id = 0;"; @@ -1004,7 +1005,7 @@ HWTEST_F(DistributedDBCloudAssetsOperationSyncTest, SyncWithAssetOperation011, T UpdateLocalTableRecord(tableName_, 0, 1); return OK; }); - virtualAssetLoader_->ForkDownload([](std::map &assets) { + virtualAssetLoader_->ForkDownload([](const std::string &tableName, std::map &assets) { EXPECT_TRUE(false); }); BlockSync(query, delegate_); @@ -1087,6 +1088,42 @@ HWTEST_F(DistributedDBCloudAssetsOperationSyncTest, SyncWithAssetOperation013, T reinterpret_cast(cursor), nullptr), SQLITE_OK); } +/** + * @tc.name: SyncWithAssetOperation014 + * @tc.desc: Test device data does not change while sync and cursor will not changes + * @tc.type: FUNC + * @tc.require: + * @tc.author: caihaoting + */ +HWTEST_F(DistributedDBCloudAssetsOperationSyncTest, SyncWithAssetOperation014, TestSize.Level0) +{ + /** + * @tc.steps:step1. Insert 5 records and sync. + * @tc.expected: step1. ok. + */ + const int actualCount = 5; + RelationalTestUtils::InsertCloudRecord(0, actualCount, tableName_, virtualCloudDb_); + InsertUserTableRecord(tableName_, 0, actualCount); + Query query = Query::Select().FromTable({ tableName_ }); + BlockSync(query, delegate_); + /** + * @tc.steps:step2. modify data and sync. + * @tc.expected: step2. ok. + */ + UpdateLocalAssetRecord(tableName_, 0, 1); + const int cursor = 6; + std::string sql = "SELECT cursor FROM " + DBCommon::GetLogTableName(tableName_) + " where data_key=1"; + EXPECT_EQ(sqlite3_exec(db_, sql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(cursor), nullptr), SQLITE_OK); + BlockSync(query, delegate_); + /** + * @tc.steps:step3. check modified data cursor and cursor is not changed. + * @tc.expected: step3. ok. + */ + EXPECT_EQ(sqlite3_exec(db_, sql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(cursor), nullptr), SQLITE_OK); +} + /** * @tc.name: IgnoreRecord001 * @tc.desc: Download Assets When local assets was removed @@ -1675,8 +1712,8 @@ HWTEST_F(DistributedDBCloudAssetsOperationSyncTest, BatchNormalDownloadAsset001, Query query = Query::Select().FromTable({ tableName_ }); BlockSync(query, delegate_); - EXPECT_EQ(virtualAssetLoader_->GetBatchDownloadCount(), 2); // download 2 times - EXPECT_EQ(virtualAssetLoader_->GetBatchRemoveCount(), 0); // remove 0 times + EXPECT_EQ(virtualAssetLoader_->GetBatchDownloadCount(), 2u); // download 2 times + EXPECT_EQ(virtualAssetLoader_->GetBatchRemoveCount(), 0u); // remove 0 times virtualAssetLoader_->Reset(); RuntimeContext::GetInstance()->SetBatchDownloadAssets(false); } @@ -1706,14 +1743,14 @@ HWTEST_F(DistributedDBCloudAssetsOperationSyncTest, BatchAbnormalDownloadAsset00 Query query = Query::Select().FromTable({ tableName_ }); BlockSync(query, delegate_); - EXPECT_EQ(virtualAssetLoader_->GetBatchDownloadCount(), 1); // download 1 times - EXPECT_EQ(virtualAssetLoader_->GetBatchRemoveCount(), 0); // remove 0 times + EXPECT_EQ(virtualAssetLoader_->GetBatchDownloadCount(), 1u); // download 1 times + EXPECT_EQ(virtualAssetLoader_->GetBatchRemoveCount(), 0u); // remove 0 times virtualAssetLoader_->Reset(); virtualAssetLoader_->ForkBatchDownload(nullptr); BlockSync(query, delegate_); - EXPECT_EQ(virtualAssetLoader_->GetBatchDownloadCount(), 2); // download 2 times - EXPECT_EQ(virtualAssetLoader_->GetBatchRemoveCount(), 0); // remove 0 times + EXPECT_EQ(virtualAssetLoader_->GetBatchDownloadCount(), 2u); // download 2 times + EXPECT_EQ(virtualAssetLoader_->GetBatchRemoveCount(), 0u); // remove 0 times RuntimeContext::GetInstance()->SetBatchDownloadAssets(false); } } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_check_sync_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_check_sync_test.cpp index 3401a31cfb97a604fc785e384ccf51e77d3734a9..0c0583a5a0881626ae2f8389faccd0610345deea 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_check_sync_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_check_sync_test.cpp @@ -1041,6 +1041,60 @@ HWTEST_F(DistributedDBCloudCheckSyncTest, CloudSyncTest008, TestSize.Level0) virtualCloudDb_->ForkInsertConflict(nullptr); } +/** + * @tc.name: CloudSyncTest009 + * @tc.desc: reopen database and sync + * @tc.type: FUNC + * @tc.require: + * @tc.author: wangxiangdong + */ +HWTEST_F(DistributedDBCloudCheckSyncTest, CloudSyncTest009, TestSize.Level0) +{ + /** + * @tc.steps: step1. insert 1 record to user table + * @tc.expected: step1. OK. + */ + const int actualCount = 1; + InsertUserTableRecord(tableName_, actualCount); + /** + * @tc.steps: step2. sync data to cloud + * @tc.expected: step2. OK. + */ + Query query = Query::Select().FromTable({ tableName_ }); + BlockSync(query, delegate_, g_actualDBStatus); + CheckCloudTableCount(tableName_, 1); + /** + * @tc.steps: step3. drop data table then close db + * @tc.expected: step3. OK. + */ + std::string deleteSql = "DROP TABLE IF EXISTS " + tableName_ + ";"; + EXPECT_EQ(SQLiteUtils::ExecuteRawSQL(db_, deleteSql), DBStatus::OK); + EXPECT_EQ(mgr_->CloseStore(delegate_), DBStatus::OK); + delegate_ = nullptr; + /** + * @tc.steps: step4. recreate data table and reopen database + * @tc.expected: step4. OK. + */ + EXPECT_EQ(SQLiteUtils::ExecuteRawSQL(db_, g_createSQL), DBStatus::OK); + RelationalStoreDelegate::Option option; + ASSERT_EQ(mgr_->OpenStore(storePath_, STORE_ID_1, option, delegate_), DBStatus::OK); + ASSERT_NE(delegate_, nullptr); + ASSERT_EQ(delegate_->CreateDistributedTable(tableName_, CLOUD_COOPERATION), DBStatus::OK); + ASSERT_EQ(delegate_->SetCloudDB(virtualCloudDb_), DBStatus::OK); + ASSERT_EQ(delegate_->SetIAssetLoader(virtualAssetLoader_), DBStatus::OK); + DataBaseSchema dataBaseSchema = GetSchema(); + ASSERT_EQ(delegate_->SetCloudDbSchema(dataBaseSchema), DBStatus::OK); + communicatorAggregator_ = new (std::nothrow) VirtualCommunicatorAggregator(); + ASSERT_TRUE(communicatorAggregator_ != nullptr); + RuntimeContext::GetInstance()->SetCommunicatorAggregator(communicatorAggregator_); + /** + * @tc.steps: step5. sync and cloud data should be deleted + * @tc.expected: step5. OK. + */ + BlockSync(query, delegate_, g_actualDBStatus); + CheckCloudTableCount(tableName_, 0); +} + /** * @tc.name: CloudSyncObserverTest001 * @tc.desc: test cloud sync multi observer diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_meta_data_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_meta_data_test.cpp index ccfb326a335867321f95b7d1736bde60ce4fe6e2..df5c8f295eddc10cde2593a6598f937c6f1d2210 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_meta_data_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_meta_data_test.cpp @@ -239,11 +239,11 @@ namespace { EXPECT_EQ(proxyObj.GetPrimaryColNamesWithAssetsFields(TABLE_NAME_1, colNames, assetFields), -E_INVALID_ARGS); VBucket assetInfo; DataInfoWithLog log; - EXPECT_EQ(proxyObj.GetInfoByPrimaryKeyOrGid(TABLE_NAME_1, assetInfo, log, assetInfo), + EXPECT_EQ(proxyObj.GetInfoByPrimaryKeyOrGid(TABLE_NAME_1, assetInfo, true, log, assetInfo), -E_INVALID_DB); EXPECT_EQ(proxyObj.FillCloudAssetForDownload(TABLE_NAME_1, assetInfo, true), -E_INVALID_DB); const Bytes hashKey; - std::pair res = proxyObj.GetAssetsByGidOrHashKey(TABLE_NAME_1, "", hashKey, assetInfo); + std::pair res = proxyObj.GetAssetsByGidOrHashKey(TABLE_NAME_1, false, "", hashKey, assetInfo); EXPECT_EQ(res.first, -E_INVALID_DB); std::string str = proxyObj.GetIdentify(); const std::string emptyStr = ""; @@ -284,7 +284,7 @@ namespace { proxyObj.FillCloudGidIfSuccess(OpType::INSERT, data); std::vector syncQuery; std::vector users; - EXPECT_EQ(proxyObj.GetCompensatedSyncQuery(syncQuery, users), -E_INVALID_DB); + EXPECT_EQ(proxyObj.GetCompensatedSyncQuery(syncQuery, users, true), -E_INVALID_DB); proxyObj.OnSyncFinish(); proxyObj.OnUploadStart(); std::shared_ptr cloudSchema; diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_save_cloud_data_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_save_cloud_data_test.cpp index 80ac40adfd2dec3cdd5266ac4c04a9a15a46d6cb..87776736c2365901da8beb1b6e2f8e44192160f2 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_save_cloud_data_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_save_cloud_data_test.cpp @@ -283,7 +283,8 @@ namespace { vBucket[CloudDbConstant::GID_FIELD] = gidStr; DataInfoWithLog dataInfoWithLog; VBucket assetInfo; - EXPECT_EQ(storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, dataInfoWithLog, assetInfo), expectCode); + EXPECT_EQ(storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, true, dataInfoWithLog, assetInfo), + expectCode); if (expectCode == E_OK) { if (pkType == PrimaryKeyType::SINGLE_PRIMARY_KEY) { int64_t val = -1; @@ -465,7 +466,7 @@ namespace { vBucket[CloudDbConstant::GID_FIELD] = gid; DataInfoWithLog dataInfoWithLog; VBucket assetInfo; - EXPECT_EQ(storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, dataInfoWithLog, assetInfo), E_OK); + EXPECT_EQ(storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, true, dataInfoWithLog, assetInfo), E_OK); EXPECT_EQ(storageProxy->Commit(), E_OK); } @@ -546,7 +547,8 @@ namespace { vBucket[CloudDbConstant::GID_FIELD] = gid; DataInfoWithLog dataInfoWithLog; VBucket assetInfo; - EXPECT_EQ(storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, dataInfoWithLog, assetInfo), expectCode); + EXPECT_EQ(storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, true, dataInfoWithLog, assetInfo), + expectCode); EXPECT_EQ(storageProxy->Commit(), E_OK); } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_task_merge_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_task_merge_test.cpp index 3f793fb2bd7f870862cb23d4400584471c764f56..f991b7164963aaccf9e9fd833d06359b58cf00d5 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_task_merge_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/cloud/distributeddb_cloud_task_merge_test.cpp @@ -102,6 +102,8 @@ protected: void InsertUserTableRecord(const std::string &tableName, int64_t recordCounts, int64_t begin = 0); void CheckCloudTableCount(const std::vector &tableName, int64_t expectCount); void SetForkQueryForCloudMergeSyncTest001(std::atomic &count); + static SyncProcessCallback GetProcessCallback(const std::function &checkFinish, + std::mutex &callbackMutex, std::condition_variable &callbackCv, size_t &finishCount); std::string testDir_; std::string storePath_; sqlite3 *db_ = nullptr; @@ -247,6 +249,27 @@ void DistributedDBCloudTaskMergeTest::SetForkQueryForCloudMergeSyncTest001(std:: }); } +SyncProcessCallback DistributedDBCloudTaskMergeTest::GetProcessCallback( + const std::function &checkFinish, std::mutex &callbackMutex, + std::condition_variable &callbackCv, size_t &finishCount) +{ + return [checkFinish, &callbackCv, &callbackMutex, &finishCount](const std::map &process) { + for (const auto &item: process) { + if (item.second.process == DistributedDB::FINISHED) { + if (checkFinish) { + checkFinish(item.second.errCode); + } + { + std::lock_guard callbackAutoLock(callbackMutex); + finishCount++; + } + LOGW("current finish %zu", finishCount); + callbackCv.notify_one(); + } + } + }; +} + /** * @tc.name: CloudSyncMergeTaskTest001 * @tc.desc: test merge sync task @@ -278,18 +301,7 @@ HWTEST_F(DistributedDBCloudTaskMergeTest, CloudSyncMergeTaskTest001, TestSize.Le std::mutex callbackMutex; std::condition_variable callbackCv; size_t finishCount = 0u; - auto callback1 = [&callbackCv, &callbackMutex, &finishCount](const std::map &process) { - for (const auto &item: process) { - if (item.second.process == DistributedDB::FINISHED) { - { - std::lock_guard callbackAutoLock(callbackMutex); - finishCount++; - } - LOGW("current finish %zu", finishCount); - callbackCv.notify_one(); - } - } - }; + auto callback1 = GetProcessCallback(nullptr, callbackMutex, callbackCv, finishCount); Query normalQuery2 = Query::Select().FromTable({ tableNameB_ }); PrepareOption(option, normalQuery2, true); @@ -461,5 +473,34 @@ HWTEST_F(DistributedDBCloudTaskMergeTest, CloudSyncMergeTaskTest003, TestSize.Le syncThread3.join(); syncThread4.join(); } + +/** + * @tc.name: CloudSyncMergeTaskTest004 + * @tc.desc: test merge sync task with async download asset + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBCloudTaskMergeTest, CloudSyncMergeTaskTest004, TestSize.Level0) +{ + size_t finishCount = 0u; + std::mutex callbackMutex; + std::condition_variable callbackCv; + auto callback = GetProcessCallback([](DBStatus status) { + EXPECT_EQ(status, OK); + }, callbackMutex, callbackCv, finishCount); + + Query normalQuery = Query::Select().FromTable({ tableNameA_ }); + CloudSyncOption option; + PrepareOption(option, normalQuery, true); + ASSERT_EQ(delegate_->Sync(option, callback), OK); + option.asyncDownloadAssets = true; + ASSERT_EQ(delegate_->Sync(option, callback), OK); + + std::unique_lock callbackLock(callbackMutex); + callbackCv.wait(callbackLock, [&finishCount]() { + return (finishCount >= 2u); // download 2 times + }); +} } #endif \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_multi_ver_vacuum_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_multi_ver_vacuum_test.cpp index 0fa56611e95e0d704f0adf69a4fe1f564d827db5..d6d3e570ef4b41131c73a1bce26486193a141ac3 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_multi_ver_vacuum_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_multi_ver_vacuum_test.cpp @@ -51,7 +51,7 @@ namespace { bool CheckVacuumTaskStatus(const MultiVerVacuum &inVacuum, const string &inDbIdentifier, VacuumTaskStatus expectStatus, uint8_t repeatLimit = 5, uint32_t repeatInterval = 100) // 5 times, 100 ms { - return RepeatCheckAsyncResult([&inVacuum, &inDbIdentifier, expectStatus]()->bool { + return RepeatCheckAsyncResult([inVacuum, inDbIdentifier, expectStatus]()->bool { VacuumTaskStatus outStatus = VacuumTaskStatus::RUN_WAIT; int errCode = inVacuum.QueryStatus(inDbIdentifier, outStatus); return errCode == E_OK && outStatus == expectStatus; diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7cb7f1e71bf6a53640da1ab071f0a9f5b8157f7b --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_rdb_collaboration_test.cpp @@ -0,0 +1,1225 @@ +/* + * Copyright (c) 2024 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 "cloud_db_sync_utils_test.h" +#include "distributeddb_data_generate_unit_test.h" +#include "distributeddb_tools_unit_test.h" +#include "rdb_data_generator.h" +#include "relational_store_client.h" +#include "relational_store_manager.h" +#include "relational_virtual_device.h" +#include "virtual_communicator_aggregator.h" + +using namespace testing::ext; +using namespace DistributedDB; +using namespace DistributedDBUnitTest; +using namespace std; + +namespace { +string g_testDir; + +class DistributedDBRDBCollaborationTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; +protected: + static DataBaseSchema GetSchema(); + static TableSchema GetTableSchema(bool upgrade = false, bool pkInStr = false); + void InitStore(); + void InitDelegate(DistributedTableMode mode = DistributedTableMode::COLLABORATION); + void CloseDb(); + std::string storePath_; + sqlite3 *db_ = nullptr; + RelationalStoreDelegate *delegate_ = nullptr; + VirtualCommunicatorAggregator *communicatorAggregator_ = nullptr; + RelationalVirtualDevice *deviceB_ = nullptr; + RelationalStoreObserverUnitTest *delegateObserver_ = nullptr; + + static constexpr const char *DEVICE_SYNC_TABLE = "DEVICE_SYNC_TABLE"; + static constexpr const char *DEVICE_SYNC_TABLE_UPGRADE = "DEVICE_SYNC_TABLE_UPGRADE"; + static constexpr const char *DEVICE_SYNC_TABLE_AUTOINCREMENT = "DEVICE_SYNC_TABLE_AUTOINCREMENT"; + static constexpr const char *CLOUD_SYNC_TABLE = "CLOUD_SYNC_TABLE"; +}; + +void DistributedDBRDBCollaborationTest::SetUpTestCase() +{ + DistributedDBToolsUnitTest::TestDirInit(g_testDir); + if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) { + LOGE("rm test db files error!"); + } +} + +void DistributedDBRDBCollaborationTest::TearDownTestCase() +{ + if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) { + LOGE("rm test db files error!"); + } +} + +void DistributedDBRDBCollaborationTest::SetUp() +{ + DistributedDBToolsUnitTest::PrintTestCaseInfo(); + InitStore(); + communicatorAggregator_ = new (std::nothrow) VirtualCommunicatorAggregator(); + ASSERT_TRUE(communicatorAggregator_ != nullptr); + RuntimeContext::GetInstance()->SetCommunicatorAggregator(communicatorAggregator_); + + deviceB_ = new (std::nothrow) RelationalVirtualDevice(UnitTestCommonConstant::DEVICE_B); + ASSERT_NE(deviceB_, nullptr); + auto syncInterfaceB = new (std::nothrow) VirtualRelationalVerSyncDBInterface(); + ASSERT_NE(syncInterfaceB, nullptr); + ASSERT_EQ(deviceB_->Initialize(communicatorAggregator_, syncInterfaceB), E_OK); +} + +void DistributedDBRDBCollaborationTest::TearDown() +{ + CloseDb(); + if (deviceB_ != nullptr) { + delete deviceB_; + deviceB_ = nullptr; + } + if (delegateObserver_ != nullptr) { + delete delegateObserver_; + delegateObserver_ = nullptr; + } + if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) { + LOGE("rm test db files error."); + } + RuntimeContext::GetInstance()->SetCommunicatorAggregator(nullptr); + communicatorAggregator_ = nullptr; +} + +DataBaseSchema DistributedDBRDBCollaborationTest::GetSchema() +{ + DataBaseSchema schema; + auto table = GetTableSchema(); + schema.tables.push_back(table); + table.name = CLOUD_SYNC_TABLE; + schema.tables.push_back(table); + schema.tables.push_back(GetTableSchema(true)); + return schema; +} + +TableSchema DistributedDBRDBCollaborationTest::GetTableSchema(bool upgrade, bool pkInStr) +{ + TableSchema tableSchema; + tableSchema.name = upgrade ? DEVICE_SYNC_TABLE_UPGRADE : DEVICE_SYNC_TABLE; + Field field; + if (!pkInStr) { + field.primary = true; + } + field.type = TYPE_INDEX; + field.colName = "pk"; + tableSchema.fields.push_back(field); + field.primary = false; + field.colName = "int_field1"; + tableSchema.fields.push_back(field); + field.colName = "int_field2"; + tableSchema.fields.push_back(field); + field.colName = "123"; + field.type = TYPE_INDEX; + if (pkInStr) { + field.primary = true; + } + tableSchema.fields.push_back(field); + if (upgrade) { + field.primary = false; + field.colName = "int_field_upgrade"; + field.type = TYPE_INDEX; + tableSchema.fields.push_back(field); + } + return tableSchema; +} + +void DistributedDBRDBCollaborationTest::InitStore() +{ + if (storePath_.empty()) { + storePath_ = g_testDir + "/" + STORE_ID_1 + ".db"; + } + db_ = RelationalTestUtils::CreateDataBase(storePath_); + ASSERT_NE(db_, nullptr); + auto schema = GetSchema(); + EXPECT_EQ(RDBDataGenerator::InitDatabase(schema, *db_), SQLITE_OK); +} + +void DistributedDBRDBCollaborationTest::InitDelegate(DistributedTableMode mode) +{ + if (delegateObserver_ == nullptr) { + delegateObserver_ = new (std::nothrow) RelationalStoreObserverUnitTest(); + ASSERT_NE(delegateObserver_, nullptr); + delegateObserver_->SetCallbackDetailsType(static_cast(CallbackDetailsType::DETAILED)); + } + RelationalStoreManager mgr(APP_ID, USER_ID); + RelationalStoreDelegate::Option option; + option.tableMode = mode; + option.observer = delegateObserver_; + ASSERT_EQ(mgr.OpenStore(storePath_, STORE_ID_1, option, delegate_), OK); + ASSERT_NE(delegate_, nullptr); +} + +void DistributedDBRDBCollaborationTest::CloseDb() +{ + if (db_ != nullptr) { + sqlite3_close_v2(db_); + db_ = nullptr; + } + if (delegate_ != nullptr) { + RelationalStoreManager mgr(APP_ID, USER_ID); + EXPECT_EQ(mgr.CloseStore(delegate_), OK); + delegate_ = nullptr; + } +} + +/** + * @tc.name: SetSchema001 + * @tc.desc: Test set distributed schema. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema001, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table and cloud table in COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + auto schema = GetSchema(); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + LOGI("[DistributedDBCloudAsyncDownloadAssetsTest] CreateDistributedTable %s", DEVICE_SYNC_TABLE); + EXPECT_EQ(delegate_->CreateDistributedTable(CLOUD_SYNC_TABLE, TableSyncType::CLOUD_COOPERATION), OK); + LOGI("[DistributedDBCloudAsyncDownloadAssetsTest] CreateDistributedTable %s", CLOUD_SYNC_TABLE); + auto distributedSchema = RDBDataGenerator::ParseSchema(schema); + for (auto &table : distributedSchema.tables) { + for (auto &field : table.fields) { + field.isSpecified = false; + } + } + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), OK); + /** + * @tc.steps: step2. Insert update delete local + * @tc.expected: step2.ok + */ + EXPECT_EQ(RDBDataGenerator::InsertLocalDBData(0, 1, db_, GetTableSchema()), E_OK); + EXPECT_EQ(RegisterClientObserver(db_, [](ClientChangedData &changedData) { + for (const auto &table : changedData.tableData) { + EXPECT_FALSE(table.second.isTrackedDataChange); + EXPECT_TRUE(table.second.isP2pSyncDataChange); + } + }), OK); + EXPECT_EQ(RDBDataGenerator::UpdateLocalDBData(0, 1, db_, GetTableSchema()), E_OK); + UnRegisterClientObserver(db_); +} + +/** + * @tc.name: SetSchema002 + * @tc.desc: Test upgrade table mode. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema002, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create cloud table in SPLIT_BY_DEVICE + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate(DistributedTableMode::SPLIT_BY_DEVICE)); + EXPECT_EQ(delegate_->CreateDistributedTable(CLOUD_SYNC_TABLE, TableSyncType::CLOUD_COOPERATION), OK); + LOGI("[DistributedDBCloudAsyncDownloadAssetsTest] CreateDistributedTable %s", CLOUD_SYNC_TABLE); + CloseDb(); + /** + * @tc.steps: step2. Create device table in COLLABORATION + * @tc.expected: step2.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + auto schema = GetSchema(); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + EXPECT_EQ(delegate_->SetDistributedSchema(RDBDataGenerator::ParseSchema(schema)), OK); + LOGI("[DistributedDBCloudAsyncDownloadAssetsTest] CreateDistributedTable %s", DEVICE_SYNC_TABLE); + CloseDb(); +} + +/** + * @tc.name: SetSchema003 + * @tc.desc: Test set distributed schema. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema003, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table and cloud table in COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + auto schema = GetSchema(); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + LOGI("[DistributedDBCloudAsyncDownloadAssetsTest] CreateDistributedTable %s", DEVICE_SYNC_TABLE); + EXPECT_EQ(delegate_->SetDistributedSchema(RDBDataGenerator::ParseSchema(schema, true)), OK); + /** + * @tc.steps: step2. Insert update delete local + * @tc.expected: step2.ok + */ + EXPECT_EQ(RDBDataGenerator::InsertLocalDBData(0, 1, db_, GetTableSchema()), E_OK); + EXPECT_EQ(RegisterClientObserver(db_, [](ClientChangedData &changedData) { + for (const auto &table : changedData.tableData) { + EXPECT_FALSE(table.second.isTrackedDataChange); + EXPECT_FALSE(table.second.isP2pSyncDataChange); + } + }), OK); + EXPECT_EQ(RDBDataGenerator::UpdateLocalDBData(0, 1, db_, GetTableSchema()), E_OK); + UnRegisterClientObserver(db_); +} + +/** + * @tc.name: SetSchema004 + * @tc.desc: Test create distributed table without schema. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema004, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table and cloud table in COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); +} + +DistributedSchema GetDistributedSchema(const std::string &tableName, const std::vector &fields) +{ + DistributedTable table; + table.tableName = tableName; + for (const auto &fieldName : fields) { + DistributedField field; + field.isP2pSync = true; + field.colName = fieldName; + table.fields.push_back(field); + } + DistributedSchema schema; + schema.tables.push_back(table); + return schema; +} + +/** + * @tc.name: SetSchema005 + * @tc.desc: Test set distributed schema with invalid schema + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema005, TestSize.Level0) +{ + /** + * @tc.steps: step1. Prepare db + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate(DistributedTableMode::COLLABORATION)); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + /** + * @tc.steps: step2. Test set distributed schema with invalid table name + * @tc.expected: step2. return SCHEMA_MISMATCH + */ + DistributedSchema schema1 = GetDistributedSchema("", {}); + EXPECT_EQ(delegate_->SetDistributedSchema(schema1), SCHEMA_MISMATCH); + DistributedSchema schema2 = GetDistributedSchema("xxx", {}); + EXPECT_EQ(delegate_->SetDistributedSchema(schema2), SCHEMA_MISMATCH); + /** + * @tc.steps: step3. Test set distributed schema with invalid fields + * @tc.expected: step3. return SCHEMA_MISMATCH OR DISTRIBUTED_FIELD_DECREASE + */ + DistributedSchema schema3 = GetDistributedSchema(DEVICE_SYNC_TABLE, {}); + EXPECT_EQ(delegate_->SetDistributedSchema(schema3), SCHEMA_MISMATCH); + DistributedSchema schema4 = GetDistributedSchema(DEVICE_SYNC_TABLE, {"xxx"}); + EXPECT_EQ(delegate_->SetDistributedSchema(schema4), SCHEMA_MISMATCH); + DistributedSchema schema5 = GetDistributedSchema(DEVICE_SYNC_TABLE, {"pk", "int_field1"}); + EXPECT_EQ(delegate_->SetDistributedSchema(schema5), OK); + DistributedSchema schema6 = GetDistributedSchema(DEVICE_SYNC_TABLE, {"pk"}); + EXPECT_EQ(delegate_->SetDistributedSchema(schema6), DISTRIBUTED_FIELD_DECREASE); + + /** + * @tc.steps: step4. Test set distributed schema with int_field1 but isP2pSync is false + * @tc.expected: step4. return DISTRIBUTED_FIELD_DECREASE + */ + DistributedSchema distributedSchema1 = {0, {{DEVICE_SYNC_TABLE, {{"int_field1", false}}}}}; + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema1), DISTRIBUTED_FIELD_DECREASE); +} + +/** + * @tc.name: SetSchema006 + * @tc.desc: Test register client observer + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema006, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table and cloud table in COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + DistributedSchema distributedSchema = GetDistributedSchema(DEVICE_SYNC_TABLE, {"pk", "int_field1"}); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), OK); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + TrackerSchema trackerSchema = { + .tableName = DEVICE_SYNC_TABLE, .extendColNames = {"int_field1"}, .trackerColNames = {"int_field1"} + }; + EXPECT_EQ(delegate_->SetTrackerTable(trackerSchema), OK); + /** + * @tc.steps: step2. Insert update local + * @tc.expected: step2.ok + */ + EXPECT_EQ(RegisterClientObserver(db_, [](ClientChangedData &changedData) { + for (const auto &table : changedData.tableData) { + EXPECT_TRUE(table.second.isTrackedDataChange); + EXPECT_TRUE(table.second.isP2pSyncDataChange); + } + }), OK); + EXPECT_EQ(RDBDataGenerator::InsertLocalDBData(0, 1, db_, GetTableSchema()), E_OK); + std::string sql = "update " + std::string(DEVICE_SYNC_TABLE) + " set int_field1 = int_field1 + 1 where pk = 0"; + EXPECT_EQ(SQLiteUtils::ExecuteRawSQL(db_, sql), E_OK); + + /** + * @tc.steps: step3. Insert data that pk = 0 and sync to real device + * @tc.expected: step3.ok + */ + auto schema = GetSchema(); + deviceB_->SetDistributedSchema(distributedSchema); + auto tableSchema = GetTableSchema(); + ASSERT_EQ(RDBDataGenerator::InsertVirtualLocalDBData(0, 1, deviceB_, tableSchema), E_OK); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(tableSchema.name, db_, deviceB_), E_OK); + Query query = Query::Select(tableSchema.name); + DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PULL_ONLY, OK, {deviceB_->GetDeviceId()}); + + /** + * @tc.steps: step4. Check extend_field + * @tc.expected: step4.ok + */ + sql = "select count(*) from " + std::string(DBConstant::RELATIONAL_PREFIX) + std::string(DEVICE_SYNC_TABLE) + "_log" + " where json_extract(extend_field, '$.int_field1')=0"; + EXPECT_EQ(sqlite3_exec(db_, sql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(1u), nullptr), SQLITE_OK); + UnRegisterClientObserver(db_); +} + +std::string GetTriggerSql(const std::string &tableName, const std::string &triggerTypeName, sqlite3 *db) +{ + if (db == nullptr) { + return ""; + } + std::string sql = "select sql from sqlite_master where type = 'trigger' and tbl_name = '" + tableName + + "' and name = 'naturalbase_rdb_" + tableName + "_ON_" + triggerTypeName + "';"; + sqlite3_stmt *stmt = nullptr; + int errCode = SQLiteUtils::GetStatement(db, sql, stmt); + if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_OK)) { + LOGE("[GetTriggerSql] prepare statement failed(%d), sys(%d), errmsg(%s)", errCode, errno, sqlite3_errmsg(db)); + return ""; + } + errCode = SQLiteUtils::StepWithRetry(stmt); + if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + LOGE("[GetTriggerSql] execute statement failed(%d), sys(%d), errmsg(%s)", errCode, errno, sqlite3_errmsg(db)); + return ""; + } + const std::string triggerSql = std::string(reinterpret_cast(sqlite3_column_text(stmt, 0))); + int ret = E_OK; + SQLiteUtils::ResetStatement(stmt, true, ret); + return triggerSql; +} + +/** + * @tc.name: SetSchema007 + * @tc.desc: Test whether setting the schema multiple times will refresh the trigger + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema007, TestSize.Level0) +{ + /** + * @tc.steps: step1. Prepare db + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate(DistributedTableMode::COLLABORATION)); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + DistributedSchema schema1 = GetDistributedSchema(DEVICE_SYNC_TABLE, {"pk"}); + EXPECT_EQ(delegate_->SetDistributedSchema(schema1), OK); + /** + * @tc.steps:step2. delete triggers + * @tc.expected: step2. Return OK. + */ + std::string oldInsertTriggerSql = GetTriggerSql(DEVICE_SYNC_TABLE, "INSERT", db_); + std::string oldUpdateTriggerSql = GetTriggerSql(DEVICE_SYNC_TABLE, "UPDATE", db_); + std::string oldDeleteTriggerSql = GetTriggerSql(DEVICE_SYNC_TABLE, "DELETE", db_); + EXPECT_FALSE(oldInsertTriggerSql.empty() || oldUpdateTriggerSql.empty() || oldDeleteTriggerSql.empty()); + std::vector triggerTypes = {"INSERT", "UPDATE", "DELETE"}; + for (const auto &triggerType : triggerTypes) { + std::string sql = "DROP TRIGGER IF EXISTS naturalbase_rdb_" + std::string(DEVICE_SYNC_TABLE) + "_ON_" + + triggerType; + SQLiteUtils::ExecuteRawSQL(db_, sql); + } + /** + * @tc.steps:step3. Set distributed schema and check if the trigger exists + * @tc.expected: step3. Check OK. + */ + DistributedSchema schema2 = GetDistributedSchema(DEVICE_SYNC_TABLE, {"pk", "int_field1"}); + EXPECT_EQ(delegate_->SetDistributedSchema(schema2), OK); + for (const auto &triggerType : triggerTypes) { + std::string sql = "select count(*) from sqlite_master where type = 'trigger' and tbl_name = '" + + std::string(DEVICE_SYNC_TABLE) + "' and name = 'naturalbase_rdb_" + std::string(DEVICE_SYNC_TABLE) + + "_ON_" + triggerType + "';"; + int count = 0; + EXPECT_EQ(SQLiteUtils::GetCountBySql(db_, sql, count), E_OK); + EXPECT_EQ(count, 1); + } + std::string newInsertTriggerSql = GetTriggerSql(DEVICE_SYNC_TABLE, "INSERT", db_); + std::string newUpdateTriggerSql = GetTriggerSql(DEVICE_SYNC_TABLE, "UPDATE", db_); + std::string newDeleteTriggerSql = GetTriggerSql(DEVICE_SYNC_TABLE, "DELETE", db_); + EXPECT_FALSE(newInsertTriggerSql.empty() || newUpdateTriggerSql.empty() || newDeleteTriggerSql.empty()); + EXPECT_TRUE(oldInsertTriggerSql == newInsertTriggerSql); + EXPECT_TRUE(oldUpdateTriggerSql != newUpdateTriggerSql); + EXPECT_TRUE(oldDeleteTriggerSql == newDeleteTriggerSql); +} + +/** + * @tc.name: SetSchema008 + * @tc.desc: Test set distributed schema with pk but pk isP2pSync is false + * @tc.type: FUNC + * @tc.require: + * @tc.author: tankaisheng + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema008, TestSize.Level0) +{ + /** + * @tc.steps: step1. Prepare db + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate(DistributedTableMode::COLLABORATION)); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + /** + * @tc.steps: step2. Test set distributed schema without pk + * @tc.expected: step2. return OK + */ + DistributedSchema distributedSchema = {0, {{DEVICE_SYNC_TABLE, {{"int_field1", true}}}}}; + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), OK); + /** + * @tc.steps: step3. Test set distributed schema with pk but pk isP2pSync is false + * @tc.expected: step3. return SCHEMA_MISMATCH + */ + DistributedSchema distributedSchema1 = {0, {{DEVICE_SYNC_TABLE, {{"pk", false}}}}}; + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema1), SCHEMA_MISMATCH); + /** + * @tc.steps: step4. Test set same distributed schema + * @tc.expected: step4. return OK + */ + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), OK); +} + +/** + * @tc.name: SetSchema009 + * @tc.desc: Test tableMode is SPLIT_BY_DEVICE then SetDistributedSchema. + * @tc.type: FUNC + * @tc.require: + * @tc.author: tankaisheng + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema009, TestSize.Level0) +{ + /** + * @tc.steps: step1. Prepare db, tableMode is SPLIT_BY_DEVICE + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate(DistributedTableMode::SPLIT_BY_DEVICE)); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + /** + * @tc.steps: step2. Test set distributed schema without pk + * @tc.expected: step2. return NOT_SUPPORT + */ + DistributedSchema distributedSchema = {0, {{DEVICE_SYNC_TABLE, {{"int_field1", true}}}}}; + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), NOT_SUPPORT); +} + +/** + * @tc.name: SetSchema010 + * @tc.desc: Test create distributed table without communicator. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema010, TestSize.Level0) +{ + if (deviceB_ != nullptr) { + delete deviceB_; + deviceB_ = nullptr; + } + RuntimeContext::GetInstance()->SetCommunicatorAggregator(nullptr); + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); +} + +/** + * @tc.name: SetSchema011 + * @tc.desc: Test set schema with not null field but isP2pSync is false + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema011, TestSize.Level0) +{ + /** + * @tc.steps: step1. Prepare db + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate(DistributedTableMode::COLLABORATION)); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + /** + * @tc.steps: step2. Test set distributed schema + * @tc.expected: step2. return SCHEMA_MISMATCH + */ + DistributedSchema schema1 = GetDistributedSchema(DEVICE_SYNC_TABLE, {"pk"}); + DistributedField &field1 = schema1.tables.front().fields.front(); + field1.isP2pSync = false; + EXPECT_EQ(delegate_->SetDistributedSchema(schema1), SCHEMA_MISMATCH); +} + +/** + * @tc.name: SetSchema012 + * @tc.desc: Test call SetDistributedSchema with empty tables + * @tc.type: FUNC + * @tc.require: + * @tc.author: liuhongyang + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema012, TestSize.Level0) +{ + /** + * @tc.steps: step1. Prepare db, tableMode is SPLIT_BY_DEVICE + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate(DistributedTableMode::SPLIT_BY_DEVICE)); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + /** + * @tc.steps: step2. Test set schema with empty tables vector + * @tc.expected: step2. return SCHEMA_MISMATCH + */ + DistributedSchema distributedSchema = {0, {}}; + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), SCHEMA_MISMATCH); + /** + * @tc.steps: step3. Test set schema with a list of empty tables + * @tc.expected: step3. return SCHEMA_MISMATCH + */ + distributedSchema = {0, {{}, {}, {}}}; + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), SCHEMA_MISMATCH); + /** + * @tc.steps: step4. Test set schema with a mix of empty and non-empty tables + * @tc.expected: step4. return SCHEMA_MISMATCH + */ + distributedSchema = {0, {{DEVICE_SYNC_TABLE, {{"int_field1", true}}}, {}}}; + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), SCHEMA_MISMATCH); +} + +/** + * @tc.name: NormalSync001 + * @tc.desc: Test set distributed schema and sync. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync001, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table and cloud table in COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + auto schema = GetSchema(); + auto distributedSchema = RDBDataGenerator::ParseSchema(schema, true); + deviceB_->SetDistributedSchema(distributedSchema); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), OK); + LOGI("[DistributedDBCloudAsyncDownloadAssetsTest] CreateDistributedTable %s", DEVICE_SYNC_TABLE); + /** + * @tc.steps: step2. Insert one data + * @tc.expected: step2.ok + */ + auto tableSchema = GetTableSchema(); + ASSERT_EQ(RDBDataGenerator::InsertVirtualLocalDBData(0, 10, deviceB_, tableSchema), E_OK); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(tableSchema.name, db_, deviceB_), E_OK); + /** + * @tc.steps: step3. Sync to real device + * @tc.expected: step3.ok + */ + Query query = Query::Select(tableSchema.name); + DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PULL_ONLY, OK, {deviceB_->GetDeviceId()}); +} + +/** + * @tc.name: NormalSync002 + * @tc.desc: Test sync with diff distributed schema [high version -> low version]. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync002, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table and cloud table in COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + /** + * @tc.steps: step2. DeviceB set schema [pk, int_field1, int_field2, int_field_upgrade] + * @tc.expected: step2.ok + */ + DataBaseSchema virtualSchema; + auto tableSchema = GetTableSchema(true); + tableSchema.name = DEVICE_SYNC_TABLE; + virtualSchema.tables.push_back(tableSchema); + auto distributedSchema = RDBDataGenerator::ParseSchema(virtualSchema); + deviceB_->SetDistributedSchema(distributedSchema); + /** + * @tc.steps: step3. Real device set schema [pk, int_field1, int_field2] + * @tc.expected: step3.ok + */ + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + LOGI("[DistributedDBCloudAsyncDownloadAssetsTest] CreateDistributedTable %s", DEVICE_SYNC_TABLE); + EXPECT_EQ(delegate_->SetDistributedSchema(RDBDataGenerator::ParseSchema(GetSchema())), OK); + /** + * @tc.steps: step4. Insert table info and virtual data into deviceB + * @tc.expected: step4.ok + */ + ASSERT_EQ(RDBDataGenerator::InsertVirtualLocalDBData(0, 10, deviceB_, tableSchema), E_OK); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(DEVICE_SYNC_TABLE_UPGRADE, DEVICE_SYNC_TABLE, db_, deviceB_), + E_OK); + /** + * @tc.steps: step5. Sync to real device + * @tc.expected: step5.ok + */ + Query query = Query::Select(tableSchema.name); + EXPECT_EQ(deviceB_->GenericVirtualDevice::Sync(SYNC_MODE_PUSH_ONLY, query, true), E_OK); +} + +/** + * @tc.name: NormalSync003 + * @tc.desc: Test sync with diff distributed schema [low version -> high version]. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync003, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table and cloud table in COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + /** + * @tc.steps: step2. DeviceB set schema [pk, int_field1, int_field2] + * @tc.expected: step2.ok + */ + DataBaseSchema virtualSchema; + auto tableSchema = GetTableSchema(); + tableSchema.name = DEVICE_SYNC_TABLE_UPGRADE; + virtualSchema.tables.push_back(tableSchema); + auto distributedSchema = RDBDataGenerator::ParseSchema(virtualSchema); + deviceB_->SetDistributedSchema(distributedSchema); + /** + * @tc.steps: step3. Real device set schema [pk, int_field1, int_field2, int_field_upgrade] + * @tc.expected: step3.ok + */ + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE_UPGRADE, TableSyncType::DEVICE_COOPERATION), OK); + LOGI("[DistributedDBCloudAsyncDownloadAssetsTest] CreateDistributedTable %s", DEVICE_SYNC_TABLE); + EXPECT_EQ(delegate_->SetDistributedSchema(RDBDataGenerator::ParseSchema(GetSchema())), OK); + /** + * @tc.steps: step4. Insert table info and virtual data into deviceB + * @tc.expected: step4.ok + */ + ASSERT_EQ(RDBDataGenerator::InsertVirtualLocalDBData(0, 10, deviceB_, tableSchema), E_OK); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(DEVICE_SYNC_TABLE, DEVICE_SYNC_TABLE_UPGRADE, db_, deviceB_), + E_OK); + /** + * @tc.steps: step5. Sync to real device + * @tc.expected: step5.ok + */ + Query query = Query::Select(tableSchema.name); + EXPECT_EQ(deviceB_->GenericVirtualDevice::Sync(SYNC_MODE_PUSH_ONLY, query, true), E_OK); +} + +/** + * @tc.name: NormalSync004 + * @tc.desc: Test sync when distributed schema was not set. + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync004, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table and cloud table in COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + auto tableSchema = GetTableSchema(); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(tableSchema.name, db_, deviceB_), E_OK); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + /** + * @tc.steps: step2. Sync to real device + * @tc.expected: step2. return SCHEMA_MISMATCH. + */ + Query query = Query::Select(tableSchema.name); + DBStatus status = delegate_->Sync({UnitTestCommonConstant::DEVICE_B}, SYNC_MODE_PUSH_ONLY, query, nullptr, true); + EXPECT_EQ(status, SCHEMA_MISMATCH); +} + +/** + * @tc.name: NormalSync005 + * @tc.desc: Test sync with specified columns + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync005, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table and cloud table in COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate(DistributedTableMode::COLLABORATION)); + DistributedSchema schema = GetDistributedSchema(DEVICE_SYNC_TABLE, {"pk", "int_field1"}); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + deviceB_->SetDistributedSchema(schema); + EXPECT_EQ(delegate_->SetDistributedSchema(schema), OK); + /** + * @tc.steps: step2. Init some data + * @tc.expected: step2.ok + */ + int64_t dataNum = 10; + EXPECT_EQ(RDBDataGenerator::InsertLocalDBData(0, dataNum / 2, db_, GetTableSchema()), E_OK); + std::string sql = "update " + std::string(DEVICE_SYNC_TABLE) + " set int_field1 = 1, int_field2 = 2 where pk >= 0"; + ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db_, sql), E_OK); + auto tableSchema = GetTableSchema(); + std::this_thread::sleep_for(std::chrono::seconds(1)); + ASSERT_EQ(RDBDataGenerator::InsertVirtualLocalDBData(0, dataNum, deviceB_, tableSchema), E_OK); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(tableSchema.name, db_, deviceB_), E_OK); + /** + * @tc.steps: step3. Sync to real device and check data + * @tc.expected: step3.ok + */ + Query query = Query::Select(tableSchema.name); + EXPECT_EQ(deviceB_->GenericVirtualDevice::Sync(SYNC_MODE_PUSH_PULL, query, true), E_OK); + sql = "select int_field1, int_field2 from " + std::string(DEVICE_SYNC_TABLE) + " order by pk;"; + sqlite3_stmt *stmt = nullptr; + ASSERT_EQ(SQLiteUtils::GetStatement(db_, sql, stmt), E_OK); + int dataIndex = 0; + while (SQLiteUtils::StepWithRetry(stmt) == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + int64_t intField1Value = sqlite3_column_int64(stmt, 0); + int64_t intField2Value = sqlite3_column_int64(stmt, 1); + EXPECT_EQ(intField1Value, dataIndex); + dataIndex++; + if (dataIndex <= dataNum / 2) { + EXPECT_EQ(intField2Value, 2); + } else { + EXPECT_EQ(intField2Value, 0); + } + } + EXPECT_EQ(dataIndex, dataNum); + int errCode; + SQLiteUtils::ResetStatement(stmt, true, errCode); +} + +/** + * @tc.name: NormalSync006 + * @tc.desc: Test set distributed schema and sync. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync006, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table and cloud table in COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + auto schema = GetSchema(); + auto distributedSchema = RDBDataGenerator::ParseSchema(schema, true); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + LOGI("[DistributedDBCloudAsyncDownloadAssetsTest] CreateDistributedTable %s", DEVICE_SYNC_TABLE); + deviceB_->SetDistributedSchema(distributedSchema); + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), OK); + /** + * @tc.steps: step2. Insert one data + * @tc.expected: step2.ok + */ + auto tableSchema = GetTableSchema(); + EXPECT_EQ(RDBDataGenerator::InsertLocalDBData(0, 1, db_, GetTableSchema()), E_OK); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(tableSchema.name, db_, deviceB_), E_OK); + /** + * @tc.steps: step3. Sync to real device + * @tc.expected: step3.ok + */ + Query query = Query::Select(tableSchema.name); + DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PUSH_ONLY, OK, {deviceB_->GetDeviceId()}); + /** + * @tc.steps: step4. Change schema to non-existent table name, then sync + * @tc.expected: step4.SCHEMA_MISMATCH + */ + tableSchema.name = "not_config_table"; + ASSERT_EQ(RDBDataGenerator::InitTable(tableSchema, true, *db_), SQLITE_OK); + ASSERT_EQ(delegate_->CreateDistributedTable(tableSchema.name), OK); + Query query2 = Query::Select(tableSchema.name); + std::map> statusMap; + SyncStatusCallback callBack2; + DBStatus callStatus = delegate_->Sync({deviceB_->GetDeviceId()}, SYNC_MODE_PUSH_ONLY, query2, callBack2, true); + EXPECT_EQ(callStatus, SCHEMA_MISMATCH); +} + +/** + * @tc.name: NormalSync007 + * @tc.desc: Test change distributed schema and sync. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync007, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table and cloud table in COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + auto schema = GetSchema(); + auto distributedSchema = RDBDataGenerator::ParseSchema(schema, true); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + LOGI("[DistributedDBCloudAsyncDownloadAssetsTest] CreateDistributedTable %s", DEVICE_SYNC_TABLE); + deviceB_->SetDistributedSchema(distributedSchema); + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), OK); + /** + * @tc.steps: step2. Insert one data + * @tc.expected: step2.ok + */ + auto tableSchema = GetTableSchema(); + ASSERT_EQ(RDBDataGenerator::InsertVirtualLocalDBData(0, 1, deviceB_, tableSchema), E_OK); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(tableSchema.name, db_, deviceB_), E_OK); + /** + * @tc.steps: step3. Sync to real device + * @tc.expected: step3.ok + */ + Query query = Query::Select(tableSchema.name); + DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PULL_ONLY, OK, {deviceB_->GetDeviceId()}); + std::string sql = std::string("select count(*) from ").append(DEVICE_SYNC_TABLE) + .append(" where pk=0 and int_field1 is null and int_field2 is null"); + int count = 0; + EXPECT_EQ(SQLiteUtils::GetCountBySql(db_, sql, count), E_OK); + EXPECT_EQ(count, 1); + /** + * @tc.steps: step4. Change schema and sync again + * @tc.expected: step4.ok + */ + distributedSchema = RDBDataGenerator::ParseSchema(schema); + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), OK); + DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PULL_ONLY, OK, {deviceB_->GetDeviceId()}); + sql = std::string("select count(*) from ").append(DEVICE_SYNC_TABLE) + .append(" where pk=0 and int_field1=0 and int_field2=0"); + count = 0; + EXPECT_EQ(SQLiteUtils::GetCountBySql(db_, sql, count), E_OK); + EXPECT_EQ(count, 1); + auto changeData = delegateObserver_->GetSavedChangedData()[std::string(DEVICE_SYNC_TABLE)]; + EXPECT_TRUE(changeData.properties.isP2pSyncDataChange); +} + +/** + * @tc.name: NormalSync008 + * @tc.desc: Test set distributed schema and sync with diff sort. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync008, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table and cloud table in COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + auto schema = GetSchema(); + auto distributedSchema = RDBDataGenerator::ParseSchema(schema); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + LOGI("[DistributedDBCloudAsyncDownloadAssetsTest] CreateDistributedTable %s", DEVICE_SYNC_TABLE); + deviceB_->SetDistributedSchema(distributedSchema); + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), OK); + /** + * @tc.steps: step2. Insert one data with diff sort col + * @tc.expected: step2.ok + */ + auto tableSchema = GetTableSchema(); + ASSERT_EQ(RDBDataGenerator::InsertVirtualLocalDBData(0, 1, deviceB_, + RDBDataGenerator::FlipTableSchema(tableSchema)), E_OK); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(tableSchema.name, db_, deviceB_), E_OK); + /** + * @tc.steps: step3. Sync to real device + * @tc.expected: step3.ok + */ + Query query = Query::Select(tableSchema.name); + DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PULL_ONLY, OK, {deviceB_->GetDeviceId()}); + std::string sql = std::string("select count(*) from ").append(DEVICE_SYNC_TABLE).append(" where pk=0;"); + int count = 0; + EXPECT_EQ(SQLiteUtils::GetCountBySql(db_, sql, count), E_OK); + EXPECT_EQ(count, 1); + sql = std::string("select count(*) from ") + .append(RelationalStoreManager::GetDistributedLogTableName(DEVICE_SYNC_TABLE)) + .append(" where data_key=0 and cursor=1;"); + count = 0; + EXPECT_EQ(SQLiteUtils::GetCountBySql(db_, sql, count), E_OK); + EXPECT_EQ(count, 1); +} + +/** + * @tc.name: NormalSync009 + * @tc.desc: Test if distributed table will be created when sync with COLLABORATION mode. + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync009, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table and cloud table in COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + auto schema = GetSchema(); + auto distributedSchema = RDBDataGenerator::ParseSchema(schema, true); + deviceB_->SetDistributedSchema(distributedSchema); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), OK); + LOGI("[DistributedDBCloudAsyncDownloadAssetsTest] CreateDistributedTable %s", DEVICE_SYNC_TABLE); + /** + * @tc.steps: step2. Insert one data + * @tc.expected: step2.ok + */ + auto tableSchema = GetTableSchema(); + ASSERT_EQ(RDBDataGenerator::InsertVirtualLocalDBData(0, 10, deviceB_, tableSchema), E_OK); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(tableSchema.name, db_, deviceB_), E_OK); + /** + * @tc.steps: step3. Sync to real device + * @tc.expected: step3.ok + */ + std::string checkSql = "select count(*) from sqlite_master where type='table' and name != '" + + DBCommon::GetLogTableName(DEVICE_SYNC_TABLE) + "' and name like 'naturalbase_rdb_aux_" + + std::string(DEVICE_SYNC_TABLE) + "_%'"; + int count = 0; + EXPECT_EQ(SQLiteUtils::GetCountBySql(db_, checkSql, count), E_OK); + EXPECT_EQ(count, 0); + Query query = Query::Select(tableSchema.name); + DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PULL_ONLY, OK, {deviceB_->GetDeviceId()}); + /** + * @tc.steps: step4. Check if the distributed table exists + * @tc.expected: step4.ok + */ + count = 0; + EXPECT_EQ(SQLiteUtils::GetCountBySql(db_, checkSql, count), E_OK); + EXPECT_EQ(count, 0); +} + +/** + * @tc.name: NormalSync010 + * @tc.desc: Test sync without not null col. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync010, TestSize.Level0) +{ + /** + * @tc.steps: step1. Recreate not null table + * @tc.expected: step1.ok + */ + std::string sql = std::string("DROP TABLE ").append(DEVICE_SYNC_TABLE); + ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db_, sql), E_OK); + auto tableSchema = GetTableSchema(); + ASSERT_EQ(RDBDataGenerator::InitTable(tableSchema, true, *db_), E_OK); + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + auto schema = GetSchema(); + auto distributedSchema = RDBDataGenerator::ParseSchema(schema, true); + deviceB_->SetDistributedSchema(distributedSchema); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), SCHEMA_MISMATCH); + /** + * @tc.steps: step2. Insert one data + * @tc.expected: step2.ok + */ + ASSERT_EQ(RDBDataGenerator::InsertVirtualLocalDBData(0, 1, deviceB_, tableSchema), E_OK); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(tableSchema.name, db_, deviceB_), E_OK); + /** + * @tc.steps: step3. Sync without str col + * @tc.expected: step3.ok + */ + Query query = Query::Select(tableSchema.name); + DBStatus callStatus = delegate_->Sync({deviceB_->GetDeviceId()}, SYNC_MODE_PULL_ONLY, query, nullptr, true); + EXPECT_EQ(callStatus, SCHEMA_MISMATCH); + /** + * @tc.steps: step4. Check if the distributed table exists + * @tc.expected: step4.ok + */ + int count = 0; + sql = std::string("select count(*) from ") + .append(RelationalStoreManager::GetDistributedLogTableName(DEVICE_SYNC_TABLE)); + EXPECT_EQ(SQLiteUtils::GetCountBySql(db_, sql, count), E_OK); + EXPECT_EQ(count, 0); +} + +/** + * @tc.name: NormalSync011 + * @tc.desc: Test set the distributed schema first then sync. + * @tc.type: FUNC + * @tc.require: + * @tc.author: bty + */ +HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync011, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table and cloud table in COLLABORATION + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + auto schema = GetSchema(); + auto distributedSchema = RDBDataGenerator::ParseSchema(schema, true); + deviceB_->SetDistributedSchema(distributedSchema); + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), OK); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + LOGI("[DistributedDBCloudAsyncDownloadAssetsTest] CreateDistributedTable %s", DEVICE_SYNC_TABLE); + /** + * @tc.steps: step2. Insert one data + * @tc.expected: step2.ok + */ + auto tableSchema = GetTableSchema(); + EXPECT_EQ(RDBDataGenerator::InsertLocalDBData(0, 1, db_, GetTableSchema()), E_OK); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(tableSchema.name, db_, deviceB_), E_OK); + /** + * @tc.steps: step3. Sync to real device + * @tc.expected: step3.ok + */ + Query query = Query::Select(tableSchema.name); + DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PUSH_ONLY, OK, {deviceB_->GetDeviceId()}); +} + +/** + * @tc.name: NormalSync012 + * @tc.desc: Test sync with autoincrement table. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRDBCollaborationTest, NormalSync012, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create auto increment table and unique index + * @tc.expected: step1.ok + */ + auto tableSchema = GetTableSchema(); + tableSchema.name = DEVICE_SYNC_TABLE_AUTOINCREMENT; + ASSERT_EQ(RDBDataGenerator::InitTable(tableSchema, true, true, *db_), E_OK); + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + tableSchema = GetTableSchema(false, true); + tableSchema.name = DEVICE_SYNC_TABLE_AUTOINCREMENT; + auto schema = GetSchema(); + schema.tables.push_back(tableSchema); + auto distributedSchema = RDBDataGenerator::ParseSchema(schema, true); + deviceB_->SetDistributedSchema(distributedSchema); + int errCode = SQLiteUtils::ExecuteRawSQL(db_, std::string("CREATE UNIQUE INDEX U_INDEX ON ") + .append(tableSchema.name).append("('123')")); + ASSERT_EQ(errCode, E_OK); + EXPECT_EQ(delegate_->CreateDistributedTable(tableSchema.name, TableSyncType::DEVICE_COOPERATION), OK); + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), OK); + /** + * @tc.steps: step2. Insert one data + * @tc.expected: step2.ok + */ + ASSERT_EQ(RDBDataGenerator::InsertVirtualLocalDBData(0, 1, deviceB_, tableSchema), E_OK); + ASSERT_EQ(RDBDataGenerator::PrepareVirtualDeviceEnv(tableSchema.name, db_, deviceB_), E_OK); + /** + * @tc.steps: step3. Sync to real device + * @tc.expected: step3.ok + */ + Query query = Query::Select(tableSchema.name); + DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PULL_ONLY, OK, {deviceB_->GetDeviceId()}); + std::string sql = std::string("select count(*) from ").append(tableSchema.name); + int count = 0; + EXPECT_EQ(SQLiteUtils::GetCountBySql(db_, sql, count), E_OK); + EXPECT_EQ(count, 1); + /** + * @tc.steps: step4. Update date and sync again + * @tc.expected: step4.ok + */ + ASSERT_EQ(RDBDataGenerator::InsertVirtualLocalDBData(0, 1, deviceB_, tableSchema), E_OK); + DistributedDBToolsUnitTest::BlockSync(*delegate_, query, SYNC_MODE_PULL_ONLY, OK, {deviceB_->GetDeviceId()}); + sql = std::string("select count(*) from ").append(tableSchema.name); + count = 0; + EXPECT_EQ(SQLiteUtils::GetCountBySql(db_, sql, count), E_OK); + EXPECT_EQ(count, 1); +} + +/** + * @tc.name: SetSchema013 + * @tc.desc: Test set tracker table for device table and check if timestamp has changed + * @tc.type: FUNC + * @tc.require: + * @tc.author: bty + */ +HWTEST_F(DistributedDBRDBCollaborationTest, SetSchema013, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create device table + * @tc.expected: step1.ok + */ + ASSERT_NO_FATAL_FAILURE(InitDelegate()); + DistributedSchema distributedSchema = GetDistributedSchema(DEVICE_SYNC_TABLE, {"pk", "int_field1"}); + EXPECT_EQ(delegate_->CreateDistributedTable(DEVICE_SYNC_TABLE, TableSyncType::DEVICE_COOPERATION), OK); + EXPECT_EQ(delegate_->SetDistributedSchema(distributedSchema), OK); + TrackerSchema trackerSchema = { + .tableName = DEVICE_SYNC_TABLE, .extendColNames = {"int_field1"}, .trackerColNames = {"int_field1"} + }; + /** + * @tc.steps: step2. Insert one data and query timestamp + * @tc.expected: step2.ok + */ + EXPECT_EQ(RDBDataGenerator::InsertLocalDBData(0, 1, db_, GetTableSchema()), E_OK); + sqlite3_stmt *stmt = nullptr; + std::string sql = "select timestamp from " + DBCommon::GetLogTableName(DEVICE_SYNC_TABLE) + + " where data_key=0"; + EXPECT_EQ(SQLiteUtils::GetStatement(db_, sql, stmt), E_OK); + EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)); + int64_t timestamp1 = static_cast(sqlite3_column_int64(stmt, 0)); + int ret = E_OK; + SQLiteUtils::ResetStatement(stmt, true, ret); + /** + * @tc.steps: step3. Set tracker table and query timestamp + * @tc.expected: step3.Equal + */ + EXPECT_EQ(delegate_->SetTrackerTable(trackerSchema), WITH_INVENTORY_DATA); + EXPECT_EQ(SQLiteUtils::GetStatement(db_, sql, stmt), E_OK); + EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)); + int64_t timestamp2 = static_cast(sqlite3_column_int64(stmt, 0)); + SQLiteUtils::ResetStatement(stmt, true, ret); + EXPECT_EQ(timestamp1, timestamp2); +} +} \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_cloud_syncable_storage_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_cloud_syncable_storage_test.cpp index 4f26d5a255c5e356e2939f855eca58b82e2da34d..70e66147aaaf3bd15da8bb96a3bd273bd693a243 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_cloud_syncable_storage_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_cloud_syncable_storage_test.cpp @@ -766,6 +766,7 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, FillCloudGid001, TestS CreateLogTable(g_tableName); int64_t insCount = 100; InitLogData(insCount, 0, insCount, insCount, g_logTblName); + CreateAndInitUserTable(0, 0, {}); CloudSyncData syncData(g_tableName); SetDbSchema(g_tableSchema); @@ -1048,7 +1049,7 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetInfoByPrimaryKeyOrG vBucket[CloudDbConstant::GID_FIELD] = std::to_string(i); VBucket assetInfo; DataInfoWithLog dataInfo; - ASSERT_EQ(g_storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, dataInfo, assetInfo), E_OK); + ASSERT_EQ(g_storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, true, dataInfo, assetInfo), E_OK); ASSERT_EQ(dataInfo.logInfo.cloudGid, std::to_string(i)); auto entry1 = assetInfo.find("assert"); auto entry2 = assetInfo.find("asserts"); @@ -1086,7 +1087,7 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetInfoByPrimaryKeyOrG vBucket[CloudDbConstant::GID_FIELD] = std::to_string(i); VBucket assetInfo; DataInfoWithLog dataInfo; - ASSERT_EQ(g_storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, dataInfo, assetInfo), E_OK); + ASSERT_EQ(g_storageProxy->GetInfoByPrimaryKeyOrGid(g_tableName, vBucket, true, dataInfo, assetInfo), E_OK); ASSERT_EQ(dataInfo.logInfo.cloudGid, std::to_string(i)); EXPECT_EQ(assetInfo.size(), 0u); } @@ -1549,7 +1550,7 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, getAsset001, TestSize. std::string gid; Bytes hashKey; EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK); - EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, gid, hashKey, assets).first, -E_INVALID_ARGS); + EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, -E_INVALID_ARGS); EXPECT_EQ(assets.size(), 0u); /** @@ -1561,7 +1562,7 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, getAsset001, TestSize. UpdateLocalAsset(g_tableName, asset, 2L); // 2 is rowid std::string pk = "2"; hashKey.assign(pk.begin(), pk.end()); - EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, gid, hashKey, assets).first, E_OK); + EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, E_OK); CheckGetAsset(assets, static_cast(AssetStatus::UPDATE)); /** @@ -1571,7 +1572,7 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, getAsset001, TestSize. assets = {}; pk = "11"; hashKey.assign(pk.begin(), pk.end()); - EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, gid, hashKey, assets).first, -E_NOT_FOUND); + EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, -E_NOT_FOUND); EXPECT_EQ(assets.size(), 0u); /** @@ -1581,7 +1582,7 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, getAsset001, TestSize. gid = "2"; pk = {}; assets = {}; - EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, gid, hashKey, assets).first, E_OK); + EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, E_OK); CheckGetAsset(assets, static_cast(AssetStatus::UPDATE)); /** @@ -1590,7 +1591,7 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, getAsset001, TestSize. */ gid = "11"; assets = {}; - EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, gid, hashKey, assets).first, -E_NOT_FOUND); + EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, -E_NOT_FOUND); EXPECT_EQ(assets.size(), 0u); EXPECT_EQ(g_storageProxy->Commit(), E_OK); } @@ -1614,7 +1615,7 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, getAsset002, TestSize. std::string pk = "2"; hashKey.assign(pk.begin(), pk.end()); EXPECT_EQ(g_storageProxy->StartTransaction(), E_OK); - EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, gid, hashKey, assets).first, E_OK); + EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, E_OK); CheckGetAsset(assets, static_cast(AssetStatus::INSERT)); /** @@ -1625,7 +1626,8 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, getAsset002, TestSize. gid = "11"; pk = "1"; hashKey.assign(pk.begin(), pk.end()); - EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, gid, hashKey, assets).first, -E_CLOUD_GID_MISMATCH); + EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, + -E_CLOUD_GID_MISMATCH); CheckGetAsset(assets, static_cast(AssetStatus::NORMAL)); /** @@ -1635,7 +1637,7 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, getAsset002, TestSize. assets = {}; pk = "12"; hashKey.assign(pk.begin(), pk.end()); - EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, gid, hashKey, assets).first, -E_NOT_FOUND); + EXPECT_EQ(g_storageProxy->GetAssetsByGidOrHashKey(g_tableName, false, gid, hashKey, assets).first, -E_NOT_FOUND); EXPECT_EQ(assets.size(), 0u); EXPECT_EQ(g_storageProxy->Commit(), E_OK); } @@ -1674,5 +1676,23 @@ HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, GetCloudData007, TestS ASSERT_EQ(g_storageProxy->GetCloudData(g_tableName, g_startTime, token, cloudSyncData), E_OK); EXPECT_EQ(g_storageProxy->Rollback(), E_OK); } + +/** + * @tc.name: ContainAssetsTable001 + * @tc.desc: Test cloud schema contain asset table + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRelationalCloudSyncableStorageTest, ContainAssetsTable001, TestSize.Level0) +{ + ASSERT_NE(g_storageProxy, nullptr); + EXPECT_FALSE(g_storageProxy->IsContainAssetsTable()); + ASSERT_NE(g_cloudStore, nullptr); + DataBaseSchema dataBaseSchema; + dataBaseSchema.tables.push_back(g_tableSchema); + EXPECT_EQ(g_cloudStore->SetCloudDbSchema(dataBaseSchema), E_OK); + EXPECT_TRUE(g_storageProxy->IsContainAssetsTable()); +} } #endif // RELATIONAL_STORE diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_get_data_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_get_data_test.cpp index 0c16248e27e6fc2ba4733001b461e47902907ab4..3b5bc65fd0f6bdfc023ad9b6bdb4150d21aacd4f 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_get_data_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_get_data_test.cpp @@ -1388,7 +1388,7 @@ HWTEST_F(DistributedDBRelationalGetDataTest, GetMaxTimestamp1, TestSize.Level1) Timestamp time1 = 0; store->GetMaxTimestamp(time1); - EXPECT_EQ(time1, 0ull); + EXPECT_EQ(time1, 0uLL); /** * @tc.steps: step3. Put 1 record into data table and get max timestamp. @@ -1422,7 +1422,7 @@ HWTEST_F(DistributedDBRelationalGetDataTest, GetMaxTimestamp1, TestSize.Level1) */ Timestamp time5 = 0; store->GetMaxTimestamp(tableName, time5); - EXPECT_EQ(time5, 0ull); + EXPECT_EQ(time5, 0uLL); sqlite3_close(db); RefObject::DecObjRef(g_store); diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_schema_analysis_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_schema_analysis_test.cpp index 789438f7e8e64a254ecea95ee2ae400f59b15349..e96c0eb586bed05b889918f3ce77e8860e26f997 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_schema_analysis_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_schema_analysis_test.cpp @@ -202,5 +202,55 @@ HWTEST_F(DistributedDBRelationalSchemaAnalysisTest, AnalysisTable005, TestSize.L index++; } } + +/** + * @tc.name: SetDistributedSchema001 + * @tc.desc: Set distributed schema + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRelationalSchemaAnalysisTest, SetDistributedSchema001, TestSize.Level0) +{ + /** + * @tc.steps: step1. Create a DistributedSchema; + */ + RelationalSchemaObject schema; + DistributedSchema distributedSchema; + distributedSchema.version = SOFTWARE_VERSION_CURRENT; + DistributedTable table; + DistributedField field; + field.colName = "field1"; + field.isP2pSync = true; + field.isSpecified = true; + table.fields.push_back(field); + field.colName = "field2"; + field.isP2pSync = false; + field.isSpecified = false; + table.fields.push_back(field); + table.tableName = "table1"; + distributedSchema.tables.push_back(table); + table.tableName = "table2"; + distributedSchema.tables.push_back(table); + schema.SetDistributedSchema(distributedSchema); + /** + * @tc.steps: step2. DistributedSchema to json string and parse it; + * @tc.expected: DistributedSchema is same. + */ + auto schemaStr = schema.ToSchemaString(); + RelationalSchemaObject parseSchemaObj; + EXPECT_EQ(parseSchemaObj.ParseFromSchemaString(schemaStr), E_OK); + auto parseSchema = parseSchemaObj.GetDistributedSchema(); + EXPECT_EQ(parseSchema.version, distributedSchema.version); + ASSERT_EQ(parseSchema.tables.size(), distributedSchema.tables.size()); + for (size_t i = 0; i < parseSchema.tables.size(); ++i) { + EXPECT_EQ(parseSchema.tables[i].tableName, distributedSchema.tables[i].tableName); + ASSERT_EQ(parseSchema.tables[i].fields.size(), distributedSchema.tables[i].fields.size()); + for (size_t j = 0; j < parseSchema.tables[i].fields.size(); ++j) { + EXPECT_EQ(parseSchema.tables[i].fields[j].colName, distributedSchema.tables[i].fields[j].colName); + EXPECT_EQ(parseSchema.tables[i].fields[j].isP2pSync, distributedSchema.tables[i].fields[j].isP2pSync); + } + } +} } #endif // RELATIONAL_STORE \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_sqlite_utils_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_sqlite_utils_test.cpp index ad3e542f5b1228bc7a2e04da92218978c88d4ddb..e8da4e9f3ad3072fb832efc8d23ee4e47a712cc8 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_sqlite_utils_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_sqlite_utils_test.cpp @@ -31,7 +31,7 @@ namespace { string g_dbDir; sqlite3 *g_db = nullptr; - const int MAX_BLOB_READ_SIZE = 5 * 1024 * 1024; // 5M limit + const int MAX_BLOB_READ_SIZE = 64 * 1024 * 1024; // 64M limit const int MAX_TEXT_READ_SIZE = 5 * 1024 * 1024; // 5M limit } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_memory_rd_single_ver_natural_store_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_memory_rd_single_ver_natural_store_test.cpp index 9163a9efebfb6364e7f294d2ed06a94c6e7a1fe0..e798fda68028412580d12fd5c00b86d0a9b7ac8e 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_memory_rd_single_ver_natural_store_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_memory_rd_single_ver_natural_store_test.cpp @@ -65,7 +65,7 @@ void DistributedDBStorageMemoryRdSingleVerNaturalStoreTest::SetUp(void) int erroCode = E_OK; g_connection = static_cast(g_store->GetDBConnection(erroCode)); ASSERT_NE(g_connection, nullptr); - g_store->DecObjRef(g_store); + RefObject::DecObjRef(g_store); EXPECT_EQ(erroCode, E_OK); } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_memory_single_ver_naturall_store_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_memory_single_ver_naturall_store_test.cpp index bb83c54475765e6c17ba99785fea12184a953fd2..55eb8ce7c0e6daa4938aeb549ac2fa4fcdd8b985 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_memory_single_ver_naturall_store_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_memory_single_ver_naturall_store_test.cpp @@ -64,7 +64,7 @@ void DistributedDBStorageMemorySingleVerNaturalStoreTest::SetUp(void) int erroCode = E_OK; g_connection = static_cast(g_store->GetDBConnection(erroCode)); ASSERT_NE(g_connection, nullptr); - g_store->DecObjRef(g_store); + RefObject::DecObjRef(g_store); EXPECT_EQ(erroCode, E_OK); } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_query_sync_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_query_sync_test.cpp index f5d8e0de25884edbc390152313aabbf59ee512c4..2242b0ea4b4d2672609a24968fd270132464c85e 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_query_sync_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_query_sync_test.cpp @@ -147,7 +147,7 @@ void DistributedDBStorageQuerySyncTest::SetUp(void) int erroCode = E_OK; g_connection = static_cast(g_store->GetDBConnection(erroCode)); ASSERT_NE(g_connection, nullptr); - g_store->DecObjRef(g_store); + RefObject::DecObjRef(g_store); EXPECT_EQ(erroCode, E_OK); std::string oriIdentifier = USER_ID + "-" + APP_ID + "-" + "QuerySyncSchema"; @@ -170,7 +170,7 @@ void DistributedDBStorageQuerySyncTest::SetUp(void) g_schemaConnect->GetEntries(option, Query::Select(), entries); ASSERT_FALSE(entries.empty()); - g_schemaStore->DecObjRef(g_schemaStore); + RefObject::DecObjRef(g_schemaStore); } void DistributedDBStorageQuerySyncTest::TearDown(void) diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_register_observer_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_register_observer_test.cpp index edbd9dcb556e56021dd2fe89ec2b96247f0ee4d0..4e9b1588e8385ae294b13b2d036383e9d431fe83 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_register_observer_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_register_observer_test.cpp @@ -180,7 +180,7 @@ void DistributedDBStorageRdRegisterObserverTest::TearDown(void) g_singleVerNaturaStoreConnection->Close(); } std::string identifierName; - g_singleVerNaturaStore->DecObjRef(g_singleVerNaturaStore); + RefObject::DecObjRef(g_singleVerNaturaStore); identifierName = DBCommon::TransferStringToHex("TestGeneralNB"); DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir + "/" + identifierName + "/" + DBConstant::SINGLE_SUB_DIR); } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_result_and_json_optimize_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_result_and_json_optimize_test.cpp index 34d2a21c2bc101cf414a4b83ca9e43a8187b8f0c..68d1d7e82ffbc7644ae3b1e9b1fb204f6b500b72 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_result_and_json_optimize_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_result_and_json_optimize_test.cpp @@ -92,7 +92,7 @@ void DistributedDBStorageRdResultAndJsonOptimizeTest::SetUp(void) int errCode = E_OK; g_connection = static_cast(g_store->GetDBConnection(errCode)); ASSERT_NE(g_connection, nullptr); - g_store->DecObjRef(g_store); + RefObject::DecObjRef(g_store); EXPECT_EQ(errCode, E_OK); IOption option; diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_single_ver_natural_executor_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_single_ver_natural_executor_test.cpp index 1655a3fba89fe69b149fcc3d3338695298c1760d..61dd5305a7c2fc8bf68a5f42a7eacf2cf1535eeb 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_single_ver_natural_executor_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_single_ver_natural_executor_test.cpp @@ -81,7 +81,7 @@ void DistributedDBStorageRdSingleVerNaturalExecutorTest::SetUp(void) int erroCode = E_OK; g_connection = static_cast(g_store->GetDBConnection(erroCode)); ASSERT_NE(g_connection, nullptr); - g_store->DecObjRef(g_store); + RefObject::DecObjRef(g_store); EXPECT_EQ(erroCode, E_OK); g_handle = static_cast( diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_single_ver_natural_store_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_single_ver_natural_store_test.cpp index 9277cd0f9042e1e6903c1e75a8768e764795b6a3..00d14c384ee3fabbba9ea9cde33eb407d695d0e2 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_single_ver_natural_store_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_single_ver_natural_store_test.cpp @@ -72,7 +72,7 @@ void DistributedDBStorageRdSingleVerNaturalStoreTest::SetUp(void) int erroCode = E_OK; g_connection = static_cast(g_store->GetDBConnection(erroCode)); ASSERT_NE(g_connection, nullptr); - g_store->DecObjRef(g_store); + RefObject::DecObjRef(g_store); EXPECT_EQ(erroCode, E_OK); } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_single_ver_storage_engine_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_single_ver_storage_engine_test.cpp index db7d9418dbcf0434eeffe805dcf0f00d67bdb342..ff652ab5820d7b170ed2ec3d9c8e3aa0f3a28657 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_single_ver_storage_engine_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_rd_single_ver_storage_engine_test.cpp @@ -82,7 +82,7 @@ void DistributedDBStorageRdSingleVerStorageEngineTest::SetUp(void) int erroCode = E_OK; g_connection = static_cast(g_store->GetDBConnection(erroCode)); ASSERT_NE(g_connection, nullptr); - g_store->DecObjRef(g_store); + RefObject::DecObjRef(g_store); EXPECT_EQ(erroCode, E_OK); } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_register_conflict_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_register_conflict_test.cpp index f90b2bb6ef1843a6bfd900c6b0e6ddc023161859..296b6f336058c6fcc51ff7d00638ddb4107701cf 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_register_conflict_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_register_conflict_test.cpp @@ -190,7 +190,7 @@ void DistributedDBStorageRegisterConflictTest::SetUp(void) int erroCode = E_OK; g_connection = static_cast(g_store->GetDBConnection(erroCode)); ASSERT_NE(g_connection, nullptr); - g_store->DecObjRef(g_store); + RefObject::DecObjRef(g_store); EXPECT_EQ(erroCode, E_OK); g_conflictData.clear(); @@ -802,7 +802,7 @@ namespace { int erroCode = E_OK; g_connection = static_cast(g_store->GetDBConnection(erroCode)); ASSERT_NE(g_connection, nullptr); - g_store->DecObjRef(g_store); + RefObject::DecObjRef(g_store); EXPECT_EQ(erroCode, E_OK); } } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_register_observer_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_register_observer_test.cpp index 7f93cf37c0359d6fbf854216d4c0e9fdc7cf9c03..6bd851134f6f6e7e2c256810d967c82c333a7ca2 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_register_observer_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_register_observer_test.cpp @@ -320,7 +320,7 @@ void DistributedDBStorageRegisterObserverTest::TearDown(void) g_singleVerNaturaStoreConnection->Close(); } std::string identifierName; - g_singleVerNaturaStore->DecObjRef(g_singleVerNaturaStore); + RefObject::DecObjRef(g_singleVerNaturaStore); identifierName = DBCommon::TransferStringToHex("TestGeneralNB"); DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir + "/" + identifierName + "/" + DBConstant::SINGLE_SUB_DIR); } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_resultset_and_json_optimize.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_resultset_and_json_optimize.cpp index 1151efae1daffffe3901639858456242d9a26023..934a502ca85f3669dd934fb63899c55d8c6d2fa9 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_resultset_and_json_optimize.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_resultset_and_json_optimize.cpp @@ -93,7 +93,7 @@ void DistributedDBStorageResultAndJsonOptimizeTest::SetUp(void) int errCode = E_OK; g_connection = static_cast(g_store->GetDBConnection(errCode)); ASSERT_NE(g_connection, nullptr); - g_store->DecObjRef(g_store); + RefObject::DecObjRef(g_store); EXPECT_EQ(errCode, E_OK); IOption option; diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_sqlite_single_ver_natural_executor_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_sqlite_single_ver_natural_executor_test.cpp index 9a03f2e6938ee8397ac7df6eaa8f6a7b2e31cce2..1103b7aa1d9fed999a724feef1d5209d4174941e 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_sqlite_single_ver_natural_executor_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_sqlite_single_ver_natural_executor_test.cpp @@ -87,7 +87,7 @@ void DistributedDBStorageSQLiteSingleVerNaturalExecutorTest::SetUp(void) int erroCode = E_OK; g_connection = static_cast(g_store->GetDBConnection(erroCode)); ASSERT_NE(g_connection, nullptr); - g_store->DecObjRef(g_store); + RefObject::DecObjRef(g_store); EXPECT_EQ(erroCode, E_OK); g_handle = static_cast( diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_sqlite_single_ver_natural_store_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_sqlite_single_ver_natural_store_test.cpp index 075e76053d76d441b31aa6ec6170de7b5daa7b10..4f428d68865d350bf01d7c8e69e55f1caefd91b8 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_sqlite_single_ver_natural_store_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_sqlite_single_ver_natural_store_test.cpp @@ -73,7 +73,7 @@ void DistributedDBStorageSQLiteSingleVerNaturalStoreTest::SetUp(void) int erroCode = E_OK; g_connection = static_cast(g_store->GetDBConnection(erroCode)); ASSERT_NE(g_connection, nullptr); - g_store->DecObjRef(g_store); + RefObject::DecObjRef(g_store); EXPECT_EQ(erroCode, E_OK); } @@ -1144,7 +1144,7 @@ HWTEST_F(DistributedDBStorageSQLiteSingleVerNaturalStoreTest, MigrationAndReleas dataMigrationThread.join(); releaseThread.join(); - store->DecObjRef(store); + RefObject::DecObjRef(store); } } } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_sqlite_single_ver_storage_engine_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_sqlite_single_ver_storage_engine_test.cpp index 3e23fd5f164cb67437901398b0a80848383937c3..5b8da2980f50597fc0df16180da15b719d7dc7f0 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_sqlite_single_ver_storage_engine_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_sqlite_single_ver_storage_engine_test.cpp @@ -95,7 +95,7 @@ void DistributedDBStorageSQLiteSingleVerStorageEngineTest::SetUp(void) int erroCode = E_OK; g_connection = static_cast(g_store->GetDBConnection(erroCode)); ASSERT_NE(g_connection, nullptr); - g_store->DecObjRef(g_store); + RefObject::DecObjRef(g_store); EXPECT_EQ(erroCode, E_OK); } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_subscribe_query_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_subscribe_query_test.cpp index 5fa3c9829447111e5fe16d4d2f958b6f65540228..b03b188645ac325e359f3e7c337a2bfac0447b7d 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_subscribe_query_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_subscribe_query_test.cpp @@ -689,7 +689,7 @@ HWTEST_F(DistributedDBStorageSubscribeQueryTest, AddSubscribeErrTest001, TestSiz EXPECT_EQ(store->CheckAndInitQueryCondition(queryObj), -E_INVALID_DB); EXPECT_EQ(store->AddSubscribe(SUBSCRIBE_ID, queryObj, false), -E_INVALID_DB); EXPECT_EQ(store->RemoveSubscribe(SUBSCRIBE_ID), -E_INVALID_DB); - store->DecObjRef(store); + RefObject::DecObjRef(store); } namespace { diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_transaction_data_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_transaction_data_test.cpp index c0a0e797f64b7c2d83b5ccbee9acbad7f29dae28..ac6beeb3636ab5f14abc22e5b1cdb48ada1c67de 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_transaction_data_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_transaction_data_test.cpp @@ -283,7 +283,7 @@ void DistributedDBStorageTransactionDataTest::TearDown(void) g_naturalStoreConnection->Close(); g_naturalStoreConnection = nullptr; } - g_naturalStore->DecObjRef(g_naturalStore); + RefObject::DecObjRef(g_naturalStore); g_naturalStore = nullptr; } DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir + "/31/" + DBConstant::MULTI_SUB_DIR); @@ -1579,7 +1579,7 @@ HWTEST_F(DistributedDBStorageTransactionDataTest, GetBranchTag001, TestSize.Leve g_naturalStoreConnection->Close(); g_naturalStoreConnection = nullptr; } - g_naturalStore->DecObjRef(g_naturalStore); + RefObject::DecObjRef(g_naturalStore); g_naturalStore = new (std::nothrow) MultiVerNaturalStore; ASSERT_NE(g_naturalStore, nullptr); EXPECT_EQ(g_naturalStore->Open(g_prop), E_OK); diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/cloud_syncer_test.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/cloud_syncer_test.h index 3a2a95ab344046cc52455cad544a114c8a9ec309..cfd27ab9bb5bec538a536791be92e68053d5ed6f 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/cloud_syncer_test.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/cloud_syncer_test.h @@ -217,9 +217,16 @@ public: return TryToAddSyncTask(std::move(taskInfo)); } + bool CallIsAlreadyHaveCompensatedSyncTask() + { + return IsAlreadyHaveCompensatedSyncTask(); + } + void PopTaskQueue() { - taskQueue_.pop_back(); + if (!taskQueue_.empty()) { + taskQueue_.erase(--taskQueue_.end()); + } } int CallPrepareSync(TaskId taskId) @@ -243,7 +250,7 @@ public: VBucket &coveredData, VBucket &beCoveredData, bool setNormalStatus = false) { int ret = E_OK; - return TagAssetsInSingleRecord(coveredData, beCoveredData, setNormalStatus, ret); + return TagAssetsInSingleRecord(coveredData, beCoveredData, setNormalStatus, false, ret); } bool TestIsDataContainDuplicateAsset(std::vector &assetFields, VBucket &data) diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_async_download_assets_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_async_download_assets_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ff25540a8809a4e7ffa5ad7f913d3ea08ab80baa --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_async_download_assets_test.cpp @@ -0,0 +1,1115 @@ +/* + * Copyright (c) 2024 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 "cloud/assets_download_manager.h" +#include "cloud/cloud_storage_utils.h" +#include "cloud/virtual_asset_loader.h" +#include "cloud/virtual_cloud_data_translate.h" +#include "cloud_db_sync_utils_test.h" +#include "distributeddb_data_generate_unit_test.h" +#include "distributeddb_tools_unit_test.h" +#include "res_finalizer.h" +#include "rdb_data_generator.h" +#include "relational_store_client.h" +#include "relational_store_manager.h" +#include "runtime_config.h" +#include "virtual_communicator_aggregator.h" + +using namespace testing::ext; +using namespace DistributedDB; +using namespace DistributedDBUnitTest; +using namespace std; + +namespace { +string g_testDir; +const std::string QUERY_INCONSISTENT_SQL = + "select count(*) from naturalbase_rdb_aux_AsyncDownloadAssetsTest_log where flag&0x20!=0;"; +typedef struct SkipAssetTestParam { + DBStatus downloadRes; + bool useBatch; + bool useAsync; + int startIndex; + int expectInconsistentCount; + DBStatus expectSyncRes; +} SkipAssetTestParamT; +class DistributedDBCloudAsyncDownloadAssetsTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; +protected: + static DataBaseSchema GetSchema(bool multiTables = false); + static TableSchema GetTableSchema(const std::string &tableName, bool withoutAsset = false); + static CloudSyncOption GetAsyncCloudSyncOption(); + static int GetAssetFieldCount(); + void InitStore(); + void CloseDb(); + void DoSkipAssetDownload(SkipAssetTestParamT param); + std::string storePath_; + sqlite3 *db_ = nullptr; + RelationalStoreDelegate *delegate_ = nullptr; + std::shared_ptr virtualCloudDb_ = nullptr; + std::shared_ptr virtualAssetLoader_ = nullptr; + VirtualCommunicatorAggregator *communicatorAggregator_ = nullptr; +}; + +void DistributedDBCloudAsyncDownloadAssetsTest::SetUpTestCase() +{ + DistributedDBToolsUnitTest::TestDirInit(g_testDir); + if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) { + LOGE("rm test db files error!"); + } +} + +void DistributedDBCloudAsyncDownloadAssetsTest::TearDownTestCase() +{ + if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) { + LOGE("rm test db files error!"); + } +} + +void DistributedDBCloudAsyncDownloadAssetsTest::SetUp() +{ + DistributedDBToolsUnitTest::PrintTestCaseInfo(); + RuntimeContext::GetInstance()->SetBatchDownloadAssets(true); + InitStore(); + communicatorAggregator_ = new (std::nothrow) VirtualCommunicatorAggregator(); + ASSERT_TRUE(communicatorAggregator_ != nullptr); + RuntimeContext::GetInstance()->SetCommunicatorAggregator(communicatorAggregator_); +} + +void DistributedDBCloudAsyncDownloadAssetsTest::TearDown() +{ + CloseDb(); + if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) { + LOGE("rm test db files error."); + } + virtualCloudDb_ = nullptr; + virtualAssetLoader_ = nullptr; + RuntimeContext::GetInstance()->SetCommunicatorAggregator(nullptr); + communicatorAggregator_ = nullptr; +} + +DataBaseSchema DistributedDBCloudAsyncDownloadAssetsTest::GetSchema(bool multiTables) +{ + DataBaseSchema schema; + schema.tables.push_back(GetTableSchema("AsyncDownloadAssetsTest")); + if (multiTables) { + schema.tables.push_back(GetTableSchema("TABLE1")); + schema.tables.push_back(GetTableSchema("TABLE2")); + } + return schema; +} + +TableSchema DistributedDBCloudAsyncDownloadAssetsTest::GetTableSchema(const std::string &tableName, bool withoutAsset) +{ + TableSchema tableSchema; + tableSchema.name = tableName; + Field field; + field.primary = true; + field.type = TYPE_INDEX; + field.colName = "pk"; + tableSchema.fields.push_back(field); + field.primary = false; + field.colName = "int_field"; + tableSchema.fields.push_back(field); + if (withoutAsset) { + return tableSchema; + } + field.type = TYPE_INDEX; + field.colName = "assets_1"; + tableSchema.fields.push_back(field); + field.colName = "asset_1"; + field.type = TYPE_INDEX; + tableSchema.fields.push_back(field); + return tableSchema; +} + +CloudSyncOption DistributedDBCloudAsyncDownloadAssetsTest::GetAsyncCloudSyncOption() +{ + CloudSyncOption option; + std::vector tables; + auto schema = GetSchema(); + for (const auto &table : schema.tables) { + tables.push_back(table.name); + LOGW("[DistributedDBCloudAsyncDownloadAssetsTest] Sync with table %s", table.name.c_str()); + } + option.devices = {"cloud"}; + option.query = Query::Select().FromTable(tables); + option.mode = SYNC_MODE_CLOUD_MERGE; + option.asyncDownloadAssets = true; + return option; +} + +int DistributedDBCloudAsyncDownloadAssetsTest::GetAssetFieldCount() +{ + int count = 0; + auto schema = GetSchema(); + for (const auto &table : schema.tables) { + for (const auto &field : table.fields) { + if (field.type == TYPE_INDEX || field.type == TYPE_INDEX) { + count++; + } + } + } + return count; +} + +void DistributedDBCloudAsyncDownloadAssetsTest::InitStore() +{ + if (storePath_.empty()) { + storePath_ = g_testDir + "/" + STORE_ID_1 + ".db"; + } + db_ = RelationalTestUtils::CreateDataBase(storePath_); + ASSERT_NE(db_, nullptr); + auto schema = GetSchema(true); + EXPECT_EQ(RDBDataGenerator::InitDatabase(schema, *db_), SQLITE_OK); + RelationalStoreManager mgr(APP_ID, USER_ID); + ASSERT_EQ(mgr.OpenStore(storePath_, STORE_ID_1, {}, delegate_), OK); + ASSERT_NE(delegate_, nullptr); + for (const auto &table : schema.tables) { + EXPECT_EQ(delegate_->CreateDistributedTable(table.name, TableSyncType::CLOUD_COOPERATION), OK); + LOGI("[DistributedDBCloudAsyncDownloadAssetsTest] CreateDistributedTable %s", table.name.c_str()); + } + virtualCloudDb_ = make_shared(); + ASSERT_NE(virtualCloudDb_, nullptr); + ASSERT_EQ(delegate_->SetCloudDB(virtualCloudDb_), DBStatus::OK); + virtualAssetLoader_ = make_shared(); + ASSERT_NE(virtualAssetLoader_, nullptr); + ASSERT_EQ(delegate_->SetIAssetLoader(virtualAssetLoader_), DBStatus::OK); + RuntimeConfig::SetCloudTranslate(std::make_shared()); + + ASSERT_EQ(delegate_->SetCloudDbSchema(schema), DBStatus::OK); +} + +void CheckInconsistentCount(sqlite3 *db, int64_t expectCount) +{ + EXPECT_EQ(sqlite3_exec(db, QUERY_INCONSISTENT_SQL.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(expectCount), nullptr), SQLITE_OK); +} + +void DistributedDBCloudAsyncDownloadAssetsTest::CloseDb() +{ + if (db_ != nullptr) { + sqlite3_close_v2(db_); + db_ = nullptr; + } + if (delegate_ != nullptr) { + RelationalStoreManager mgr(APP_ID, USER_ID); + EXPECT_EQ(mgr.CloseStore(delegate_), OK); + } +} + +/** + * @tc.name: AsyncDownloadAssetConfig001 + * @tc.desc: Test config with valid and invalid param. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, AsyncDownloadAssetConfig001, TestSize.Level0) +{ + /** + * @tc.steps: step1. Set valid param + * @tc.expected: step1.ok + */ + AsyncDownloadAssetsConfig config; + AssetsDownloadManager manager; + EXPECT_EQ(manager.SetAsyncDownloadAssetsConfig(config), E_OK); + config.maxDownloadTask = CloudDbConstant::MAX_ASYNC_DOWNLOAD_TASK; + EXPECT_EQ(manager.SetAsyncDownloadAssetsConfig(config), E_OK); + config.maxDownloadAssetsCount = CloudDbConstant::MAX_ASYNC_DOWNLOAD_ASSETS; + EXPECT_EQ(manager.SetAsyncDownloadAssetsConfig(config), E_OK); + + /** + * @tc.steps: step2. Set invalid param + * @tc.expected: step2.invalid args + */ + config.maxDownloadTask += 1u; + EXPECT_EQ(manager.SetAsyncDownloadAssetsConfig(config), -E_INVALID_ARGS); + config.maxDownloadTask = CloudDbConstant::MAX_ASYNC_DOWNLOAD_TASK; + config.maxDownloadAssetsCount += 1u; + EXPECT_EQ(manager.SetAsyncDownloadAssetsConfig(config), -E_INVALID_ARGS); +} + +/** + * @tc.name: AsyncDownloadAssetConfig002 + * @tc.desc: Test config work correctly. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, AsyncDownloadAssetConfig002, TestSize.Level0) +{ + /** + * @tc.steps: step1. Set valid param twice + * @tc.expected: step1. ok + */ + AsyncDownloadAssetsConfig config; + config.maxDownloadTask = 10; + EXPECT_EQ(RuntimeConfig::SetAsyncDownloadAssetsConfig(config), OK); + config.maxDownloadTask = 1; + EXPECT_EQ(RuntimeConfig::SetAsyncDownloadAssetsConfig(config), OK); + /** + * @tc.steps: step2. Insert cloud data + * @tc.expected: step2. ok + */ + const int cloudCount = 20; + auto schema = GetSchema(); + EXPECT_EQ(RDBDataGenerator::InsertCloudDBData(0, cloudCount, 0, schema, virtualCloudDb_), OK); + /** + * @tc.steps: step3. Begin download first, block async task + * @tc.expected: step3. ok + */ + auto manager = RuntimeContext::GetInstance()->GetAssetsDownloadManager(); + int finishCount = 0; + std::mutex finishMutex; + std::condition_variable cv; + auto finishAction = [&finishCount, &finishMutex, &cv](void *) { + std::lock_guard autoLock(finishMutex); + finishCount++; + cv.notify_all(); + }; + auto [errCode, listener] = manager->BeginDownloadWithListener(finishAction); + ASSERT_EQ(errCode, E_OK); + ASSERT_EQ(listener, nullptr); + ASSERT_EQ(manager->GetCurrentDownloadCount(), 1u); + std::tie(errCode, listener) = manager->BeginDownloadWithListener(finishAction); + ASSERT_EQ(errCode, -E_MAX_LIMITS); + ASSERT_NE(listener, nullptr); + /** + * @tc.steps: step4. Async cloud data + * @tc.expected: step4. ok and async task still one + */ + CloudSyncOption option = GetAsyncCloudSyncOption(); + RelationalTestUtils::CloudBlockSync(option, delegate_); + EXPECT_EQ(manager->GetCurrentDownloadCount(), 1u); + /** + * @tc.steps: step5. Notify async task finish + * @tc.expected: step5. wait util another async task finish + */ + manager->FinishDownload(); + std::unique_lock uniqueLock(finishMutex); + auto res = cv.wait_for(uniqueLock, std::chrono::milliseconds(DBConstant::MIN_TIMEOUT), [&finishCount]() { + return finishCount >= 2; // 2 async task + }); + EXPECT_TRUE(res); + listener->Drop(true); +} + +/** + * @tc.name: AsyncDownloadAssetConfig003 + * @tc.desc: Test asyncDownloadAssets and compensatedSyncOnly both true. + * @tc.type: FUNC + * @tc.require: + * @tc.author: tankaisheng + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, AsyncDownloadAssetConfig003, TestSize.Level0) +{ + /** + * @tc.steps: step1. Insert cloud data + * @tc.expected: step1. ok + */ + const int cloudCount = 10; + auto schema = GetSchema(); + EXPECT_EQ(RDBDataGenerator::InsertCloudDBData(0, cloudCount, 0, schema, virtualCloudDb_), OK); + /** + * @tc.steps: step2. set compensatedSyncOnly true and sync return NOT_SUPPORT. + * @tc.expected: step2. NOT_SUPPORT + */ + CloudSyncOption option = GetAsyncCloudSyncOption(); + option.compensatedSyncOnly = true; + DBStatus result = delegate_->Sync(option, nullptr); + EXPECT_EQ(result, NOT_SUPPORT); +} + +/** + * @tc.name: FinishListener001 + * @tc.desc: Test listen download finish event. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, FinishListener001, TestSize.Level0) +{ + /** + * @tc.steps: step1. Begin download first time + * @tc.expected: step1.ok + */ + AssetsDownloadManager manager; + std::atomic finished = false; + auto finishAction = [&finished](void *) { + EXPECT_TRUE(finished); + }; + auto [errCode, listener] = manager.BeginDownloadWithListener(finishAction); + ASSERT_EQ(errCode, E_OK); + ASSERT_EQ(listener, nullptr); + /** + * @tc.steps: step2. Begin download twice + * @tc.expected: step2. -E_MAX_LIMITS because default one task + */ + std::tie(errCode, listener) = manager.BeginDownloadWithListener(finishAction); + EXPECT_EQ(errCode, -E_MAX_LIMITS); + EXPECT_NE(listener, nullptr); + /** + * @tc.steps: step3. Finish download + * @tc.expected: step3. finished is true in listener + */ + finished = true; + manager.FinishDownload(); + listener->Drop(true); +} + +/** + * @tc.name: AsyncComplexDownload001 + * @tc.desc: Test complex async download. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, AsyncComplexDownload001, TestSize.Level0) +{ + /** + * @tc.steps: step1. Set max download task 1 + * @tc.expected: step1. ok + */ + AsyncDownloadAssetsConfig config; + config.maxDownloadTask = 1; + config.maxDownloadAssetsCount = 1; + EXPECT_EQ(RuntimeConfig::SetAsyncDownloadAssetsConfig(config), OK); + /** + * @tc.steps: step2. Insert cloud data + * @tc.expected: step2. ok + */ + const int cloudCount = 10; + auto schema = GetSchema(); + EXPECT_EQ(RDBDataGenerator::InsertCloudDBData(0, cloudCount, 0, schema, virtualCloudDb_), OK); + /** + * @tc.steps: step3. Async cloud data + * @tc.expected: step3. ok + */ + CloudSyncOption option = GetAsyncCloudSyncOption(); + RelationalTestUtils::CloudBlockSync(option, delegate_); + /** + * @tc.steps: step3. Block download cloud data + * @tc.expected: step3. ok + */ + option.asyncDownloadAssets = false; + RelationalTestUtils::CloudBlockSync(option, delegate_); +} + +/** + * @tc.name: AsyncComplexDownload002 + * @tc.desc: Test complex async download. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, AsyncComplexDownload002, TestSize.Level0) +{ + /** + * @tc.steps: step1. Set max download task 1 + * @tc.expected: step1. ok + */ + AsyncDownloadAssetsConfig config; + config.maxDownloadTask = 1; + config.maxDownloadAssetsCount = 1; + EXPECT_EQ(RuntimeConfig::SetAsyncDownloadAssetsConfig(config), OK); + /** + * @tc.steps: step2. Insert cloud data + * @tc.expected: step2. ok + */ + const int cloudCount = 10; + auto schema = GetSchema(); + EXPECT_EQ(RDBDataGenerator::InsertCloudDBData(0, cloudCount, 0, schema, virtualCloudDb_), OK); + /** + * @tc.steps: step3. Complex cloud data + * @tc.expected: step3. ok + */ + CloudSyncOption option = GetAsyncCloudSyncOption(); + for (int i = 0; i < 10; ++i) { // loop 10 times + option.asyncDownloadAssets = false; + RelationalTestUtils::CloudBlockSync(option, delegate_); + option.asyncDownloadAssets = true; + RelationalTestUtils::CloudBlockSync(option, delegate_); + } +} + +/** + * @tc.name: AsyncAbnormalDownload001 + * @tc.desc: Test abnormal async download. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, AsyncAbnormalDownload001, TestSize.Level4) +{ + /** + * @tc.steps: step1. Set max download task 1 + * @tc.expected: step1. ok + */ + AsyncDownloadAssetsConfig config; + config.maxDownloadTask = 1; + config.maxDownloadAssetsCount = 1; + EXPECT_EQ(RuntimeConfig::SetAsyncDownloadAssetsConfig(config), OK); + /** + * @tc.steps: step2. Insert cloud data + * @tc.expected: step2. ok + */ + const int cloudCount = 10; + auto schema = GetSchema(); + EXPECT_EQ(RDBDataGenerator::InsertCloudDBData(0, cloudCount, 0, schema, virtualCloudDb_), OK); + /** + * @tc.steps: step3. Fork download abnormal + */ + virtualAssetLoader_->SetDownloadStatus(DB_ERROR); + /** + * @tc.steps: step4. Async cloud data + * @tc.expected: step4. ok + */ + CloudSyncOption option = GetAsyncCloudSyncOption(); + RelationalTestUtils::CloudBlockSync(option, delegate_); + auto [status, downloadCount] = delegate_->GetDownloadingAssetsCount(); + EXPECT_EQ(status, OK); + EXPECT_EQ(downloadCount, cloudCount * GetAssetFieldCount()); + EXPECT_FALSE(RelationalTestUtils::IsExistEmptyHashAsset(db_, GetTableSchema("AsyncDownloadAssetsTest"))); + std::this_thread::sleep_for(std::chrono::seconds(1)); + /** + * @tc.steps: step5. Async cloud data with download ok + * @tc.expected: step5. ok + */ + virtualAssetLoader_->SetDownloadStatus(OK); + LOGW("set download ok"); + int count = 0; + std::mutex countMutex; + std::condition_variable cv; + virtualAssetLoader_->ForkDownload([&count, &countMutex, &cv](const std::string &tableName, + std::map &) { + std::lock_guard autoLock(countMutex); + count++; + if (count == 1) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + cv.notify_all(); + }); + RelationalTestUtils::CloudBlockSync(option, delegate_); + std::unique_lock uniqueLock(countMutex); + cv.wait_for(uniqueLock, std::chrono::milliseconds(DBConstant::MIN_TIMEOUT), [&count]() { + return count >= cloudCount; + }); + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::tie(status, downloadCount) = delegate_->GetDownloadingAssetsCount(); + EXPECT_EQ(status, OK); + EXPECT_EQ(downloadCount, 0); + virtualAssetLoader_->ForkDownload(nullptr); +} + +/** + * @tc.name: AsyncAbnormalDownload002 + * @tc.desc: Test abnormal sync download. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, AsyncAbnormalDownload002, TestSize.Level0) +{ + /** + * @tc.steps: step1. Insert cloud data + * @tc.expected: step1. ok + */ + const int cloudCount = 10; + auto schema = GetSchema(); + EXPECT_EQ(RDBDataGenerator::InsertCloudDBData(0, cloudCount, 0, schema, virtualCloudDb_), OK); + /** + * @tc.steps: step2. Fork download abnormal + */ + virtualAssetLoader_->SetDownloadStatus(DB_ERROR); + /** + * @tc.steps: step3. Sync cloud data + * @tc.expected: step3. DB_ERROR and not exist downloading assets count + */ + CloudSyncOption option = GetAsyncCloudSyncOption(); + option.asyncDownloadAssets = false; + RelationalTestUtils::CloudBlockSync(option, delegate_, OK, CLOUD_ERROR); + auto [status, downloadCount] = delegate_->GetDownloadingAssetsCount(); + EXPECT_EQ(status, OK); + EXPECT_EQ(downloadCount, 0); + virtualAssetLoader_->SetDownloadStatus(OK); +} + +/** + * @tc.name: AsyncAbnormalDownload003 + * @tc.desc: Test abnormal async download. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, AsyncAbnormalDownload003, TestSize.Level4) +{ + /** + * @tc.steps: step1. Set max download task 1 + * @tc.expected: step1. ok + */ + AsyncDownloadAssetsConfig config; + config.maxDownloadTask = 1; + config.maxDownloadAssetsCount = 4; // 1 record has 2 asset, config 1 batch has 2 record + EXPECT_EQ(RuntimeConfig::SetAsyncDownloadAssetsConfig(config), OK); + /** + * @tc.steps: step2. Insert cloud data + * @tc.expected: step2. ok + */ + const int cloudCount = 5; + auto schema = GetSchema(); + EXPECT_EQ(RDBDataGenerator::InsertCloudDBData(0, cloudCount, 0, schema, virtualCloudDb_), OK); + /** + * @tc.steps: step3. Fork download abnormal + */ + virtualAssetLoader_->SetDownloadStatus(DB_ERROR); + /** + * @tc.steps: step4. Sync cloud data + * @tc.expected: step4. DB_ERROR and exist downloading assets count + */ + CloudSyncOption option = GetAsyncCloudSyncOption(); + EXPECT_NO_FATAL_FAILURE(RelationalTestUtils::CloudBlockSync(option, delegate_)); + auto [status, downloadCount] = delegate_->GetDownloadingAssetsCount(); + EXPECT_EQ(status, OK); + EXPECT_EQ(downloadCount, cloudCount * 2); // 1 record has 2 asset + CheckInconsistentCount(db_, 5); + std::this_thread::sleep_for(std::chrono::seconds(1)); + /** + * @tc.steps: step5. Sync cloud data again and block upload + * @tc.expected: step5. DB_ERROR and exist downloading assets count + */ + EXPECT_EQ(RDBDataGenerator::InsertLocalDBData(cloudCount + 1, 1, db_, GetSchema()), E_OK); + virtualAssetLoader_->SetDownloadStatus(OK); + virtualCloudDb_->ForkUpload([delegate = delegate_](const std::string &, VBucket &) { + std::this_thread::sleep_for(std::chrono::seconds(2)); // sleep 2s + auto [ret, count] = delegate->GetDownloadingAssetsCount(); + EXPECT_EQ(ret, OK); + EXPECT_EQ(count, 0); + }); + EXPECT_NO_FATAL_FAILURE(RelationalTestUtils::CloudBlockSync(option, delegate_)); + virtualAssetLoader_->ForkBatchDownload(nullptr); +} + +/** + * @tc.name: AsyncAbnormalDownload004 + * @tc.desc: Test update trigger retain 0x1000 flag. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, AsyncAbnormalDownload004, TestSize.Level0) +{ + /** + * @tc.steps: step1. Set async config + * @tc.expected: step1. ok + */ + AsyncDownloadAssetsConfig config; + EXPECT_EQ(RuntimeConfig::SetAsyncDownloadAssetsConfig(config), OK); + /** + * @tc.steps: step2. Insert cloud data + * @tc.expected: step2. ok + */ + const int cloudCount = 1; + auto schema = GetSchema(); + EXPECT_EQ(RDBDataGenerator::InsertCloudDBData(0, cloudCount, 0, schema, virtualCloudDb_), OK); + /** + * @tc.steps: step3. Fork download abnormal + */ + virtualAssetLoader_->SetDownloadStatus(DB_ERROR); + /** + * @tc.steps: step4. Sync cloud data + * @tc.expected: step4. DB_ERROR and exist downloading assets count + */ + CloudSyncOption option = GetAsyncCloudSyncOption(); + EXPECT_NO_FATAL_FAILURE(RelationalTestUtils::CloudBlockSync(option, delegate_)); + auto [status, downloadCount] = delegate_->GetDownloadingAssetsCount(); + EXPECT_EQ(status, OK); + EXPECT_EQ(downloadCount, cloudCount * 2); // 1 record has 2 asset + /** + * @tc.steps: step5. Update local data + * @tc.expected: step5. Exist downloading assets count + */ + EXPECT_EQ(RDBDataGenerator::UpsertLocalDBData(0, cloudCount, db_, + GetTableSchema("AsyncDownloadAssetsTest", true)), OK); + std::tie(status, downloadCount) = delegate_->GetDownloadingAssetsCount(); + EXPECT_EQ(status, OK); + EXPECT_EQ(downloadCount, cloudCount * 2); // 1 record has 2 asset +} + +/** + * @tc.name: AsyncAbnormalDownload005 + * @tc.desc: Test download assets which was locked + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, AsyncAbnormalDownload005, TestSize.Level1) +{ + /** + * @tc.steps: step1. Set async config + * @tc.expected: step1. ok + */ + AsyncDownloadAssetsConfig config; + EXPECT_EQ(RuntimeConfig::SetAsyncDownloadAssetsConfig(config), OK); + /** + * @tc.steps: step2. Init data + * @tc.expected: step2. ok + */ + const int cloudCount = 10; + auto schema = GetSchema(); + ASSERT_TRUE(!schema.tables.empty()); + EXPECT_EQ(RDBDataGenerator::InsertCloudDBData(0, cloudCount, 0, schema, virtualCloudDb_), OK); + CloudSyncOption option = GetAsyncCloudSyncOption(); + option.asyncDownloadAssets = false; + RelationalTestUtils::CloudBlockSync(option, delegate_, OK, OK); + /** + * @tc.steps: step3. Update cloud data and lock local data + * @tc.expected: step3. ok + */ + auto [records, extends] = + RDBDataGenerator::GenerateDataRecords(0, cloudCount, 0, schema.tables.front().fields); + Asset asset = {.name = "asset_1", .hash = "new_hash"}; + for (auto &record : records) { + record.insert_or_assign("asset_1", asset); + } + std::string table = schema.tables.front().name; + EXPECT_EQ(virtualCloudDb_->BatchUpdate(table, std::move(records), extends), OK); + virtualAssetLoader_->ForkDownload([&](const std::string &tableName, + std::map &) { + std::vector> hashKey; + CloudDBSyncUtilsTest::GetHashKey(table, "data_key < 5", db_, hashKey); // lock half of the data + EXPECT_EQ(Lock(table, hashKey, db_), OK); + }); + /** + * @tc.steps: step4. Sync and check data + * @tc.expected: step4. ok + */ + option.asyncDownloadAssets = true; + EXPECT_NO_FATAL_FAILURE(RelationalTestUtils::CloudBlockSync(option, delegate_)); + std::this_thread::sleep_for(std::chrono::seconds(1)); + auto [status, downloadCount] = delegate_->GetDownloadingAssetsCount(); + EXPECT_EQ(status, OK); + EXPECT_EQ(downloadCount, cloudCount / 2); // half of the data was not downloaded due to being locked + virtualAssetLoader_->ForkDownload(nullptr); +} + +/** + * @tc.name: AsyncNormalDownload001 + * @tc.desc: Test abnormal async download. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, AsyncNormalDownload001, TestSize.Level0) +{ + /** + * @tc.steps: step1. Register observer + * @tc.expected: step1. ok + */ + auto rdbObserver = new(std::nothrow) RelationalStoreObserverUnitTest(); + ASSERT_NE(rdbObserver, nullptr); + ResFinalizer resFinalizer([rdbObserver, this]() { + delegate_->UnRegisterObserver(rdbObserver); + delete rdbObserver; + }); + EXPECT_EQ(delegate_->RegisterObserver(rdbObserver), OK); + /** + * @tc.steps: step2. Insert cloud data + * @tc.expected: step2. ok + */ + const int cloudCount = 1; + auto schema = GetSchema(); + EXPECT_EQ(RDBDataGenerator::InsertCloudDBData(0, cloudCount, 0, schema, virtualCloudDb_), OK); + EXPECT_EQ(RDBDataGenerator::InsertLocalDBData(cloudCount + 1, 1, db_, GetSchema()), E_OK); + /** + * @tc.steps: step3. Block upload while async donwload asset + * @tc.expected: step3. Sync ok + */ + auto hook = RelationalTestUtils::GetRDBStorageHook(USER_ID, APP_ID, STORE_ID_1, storePath_); + ASSERT_NE(hook, nullptr); + hook->SetBeforeUploadTransaction([]() { + int count = 1; + const int maxLoop = 5; + do { + std::this_thread::sleep_for(std::chrono::seconds(1)); + count++; + } while (RuntimeContext::GetInstance()->GetAssetsDownloadManager()->GetCurrentDownloadCount() > 0 && + count < maxLoop); + LOGW("AsyncNormalDownload001 End hook"); + }); + CloudSyncOption option = GetAsyncCloudSyncOption(); + EXPECT_NO_FATAL_FAILURE(RelationalTestUtils::CloudBlockSync(option, delegate_)); + EXPECT_TRUE(rdbObserver->IsAssetChange(GetTableSchema("AsyncDownloadAssetsTest").name)); + hook->SetBeforeUploadTransaction(nullptr); +} + +/** + * @tc.name: AsyncNormalDownload002 + * @tc.desc: Test sync download when download task pool is full + * @tc.type: FUNC + * @tc.require: + * @tc.author: lhy + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, AsyncNormalDownload002, TestSize.Level4) +{ + /** + * @tc.steps: step1. Set max download task 1 + * @tc.expected: step1. Ok + */ + AsyncDownloadAssetsConfig config; + config.maxDownloadTask = 1; + EXPECT_EQ(RuntimeConfig::SetAsyncDownloadAssetsConfig(config), OK); + /** + * @tc.steps: step2. Insert cloud data + * @tc.expected: step2. Ok + */ + const int cloudCount = 1; + auto schema = GetSchema(); + EXPECT_EQ(RDBDataGenerator::InsertCloudDBData(0, cloudCount, 0, schema, virtualCloudDb_), OK); + /** + * @tc.steps: step3. Fork download abnormal + */ + virtualAssetLoader_->SetDownloadStatus(DB_ERROR); + /** + * @tc.steps: step4. Async cloud data, with abnormal result + * @tc.expected: step4. Ok + */ + CloudSyncOption option = GetAsyncCloudSyncOption(); + RelationalTestUtils::CloudBlockSync(option, delegate_); + auto [status, downloadCount] = delegate_->GetDownloadingAssetsCount(); + EXPECT_EQ(status, OK); + EXPECT_EQ(downloadCount, cloudCount * GetAssetFieldCount()); + EXPECT_FALSE(RelationalTestUtils::IsExistEmptyHashAsset(db_, GetTableSchema("AsyncDownloadAssetsTest"))); + /** + * @tc.steps: step5. Wait for failed download to finish + * @tc.expected: step5. Download task changes from 1 to 0 + */ + auto manager = RuntimeContext::GetInstance()->GetAssetsDownloadManager(); + EXPECT_EQ(manager->GetCurrentDownloadCount(), 1u); + std::this_thread::sleep_for(std::chrono::seconds(1)); + EXPECT_EQ(manager->GetCurrentDownloadCount(), 0u); + /** + * @tc.steps: step6. Start a new download task to reach maxDownloadTask + * @tc.expected: step6. 1 task is downloading + */ + auto [errCode, listener] = manager->BeginDownloadWithListener(nullptr); + ASSERT_EQ(errCode, E_OK); + ASSERT_EQ(listener, nullptr); + ASSERT_EQ(manager->GetCurrentDownloadCount(), 1u); + /** + * @tc.steps: step7. Set download status to ok then try sync while task pool is full + * @tc.expected: step7. Download should be waiting instead of doing compensated sync + */ + virtualAssetLoader_->SetDownloadStatus(OK); + LOGW("set download ok"); + int count = 0; + std::mutex countMutex; + std::condition_variable cv; + virtualAssetLoader_->ForkDownload([&count, &countMutex, &cv](const std::string &tableName, + std::map &) { + std::lock_guard autoLock(countMutex); + count++; + if (count == 1) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + cv.notify_all(); + }); + RelationalTestUtils::CloudBlockSync(option, delegate_); + std::this_thread::sleep_for(std::chrono::seconds(1)); + EXPECT_EQ(count, 0); + /** + * @tc.steps: step8. Finish the download task, to let sync continue + * @tc.expected: step8. Only 1 actural download through virtualAssetLoader_ + */ + manager->FinishDownload(); + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::unique_lock uniqueLock(countMutex); + cv.wait_for(uniqueLock, std::chrono::milliseconds(DBConstant::MIN_TIMEOUT), [&count]() { + return count >= cloudCount; + }); + EXPECT_EQ(count, 1); + virtualAssetLoader_->ForkDownload(nullptr); +} + +/** + * @tc.name: AsyncNormalDownload003 + * @tc.desc: Test:async asset task paused + * @tc.type: FUNC + * @tc.require: + * @tc.author: bty + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, AsyncNormalDownload003, TestSize.Level4) +{ + /** + * @tc.steps: step1. Set max download task 1 + * @tc.expected: step1. Ok + */ + AsyncDownloadAssetsConfig config; + config.maxDownloadTask = 1; + EXPECT_EQ(RuntimeConfig::SetAsyncDownloadAssetsConfig(config), OK); + /** + * @tc.steps: step2. Insert cloud data + * @tc.expected: step2. Ok + */ + const int cloudCount = 1; + auto schema = GetSchema(); + EXPECT_EQ(RDBDataGenerator::InsertCloudDBData(0, cloudCount, 0, schema, virtualCloudDb_), OK); + /** + * @tc.steps: step3. async asset task submit + * @tc.expected: step3. Ok + */ + int count = 0; + int expQueryTimes = 3; + std::mutex mutex; + std::condition_variable cond; + virtualCloudDb_->ForkQuery([&count, &cond, expQueryTimes](const std::string &, VBucket &extend) { + count++; + if (count == 1) { + cond.notify_all(); + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + if (count == expQueryTimes) { + std::string cursor; + CloudStorageUtils::GetValueFromVBucket(CloudDbConstant::CURSOR_FIELD, extend, cursor); + EXPECT_EQ(cursor, std::string("1")); + } + }); + std::thread t1([this]{ + CloudSyncOption option = GetAsyncCloudSyncOption(); + EXPECT_NO_FATAL_FAILURE(RelationalTestUtils::CloudBlockSync(option, delegate_)); + }); + /** + * @tc.steps: step4. wait for async task query + * @tc.expected: step4. Ok + */ + { + std::unique_lock lock(mutex); + (void)cond.wait_for(lock, std::chrono::seconds(1), [&count]() { + return count == 1; + }); + } + /** + * @tc.steps: step5. priority task submit + * @tc.expected: step5. Ok + */ + CloudSyncOption priOption = GetAsyncCloudSyncOption(); + std::vector inValue = {3, 4}; + priOption.priorityTask = true; + priOption.query = Query::Select().From("AsyncDownloadAssetsTest").In("pk", inValue); + priOption.asyncDownloadAssets = false; + EXPECT_NO_FATAL_FAILURE(RelationalTestUtils::CloudBlockSync(priOption, delegate_)); + t1.join(); + virtualCloudDb_->ForkQuery(nullptr); + EXPECT_EQ(count, expQueryTimes); +} + +/** + * @tc.name: AsyncNormalDownload004 + * @tc.desc: Test multiple tables and multiple batches of asset downloads + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, AsyncNormalDownload004, TestSize.Level1) +{ + /** + * @tc.steps: step1. Set max download task 1 + * @tc.expected: step1. Ok + */ + AsyncDownloadAssetsConfig config; + config.maxDownloadAssetsCount = 25; + EXPECT_EQ(RuntimeConfig::SetAsyncDownloadAssetsConfig(config), OK); + /** + * @tc.steps: step2. Insert cloud data + * @tc.expected: step2. Ok + */ + const int cloudCount = 100; + std::string table1 = "TABLE1"; + std::string table2 = "TABLE2"; + DataBaseSchema schema; + schema.tables.push_back(GetTableSchema(table1)); + schema.tables.push_back(GetTableSchema(table2)); + EXPECT_EQ(RDBDataGenerator::InitDatabase(schema, *db_), SQLITE_OK); + auto [record1, extend1] = RDBDataGenerator::GenerateDataRecords(0, cloudCount, 0, GetTableSchema(table1).fields); + EXPECT_EQ(virtualCloudDb_->BatchInsertWithGid(table1, std::move(record1), extend1), OK); + auto [record2, extend2] = RDBDataGenerator::GenerateDataRecords(0, cloudCount, cloudCount, + GetTableSchema(table2).fields); + EXPECT_EQ(virtualCloudDb_->BatchInsertWithGid(table2, std::move(record2), extend2), OK); + /** + * @tc.steps: step3. async asset task submit + * @tc.expected: step3. Ok + */ + int assetsDownloadTime = 0; + virtualAssetLoader_->ForkDownload([&table1, &table2, &assetsDownloadTime](const std::string &tableName, + std::map &) { + if (assetsDownloadTime < 100) { // 100 assets + EXPECT_EQ(tableName, table1); + } else { + EXPECT_EQ(tableName, table2); + } + assetsDownloadTime++; + }); + CloudSyncOption option; + option.devices = {"cloud"}; + option.asyncDownloadAssets = true; + Query query = Query::Select().FromTable({table1, table2}); + option.query = query; + EXPECT_NO_FATAL_FAILURE(RelationalTestUtils::CloudBlockSync(option, delegate_)); + std::this_thread::sleep_for(std::chrono::seconds(5)); + EXPECT_EQ(assetsDownloadTime, 200); + virtualAssetLoader_->ForkDownload(nullptr); +} + +DBStatus ModifySkippedAsset(int rowIndex, std::map &assets, DBStatus fakeStatus) +{ + if (rowIndex != 1) { + return OK; + } + for (auto &asset : assets) { + for (auto &item : asset.second) { + if (item.name == "asset_1" + std::to_string(rowIndex)) { + item.status = static_cast(AssetStatus::ABNORMAL); + } + } + } + return fakeStatus; +} + +void DistributedDBCloudAsyncDownloadAssetsTest::DoSkipAssetDownload(SkipAssetTestParamT param) +{ + /** + * @tc.steps: step1 change max download task + * @tc.expected: step1. Ok + */ + AsyncDownloadAssetsConfig config; + config.maxDownloadTask = CloudDbConstant::MAX_ASYNC_DOWNLOAD_TASK; // maximum of tasks + config.maxDownloadAssetsCount = CloudDbConstant::MAX_ASYNC_DOWNLOAD_ASSETS; // maximum of asset counts + EXPECT_EQ(RuntimeConfig::SetAsyncDownloadAssetsConfig(config), OK); + /** + * @tc.steps: step2 Insert cloud data + * @tc.expected: step2. Ok + */ + const int cloudCount = 5; + auto schema = GetSchema(); + std::string tableName = "AsyncDownloadAssetsTest"; + EXPECT_EQ(RDBDataGenerator::InsertCloudDBData(param.startIndex, cloudCount, 0, schema, virtualCloudDb_), OK); + CloudDBSyncUtilsTest::CheckLocalRecordNum(db_, tableName, param.startIndex); + /** + * @tc.steps: step3 Fork download abnormal + * @tc.expected: step3. Ok + */ + int count = 0; + std::mutex countMutex; + std::condition_variable cv; + if (param.useBatch) { + RuntimeContext::GetInstance()->SetBatchDownloadAssets(true); + virtualAssetLoader_->ForkBatchDownload([&count, &countMutex, &cv, param](int rowIndex, + std::map &assets) { + std::lock_guard autoLock(countMutex); + count++; + auto ret = ModifySkippedAsset(rowIndex, assets, param.downloadRes); + if (count == 1) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + cv.notify_all(); + return ret; + }); + } else { + RuntimeContext::GetInstance()->SetBatchDownloadAssets(false); + virtualAssetLoader_->SetDownloadStatus(param.downloadRes); + } + /** + * @tc.steps: step4. sync cloud data + * @tc.expected: step4. Ok + */ + CloudSyncOption option = GetAsyncCloudSyncOption(); + option.asyncDownloadAssets = param.useAsync; + RelationalTestUtils::CloudBlockSync(option, delegate_, param.expectSyncRes); + /** + * @tc.steps: step5. wait for sync to finish + * @tc.expected: step5. check local record number and inconsistent count + */ + std::unique_lock uniqueLock(countMutex); + auto res = cv.wait_for(uniqueLock, std::chrono::seconds(DBConstant::MAX_SYNC_TIMEOUT), + [&count, param, cloudCount] { + return count >= cloudCount || !param.useBatch; + }); + EXPECT_TRUE(res); + std::this_thread::sleep_for(std::chrono::seconds(1)); + CloudDBSyncUtilsTest::CheckLocalRecordNum(db_, tableName, param.startIndex + cloudCount); + CheckInconsistentCount(db_, param.expectInconsistentCount); + /** + * @tc.steps: step6. clear + */ + virtualAssetLoader_->SetDownloadStatus(OK); + virtualAssetLoader_->Reset(); + virtualAssetLoader_->ForkBatchDownload(nullptr); +} + +/** + * @tc.name: SkipAssetDownloadTest001 + * @tc.desc: Test async batch download returns Skip_Assets + * @tc.type: FUNC + * @tc.require: + * @tc.author: liuhongyang + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, SkipAssetDownloadTest001, TestSize.Level1) +{ + /** + * @tc.expected: step1. sync return OK, and has 0 inconsistent records + */ + SkipAssetTestParamT param = {.downloadRes = SKIP_ASSET, .useBatch = true, .useAsync = true, + .startIndex = 0, .expectInconsistentCount = 0, .expectSyncRes = OK}; + DoSkipAssetDownload(param); +} + +/** + * @tc.name: SkipAssetDownloadTest002 + * @tc.desc: Test sync batch download returns Skip_Assets + * @tc.type: FUNC + * @tc.require: + * @tc.author: liuhongyang + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, SkipAssetDownloadTest002, TestSize.Level1) +{ + /** + * @tc.expected: step1. sync return OK, and has 1 inconsistent records + */ + SkipAssetTestParamT param = {.downloadRes = SKIP_ASSET, .useBatch = true, .useAsync = false, + .startIndex = 0, .expectInconsistentCount = 1, .expectSyncRes = OK}; + DoSkipAssetDownload(param); +} + +/** + * @tc.name: SkipAssetDownloadTest003 + * @tc.desc: Test sync one-by-one download returns Skip_Assets + * @tc.type: FUNC + * @tc.require: + * @tc.author: liuhongyang + */ +HWTEST_F(DistributedDBCloudAsyncDownloadAssetsTest, SkipAssetDownloadTest003, TestSize.Level1) +{ + /** + * @tc.expected: step1. sync return OK, and has 5 inconsistent records + */ + SkipAssetTestParamT param = {.downloadRes = SKIP_ASSET, .useBatch = false, .useAsync = false, + .startIndex = 0, .expectInconsistentCount = 5, .expectSyncRes = OK}; + DoSkipAssetDownload(param); +} +} \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_db_proxy_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_db_proxy_test.cpp index 904aae4c11a727b81e1b39ccc7c57bac559abcdf..682e158b6cf5cc99b660570bad8167a1af28ef21 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_db_proxy_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_db_proxy_test.cpp @@ -986,7 +986,7 @@ HWTEST_F(DistributedDBCloudDBProxyTest, CloudDBProxyTest015, TestSize.Level0) ret = proxy.BatchDownload(TABLE_NAME, downloadAssets); EXPECT_EQ(ret, E_OK); - EXPECT_EQ(virtialAssetLoader->GetBatchDownloadCount(), 1); + EXPECT_EQ(virtialAssetLoader->GetBatchDownloadCount(), 1u); EXPECT_EQ(totalRecordsUsed, 2); EXPECT_EQ(downloadAssets[0].status, OK); EXPECT_EQ(downloadAssets[1].status, DB_ERROR); @@ -996,6 +996,22 @@ HWTEST_F(DistributedDBCloudDBProxyTest, CloudDBProxyTest015, TestSize.Level0) EXPECT_EQ(downloadAssets[3].assets["a2"][0].version, uintExpected); } +/** + * @tc.name: CloudDBProxyTest016 + * @tc.desc: Verify cancel download + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBCloudDBProxyTest, CloudDBProxyTest016, TestSize.Level0) +{ + auto proxy = std::make_shared(); + auto loader = make_shared(); + proxy->SetIAssetLoader(loader); + proxy->CancelDownload(); + EXPECT_EQ(loader->GetCancelCount(), 0u); +} + /** * @tc.name: CloudSyncUtilsTest * @tc.desc: Verify CloudSyncUtils interfaces diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_kv_syncer_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_kv_syncer_test.cpp index 4957feda7c26ddbb421d23b8e09cd30bd8eb8379..9fc1014ebf18ac472154e910fd50387d413d8cc0 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_kv_syncer_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_kv_syncer_test.cpp @@ -494,6 +494,29 @@ HWTEST_F(DistributedDBCloudKvSyncerTest, UploadAbnormalSync004, TestSize.Level0) virtualCloudDb_->SetActionStatus(OK); } +/** + * @tc.name: UploadAbnormalSync005 + * @tc.desc: Test sync return CLOUD_DISABLED + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBCloudKvSyncerTest, UploadAbnormalSync005, TestSize.Level0) +{ + /** + * @tc.steps:step1. Put 1 record to cloud + * @tc.expected: step1 OK + */ + EXPECT_EQ(kvDelegatePtrS1_->Put(KEY_1, VALUE_1), OK); + BlockSync(kvDelegatePtrS1_, OK, g_CloudSyncoption); + /** + * @tc.steps:step2. Set error code CLOUD_DISABLED when query cloud data, and sync + * @tc.expected: step2 return CLOUD_DISABLED + */ + virtualCloudDb_->SetActionStatus(CLOUD_DISABLED); + BlockSync(kvDelegatePtrS2_, CLOUD_DISABLED, g_CloudSyncoption); +} + /** * @tc.name: QueryParsingProcessTest001 * @tc.desc: Test Query parsing process. @@ -518,7 +541,7 @@ HWTEST_F(DistributedDBCloudKvSyncerTest, QueryParsingProcessTest001, TestSize.Le * @tc.steps:step2. Test Query parsing Process * @tc.expected: step2 OK. */ - QuerySyncObject syncObject; + std::vector syncObject; std::vector syncDataPk; VBucket bucket; bucket.insert_or_assign(std::string("k"), std::string("k")); @@ -527,16 +550,16 @@ HWTEST_F(DistributedDBCloudKvSyncerTest, QueryParsingProcessTest001, TestSize.Le ASSERT_EQ(CloudStorageUtils::GetSyncQueryByPk(tableName, syncDataPk, true, syncObject), E_OK); Bytes bytes; - bytes.resize(syncObject.CalculateParcelLen(SOFTWARE_VERSION_CURRENT)); + bytes.resize(syncObject[0].CalculateParcelLen(SOFTWARE_VERSION_CURRENT)); Parcel parcel(bytes.data(), bytes.size()); - ASSERT_EQ(syncObject.SerializeData(parcel, SOFTWARE_VERSION_CURRENT), E_OK); + ASSERT_EQ(syncObject[0].SerializeData(parcel, SOFTWARE_VERSION_CURRENT), E_OK); /** * @tc.steps:step3. Check Node's type is QueryNodeType::IN. * @tc.expected: step3 OK. */ std::vector queryNodes; - syncObject.ParserQueryNodes(bytes, queryNodes); + syncObject[0].ParserQueryNodes(bytes, queryNodes); ASSERT_EQ(queryNodes[0].type, QueryNodeType::IN); } @@ -701,6 +724,62 @@ HWTEST_F(DistributedDBCloudKvSyncerTest, SyncWithMultipleUsers002, TestSize.Leve EXPECT_EQ(insertCount, 0u); } +/** + * @tc.name: SyncWithMultipleUsers003. + * @tc.desc: Test sync data with multiple users same key. + * @tc.type: FUNC + * @tc.require: + * @tc.author: wangxiangdong + */ +HWTEST_F(DistributedDBCloudKvSyncerTest, SyncWithMultipleUsers003, TestSize.Level0) +{ + /** + * @tc.steps: step1. put k v by user1. + * @tc.expected: step1. return ok. + */ + Key key = {'k', '1'}; + Value value = {'v', '1'}; + ASSERT_EQ(kvDelegatePtrS1_->Put(key, value), OK); + CloudSyncOption syncOption; + syncOption.mode = SyncMode::SYNC_MODE_CLOUD_MERGE; + syncOption.users.push_back(USER_ID); + syncOption.devices.push_back("cloud"); + BlockSync(kvDelegatePtrS1_, OK, syncOption); + /** + * @tc.steps: step2. put k v2 by user1. + * @tc.expected: step2. return ok. + */ + Value value2 = {'v', '2'}; + ASSERT_EQ(kvDelegatePtrS1_->Put(key, value2), OK); + syncOption.mode = SyncMode::SYNC_MODE_CLOUD_MERGE; + syncOption.users.clear(); + syncOption.users.push_back(USER_ID_2); + BlockSync(kvDelegatePtrS1_, OK, syncOption); + /** + * @tc.steps: step3. sync by user1. + * @tc.expected: step3. return ok. + */ + syncOption.users.clear(); + syncOption.users.push_back(USER_ID_2); + BlockSync(kvDelegatePtrS2_, OK, syncOption); + Value actualValue1; + /** + * @tc.steps: step4. sync by user2. + * @tc.expected: step4. return ok. + */ + EXPECT_EQ(kvDelegatePtrS2_->Get(key, actualValue1), OK); + syncOption.users.clear(); + syncOption.users.push_back(USER_ID); + BlockSync(kvDelegatePtrS2_, OK, syncOption); + Value actualValue2; + /** + * @tc.steps: step5. get k1. + * @tc.expected: step5. get v2. + */ + EXPECT_EQ(kvDelegatePtrS2_->Get(key, actualValue2), OK); + EXPECT_EQ(actualValue2, value2); +} + /** * @tc.name: AbnormalCloudKvExecutorTest001 * @tc.desc: Check SqliteCloudKvExecutorUtils interfaces abnormal scene. diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_kv_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_kv_test.cpp index 53a821da49c9933009943a2008ce12d0ddc76026..a5b82a242646ac38182bc7404b47163e2046e088 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_kv_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_kv_test.cpp @@ -2247,6 +2247,7 @@ HWTEST_F(DistributedDBCloudKvTest, NormalSync049, TestSize.Level0) ASSERT_TRUE(sqlite3_open_v2(fileUrl.c_str(), &db_, openFlag, nullptr) == SQLITE_OK); std::string sql = "UPDATE sync_data SET modify_time = modify_time + modify_time where rowid>0"; EXPECT_EQ(SQLiteUtils::ExecuteRawSQL(db_, sql), E_OK); + EXPECT_EQ(sqlite3_close_v2(db_), SQLITE_OK); BlockSync(kvDelegatePtrS1_, OK, g_CloudSyncoption); /** * @tc.steps: step3. put {k, v2} in another device diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_kvstore_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_kvstore_test.cpp index 8daf7c4cc224746376b85bc309c28fc521a298e5..af3f7bbc539a5a6600d0c949d80aee8803c66df7 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_kvstore_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_kvstore_test.cpp @@ -86,6 +86,7 @@ void DistributedDBCloudKvStoreTest::SetUpTestCase() if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) { LOGE("rm test db files error!"); } + RuntimeContext::GetInstance()->ClearAllDeviceTimeInfo(); g_CloudSyncoption.mode = SyncMode::SYNC_MODE_CLOUD_MERGE; g_CloudSyncoption.users.push_back(USER_ID); g_CloudSyncoption.devices.push_back("cloud"); @@ -1261,7 +1262,7 @@ HWTEST_F(DistributedDBCloudKvStoreTest, RemoveDeviceTest007, TestSize.Level0) * @tc.desc: remove record without mode. * @tc.type: FUNC * @tc.require: - * @tc.author: liaoyonnghuang + * @tc.author: liaoyonghuang */ HWTEST_F(DistributedDBCloudKvStoreTest, RemoveDeviceTest008, TestSize.Level0) { @@ -1313,7 +1314,7 @@ HWTEST_F(DistributedDBCloudKvStoreTest, RemoveDeviceTest008, TestSize.Level0) * @tc.desc: remove record without mode FLAG_AND_DATA. * @tc.type: FUNC * @tc.require: - * @tc.author: liaoyonnghuang + * @tc.author: liaoyonghuang */ HWTEST_F(DistributedDBCloudKvStoreTest, RemoveDeviceTest009, TestSize.Level0) { diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_simple_asset_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_simple_asset_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..611024a9b17e543cf1edc10e35b07a556b9b68e6 --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_simple_asset_test.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2024 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. + */ +#ifdef RELATIONAL_STORE +#include "cloud/cloud_sync_tag_assets.h" +#include + +using namespace testing::ext; +using namespace DistributedDB; +using namespace std; + +namespace { +class DistributedDBCloudSimpleAssetTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void DistributedDBCloudSimpleAssetTest::SetUpTestCase() +{ +} + +void DistributedDBCloudSimpleAssetTest::TearDownTestCase() +{ +} + +void DistributedDBCloudSimpleAssetTest::SetUp() +{ +} + +void DistributedDBCloudSimpleAssetTest::TearDown() +{ +} + +/* + * @tc.name: DownloadAssetForDupDataTest001 + * @tc.desc: Test tag asset with diff hash and downloading. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBCloudSimpleAssetTest, TagAsset001, TestSize.Level0) +{ + /** + * @tc.steps:step1. Local asset is downloading. + */ + Asset asset; + asset.name = "test"; + asset.hash = "insert"; + asset.status = static_cast(AssetStatus::DOWNLOADING); + VBucket beCovered; + Assets beCoveredAssets; + beCoveredAssets.push_back(asset); + beCovered["field"] = beCoveredAssets; + /** + * @tc.steps:step2. Cloud asset has diff hash. + */ + VBucket covered; + Assets coveredAssets; + asset.hash = "update"; + asset.status = static_cast(AssetStatus::NORMAL); + coveredAssets.push_back(asset); + covered["field"] = coveredAssets; + /** + * @tc.steps:step3. Tag assets. + * @tc.expected: step3. Local asset change hash + */ + Field field; + field.colName = "field"; + field.type = TYPE_INDEX; + int errCode = E_OK; + TagAssetsInfo tagAssetsInfo = {covered, beCovered, false, false}; + Assets res = TagAssetsInSingleCol(tagAssetsInfo, field, errCode); + for (const auto &item : res) { + EXPECT_EQ(item.hash, asset.hash); + } +} +} +#endif \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_download_assets_only_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_download_assets_only_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8f8f361f796170606210b6c2d113ee8405f464ff --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_download_assets_only_test.cpp @@ -0,0 +1,1568 @@ +/* + * 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. + */ +#ifdef RELATIONAL_STORE +#include "cloud/asset_operation_utils.h" +#include "cloud/cloud_storage_utils.h" +#include "cloud/cloud_db_constant.h" +#include "cloud_db_sync_utils_test.h" +#include "distributeddb_data_generate_unit_test.h" +#include "distributeddb_tools_unit_test.h" +#include "mock_asset_loader.h" +#include "process_system_api_adapter_impl.h" +#include "relational_store_client.h" +#include "relational_store_delegate_impl.h" +#include "relational_store_instance.h" +#include "relational_store_manager.h" +#include "runtime_config.h" +#include "sqlite_relational_store.h" +#include "sqlite_relational_utils.h" +#include "time_helper.h" +#include "virtual_asset_loader.h" +#include "virtual_cloud_data_translate.h" +#include "virtual_cloud_db.h" +#include "virtual_communicator_aggregator.h" +#include +#include + +using namespace testing::ext; +using namespace DistributedDB; +using namespace DistributedDBUnitTest; +using namespace std; + +namespace { +const string STORE_ID = "Relational_Store_SYNC"; +const string DB_SUFFIX = ".db"; +const string ASSETS_TABLE_NAME = "student"; +const string ASSETS_TABLE_NAME_SHARED = "student_shared"; +const string NO_PRIMARY_TABLE = "teacher"; +const string NO_PRIMARY_TABLE_SHARED = "teacher_shared"; +const string COMPOUND_PRIMARY_TABLE = "worker1"; +const string COMPOUND_PRIMARY_TABLE_SHARED = "worker1_shared"; +const string DEVICE_CLOUD = "cloud_dev"; +const string COL_ID = "id"; +const string COL_NAME = "name"; +const string COL_HEIGHT = "height"; +const string COL_ASSET = "asset"; +const string COL_ASSETS = "assets"; +const string COL_AGE = "age"; +const int64_t SYNC_WAIT_TIME = 600; +const int64_t COMPENSATED_SYNC_WAIT_TIME = 5; +const std::vector CLOUD_FIELDS = {{COL_ID, TYPE_INDEX, true}, {COL_NAME, TYPE_INDEX}, + {COL_HEIGHT, TYPE_INDEX}, {COL_ASSET, TYPE_INDEX}, {COL_ASSETS, TYPE_INDEX}, + {COL_AGE, TYPE_INDEX}}; +const std::vector NO_PRIMARY_FIELDS = {{COL_ID, TYPE_INDEX}, {COL_NAME, TYPE_INDEX}, + {COL_HEIGHT, TYPE_INDEX}, {COL_ASSET, TYPE_INDEX}, {COL_ASSETS, TYPE_INDEX}, + {COL_AGE, TYPE_INDEX}}; +const std::vector COMPOUND_PRIMARY_FIELDS = {{COL_ID, TYPE_INDEX, true}, + {COL_NAME, TYPE_INDEX}, {COL_HEIGHT, TYPE_INDEX}, {COL_ASSET, TYPE_INDEX}, + {COL_ASSETS, TYPE_INDEX}, {COL_AGE, TYPE_INDEX, true}}; +const string CREATE_SINGLE_PRIMARY_KEY_TABLE = "CREATE TABLE IF NOT EXISTS " + ASSETS_TABLE_NAME + "(" + COL_ID + + " INTEGER PRIMARY KEY," + COL_NAME + " TEXT ," + COL_HEIGHT + " REAL ," + COL_ASSET + " ASSET," + + COL_ASSETS + " ASSETS," + COL_AGE + " INT);"; +const string CREATE_NO_PRIMARY_KEY_TABLE = "CREATE TABLE IF NOT EXISTS " + NO_PRIMARY_TABLE + "(" + COL_ID + + " INTEGER," + COL_NAME + " TEXT ," + COL_HEIGHT + " REAL ," + COL_ASSET + " ASSET," + COL_ASSETS + + " ASSETS," + COL_AGE + " INT);"; +const string CREATE_COMPOUND_PRIMARY_KEY_TABLE = "CREATE TABLE IF NOT EXISTS " + COMPOUND_PRIMARY_TABLE + "(" + COL_ID + + " INTEGER," + COL_NAME + " TEXT ," + COL_HEIGHT + " REAL ," + COL_ASSET + " ASSET," + COL_ASSETS + " ASSETS," + + COL_AGE + " INT, PRIMARY KEY (id, age));"; +const Asset ASSET_COPY = {.version = 1, + .name = "Phone", + .assetId = "0", + .subpath = "/local/sync", + .uri = "/local/sync", + .modifyTime = "123456", + .createTime = "", + .size = "256", + .hash = "ASE"}; +const Asset ASSET_COPY2 = {.version = 1, + .name = "Phone_copy_2", + .assetId = "0", + .subpath = "/local/sync", + .uri = "/local/sync", + .modifyTime = "123456", + .createTime = "", + .size = "256", + .hash = "ASE"}; +const Assets ASSETS_COPY1 = { ASSET_COPY, ASSET_COPY2 }; +const std::string QUERY_CONSISTENT_SQL = "select count(*) from naturalbase_rdb_aux_student_log where flag&0x20=0;"; +const std::string QUERY_COMPENSATED_SQL = "select count(*) from naturalbase_rdb_aux_student_log where flag&0x10!=0;"; + +string g_storePath; +string g_testDir; +RelationalStoreObserverUnitTest *g_observer = nullptr; +DistributedDB::RelationalStoreManager g_mgr(APP_ID, USER_ID); +RelationalStoreDelegate *g_delegate = nullptr; +std::shared_ptr g_virtualCloudDb; +std::shared_ptr g_virtualAssetLoader; +std::shared_ptr g_virtualCloudDataTranslate; +SyncProcess g_syncProcess; +std::condition_variable g_processCondition; +std::mutex g_processMutex; +IRelationalStore *g_store = nullptr; +ICloudSyncStorageHook *g_cloudStoreHook = nullptr; +using CloudSyncStatusCallback = std::function &onProcess)>; + +void InitDatabase(sqlite3 *&db) +{ + EXPECT_EQ(RelationalTestUtils::ExecSql(db, "PRAGMA journal_mode=WAL;"), SQLITE_OK); + EXPECT_EQ(RelationalTestUtils::ExecSql(db, CREATE_SINGLE_PRIMARY_KEY_TABLE), SQLITE_OK); + EXPECT_EQ(RelationalTestUtils::ExecSql(db, CREATE_NO_PRIMARY_KEY_TABLE), SQLITE_OK); + EXPECT_EQ(RelationalTestUtils::ExecSql(db, CREATE_COMPOUND_PRIMARY_KEY_TABLE), SQLITE_OK); +} + +void GetCloudDbSchema(DataBaseSchema &dataBaseSchema) +{ + TableSchema assetsTableSchema = {.name = ASSETS_TABLE_NAME, .sharedTableName = ASSETS_TABLE_NAME_SHARED, + .fields = CLOUD_FIELDS}; + dataBaseSchema.tables.push_back(assetsTableSchema); + assetsTableSchema = {.name = NO_PRIMARY_TABLE, .sharedTableName = NO_PRIMARY_TABLE_SHARED, + .fields = NO_PRIMARY_FIELDS}; + dataBaseSchema.tables.push_back(assetsTableSchema); + assetsTableSchema = {.name = COMPOUND_PRIMARY_TABLE, .sharedTableName = COMPOUND_PRIMARY_TABLE_SHARED, + .fields = COMPOUND_PRIMARY_FIELDS}; + dataBaseSchema.tables.push_back(assetsTableSchema); +} + +void GenerateDataRecords( + int64_t begin, int64_t count, int64_t gidStart, std::vector &record, std::vector &extend) +{ + for (int64_t i = begin; i < begin + count; i++) { + Assets assets; + Asset asset = ASSET_COPY; + asset.name = ASSET_COPY.name + std::to_string(i); + assets.emplace_back(asset); + asset.name = ASSET_COPY.name + std::to_string(i) + "_copy"; + assets.emplace_back(asset); + VBucket data; + data.insert_or_assign(COL_ID, i); + data.insert_or_assign(COL_NAME, "name" + std::to_string(i)); + data.insert_or_assign(COL_HEIGHT, 166.0 * i); // 166.0 is random double value + data.insert_or_assign(COL_ASSETS, assets); + data.insert_or_assign(COL_AGE, 18L + i); // 18 is random int value + record.push_back(data); + + VBucket log; + Timestamp now = TimeHelper::GetSysCurrentTime(); + log.insert_or_assign(CloudDbConstant::CREATE_FIELD, (int64_t)now / CloudDbConstant::TEN_THOUSAND); + log.insert_or_assign(CloudDbConstant::MODIFY_FIELD, (int64_t)now / CloudDbConstant::TEN_THOUSAND); + log.insert_or_assign(CloudDbConstant::DELETE_FIELD, false); + log.insert_or_assign(CloudDbConstant::GID_FIELD, std::to_string(i + gidStart)); + extend.push_back(log); + } +} + +void InsertLocalData(sqlite3 *&db, int64_t begin, int64_t count, const std::string &tableName, bool isAssetNull = true) +{ + int errCode; + std::vector record; + std::vector extend; + GenerateDataRecords(begin, count, 0, record, extend); + const string sql = "insert or replace into " + tableName + " values (?,?,?,?,?,?);"; + for (VBucket vBucket : record) { + sqlite3_stmt *stmt = nullptr; + ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK); + ASSERT_EQ(SQLiteUtils::BindInt64ToStatement(stmt, 1, std::get(vBucket[COL_ID])), E_OK); // 1 is id + ASSERT_EQ(SQLiteUtils::BindTextToStatement(stmt, 2, std::get(vBucket[COL_NAME])), E_OK); // 2 is name + ASSERT_EQ(SQLiteUtils::MapSQLiteErrno( + sqlite3_bind_double(stmt, 3, std::get(vBucket[COL_HEIGHT]))), E_OK); // 3 is height + if (isAssetNull) { + ASSERT_EQ(sqlite3_bind_null(stmt, 4), SQLITE_OK); // 4 is asset + } else { + std::vector assetBlob = g_virtualCloudDataTranslate->AssetToBlob(ASSET_COPY); + ASSERT_EQ(SQLiteUtils::BindBlobToStatement(stmt, 4, assetBlob, false), E_OK); // 4 is asset + } + std::vector assetsBlob = g_virtualCloudDataTranslate->AssetsToBlob( + std::get(vBucket[COL_ASSETS])); + ASSERT_EQ(SQLiteUtils::BindBlobToStatement(stmt, 5, assetsBlob, false), E_OK); // 5 is assets + ASSERT_EQ(SQLiteUtils::BindInt64ToStatement(stmt, 6, std::get(vBucket[COL_AGE])), E_OK); // 6 is age + EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)); + SQLiteUtils::ResetStatement(stmt, true, errCode); + } +} + +void UpdateLocalData(sqlite3 *&db, const std::string &tableName, const Assets &assets, bool isEmptyAssets = false) +{ + int errCode; + std::vector assetBlob; + const string sql = "update " + tableName + " set assets=?;"; + sqlite3_stmt *stmt = nullptr; + ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK); + if (isEmptyAssets) { + ASSERT_EQ(sqlite3_bind_null(stmt, 1), SQLITE_OK); + } else { + assetBlob = g_virtualCloudDataTranslate->AssetsToBlob(assets); + ASSERT_EQ(SQLiteUtils::BindBlobToStatement(stmt, 1, assetBlob, false), E_OK); + } + EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)); + SQLiteUtils::ResetStatement(stmt, true, errCode); +} + +void UpdateLocalData(sqlite3 *&db, const std::string &tableName, const Assets &assets, int32_t begin, int32_t end) +{ + int errCode; + std::vector assetBlob; + const string sql = "update " + tableName + " set assets=? " + "where id>=" + std::to_string(begin) + + " and id<=" + std::to_string(end) + ";"; + sqlite3_stmt *stmt = nullptr; + ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK); + assetBlob = g_virtualCloudDataTranslate->AssetsToBlob(assets); + ASSERT_EQ(SQLiteUtils::BindBlobToStatement(stmt, 1, assetBlob, false), E_OK); + EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)); + SQLiteUtils::ResetStatement(stmt, true, errCode); +} + +void DeleteLocalRecord(sqlite3 *&db, int64_t begin, int64_t count, const std::string &tableName) +{ + ASSERT_NE(db, nullptr); + for (int64_t i = begin; i < begin + count; i++) { + string sql = "DELETE FROM " + tableName + " WHERE id ='" + std::to_string(i) + "';"; + ASSERT_EQ(SQLiteUtils::ExecuteRawSQL(db, sql), E_OK); + } +} + +void DeleteCloudDBData(int64_t begin, int64_t count, const std::string &tableName) +{ + for (int64_t i = begin; i < begin + count; i++) { + VBucket idMap; + idMap.insert_or_assign("#_gid", std::to_string(i)); + ASSERT_EQ(g_virtualCloudDb->DeleteByGid(tableName, idMap), DBStatus::OK); + } +} + +void UpdateCloudDBData(int64_t begin, int64_t count, int64_t gidStart, int64_t versionStart, + const std::string &tableName) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::vector record; + std::vector extend; + GenerateDataRecords(begin, count, gidStart, record, extend); + for (auto &entry: extend) { + entry[CloudDbConstant::VERSION_FIELD] = std::to_string(versionStart++); + } + ASSERT_EQ(g_virtualCloudDb->BatchUpdate(tableName, std::move(record), extend), DBStatus::OK); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); +} + +int QueryStatusCallback(void *data, int count, char **colValue, char **colName) +{ + auto status = static_cast *>(data); + const int decimal = 10; + for (int i = 0; i < count; i++) { + status->push_back(strtol(colValue[0], nullptr, decimal)); + } + return 0; +} + +void CheckLockStatus(sqlite3 *db, int startId, int endId, LockStatus lockStatus) +{ + std::string logName = DBCommon::GetLogTableName(ASSETS_TABLE_NAME); + std::string sql = "select status from " + logName + " where data_key >=" + std::to_string(startId) + + " and data_key <=" + std::to_string(endId) + ";"; + std::vector status; + char *str = NULL; + EXPECT_EQ(sqlite3_exec(db, sql.c_str(), QueryStatusCallback, static_cast(&status), &str), + SQLITE_OK); + ASSERT_EQ(static_cast(endId - startId + 1), status.size()); + + for (auto stat : status) { + ASSERT_EQ(static_cast(lockStatus), stat); + } +} + +void InsertCloudDBData(int64_t begin, int64_t count, int64_t gidStart, const std::string &tableName) +{ + std::vector record; + std::vector extend; + GenerateDataRecords(begin, count, gidStart, record, extend); + if (tableName == ASSETS_TABLE_NAME_SHARED) { + for (auto &vBucket: record) { + vBucket.insert_or_assign(CloudDbConstant::CLOUD_OWNER, std::string("cloudA")); + } + } + ASSERT_EQ(g_virtualCloudDb->BatchInsertWithGid(tableName, std::move(record), extend), DBStatus::OK); +} + +void WaitForSyncFinish(SyncProcess &syncProcess, const int64_t &waitTime) +{ + std::unique_lock lock(g_processMutex); + bool result = g_processCondition.wait_for( + lock, std::chrono::seconds(waitTime), [&syncProcess]() { return syncProcess.process == FINISHED; }); + ASSERT_EQ(result, true); + LOGD("-------------------sync end--------------"); +} + +void CallSync(const std::vector &tableNames, SyncMode mode, DBStatus dbStatus, DBStatus errCode = OK) +{ + g_syncProcess = {}; + Query query = Query::Select().FromTable(tableNames); + std::vector expectProcess; + CloudSyncStatusCallback callback = [&errCode](const std::map &process) { + ASSERT_EQ(process.begin()->first, DEVICE_CLOUD); + std::unique_lock lock(g_processMutex); + g_syncProcess = process.begin()->second; + if (g_syncProcess.process == FINISHED) { + g_processCondition.notify_one(); + ASSERT_EQ(g_syncProcess.errCode, errCode); + } + }; + CloudSyncOption option; + option.devices = {DEVICE_CLOUD}; + option.mode = mode; + option.query = query; + option.waitTime = SYNC_WAIT_TIME; + option.lockAction = static_cast(0xff); // lock all + ASSERT_EQ(g_delegate->Sync(option, callback), dbStatus); + + if (dbStatus == DBStatus::OK) { + WaitForSyncFinish(g_syncProcess, SYNC_WAIT_TIME); + } +} + +void CheckDownloadForTest001(int index, map &assets) +{ + for (auto &item : assets) { + for (auto &asset : item.second) { + EXPECT_EQ(AssetOperationUtils::EraseBitMask(asset.status), static_cast(AssetStatus::INSERT)); + if (index < 4) { // 1-4 is inserted + EXPECT_EQ(asset.flag, static_cast(AssetOpType::INSERT)); + } + LOGD("asset [name]:%s, [status]:%u, [flag]:%u, [index]:%d", asset.name.c_str(), asset.status, asset.flag, + index); + } + } +} + +void CheckDownloadFailedForTest002(sqlite3 *&db) +{ + std::string sql = "SELECT assets from " + ASSETS_TABLE_NAME; + sqlite3_stmt *stmt = nullptr; + ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK); + while (SQLiteUtils::StepWithRetry(stmt) == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + ASSERT_EQ(sqlite3_column_type(stmt, 0), SQLITE_BLOB); + Type cloudValue; + ASSERT_EQ(SQLiteRelationalUtils::GetCloudValueByType(stmt, TYPE_INDEX, 0, cloudValue), E_OK); + std::vector assetsBlob; + Assets assets; + ASSERT_EQ(CloudStorageUtils::GetValueFromOneField(cloudValue, assetsBlob), E_OK); + ASSERT_EQ(RuntimeContext::GetInstance()->BlobToAssets(assetsBlob, assets), E_OK); + ASSERT_EQ(assets.size(), 2u); // 2 is asset num + for (size_t i = 0; i < assets.size(); ++i) { + EXPECT_EQ(assets[i].status, AssetStatus::ABNORMAL); + } + } + int errCode; + SQLiteUtils::ResetStatement(stmt, true, errCode); +} + +void UpdateAssetsForLocal(sqlite3 *&db, int id, uint32_t status) +{ + Assets assets; + Asset asset = ASSET_COPY; + asset.name = ASSET_COPY.name + std::to_string(id); + asset.status = status; + assets.emplace_back(asset); + asset.name = ASSET_COPY.name + std::to_string(id) + "_copy"; + assets.emplace_back(asset); + int errCode; + std::vector assetBlob; + const string sql = "update " + ASSETS_TABLE_NAME + " set assets=? where id = " + std::to_string(id); + sqlite3_stmt *stmt = nullptr; + ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK); + assetBlob = g_virtualCloudDataTranslate->AssetsToBlob(assets); + ASSERT_EQ(SQLiteUtils::BindBlobToStatement(stmt, 1, assetBlob, false), E_OK); + EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)); + SQLiteUtils::ResetStatement(stmt, true, errCode); +} + +void CheckConsistentCount(sqlite3 *db, int64_t expectCount) +{ + EXPECT_EQ(sqlite3_exec(db, QUERY_CONSISTENT_SQL.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(expectCount), nullptr), SQLITE_OK); +} + +void CheckCompensatedCount(sqlite3 *db, int64_t expectCount) +{ + EXPECT_EQ(sqlite3_exec(db, QUERY_COMPENSATED_SQL.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(expectCount), nullptr), SQLITE_OK); +} + +void CloseDb() +{ + if (g_delegate != nullptr) { + EXPECT_EQ(g_mgr.CloseStore(g_delegate), DBStatus::OK); + g_delegate = nullptr; + } + delete g_observer; + g_virtualCloudDb = nullptr; +} + +class DistributedDBCloudSyncerDownloadAssetsOnlyTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + +protected: + void CheckLocaLAssets(const std::string &tableName, const std::string &expectAssetId, + const std::set &failIndex); + void CheckLocalAssetIsEmpty(const std::string &tableName); + void CheckCursorData(const std::string &tableName, int begin); + void WaitForSync(int &syncCount); + const RelationalSyncAbleStorage *GetRelationalStore(); + void InitDataStatusTest(bool needDownload); + void DataStatusTest001(bool needDownload); + void DataStatusTest003(); + void DataStatusTest004(); + void DataStatusTest005(); + void DataStatusTest006(); + void DataStatusTest007(); + sqlite3 *db = nullptr; + VirtualCommunicatorAggregator *communicatorAggregator_ = nullptr; +}; + +void DistributedDBCloudSyncerDownloadAssetsOnlyTest::SetUpTestCase(void) +{ + DistributedDBToolsUnitTest::TestDirInit(g_testDir); + g_storePath = g_testDir + "/" + STORE_ID + DB_SUFFIX; + LOGI("The test db is:%s", g_storePath.c_str()); + g_virtualCloudDataTranslate = std::make_shared(); + RuntimeConfig::SetCloudTranslate(g_virtualCloudDataTranslate); +} + +void DistributedDBCloudSyncerDownloadAssetsOnlyTest::TearDownTestCase(void) {} + +void DistributedDBCloudSyncerDownloadAssetsOnlyTest::SetUp(void) +{ + RuntimeContext::GetInstance()->SetBatchDownloadAssets(false); + if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) { + LOGE("rm test db files error."); + } + DistributedDBToolsUnitTest::PrintTestCaseInfo(); + LOGD("Test dir is %s", g_testDir.c_str()); + db = RelationalTestUtils::CreateDataBase(g_storePath); + ASSERT_NE(db, nullptr); + InitDatabase(db); + g_observer = new (std::nothrow) RelationalStoreObserverUnitTest(); + ASSERT_NE(g_observer, nullptr); + ASSERT_EQ( + g_mgr.OpenStore(g_storePath, STORE_ID, RelationalStoreDelegate::Option{.observer = g_observer}, g_delegate), + DBStatus::OK); + ASSERT_NE(g_delegate, nullptr); + ASSERT_EQ(g_delegate->CreateDistributedTable(ASSETS_TABLE_NAME, CLOUD_COOPERATION), DBStatus::OK); + ASSERT_EQ(g_delegate->CreateDistributedTable(NO_PRIMARY_TABLE, CLOUD_COOPERATION), DBStatus::OK); + ASSERT_EQ(g_delegate->CreateDistributedTable(COMPOUND_PRIMARY_TABLE, CLOUD_COOPERATION), DBStatus::OK); + g_virtualCloudDb = make_shared(); + g_virtualAssetLoader = make_shared(); + g_syncProcess = {}; + ASSERT_EQ(g_delegate->SetCloudDB(g_virtualCloudDb), DBStatus::OK); + ASSERT_EQ(g_delegate->SetIAssetLoader(g_virtualAssetLoader), DBStatus::OK); + DataBaseSchema dataBaseSchema; + GetCloudDbSchema(dataBaseSchema); + ASSERT_EQ(g_delegate->SetCloudDbSchema(dataBaseSchema), DBStatus::OK); + g_cloudStoreHook = (ICloudSyncStorageHook *) GetRelationalStore(); + ASSERT_NE(g_cloudStoreHook, nullptr); + communicatorAggregator_ = new (std::nothrow) VirtualCommunicatorAggregator(); + ASSERT_TRUE(communicatorAggregator_ != nullptr); + RuntimeContext::GetInstance()->SetCommunicatorAggregator(communicatorAggregator_); +} + +void DistributedDBCloudSyncerDownloadAssetsOnlyTest::TearDown(void) +{ + RefObject::DecObjRef(g_store); + g_virtualCloudDb->ForkUpload(nullptr); + CloseDb(); + EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK); + if (DistributedDBToolsUnitTest::RemoveTestDbFiles(g_testDir) != 0) { + LOGE("rm test db files error."); + } + RuntimeContext::GetInstance()->SetCommunicatorAggregator(nullptr); + communicatorAggregator_ = nullptr; + RuntimeContext::GetInstance()->SetProcessSystemApiAdapter(nullptr); +} + +void DistributedDBCloudSyncerDownloadAssetsOnlyTest::CheckLocaLAssets(const std::string &tableName, + const std::string &expectAssetId, const std::set &failIndex) +{ + std::string sql = "SELECT assets FROM " + tableName + ";"; + sqlite3_stmt *stmt = nullptr; + ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK); + int index = 0; + while (SQLiteUtils::StepWithRetry(stmt) != SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + ASSERT_EQ(sqlite3_column_type(stmt, 0), SQLITE_BLOB); + Type cloudValue; + ASSERT_EQ(SQLiteRelationalUtils::GetCloudValueByType(stmt, TYPE_INDEX, 0, cloudValue), E_OK); + Assets assets = g_virtualCloudDataTranslate->BlobToAssets(std::get(cloudValue)); + for (const auto &asset : assets) { + index++; + if (failIndex.find(index) != failIndex.end()) { + EXPECT_EQ(asset.assetId, "0"); + } else { + EXPECT_EQ(asset.assetId, expectAssetId); + } + } + } + int errCode = E_OK; + SQLiteUtils::ResetStatement(stmt, true, errCode); +} + +void DistributedDBCloudSyncerDownloadAssetsOnlyTest::CheckLocalAssetIsEmpty(const std::string &tableName) +{ + std::string sql = "SELECT asset FROM " + tableName + ";"; + sqlite3_stmt *stmt = nullptr; + ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK); + while (SQLiteUtils::StepWithRetry(stmt) != SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + ASSERT_EQ(sqlite3_column_type(stmt, 0), SQLITE_NULL); + } + int errCode = E_OK; + SQLiteUtils::ResetStatement(stmt, true, errCode); +} + +void DistributedDBCloudSyncerDownloadAssetsOnlyTest::CheckCursorData(const std::string &tableName, int begin) +{ + std::string logTableName = DBCommon::GetLogTableName(tableName); + std::string sql = "SELECT cursor FROM " + logTableName + ";"; + sqlite3_stmt *stmt = nullptr; + ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK); + while (SQLiteUtils::StepWithRetry(stmt) != SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + ASSERT_EQ(sqlite3_column_type(stmt, 0), SQLITE_INTEGER); + Type cloudValue; + ASSERT_EQ(SQLiteRelationalUtils::GetCloudValueByType(stmt, TYPE_INDEX, 0, cloudValue), E_OK); + EXPECT_EQ(std::get(cloudValue), begin); + begin++; + } + int errCode = E_OK; + SQLiteUtils::ResetStatement(stmt, true, errCode); +} + +void DistributedDBCloudSyncerDownloadAssetsOnlyTest::WaitForSync(int &syncCount) +{ + std::unique_lock lock(g_processMutex); + bool result = g_processCondition.wait_for(lock, std::chrono::seconds(COMPENSATED_SYNC_WAIT_TIME), + [&syncCount]() { return syncCount == 2; }); // 2 is compensated sync + ASSERT_EQ(result, true); +} + +const RelationalSyncAbleStorage* DistributedDBCloudSyncerDownloadAssetsOnlyTest::GetRelationalStore() +{ + RelationalDBProperties properties; + CloudDBSyncUtilsTest::InitStoreProp(g_storePath, APP_ID, USER_ID, STORE_ID, properties); + int errCode = E_OK; + g_store = RelationalStoreInstance::GetDataBase(properties, errCode); + if (g_store == nullptr) { + return nullptr; + } + return static_cast(g_store)->GetStorageEngine(); +} + +void DistributedDBCloudSyncerDownloadAssetsOnlyTest::InitDataStatusTest(bool needDownload) +{ + int cloudCount = 20; + int localCount = 10; + InsertLocalData(db, 0, cloudCount, ASSETS_TABLE_NAME, true); + if (needDownload) { + UpdateLocalData(db, ASSETS_TABLE_NAME, ASSETS_COPY1); + } + std::string logName = DBCommon::GetLogTableName(ASSETS_TABLE_NAME); + std::string sql = "update " + logName + " SET status = 1 where data_key in (1,11);"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK); + sql = "update " + logName + " SET status = 2 where data_key in (2,12);"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK); + sql = "update " + logName + " SET status = 3 where data_key in (3,13);"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + InsertCloudDBData(0, localCount, 0, ASSETS_TABLE_NAME); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + sql = "update " + ASSETS_TABLE_NAME + " set age='666' where id in (4);"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK); + sql = "update " + logName + " SET status = 1 where data_key in (4);"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), E_OK); +} + +struct ProcessParam { + const std::map &OnProcess; + const SyncProcess &process; + std::mutex &processMutex; + std::condition_variable &cv; + bool &finish; + const CloudSyncStatusCallback &onFinish; + DBStatus expectResult; +}; + +void HandleProcessFinish(ProcessParam ¶m) +{ + if (param.process.process == FINISHED) { + if (param.onFinish) { + param.onFinish(param.OnProcess); + } + EXPECT_EQ(param.process.errCode, param.expectResult); + std::unique_lock lock(param.processMutex); + param.finish = true; + param.cv.notify_one(); + } +} + +void PriorityLevelSync(int32_t priorityLevel, const Query &query, const CloudSyncStatusCallback &onFinish, + SyncMode mode, DBStatus expectResult = DBStatus::OK) +{ + std::mutex processMutex; + std::vector expectProcess; + std::condition_variable cv; + bool finish = false; + auto callback = [&cv, &onFinish, &finish, &processMutex, &expectResult] + (const std::map &process) { + for (auto &item : process) { + ProcessParam param = {process, item.second, processMutex, cv, finish, onFinish, expectResult}; + HandleProcessFinish(param); + } + }; + CloudSyncOption option; + option.devices = {DEVICE_CLOUD}; + option.query = query; + option.mode = mode; + option.priorityTask = true; + option.priorityLevel = priorityLevel; + DBStatus syncResult = g_delegate->Sync(option, callback); + EXPECT_EQ(syncResult, DBStatus::OK); + + std::unique_lock lock(processMutex); + cv.wait(lock, [&finish]() { + return finish; + }); +} + +void PriorityLevelSync(int32_t priorityLevel, const Query &query, SyncMode mode, DBStatus expectResult = DBStatus::OK) +{ + std::mutex processMutex; + std::vector expectProcess; + std::condition_variable cv; + bool finish = expectResult == DBStatus::OK ? false : true; + auto callback = [&cv, &finish, &processMutex] + (const std::map &process) { + for (auto &item : process) { + if (item.second.process == FINISHED) { + std::unique_lock lock(processMutex); + finish = true; + cv.notify_one(); + } + } + }; + CloudSyncOption option; + option.devices = {DEVICE_CLOUD}; + option.query = query; + option.mode = mode; + option.priorityTask = true; + option.priorityLevel = priorityLevel; + DBStatus syncResult = g_delegate->Sync(option, callback); + EXPECT_EQ(syncResult, expectResult); + + std::unique_lock lock(processMutex); + cv.wait(lock, [&finish]() { + return finish; + }); +} + +void CheckAsset(sqlite3 *db, const std::string &tableName, int id, const Asset &expectAsset, bool expectFound) +{ + std::string sql = "select assets from " + tableName + " where id = " + std::to_string(id); + sqlite3_stmt *stmt = nullptr; + ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK); + int errCode = SQLiteUtils::StepWithRetry(stmt); + ASSERT_EQ(errCode, SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)); + if (expectFound) { + ASSERT_EQ(sqlite3_column_type(stmt, 0), SQLITE_BLOB); + } + Type cloudValue; + ASSERT_EQ(SQLiteRelationalUtils::GetCloudValueByType(stmt, TYPE_INDEX, 0, cloudValue), E_OK); + Assets assets = g_virtualCloudDataTranslate->BlobToAssets(std::get(cloudValue)); + bool found = false; + for (const auto &asset : assets) { + if (asset.name != expectAsset.name) { + continue; + } + found = true; + EXPECT_EQ(asset.status, expectAsset.status); + EXPECT_EQ(asset.hash, expectAsset.hash); + EXPECT_EQ(asset.assetId, expectAsset.assetId); + EXPECT_EQ(asset.uri, expectAsset.uri); + } + EXPECT_EQ(found, expectFound); + errCode = E_OK; + SQLiteUtils::ResetStatement(stmt, true, errCode); + EXPECT_EQ(errCode, E_OK); +} + +void CheckDBValue(sqlite3 *db, const std::string &tableName, int id, const std::string &field, + const std::string &expectValue) +{ + std::string sql = "select " + field + " from " + tableName + " where id = " + std::to_string(id); + sqlite3_stmt *stmt = nullptr; + ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK); + int errCode = SQLiteUtils::StepWithRetry(stmt); + if (expectValue.empty()) { + EXPECT_EQ(errCode, SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)); + } + ASSERT_EQ(errCode, SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)); + std::string str; + (void)SQLiteUtils::GetColumnTextValue(stmt, 0, str); + EXPECT_EQ(str, expectValue); + SQLiteUtils::ResetStatement(stmt, true, errCode); + errCode = E_OK; + EXPECT_EQ(errCode, E_OK); +} + +/** + * @tc.name: DownloadAssetsOnly001 + * @tc.desc: Test sync with priorityLevel + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly001, TestSize.Level1) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int cloudCount = 15; // 15 is num of cloud + InsertCloudDBData(0, cloudCount, 0, ASSETS_TABLE_NAME); + /** + * @tc.steps:step2. Call sync with different priorityLevel + * @tc.expected: step2. OK + */ + int syncFinishCount = 0; + g_virtualCloudDb->SetBlockTime(100); + std::thread syncThread1([&]() { + CloudSyncStatusCallback callback = [&syncFinishCount](const std::map &process) { + syncFinishCount++; + EXPECT_EQ(syncFinishCount, 3); + }; + std::vector inValue = {0, 1, 2, 3, 4}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).In("id", inValue); + PriorityLevelSync(0, query, callback, SyncMode::SYNC_MODE_CLOUD_MERGE); + }); + + std::thread syncThread2([&]() { + CloudSyncStatusCallback callback = [&syncFinishCount](const std::map &process) { + syncFinishCount++; + EXPECT_EQ(syncFinishCount, 2); + }; + std::vector inValue = {5, 6, 7, 8, 9}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).In("id", inValue); + PriorityLevelSync(1, query, callback, SyncMode::SYNC_MODE_CLOUD_MERGE); + }); + + std::thread syncThread3([&]() { + CloudSyncStatusCallback callback = [&syncFinishCount](const std::map &process) { + syncFinishCount++; + EXPECT_EQ(syncFinishCount, 1); + }; + std::vector inValue = {10, 11, 12, 13, 14}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).In("id", inValue); + PriorityLevelSync(2, query, callback, SyncMode::SYNC_MODE_CLOUD_MERGE); + }); + syncThread1.join(); + syncThread2.join(); + syncThread3.join(); +} + +/** + * @tc.name: DownloadAssetsOnly002 + * @tc.desc: Test download specified assets with unsupported mode + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly002, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int localDataCount = 10; + InsertLocalData(db, 0, localDataCount, ASSETS_TABLE_NAME, true); + UpdateLocalData(db, ASSETS_TABLE_NAME, {ASSET_COPY}, true); + int cloudCount = 10; + InsertCloudDBData(0, cloudCount, 0, ASSETS_TABLE_NAME); + /** + * @tc.steps:step2. Download specified assets with mode SYNC_MODE_CLOUD_MERGE and SYNC_MODE_CLOUD_FORCE_PUSH + * @tc.expected: step2. sync fail + */ + std::vector inValue = {0}; + std::map> assets; + assets["assets"] = {ASSET_COPY.name + "0"}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).In("id", inValue).And().AssetsOnly(assets); + + CloudSyncOption option; + option.devices = {DEVICE_CLOUD}; + option.query = query; + option.mode = SyncMode::SYNC_MODE_CLOUD_MERGE; + option.priorityTask = true; + option.priorityLevel = 2u; + EXPECT_EQ(g_delegate->Sync(option, nullptr), DBStatus::NOT_SUPPORT); + + option.mode = SyncMode::SYNC_MODE_CLOUD_FORCE_PUSH; + EXPECT_EQ(g_delegate->Sync(option, nullptr), DBStatus::NOT_SUPPORT); +} + +/** + * @tc.name: DownloadAssetsOnly004 + * @tc.desc: Test download specified assets + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly003, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int dataCount = 10; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + for (int i = 0; i < dataCount; i++) { + Asset asset = ASSET_COPY; + asset.name += std::to_string(i); + asset.status = AssetStatus::UPDATE; + asset.hash = "local_new"; + Assets assets = {asset}; + asset.name += "_new"; + assets.push_back(asset); + UpdateLocalData(db, ASSETS_TABLE_NAME, assets, i, i); + } + /** + * @tc.steps:step2. Download specified assets + * @tc.expected: step2. return OK. + */ + std::vector inValue = {0}; + std::map> assets; + assets["assets"] = {ASSET_COPY.name + "0"}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).In("id", inValue).And().AssetsOnly(assets); + PriorityLevelSync(2, query, nullptr, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::OK); + + Asset assetCloud = ASSET_COPY; + assetCloud.name += std::to_string(0); + Asset assetLocal = ASSET_COPY; + assetLocal.name +=std::to_string(0) + "_new"; + assetLocal.hash = "local_new"; + assetLocal.status = AssetStatus::UPDATE; + CheckAsset(db, ASSETS_TABLE_NAME, 0, assetCloud, true); + CheckAsset(db, ASSETS_TABLE_NAME, 0, assetLocal, true); + + for (int i = 1; i < dataCount; i++) { + Asset assetLocal1 = ASSET_COPY; + assetLocal1.name += std::to_string(i); + Asset assetLocal2 = ASSET_COPY; + assetLocal2.name +=std::to_string(i) + "_new"; + assetLocal1.hash = "local_new"; + assetLocal2.hash = "local_new"; + assetLocal1.status = AssetStatus::UPDATE; + assetLocal2.status = AssetStatus::UPDATE; + CheckAsset(db, ASSETS_TABLE_NAME, i, assetLocal1, true); + CheckAsset(db, ASSETS_TABLE_NAME, i, assetLocal2, true); + } +} + +/** + * @tc.name: DownloadAssetsOnly004 + * @tc.desc: Test download specified assets + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly004, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int dataCount = 10; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + std::vector record; + std::vector extend; + GenerateDataRecords(0, dataCount, 0, record, extend); + for (int i = 0; i < dataCount; i++) { + Asset asset1 = ASSET_COPY; + Asset asset2 = ASSET_COPY; + asset1.name += std::to_string(i); + asset2.name += std::to_string(i) + "_new"; + asset1.hash = "cloud"; + asset2.hash = "cloud"; + Assets assets = {asset1, asset2}; + record[i].insert_or_assign(COL_ASSETS, assets); + std::string newName = "name" + std::to_string(i) + "_new"; + record[i].insert_or_assign(COL_NAME, newName); + } + ASSERT_EQ(g_virtualCloudDb->BatchUpdate(ASSETS_TABLE_NAME, std::move(record), extend), DBStatus::OK); + /** + * @tc.steps:step2. Download specified assets + * @tc.expected: step2. return OK. + */ + std::vector inValue = {0}; + std::map> assets; + assets["assets"] = {ASSET_COPY.name + "0"}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).In("id", inValue).And().AssetsOnly(assets); + PriorityLevelSync(2, query, nullptr, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::OK); + + Asset assetCloud1 = ASSET_COPY; + assetCloud1.name += std::to_string(0); + assetCloud1.hash = "cloud"; + Asset assetCloud2 = ASSET_COPY; + assetCloud2.name +=std::to_string(0) + "_new"; + assetCloud2.hash = "cloud"; + CheckAsset(db, ASSETS_TABLE_NAME, 0, assetCloud1, true); + CheckAsset(db, ASSETS_TABLE_NAME, 0, assetCloud2, false); + CheckDBValue(db, ASSETS_TABLE_NAME, 0, COL_NAME, "name0"); + + for (int i = 1; i < dataCount; i++) { + Asset assetLocal1 = ASSET_COPY; + assetLocal1.name += std::to_string(i); + Asset assetLocal2 = ASSET_COPY; + assetLocal2.name +=std::to_string(i) + "_new"; + CheckAsset(db, ASSETS_TABLE_NAME, i, assetLocal1, true); + CheckAsset(db, ASSETS_TABLE_NAME, i, assetLocal2, false); + CheckDBValue(db, ASSETS_TABLE_NAME, i, COL_NAME, "name" + std::to_string(i)); + } +} + +/** + * @tc.name: DownloadAssetsOnly005 + * @tc.desc: Test download asseets which local no found + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly005, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int dataCount = 10; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + InsertCloudDBData(dataCount, 1, 0, ASSETS_TABLE_NAME); + /** + * @tc.steps:step2. Download assets which local no found + * @tc.expected: step2. return ASSET_NOT_FOUND_FOR_DOWN_ONLY. + */ + std::vector inValue = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + std::map> assets; + assets["assets"] = {ASSET_COPY.name + "10"}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).In("id", inValue).And().AssetsOnly(assets); + PriorityLevelSync(2, query, nullptr, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::ASSET_NOT_FOUND_FOR_DOWN_ONLY); +} + +/** + * @tc.name: DownloadAssetsOnly006 + * @tc.desc: Test download asseets which cloud no found + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly006, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int dataCount = 10; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + InsertLocalData(db, dataCount, 1, ASSETS_TABLE_NAME, true); + /** + * @tc.steps:step2. Download assets which cloud no found + * @tc.expected: step2. return ASSET_NOT_FOUND_FOR_DOWN_ONLY. + */ + std::vector inValue = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + std::map> assets; + assets["assets"] = {ASSET_COPY.name + "10"}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).In("id", inValue).And().AssetsOnly(assets); + PriorityLevelSync(2, query, nullptr, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::ASSET_NOT_FOUND_FOR_DOWN_ONLY); +} + +/** + * @tc.name: DownloadAssetsOnly007 + * @tc.desc: Test download specified assets with group + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly007, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int dataCount = 10; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + for (int i = 0; i < dataCount; i++) { + Asset asset = ASSET_COPY; + asset.name += std::to_string(i); + asset.status = AssetStatus::UPDATE; + asset.hash = "local_new"; + Assets assets = {asset}; + asset.name += "_new"; + assets.push_back(asset); + UpdateLocalData(db, ASSETS_TABLE_NAME, assets, i, i); + } + /** + * @tc.steps:step2. Download specified assets + * @tc.expected: step2. return OK. + */ + std::map> assets; + assets["assets"] = {ASSET_COPY.name + "0"}; + std::map> assets1; + assets1["assets"] = {ASSET_COPY.name + "1"}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).BeginGroup().EqualTo("id", 0).And().AssetsOnly(assets). + EndGroup().Or().BeginGroup().EqualTo("id", 1).And().AssetsOnly(assets1).EndGroup(); + PriorityLevelSync(2, query, nullptr, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::OK); + + Asset assetCloud = ASSET_COPY; + assetCloud.name += std::to_string(0); + Asset assetLocal = ASSET_COPY; + assetLocal.name +=std::to_string(0) + "_new"; + assetLocal.hash = "local_new"; + assetLocal.status = AssetStatus::UPDATE; + CheckAsset(db, ASSETS_TABLE_NAME, 0, assetCloud, true); + CheckAsset(db, ASSETS_TABLE_NAME, 0, assetLocal, true); + + for (int i = 2; i < dataCount; i++) { + Asset assetLocal1 = ASSET_COPY; + assetLocal1.name += std::to_string(i); + Asset assetLocal2 = ASSET_COPY; + assetLocal2.name +=std::to_string(i) + "_new"; + assetLocal1.hash = "local_new"; + assetLocal2.hash = "local_new"; + assetLocal1.status = AssetStatus::UPDATE; + assetLocal2.status = AssetStatus::UPDATE; + CheckAsset(db, ASSETS_TABLE_NAME, i, assetLocal1, true); + CheckAsset(db, ASSETS_TABLE_NAME, i, assetLocal2, true); + } +} + +/** + * @tc.name: DownloadAssetsOnly008 + * @tc.desc: Test download asseets which local no found + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly008, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int dataCount = 10; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + InsertCloudDBData(dataCount, 1, 0, ASSETS_TABLE_NAME); + /** + * @tc.steps:step2. Download assets which local no found + * @tc.expected: step2. return ASSET_NOT_FOUND_FOR_DOWN_ONLY. + */ + std::vector inValue = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + std::map> assets; + assets["assets"] = {ASSET_COPY.name + "0"}; + std::map> assets1; + assets1["assets"] = {ASSET_COPY.name + "10"}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).BeginGroup().EqualTo("id", 0).And().AssetsOnly(assets). + EndGroup().Or().BeginGroup().In("id", inValue).And().AssetsOnly(assets1).EndGroup(); + PriorityLevelSync(2, query, nullptr, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::ASSET_NOT_FOUND_FOR_DOWN_ONLY); +} + +/** + * @tc.name: DownloadAssetsOnly009 + * @tc.desc: Test download asseets which cloud no found + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly009, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int dataCount = 10; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + InsertLocalData(db, dataCount, 1, ASSETS_TABLE_NAME, true); + /** + * @tc.steps:step2. Download assets which cloud no found + * @tc.expected: step2. return ASSET_NOT_FOUND_FOR_DOWN_ONLY. + */ + std::map> assets; + assets["assets"] = {ASSET_COPY.name + "0"}; + std::map> assets1; + assets1["assets"] = {ASSET_COPY.name + "10"}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).BeginGroup().EqualTo("id", 0).And().AssetsOnly(assets). + EndGroup().Or().BeginGroup().EqualTo("id", 10).And().AssetsOnly(assets1).EndGroup(); + PriorityLevelSync(2, query, nullptr, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::ASSET_NOT_FOUND_FOR_DOWN_ONLY); +} + +/** + * @tc.name: DownloadAssetsOnly010 + * @tc.desc: Test assets only multi time. + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly010, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + RuntimeContext::GetInstance()->SetBatchDownloadAssets(true); + int dataCount = 10; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + + /** + * @tc.steps:step2. AssetsOnly twice + * @tc.expected: step2. check notify count. + */ + std::map> assets; + assets["assets"] = {ASSET_COPY.name + "0"}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).BeginGroup().EqualTo("id", 0).And().AssetsOnly(assets).And(). + AssetsOnly(assets).EndGroup(); + g_observer->ResetCloudSyncToZero(); + PriorityLevelSync(2, query, nullptr, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::OK); + auto changedData = g_observer->GetSavedChangedData(); + EXPECT_EQ(changedData.size(), 0u); + + /** + * @tc.steps:step3. AssetsOnly behine EndGroup + * @tc.expected: step3. check notify count. + */ + Query query1 = Query::Select().From(ASSETS_TABLE_NAME).BeginGroup().EqualTo("id", 0).EndGroup().And(). + AssetsOnly(assets); + g_observer->ResetCloudSyncToZero(); + PriorityLevelSync(2, query1, nullptr, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::OK); + changedData = g_observer->GetSavedChangedData(); + EXPECT_EQ(changedData.size(), 0u); + + /** + * @tc.steps:step4. AssetsOnly EndGroup use And + * @tc.expected: step4. check notify count. + */ + Query query2 = Query::Select().From(ASSETS_TABLE_NAME).BeginGroup().EqualTo("id", 0).And().AssetsOnly(assets). + EndGroup().And().BeginGroup().EqualTo("id", 0).And().AssetsOnly(assets).EndGroup(); + g_observer->ResetCloudSyncToZero(); + PriorityLevelSync(2, query2, nullptr, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::OK); + changedData = g_observer->GetSavedChangedData(); + EXPECT_EQ(changedData.size(), 0u); +} + +/** + * @tc.name: DownloadAssetsOnly011 + * @tc.desc: Check assets only sync will up. + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly011, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + RuntimeContext::GetInstance()->SetBatchDownloadAssets(true); + int dataCount = 10; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + + /** + * @tc.steps:step2. assets only sync + * @tc.expected: step2. check assets sync result. + */ + std::map> assets; + assets["assets"] = {ASSET_COPY.name + "0"}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).BeginGroup().EqualTo("id", 0).And().AssetsOnly(assets). + EndGroup(); + PriorityLevelSync(2, query, nullptr, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::OK); + + /** + * @tc.steps:step3. check cursor and flag + * @tc.expected: step3. ok. + */ + std::string sql = "select cursor from naturalbase_rdb_aux_student_log where data_key=0;"; + EXPECT_EQ(sqlite3_exec(db, sql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(21u), nullptr), SQLITE_OK); + + sql = "select flag from naturalbase_rdb_aux_student_log where data_key=0;"; + EXPECT_EQ(sqlite3_exec(db, sql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(0u), nullptr), SQLITE_OK); + RuntimeContext::GetInstance()->SetBatchDownloadAssets(false); +} + +/** + * @tc.name: DownloadAssetsOnly012 + * @tc.desc: Test sync with same priorityLevel should be sync in order. + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly012, TestSize.Level1) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int cloudCount = 15; // 15 is num of cloud + InsertCloudDBData(0, cloudCount, 0, ASSETS_TABLE_NAME); + /** + * @tc.steps:step2. Call sync with same priorityLevel + * @tc.expected: step2. OK + */ + int syncFinishCount = 0; + g_virtualCloudDb->SetBlockTime(1000); + std::thread syncThread1([&]() { + CloudSyncStatusCallback callback = [&syncFinishCount](const std::map &process) { + syncFinishCount++; + EXPECT_EQ(syncFinishCount, 1); + }; + std::vector inValue = {0, 1, 2, 3, 4}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).In("id", inValue); + PriorityLevelSync(0, query, callback, SyncMode::SYNC_MODE_CLOUD_MERGE); + }); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + std::thread syncThread2([&]() { + CloudSyncStatusCallback callback = [&syncFinishCount](const std::map &process) { + syncFinishCount++; + EXPECT_EQ(syncFinishCount, 2); + }; + std::vector inValue = {5, 6, 7, 8, 9}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).In("id", inValue); + PriorityLevelSync(0, query, callback, SyncMode::SYNC_MODE_CLOUD_MERGE); + }); + syncThread1.join(); + syncThread2.join(); +} + +/** + * @tc.name: DownloadAssetsOnly013 + * @tc.desc: Check assets only sync no data notify. + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly013, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + RuntimeContext::GetInstance()->SetBatchDownloadAssets(true); + int dataCount = 10; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + + /** + * @tc.steps:step2. assets only sync + * @tc.expected: step2. check notify count. + */ + std::map> assets; + assets["assets"] = {ASSET_COPY.name + "0"}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).BeginGroup().EqualTo("id", 0).And().AssetsOnly(assets). + EndGroup(); + PriorityLevelSync(2, query, nullptr, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::OK); + auto changedData = g_observer->GetSavedChangedData(); + EXPECT_EQ(changedData.size(), 1u); +} + +/** + * @tc.name: DownloadAssetsOnly014 + * @tc.desc: test assets only sync with cloud delete data. + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly014, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int dataCount = 10; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + DeleteCloudDBData(0, 1, ASSETS_TABLE_NAME); + /** + * @tc.steps:step2. Download assets which cloud delete. + * @tc.expected: step2. return ASSET_NOT_FOUND_FOR_DOWN_ONLY. + */ + std::map> assets; + assets["assets"] = {ASSET_COPY.name + "0"}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).BeginGroup().EqualTo("id", 0).And().AssetsOnly(assets). + EndGroup(); + PriorityLevelSync(2, query, nullptr, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::ASSET_NOT_FOUND_FOR_DOWN_ONLY); +} + +/** + * @tc.name: DownloadAssetsOnly015 + * @tc.desc: test compensated sync. + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly015, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int dataCount = 10; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + + /** + * @tc.steps:step2. set all data wait compensated. + * @tc.expected: step2. return ok. + */ + std::string sql = "update " + DBCommon::GetLogTableName(ASSETS_TABLE_NAME) + " set flag=flag|0x10;"; + EXPECT_EQ(sqlite3_exec(db, sql.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); + sql = "select count(*) from " + DBCommon::GetLogTableName(ASSETS_TABLE_NAME) + " where flag&0x10=0x10;"; + EXPECT_EQ(sqlite3_exec(db, sql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(10u), nullptr), SQLITE_OK); + + /** + * @tc.steps:step3. sync with compensated. + * @tc.expected: step3. return ok. + */ + std::mutex processMutex; + std::vector expectProcess; + std::condition_variable cv; + bool finish = false; + auto callback = [&cv, &finish, &processMutex] + (const std::map &process) { + for (auto &item : process) { + if (item.second.process == FINISHED) { + EXPECT_EQ(item.second.errCode, DBStatus::OK); + std::unique_lock lock(processMutex); + finish = true; + cv.notify_one(); + } + } + }; + CloudSyncOption option; + option.devices = {DEVICE_CLOUD}; + option.priorityTask = true; + option.compensatedSyncOnly = true; + DBStatus syncResult = g_delegate->Sync(option, callback); + EXPECT_EQ(syncResult, DBStatus::OK); + + /** + * @tc.steps:step4. wait sync finish and check data. + * @tc.expected: step4. return ok. + */ + std::unique_lock lock(processMutex); + cv.wait(lock, [&finish]() { + return finish; + }); + EXPECT_EQ(sqlite3_exec(db, sql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(0u), nullptr), SQLITE_OK); +} + +/** + * @tc.name: DownloadAssetsOnly016 + * @tc.desc: test assets only sync with lock data. + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly016, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int dataCount = 10; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + + /** + * @tc.steps:step2. lock data. + * @tc.expected: step2. return OK. + */ + std::vector> hashKey; + CloudDBSyncUtilsTest::GetHashKey(ASSETS_TABLE_NAME, " cloud_gid=0 ", db, hashKey); + EXPECT_EQ(Lock(ASSETS_TABLE_NAME, hashKey, db), OK); + + /** + * @tc.steps:step3. assets only sync. + * @tc.expected: step3. return OK. + */ + std::map> assets; + assets["assets"] = {ASSET_COPY.name + "0"}; + std::map> assets1; + assets1["assets"] = {ASSET_COPY.name + "1"}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).BeginGroup().EqualTo("id", 0).And().AssetsOnly(assets). + EndGroup().Or().BeginGroup().EqualTo("id", 1).And().AssetsOnly(assets1).EndGroup(); + g_observer->ResetCloudSyncToZero(); + PriorityLevelSync(2, query, nullptr, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::OK); + + /** + * @tc.steps:step4. check asset changed data. + * @tc.expected: step4. return OK. + */ + auto changedData = g_observer->GetSavedChangedData(); + EXPECT_EQ(changedData.size(), 1u); + auto item = changedData[ASSETS_TABLE_NAME]; + auto assetMsg = item.primaryData[1]; + EXPECT_EQ(assetMsg.size(), 1u); +} + +/** + * @tc.name: DownloadAssetsOnly017 + * @tc.desc: test assets only sync with error priority level. + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly017, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int dataCount = 10; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + + /** + * @tc.steps:step2. assets only sync with error priority level. + * @tc.expected: step2. return INVALID_ARGS. + */ + std::map> assets; + assets["assets"] = {ASSET_COPY.name + "0"}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).BeginGroup().EqualTo("id", 0).And().AssetsOnly(assets). + EndGroup(); + PriorityLevelSync(0, query, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::INVALID_ARGS); + + /** + * @tc.steps:step3. priority sync with error priority level. + * @tc.expected: step3. return INVALID_ARGS. + */ + query = Query::Select().From(ASSETS_TABLE_NAME).BeginGroup().EqualTo("id", 0).EndGroup(); + PriorityLevelSync(3, query, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::INVALID_ARGS); +} + +/** + * @tc.name: DownloadAssetsOnly018 + * @tc.desc: test assets only sync same record can merge assets map. + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly018, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int dataCount = 10; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + + /** + * @tc.steps:step2. assets only sync. + * @tc.expected: step2. return OK. + */ + std::map> assets; + assets["assets"] = {ASSET_COPY.name + "0"}; + std::map> assets1; + assets1["assets"] = {ASSET_COPY.name + "0_copy"}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).BeginGroup().EqualTo("id", 0).And().AssetsOnly(assets). + EndGroup().Or().BeginGroup().EqualTo("id", 0).And().AssetsOnly(assets1).EndGroup(); + PriorityLevelSync(2, query, nullptr, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::OK); + + /** + * @tc.steps:step3. check asset changed data. + * @tc.expected: step3. return OK. + */ + auto changedData = g_observer->GetSavedChangedData(); + EXPECT_EQ(changedData.size(), 1u); + auto item = changedData[ASSETS_TABLE_NAME]; + auto assetMsg = item.primaryData[1]; + EXPECT_EQ(assetMsg.size(), 1u); +} + +/** + * @tc.name: DownloadAssetsOnly019 + * @tc.desc: test assets only sync with cloud delete data. + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly019, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int dataCount = 10; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + DeleteCloudDBData(0, dataCount, ASSETS_TABLE_NAME); + /** + * @tc.steps:step2. Download assets which cloud delete. + * @tc.expected: step2. return ASSET_NOT_FOUND_FOR_DOWN_ONLY. + */ + std::map> assets; + assets["assets"] = {ASSET_COPY.name + "0"}; + Query query = Query::Select().From(ASSETS_TABLE_NAME).BeginGroup().EqualTo("id", 0).And().AssetsOnly(assets). + EndGroup(); + PriorityLevelSync(2, query, nullptr, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::ASSET_NOT_FOUND_FOR_DOWN_ONLY); +} + +/** + * @tc.name: DownloadAssetsOnly021 + * @tc.desc: test force pull mode pull mode can forcibly pull assets. + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsOnlyTest, DownloadAssetsOnly021, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int dataCount = 10; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + /** + * @tc.steps:step2. Download id 0 with force pull mode. + * @tc.expected: step2. return ok. + */ + Query query = Query::Select().From(ASSETS_TABLE_NAME).BeginGroup().EqualTo("id", 0).EndGroup(); + g_observer->ResetCloudSyncToZero(); + PriorityLevelSync(2, query, nullptr, SyncMode::SYNC_MODE_CLOUD_FORCE_PULL, DBStatus::OK); + /** + * @tc.steps:step3. check data type. + * @tc.expected: step3. return ok. + */ + auto data = g_observer->GetSavedChangedData(); + EXPECT_EQ(data.size(), 1u); + EXPECT_EQ(data[ASSETS_TABLE_NAME].type, ChangedDataType::ASSET); +} +} // namespace +#endif // RELATIONAL_STORE diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_download_assets_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_download_assets_test.cpp index b1b5e974660c0a32f4ab420d0df21e7e423d6d3d..14f90be27af9b61da5037e8028e7ac10ba23aa96 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_download_assets_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_download_assets_test.cpp @@ -192,15 +192,19 @@ void InsertLocalData(sqlite3 *&db, int64_t begin, int64_t count, const std::stri } } -void UpdateLocalData(sqlite3 *&db, const std::string &tableName, const Assets &assets) +void UpdateLocalData(sqlite3 *&db, const std::string &tableName, const Assets &assets, bool isEmptyAssets = false) { int errCode; std::vector assetBlob; const string sql = "update " + tableName + " set assets=?;"; sqlite3_stmt *stmt = nullptr; ASSERT_EQ(SQLiteUtils::GetStatement(db, sql, stmt), E_OK); - assetBlob = g_virtualCloudDataTranslate->AssetsToBlob(assets); - ASSERT_EQ(SQLiteUtils::BindBlobToStatement(stmt, 1, assetBlob, false), E_OK); + if (isEmptyAssets) { + ASSERT_EQ(sqlite3_bind_null(stmt, 1), SQLITE_OK); + } else { + assetBlob = g_virtualCloudDataTranslate->AssetsToBlob(assets); + ASSERT_EQ(SQLiteUtils::BindBlobToStatement(stmt, 1, assetBlob, false), E_OK); + } EXPECT_EQ(SQLiteUtils::StepWithRetry(stmt), SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)); SQLiteUtils::ResetStatement(stmt, true, errCode); } @@ -299,7 +303,8 @@ void WaitForSyncFinish(SyncProcess &syncProcess, const int64_t &waitTime) LOGD("-------------------sync end--------------"); } -void CallSync(const std::vector &tableNames, SyncMode mode, DBStatus dbStatus, DBStatus errCode = OK) +void CallSync(const std::vector &tableNames, SyncMode mode, DBStatus dbStatus, DBStatus errCode = OK, + bool isMerge = false) { g_syncProcess = {}; Query query = Query::Select().FromTable(tableNames); @@ -319,6 +324,7 @@ void CallSync(const std::vector &tableNames, SyncMode mode, DBStatu option.query = query; option.waitTime = SYNC_WAIT_TIME; option.lockAction = static_cast(0xff); // lock all + option.merge = isMerge; ASSERT_EQ(g_delegate->Sync(option, callback), dbStatus); if (dbStatus == DBStatus::OK) { @@ -355,7 +361,6 @@ void CheckDownloadFailedForTest002(sqlite3 *&db) ASSERT_EQ(RuntimeContext::GetInstance()->BlobToAssets(assetsBlob, assets), E_OK); ASSERT_EQ(assets.size(), 2u); // 2 is asset num for (size_t i = 0; i < assets.size(); ++i) { - EXPECT_EQ(assets[i].hash, ""); EXPECT_EQ(assets[i].status, AssetStatus::ABNORMAL); } } @@ -629,7 +634,8 @@ void DistributedDBCloudSyncerDownloadAssetsTest::DataStatusTest003() } }); int downLoadCount = 0; - g_virtualAssetLoader->ForkDownload([this, &downLoadCount](std::map &assets) { + g_virtualAssetLoader->ForkDownload([this, &downLoadCount](const std::string &tableName, + std::map &assets) { downLoadCount++; if (downLoadCount == 1) { std::vector> hashKey; @@ -640,6 +646,7 @@ void DistributedDBCloudSyncerDownloadAssetsTest::DataStatusTest003() InitDataStatusTest(true); CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK); WaitForSync(count); + g_virtualAssetLoader->ForkDownload(nullptr); } void DistributedDBCloudSyncerDownloadAssetsTest::DataStatusTest004() @@ -660,7 +667,8 @@ void DistributedDBCloudSyncerDownloadAssetsTest::DataStatusTest004() } }); int downLoadCount = 0; - g_virtualAssetLoader->ForkDownload([this, &downLoadCount](std::map &assets) { + g_virtualAssetLoader->ForkDownload([this, &downLoadCount](const std::string &tableName, + std::map &assets) { downLoadCount++; if (downLoadCount == 1) { std::vector> hashKey; @@ -682,6 +690,8 @@ void DistributedDBCloudSyncerDownloadAssetsTest::DataStatusTest004() InitDataStatusTest(true); CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK); WaitForSync(count); + g_virtualAssetLoader->ForkDownload(nullptr); + g_virtualCloudDb->ForkQuery(nullptr); } void DistributedDBCloudSyncerDownloadAssetsTest::DataStatusTest005() @@ -702,7 +712,8 @@ void DistributedDBCloudSyncerDownloadAssetsTest::DataStatusTest005() } }); int downLoadCount = 0; - g_virtualAssetLoader->ForkDownload([this, &downLoadCount](std::map &assets) { + g_virtualAssetLoader->ForkDownload([this, &downLoadCount](const std::string &tableName, + std::map &assets) { downLoadCount++; if (downLoadCount == 1) { std::vector> hashKey; @@ -715,6 +726,7 @@ void DistributedDBCloudSyncerDownloadAssetsTest::DataStatusTest005() InitDataStatusTest(true); CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK); WaitForSync(count); + g_virtualAssetLoader->ForkDownload(nullptr); } void DistributedDBCloudSyncerDownloadAssetsTest::DataStatusTest006() @@ -736,7 +748,8 @@ void DistributedDBCloudSyncerDownloadAssetsTest::DataStatusTest006() } }); int downLoadCount = 0; - g_virtualAssetLoader->ForkDownload([this, &downLoadCount](std::map &assets) { + g_virtualAssetLoader->ForkDownload([this, &downLoadCount](const std::string &tableName, + std::map &assets) { downLoadCount++; if (downLoadCount == 1) { std::vector> hashKey; @@ -750,6 +763,7 @@ void DistributedDBCloudSyncerDownloadAssetsTest::DataStatusTest006() InitDataStatusTest(true); CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK); WaitForSync(count); + g_virtualAssetLoader->ForkDownload(nullptr); } void DistributedDBCloudSyncerDownloadAssetsTest::DataStatusTest007() @@ -2415,7 +2429,7 @@ HWTEST_F(DistributedDBCloudSyncerDownloadAssetsTest, DownloadAssetTest001, TestS EXPECT_EQ(asset.status, AssetStatus::NORMAL); } } - EXPECT_EQ(g_virtualAssetLoader->GetBatchDownloadCount(), 0); + EXPECT_EQ(g_virtualAssetLoader->GetBatchDownloadCount(), 0u); RuntimeContext::GetInstance()->SetBatchDownloadAssets(false); } @@ -2690,5 +2704,125 @@ HWTEST_F(DistributedDBCloudSyncerDownloadAssetsTest, CloudTaskStatusTest001, Tes SyncProcess process3 = g_delegate->GetCloudTaskStatus(1); EXPECT_EQ(process3.errCode, DB_ERROR); } + +/** + * @tc.name: CloudTaskStatusTest002 + * @tc.desc: Test get cloud task status when task merge + * @tc.type: FUNC + * @tc.require: + * @tc.author: suyue + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsTest, CloudTaskStatusTest002, TestSize.Level1) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK + */ + int cloudCount = 100; // 100 is num of cloud + InsertCloudDBData(0, cloudCount, 0, ASSETS_TABLE_NAME); + + /** + * @tc.steps:step2. sync tasks 2 and 3 that can be merged when synchronizing task 1, get status of the merge task + * @tc.expected: step2. the errCode of task 2 and task 3 is OK or NOT_FOUND + */ + g_virtualCloudDb->SetBlockTime(1000); + Query query = Query::Select().FromTable({ASSETS_TABLE_NAME}); + CloudSyncStatusCallback callback = [](const std::map &process) { + std::unique_lock lock(g_processMutex); + if (process.begin()->second.process == FINISHED) { + g_processCondition.notify_one(); + } + }; + CloudSyncOption option = {.devices = {DEVICE_CLOUD}, .mode = SYNC_MODE_CLOUD_MERGE, .query = query, + .waitTime = SYNC_WAIT_TIME, .lockAction = static_cast(0xff)}; + + std::thread syncThread1([option, callback]() { + ASSERT_EQ(g_delegate->Sync(option, callback), DBStatus::OK); + }); + option.merge = true; + std::thread syncThread2([option, callback]() { + ASSERT_EQ(g_delegate->Sync(option, callback), DBStatus::OK); + }); + std::thread syncThread3([option, callback]() { + ASSERT_EQ(g_delegate->Sync(option, callback), DBStatus::OK); + }); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + SyncProcess process1 = g_delegate->GetCloudTaskStatus(1); + SyncProcess process2 = g_delegate->GetCloudTaskStatus(2); + SyncProcess process3 = g_delegate->GetCloudTaskStatus(3); + syncThread1.join(); + syncThread2.join(); + syncThread3.join(); + // Due to the task execution sequence, task 2 may be combined into 3 or task 3 may be combined into 2. + // Therefore, the errCode of task 2 and 3 may be OK or NOT_FOUND. + EXPECT_TRUE(process2.errCode == OK || process2.errCode == NOT_FOUND); + EXPECT_TRUE(process3.errCode == OK || process3.errCode == NOT_FOUND); +} + +/** + * @tc.name: CompensatedSyncTest001 + * @tc.desc: test compensated count more than 100. + * @tc.type: FUNC + * @tc.require: + * @tc.author: tankaisheng + */ +HWTEST_F(DistributedDBCloudSyncerDownloadAssetsTest, CompensatedSyncTest001, TestSize.Level0) +{ + /** + * @tc.steps:step1. init data + * @tc.expected: step1. return OK. + */ + int dataCount = 120; + InsertCloudDBData(0, dataCount, 0, ASSETS_TABLE_NAME); + CallSync({ASSETS_TABLE_NAME}, SYNC_MODE_CLOUD_MERGE, DBStatus::OK, DBStatus::OK); + + /** + * @tc.steps:step2. set all data wait compensated. + * @tc.expected: step2. return ok. + */ + std::string sql = "update " + DBCommon::GetLogTableName(ASSETS_TABLE_NAME) + " set flag=flag|0x10;"; + EXPECT_EQ(sqlite3_exec(db, sql.c_str(), nullptr, nullptr, nullptr), SQLITE_OK); + sql = "select count(*) from " + DBCommon::GetLogTableName(ASSETS_TABLE_NAME) + " where flag&0x10=0x10;"; + EXPECT_EQ(sqlite3_exec(db, sql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(120u), nullptr), SQLITE_OK); + + /** + * @tc.steps:step3. sync with compensated. + * @tc.expected: step3. return ok. + */ + std::mutex processMutex; + std::vector expectProcess; + std::condition_variable cv; + bool finish = false; + auto callback = [&cv, &finish, &processMutex] + (const std::map &process) { + for (auto &item : process) { + if (item.second.process == FINISHED) { + EXPECT_EQ(item.second.errCode, DBStatus::OK); + std::unique_lock lock(processMutex); + finish = true; + cv.notify_one(); + } + } + }; + CloudSyncOption option; + option.devices = {DEVICE_CLOUD}; + option.priorityTask = true; + option.compensatedSyncOnly = true; + DBStatus syncResult = g_delegate->Sync(option, callback); + EXPECT_EQ(syncResult, DBStatus::OK); + + /** + * @tc.steps:step4. wait sync finish and check data. + * @tc.expected: step4. return ok. + */ + std::unique_lock lock(processMutex); + cv.wait(lock, [&finish]() { + return finish; + }); + std::this_thread::sleep_for(std::chrono::seconds(1)); + EXPECT_EQ(sqlite3_exec(db, sql.c_str(), CloudDBSyncUtilsTest::QueryCountCallback, + reinterpret_cast(0u), nullptr), SQLITE_OK); +} } // namespace #endif // RELATIONAL_STORE diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_lock_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_lock_test.cpp index c6e9694d21eae77b28788168d3c0677d499e7ab9..0b113f6ab2ad577c2984e8129ab804d6dafb5419 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_lock_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_lock_test.cpp @@ -483,6 +483,40 @@ HWTEST_F(DistributedDBCloudSyncerLockTest, RDBUnlockCloudSync001, TestSize.Level reinterpret_cast(cloudCount), nullptr), SQLITE_OK); } +/** + * @tc.name: RDBLockSyncTest001 + * @tc.desc: Test sync deleted data which status is LOCKING. + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBCloudSyncerLockTest, RDBLockSyncTest001, TestSize.Level0) +{ + /** + * @tc.steps:step1. init deleted data which status is LOCKING. + * @tc.expected: step1. return ok. + */ + int dataCount = 10; + InsertLocalData(0, dataCount, ASSETS_TABLE_NAME, true); + CloudSyncOption option1 = PrepareOption(Query::Select().FromTable({ ASSETS_TABLE_NAME }), LockAction::INSERT); + CallSync(option1); + std::vector> hashKeys; + CloudDBSyncUtilsTest::GetHashKey(ASSETS_TABLE_NAME, " data_key = 0", db, hashKeys); + EXPECT_EQ(Lock(ASSETS_TABLE_NAME, hashKeys, db), OK); + std::string sql = "delete from " + ASSETS_TABLE_NAME + " where _rowid_ = 0"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql), SQLITE_OK); + /** + * @tc.steps:step2. sync, check upload info + * @tc.expected: step2. return ok. + */ + CloudSyncOption option2 = PrepareOption(Query::Select().FromTable({ ASSETS_TABLE_NAME }), LockAction::INSERT, + false, true); + CallSync(option2); + for (const auto &table : g_syncProcess.tableProcess) { + EXPECT_TRUE(table.second.upLoadInfo.successCount != 0u); + } +} + /** * @tc.name: RDBConflictCloudSync001 * @tc.desc: Both cloud and local are available, local version is empty, with cloud updates before upload @@ -698,7 +732,7 @@ HWTEST_F(DistributedDBCloudSyncerLockTest, DownloadAssetStatusTest001, TestSize. * @tc.steps:step2. sync * @tc.expected: step2. assets status is INSERT before download. */ - g_virtualAssetLoader->ForkDownload([](std::map &assets) { + g_virtualAssetLoader->ForkDownload([](const std::string &tableName, std::map &assets) { for (const auto &item: assets) { for (const auto &asset: item.second) { EXPECT_EQ(asset.status, static_cast(AssetStatus::INSERT)); @@ -746,7 +780,8 @@ HWTEST_F(DistributedDBCloudSyncerLockTest, DownloadAssetStatusTest002, TestSize. * @tc.steps:step3. sync * @tc.expected: step3. download status is a -> DELETE, b2 -> DELETE, b3 -> INSERT */ - g_virtualAssetLoader->ForkDownload([&b1, &b3](std::map &assets) { + g_virtualAssetLoader->ForkDownload([&b1, &b3](const std::string &tableName, + std::map &assets) { auto it = assets.find(COL_ASSETS); ASSERT_EQ(it != assets.end(), true); ASSERT_EQ(it->second.size(), 1u); // 1 is download size @@ -811,7 +846,8 @@ HWTEST_F(DistributedDBCloudSyncerLockTest, DownloadAssetStatusTest003, TestSize. * @tc.steps:step3. sync * @tc.expected: step3. download status is a -> UPDATE, b2 -> UPDATE */ - g_virtualAssetLoader->ForkDownload([&b1, &b2](std::map &assets) { + g_virtualAssetLoader->ForkDownload([&b1, &b2](const std::string &tableName, + std::map &assets) { auto it = assets.find(COL_ASSET); ASSERT_EQ(it != assets.end(), true); ASSERT_EQ(it->second.size(), 1u); @@ -866,7 +902,7 @@ HWTEST_F(DistributedDBCloudSyncerLockTest, RecordConflictTest001, TestSize.Level * @tc.expected: step2. return ok. */ g_virtualAssetLoader->SetDownloadStatus(DBStatus::OK); - g_virtualAssetLoader->ForkDownload([](std::map &assets) { + g_virtualAssetLoader->ForkDownload([](const std::string &tableName, std::map &assets) { EXPECT_EQ(assets.find(COL_ASSET) != assets.end(), true); }); CallSync(option); @@ -877,6 +913,7 @@ HWTEST_F(DistributedDBCloudSyncerLockTest, RecordConflictTest001, TestSize.Level ASSERT_EQ(result, true); } g_cloudStoreHook->SetSyncFinishHook(nullptr); + g_virtualAssetLoader->ForkDownload(nullptr); } /** @@ -1274,7 +1311,8 @@ HWTEST_F(DistributedDBCloudSyncerLockTest, RemoveAssetsFailTest001, TestSize.Lev * @tc.expected: step3. return ok. */ int downLoadCount = 0; - g_virtualAssetLoader->ForkDownload([this, &downLoadCount](std::map &assets) { + g_virtualAssetLoader->ForkDownload([this, &downLoadCount](const std::string &tableName, + std::map &assets) { downLoadCount++; if (downLoadCount == 1) { std::string sql = "delete from " + ASSETS_TABLE_NAME + " WHERE id=0"; @@ -1287,6 +1325,74 @@ HWTEST_F(DistributedDBCloudSyncerLockTest, RemoveAssetsFailTest001, TestSize.Lev } g_virtualAssetLoader->SetRemoveStatus(DBStatus::OK); RuntimeContext::GetInstance()->SetBatchDownloadAssets(false); + g_virtualAssetLoader->ForkDownload(nullptr); +} + +/** + * @tc.name: CompensateSyncTest001 + * @tc.desc: Test only compensates for the sync of deleted data + * @tc.type: FUNC + * @tc.require: + * @tc.author: bty + */ +HWTEST_F(DistributedDBCloudSyncerLockTest, CompensateSyncTest001, TestSize.Level1) +{ + /** + * @tc.steps:step1. insert cloud and sync + * @tc.expected: step1. return ok. + */ + int cloudCount = 30; + InsertCloudDBData(0, cloudCount, 0, ASSETS_TABLE_NAME); + CloudSyncOption option = PrepareOption(Query::Select().FromTable({ ASSETS_TABLE_NAME }), LockAction::INSERT); + CallSync(option); + + /** + * @tc.steps:step2. lock and delete 1-10 + * @tc.expected: step2. return ok. + */ + std::vector> hashKeys; + CloudDBSyncUtilsTest::GetHashKey(ASSETS_TABLE_NAME, " data_key < 10 ", db, hashKeys); + EXPECT_EQ(Lock(ASSETS_TABLE_NAME, hashKeys, db), OK); + std::string sql = "delete from " + ASSETS_TABLE_NAME + " where id < 10;"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql.c_str()), SQLITE_OK); + + /** + * @tc.steps:step3. compensate sync and check query type + * @tc.expected: step3. return ok. + */ + g_virtualCloudDb->ForkQuery([](const std::string &, VBucket &extend) { + int64_t type; + CloudStorageUtils::GetValueFromVBucket(CloudDbConstant::TYPE_FIELD, extend, type); + EXPECT_EQ(type, 1u); + }); + CloudSyncOption cOption = PrepareOption(Query::Select().FromTable({ ASSETS_TABLE_NAME }), LockAction::INSERT, + true, true); + CallSync(cOption); + sleep(1); + + /** + * @tc.steps:step4. lock and delete id 30 + * @tc.expected: step4. return ok. + */ + InsertLocalData(cloudCount, 1, ASSETS_TABLE_NAME, true); + hashKeys.clear(); + CloudDBSyncUtilsTest::GetHashKey(ASSETS_TABLE_NAME, " data_key = 30 ", db, hashKeys); + EXPECT_EQ(Lock(ASSETS_TABLE_NAME, hashKeys, db), OK); + sql = "delete from " + ASSETS_TABLE_NAME + " where id = 30;"; + EXPECT_EQ(RelationalTestUtils::ExecSql(db, sql.c_str()), SQLITE_OK); + + /** + * @tc.steps:step5. compensate sync and check query type + * @tc.expected: step5. return ok. + */ + g_virtualCloudDb->ForkQuery([](const std::string &, VBucket &extend) { + int64_t type; + CloudStorageUtils::GetValueFromVBucket(CloudDbConstant::TYPE_FIELD, extend, type); + EXPECT_EQ(type, 0u); + }); + CallSync(cOption); + sleep(1); + g_virtualCloudDb->ForkQuery(nullptr); } } // namespace #endif // RELATIONAL_STORE \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_progress_manager_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_progress_manager_test.cpp index f38a38587c6aada0b8df76a129020872f11e9284..1a92ff31698a7204315169b71b52507551b3fdc2 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_progress_manager_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/distributeddb_cloud_syncer_progress_manager_test.cpp @@ -362,4 +362,41 @@ HWTEST_F(DistributedDBCloudSyncerProgressManagerTest, SyncerMockCheck002, TestSi storageProxy = nullptr; delete iCloud; } + +/** + * @tc.name: SyncerMgrCheck006 + * @tc.desc: Test check if compensated sync task is in queue + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBCloudSyncerProgressManagerTest, SyncerMgrCheck006, TestSize.Level1) +{ + MockICloudSyncStorageInterface *iCloud = new MockICloudSyncStorageInterface(); + std::shared_ptr storageProxy = std::make_shared(iCloud); + TestCloudSyncer cloudSyncer(storageProxy); + std::shared_ptr idb = std::make_shared(); + cloudSyncer.SetMockICloudDB(idb); + std::vector tables = {"TestTableA", "TestTableB"}; + SyncProcessCallback onProcess; + /** + * @tc.steps:step1. add compensated task to task queue. + * @tc.expected: step1. return OK + */ + cloudSyncer.taskInfo_ = cloudSyncer.SetAndGetCloudTaskInfo(SYNC_MODE_CLOUD_FORCE_PUSH, tables, onProcess, 5000); + cloudSyncer.taskInfo_.compensatedTask = true; + int errCode = cloudSyncer.CallTryToAddSyncTask(std::move(cloudSyncer.taskInfo_)); + EXPECT_EQ(errCode, E_OK); + + /** + * @tc.steps:step2. check compensated task. + * @tc.expected: step2. return true + */ + EXPECT_EQ(cloudSyncer.CallIsAlreadyHaveCompensatedSyncTask(), true); + + RuntimeContext::GetInstance()->StopTaskPool(); + storageProxy.reset(); + delete iCloud; + idb = nullptr; +} } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/mock_icloud_sync_storage_interface.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/mock_icloud_sync_storage_interface.h index 76e7912a7ebb73f46869d9d55183f99101d4d4ad..0c41d70425b9367115f31810ad96ffcbf31ae0a4 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/mock_icloud_sync_storage_interface.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/mock_icloud_sync_storage_interface.h @@ -41,17 +41,22 @@ public: MOCK_METHOD1(ReleaseCloudDataToken, int(ContinueToken &)); MOCK_METHOD4(GetInfoByPrimaryKeyOrGid, int(const std::string &, const VBucket &, DataInfoWithLog &, VBucket &)); MOCK_METHOD2(PutCloudSyncData, int(const std::string &, DownloadData &)); + MOCK_METHOD2(UpdateAssetStatusForAssetOnly, int(const std::string &, VBucket &)); MOCK_METHOD3(TriggerObserverAction, void(const std::string &, ChangedData &&, bool)); MOCK_METHOD4(CleanCloudData, int(ClearMode mode, const std::vector &tableNameList, const RelationalSchemaObject &localSchema, std::vector &assets)); MOCK_METHOD3(FillCloudAssetForDownload, int(const std::string &, VBucket &, bool)); + MOCK_METHOD3(FillCloudAssetForAsyncDownload, int(const std::string &, VBucket &, bool)); MOCK_METHOD1(SetLogTriggerStatus, int(bool)); + MOCK_METHOD1(SetLogTriggerStatusForAsyncDownload, int(bool)); MOCK_METHOD4(FillCloudLogAndAsset, int(OpType, const CloudSyncData &, bool, bool)); MOCK_CONST_METHOD0(GetIdentify, std::string()); MOCK_METHOD1(CheckQueryValid, int(const QuerySyncObject &)); MOCK_METHOD1(IsSharedTable, bool(const std::string &)); MOCK_CONST_METHOD0(GetCloudSyncConfig, CloudSyncConfig()); MOCK_METHOD3(GetLocalDataCount, int(const std::string &, int &, int &)); + MOCK_METHOD0(GetDownloadAssetTable, std::pair>(void)); + MOCK_METHOD2(GetDownloadAssetRecords, std::pair>(const std::string &, int64_t)); }; } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_asset_loader.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_asset_loader.cpp index e05e9f67f89e6c911b59f15f0638bc8cf3f3a400..f25aad41da43175427b01aa11da7fdf66105a11b 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_asset_loader.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_asset_loader.cpp @@ -25,9 +25,9 @@ DBStatus VirtualAssetLoader::Download(const std::string &tableName, const std::s return downloadStatus_; } } - LOGD("Download GID:%s", gid.c_str()); + LOGD("Download GID:%s, table %s", gid.c_str(), tableName.c_str()); if (downloadCallBack_) { - downloadCallBack_(assets); + downloadCallBack_(tableName, assets); } for (auto &item: assets) { for (auto &asset: item.second) { @@ -147,12 +147,12 @@ void VirtualAssetLoader::BatchRemoveLocalAssets(const std::string &tableName, } } -int VirtualAssetLoader::GetBatchDownloadCount() +uint32_t VirtualAssetLoader::GetBatchDownloadCount() { return downloadCount_; } -int VirtualAssetLoader::GetBatchRemoveCount() +uint32_t VirtualAssetLoader::GetBatchRemoveCount() { return removeCount_; } @@ -167,4 +167,15 @@ void VirtualAssetLoader::ForkBatchDownload(const BatchDownloadCallback &callback { batchDownloadCallback_ = callback; } + +DBStatus VirtualAssetLoader::CancelDownload() +{ + cancelCount_++; + return OK; +} + +uint32_t VirtualAssetLoader::GetCancelCount() const +{ + return cancelCount_; +} } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_asset_loader.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_asset_loader.h index 374e7d5294ef5edca760f906e44f7b949c5b61b6..4f294054d2db5a45b3062781ba93907b681379b2 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_asset_loader.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_asset_loader.h @@ -20,7 +20,7 @@ #include "iAssetLoader.h" namespace DistributedDB { -using DownloadCallBack = std::function &assets)>; +using DownloadCallBack = std::function &assets)>; using RemoveAssetsCallBack = std::function &assets)>; using RemoveLocalAssetsCallBack = std::function &assets)>; using BatchDownloadCallback = std::function &assets)>; @@ -53,13 +53,17 @@ public: void BatchRemoveLocalAssets(const std::string &tableName, std::vector &removeAssets) override; - int GetBatchDownloadCount(); + uint32_t GetBatchDownloadCount(); - int GetBatchRemoveCount(); + uint32_t GetBatchRemoveCount(); void Reset(); void ForkBatchDownload(const BatchDownloadCallback &callback); + + DBStatus CancelDownload() override; + + uint32_t GetCancelCount() const; private: DBStatus RemoveLocalAssetsInner(const std::string &tableName, const std::string &gid, const Type &prefix, std::map &assets); @@ -68,11 +72,12 @@ private: DBStatus downloadStatus_ = OK; DBStatus removeStatus_ = OK; DBStatus batchRemoveStatus_ = OK; + std::atomic downloadCount_ = 0; + std::atomic removeCount_ = 0; + std::atomic cancelCount_ = 0; DownloadCallBack downloadCallBack_; RemoveAssetsCallBack removeAssetsCallBack_; RemoveLocalAssetsCallBack removeLocalAssetsCallBack_; - std::atomic downloadCount_ = 0; - std::atomic removeCount_ = 0; BatchDownloadCallback batchDownloadCallback_; }; } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_syncer.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_syncer.cpp index 43fb8c5413c715c2766258d5520969d3bae61d40..cbcc3581a5072a5616cf919ba524a1f863ca9719 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_syncer.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/cloud/virtual_cloud_syncer.cpp @@ -93,7 +93,7 @@ void VirtualCloudSyncer::Notify(bool notifyIfError) size_t VirtualCloudSyncer::GetQueueCount() { std::lock_guard autoLock(dataLock_); - return taskQueue_.size(); + return GetCurrentCommonTaskNum(); } void VirtualCloudSyncer::SetCurrentTaskInfo(const SyncProcessCallback &callback, diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_communicator_proxy_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_communicator_proxy_test.cpp index 2706f6154fb7f7371a16da051c8cceea5d41a7b8..1f8149d9c2a5eea2b455fddd78007e88e1bf9d9b 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_communicator_proxy_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_communicator_proxy_test.cpp @@ -160,6 +160,51 @@ HWTEST_F(DistributedDBCommunicatorProxyTest, InterfaceSetEqualId001, TestSize.Le EXPECT_EQ(status, DBStatus::OK); } +/** + * @tc.name: Interface set equal 002 + * @tc.desc: Test different user set same equal identifier + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBCommunicatorProxyTest, InterfaceSetEqualId002, TestSize.Level0) +{ + /** + * @tc.steps: step1. Get DB of user1 + * @tc.expected: step1. OK. + */ + std::string userId1 = "user1"; + KvStoreDelegateManager mgr1(APP_ID, userId1); + KvStoreNbDelegate *delegate1 = nullptr; + auto delegate1Callback = bind(&DistributedDBToolsUnitTest::KvStoreNbDelegateCallback, + placeholders::_1, placeholders::_2, std::ref(g_kvDelegateStatus), std::ref(delegate1)); + KvStoreNbDelegate::Option option; + mgr1.SetKvStoreConfig(g_config); + mgr1.GetKvStore(STORE_ID, option, delegate1Callback); + ASSERT_TRUE(g_kvDelegateStatus == OK); + ASSERT_TRUE(delegate1 != nullptr); + /** + * @tc.steps: step2. Get identifier with syncDualTupleMode + * @tc.expected: step2. OK. + */ + std::string identifier = g_mgr.GetKvStoreIdentifier(USER_ID, APP_ID, STORE_ID, true); + std::string identifier1 = mgr1.GetKvStoreIdentifier(userId1, APP_ID, STORE_ID, true); + EXPECT_EQ(identifier, identifier1); + /** + * @tc.steps: step3. Set identifier + * @tc.expected: step3. OK. + */ + DBStatus status = g_kvDelegatePtr->SetEqualIdentifier(identifier, { DEVICE_B, DEVICE_D, DEVICE_E }); + EXPECT_EQ(status, DBStatus::OK); + DBStatus status1 = delegate1->SetEqualIdentifier(identifier1, { DEVICE_B, DEVICE_D, DEVICE_E }); + EXPECT_EQ(status1, DBStatus::OK); + + ASSERT_EQ(mgr1.CloseKvStore(delegate1), OK); + delegate1 = nullptr; + status = mgr1.DeleteKvStore(STORE_ID); + ASSERT_TRUE(status == OK); +} + /** * @tc.name: Register callback 001 * @tc.desc: Test register callback from CommunicatorProxy. @@ -212,8 +257,8 @@ HWTEST_F(DistributedDBCommunicatorProxyTest, Activate001, TestSize.Level1) * @tc.steps: step1. Call Activate from CommProxy. * @tc.expected: step1. mainComm and extComm's Activate should be called once. */ - EXPECT_CALL(extComm_, Activate()).Times(1); - EXPECT_CALL(mainComm_, Activate()).Times(1); + EXPECT_CALL(extComm_, Activate("")).Times(1); + EXPECT_CALL(mainComm_, Activate("")).Times(1); commProxy_->Activate(); } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_mock_sync_module_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_mock_sync_module_test.cpp index 6a7c43d3c469d30955b5b05f9f79a44d1cfaaf66..827a7b8e557fe07e92653d8cdde1bd75a46dd697 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_mock_sync_module_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_mock_sync_module_test.cpp @@ -39,10 +39,8 @@ #include "single_ver_kv_syncer.h" #include "single_ver_relational_sync_task_context.h" #include "virtual_communicator_aggregator.h" -#include "virtual_single_ver_sync_db_Interface.h" -#ifdef DATA_SYNC_CHECK_003 #include "virtual_relational_ver_sync_db_interface.h" -#endif +#include "virtual_single_ver_sync_db_Interface.h" using namespace testing::ext; using namespace testing; @@ -247,7 +245,7 @@ void AbilitySync004() std::unique_lock lock(mutex); std::condition_variable cv; for (int i = 0; i < loopCount; i++) { - std::thread t = std::thread([&] { + std::thread t = std::thread([&context, &finishCount, &cv] { DbAbility dbAbility; context->SetDbAbility(dbAbility); finishCount++; @@ -926,12 +924,12 @@ HWTEST_F(DistributedDBMockSyncModuleTest, SyncDataSync003, TestSize.Level1) /** * @tc.steps: step2. call RemoveDeviceDataIfNeed in diff thread and then put data */ - std::thread thread1([&]() { + std::thread thread1([&dataSync, &syncTaskContext, &storage, deviceId, k1, v1]() { (void)dataSync.CallRemoveDeviceDataIfNeed(&syncTaskContext); storage.PutDeviceData(deviceId, k1, v1); LOGD("PUT FINISH"); }); - std::thread thread2([&]() { + std::thread thread2([&dataSync, &syncTaskContext, &storage, deviceId, k2, v2]() { (void)dataSync.CallRemoveDeviceDataIfNeed(&syncTaskContext); storage.PutDeviceData(deviceId, k2, v2); LOGD("PUT FINISH"); @@ -1154,6 +1152,55 @@ HWTEST_F(DistributedDBMockSyncModuleTest, SyncLifeTest005, TestSize.Level3) delete syncDBInterface; } +/** + * @tc.name: SyncLifeTest006 + * @tc.desc: Test close and sync concurrently + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBMockSyncModuleTest, SyncLifeTest006, TestSize.Level1) +{ + /** + * @tc.steps:step1. Init syncer + * @tc.expected: step1. Return OK. + */ + std::shared_ptr syncer = std::make_shared(); + VirtualCommunicatorAggregator *virtualCommunicatorAggregator = new VirtualCommunicatorAggregator(); + ASSERT_NE(virtualCommunicatorAggregator, nullptr); + RuntimeContext::GetInstance()->SetCommunicatorAggregator(virtualCommunicatorAggregator); + const std::string DEVICE_B = "deviceB"; + VirtualSingleVerSyncDBInterface *syncDBInterface = new VirtualSingleVerSyncDBInterface(); + ASSERT_NE(syncDBInterface, nullptr); + std::string userId = "userid_0"; + std::string storeId = "storeId_0"; + std::string appId = "appid_0"; + std::string identifier = KvStoreDelegateManager::GetKvStoreIdentifier(userId, appId, storeId); + std::vector identifierVec(identifier.begin(), identifier.end()); + syncDBInterface->SetIdentifier(identifierVec); + /** + * @tc.steps:step2. close and sync concurrently + * @tc.expected: step2. No deadlock occurs + */ + for (int i = 0; i < 100; i++) { // run 100 times + EXPECT_EQ(syncer->Initialize(syncDBInterface, true), E_OK); + virtualCommunicatorAggregator->OnlineDevice(DEVICE_B); + std::thread writeThread([syncer, &DEVICE_B]() { + EXPECT_EQ(syncer->Sync({DEVICE_B}, PUSH_AND_PULL, nullptr, nullptr, true), E_OK); + }); + std::thread closeThread([syncer, &syncDBInterface]() { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + EXPECT_EQ(syncer->Close(true), E_OK); + }); + closeThread.join(); + writeThread.join(); + } + syncer = nullptr; + std::this_thread::sleep_for(std::chrono::seconds(1)); + RuntimeContext::GetInstance()->SetCommunicatorAggregator(nullptr); + delete syncDBInterface; +} + /** * @tc.name: MessageScheduleTest001 * @tc.desc: Test MessageSchedule stop timer when no message. @@ -1206,7 +1253,7 @@ HWTEST_F(DistributedDBMockSyncModuleTest, SyncEngineTest001, TestSize.Level1) auto communicator = static_cast(virtualCommunicatorAggregator->GetCommunicator("real_device")); RefObject::IncObjRef(communicator); - std::thread thread1([&]() { + std::thread thread1([&communicator]() { if (communicator == nullptr) { return; } @@ -1218,7 +1265,7 @@ HWTEST_F(DistributedDBMockSyncModuleTest, SyncEngineTest001, TestSize.Level1) communicator->CallbackOnMessage("src", message); } }); - std::thread thread2([&]() { + std::thread thread2([&enginePtr]() { std::this_thread::sleep_for(std::chrono::milliseconds(1)); enginePtr->Close(); }); @@ -1342,6 +1389,56 @@ HWTEST_F(DistributedDBMockSyncModuleTest, SyncEngineTest004, TestSize.Level0) RefObject::KillAndDecObjRef(enginePtr); } +/** + * @tc.name: SyncEngineTest005 + * @tc.desc: Test alloc communicator with userId, test set and release equal identifier. + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBMockSyncModuleTest, SyncEngineTest005, TestSize.Level0) +{ + /** + * @tc.steps: step1. Get communicator aggregator and set callback to check userId. + * @tc.expected: step1. ok + */ + std::unique_ptr enginePtr = std::make_unique(); + MockKvSyncInterface syncDBInterface; + KvDBProperties kvDBProperties; + std::string userId1 = "user_1"; + kvDBProperties.SetStringProp(DBProperties::USER_ID, userId1); + std::vector identifier(COMM_LABEL_LENGTH, 1u); + syncDBInterface.SetIdentifier(identifier); + syncDBInterface.SetDbProperties(kvDBProperties); + std::shared_ptr metaData = std::make_shared(); + metaData->Initialize(&syncDBInterface); + VirtualCommunicatorAggregator *virtualCommunicatorAggregator = new VirtualCommunicatorAggregator(); + ASSERT_NE(virtualCommunicatorAggregator, nullptr); + virtualCommunicatorAggregator->SetAllocCommunicatorCallback([&userId1](const std::string &userId) { + EXPECT_EQ(userId1, userId); + }); + RuntimeContext::GetInstance()->SetCommunicatorAggregator(virtualCommunicatorAggregator); + /** + * @tc.steps: step2. Initialize sync engine. + * @tc.expected: step2. ok + */ + ISyncEngine::InitCallbackParam param = { nullptr, nullptr, nullptr }; + enginePtr->Initialize(&syncDBInterface, metaData, param); + virtualCommunicatorAggregator->SetAllocCommunicatorCallback(nullptr); + /** + * @tc.steps: step3. Set equal identifier. + * @tc.expected: step3. ok + */ + virtualCommunicatorAggregator->SetReleaseCommunicatorCallback([&userId1](const std::string &userId) { + EXPECT_EQ(userId, userId1); + }); + EXPECT_EQ(enginePtr->SetEqualIdentifier(DBCommon::TransferHashString("LABEL"), { "DEVICE" }), E_OK); + enginePtr->Close(); + virtualCommunicatorAggregator->SetReleaseCommunicatorCallback(nullptr); + RuntimeContext::GetInstance()->SetCommunicatorAggregator(nullptr); + virtualCommunicatorAggregator = nullptr; +} + /** * @tc.name: remote query packet 001 * @tc.desc: Test RemoteExecutorRequestPacket Serialization And DeSerialization @@ -1831,6 +1928,57 @@ HWTEST_F(DistributedDBMockSyncModuleTest, SyncTaskContextCheck006, TestSize.Leve RefObject::KillAndDecObjRef(context); RefObject::KillAndDecObjRef(communicator); } + +/** + * @tc.name: SyncTaskContextCheck007 + * @tc.desc: test get query sync id for field sync + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBMockSyncModuleTest, SyncTaskContextCheck007, TestSize.Level0) +{ + /** + * @tc.steps: step1. prepare context + * @tc.expected: OK + */ + auto context = new (std::nothrow) SingleVerRelationalSyncTaskContext(); + ASSERT_NE(context, nullptr); + SingleVerSyncStateMachine stateMachine; + VirtualCommunicator communicator("device", nullptr); + VirtualRelationalVerSyncDBInterface dbSyncInterface; + std::shared_ptr metadata = std::make_shared(); + ASSERT_EQ(metadata->Initialize(&dbSyncInterface), E_OK); + (void)context->Initialize("device", &dbSyncInterface, metadata, &communicator); + (void)stateMachine.Initialize(context, &dbSyncInterface, metadata, &communicator); + /** + * @tc.steps: step2. prepare table and query + * @tc.expected: OK + */ + FieldInfo field; + field.SetFieldName("abc"); + field.SetColumnId(0); + TableInfo table; + table.SetTableName("tableA"); + table.AddField(field); + RelationalSchemaObject schemaObj; + schemaObj.AddRelationalTable(table); + dbSyncInterface.SetSchemaInfo(schemaObj); + QuerySyncObject query; + query.SetTableName("tableA"); + context->SetQuery(query); + /** + * @tc.steps: step3. get and check queryId + * @tc.expected: OK + */ + context->SetRemoteSoftwareVersion(SOFTWARE_VERSION_CURRENT); + std::string expectQuerySyncId = DBCommon::TransferStringToHex(DBCommon::TransferHashString("abc")); + std::string actualQuerySyncId = context->GetQuerySyncId(); + EXPECT_EQ(expectQuerySyncId, actualQuerySyncId); + context->Clear(); + RefObject::KillAndDecObjRef(context); +} + #ifdef RUN_AS_ROOT /** * @tc.name: TimeChangeListenerTest001 @@ -2253,4 +2401,4 @@ HWTEST_F(DistributedDBMockSyncModuleTest, SyncTimerResetTest001, TestSize.Level1 EXPECT_EQ(stateMachine.CallPrepareNextSyncTask(), E_OK); stateMachine.CallStopWatchDog(); } -} \ No newline at end of file +} diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_relational_multi_user_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_relational_multi_user_test.cpp index 18a8aba27eb089bcf8948d6f2301f1be017126a1..8aaacac660fc4ae92e48d249d8894fa73956df58 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_relational_multi_user_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_relational_multi_user_test.cpp @@ -259,6 +259,23 @@ namespace { return true; }; + const AutoLaunchRequestCallback g_callback2 = [](const std::string &identifier, AutoLaunchParam ¶m) { + if (g_identifier != identifier) { + LOGD("g_identifier(%s) != identifier(%s)", g_identifier.c_str(), identifier.c_str()); + return false; + } + param.subUser = SUB_USER_1; + param.path = g_testDir + "/test2.db"; + param.appId = APP_ID; + param.storeId = STORE_ID; + CipherPassword passwd; + param.option = {true, false, CipherType::DEFAULT, passwd, "", false, g_testDir, nullptr, + 0, nullptr}; + param.notifier = g_notifier; + param.option.syncDualTupleMode = false; + return true; + }; + void DoRemoteQuery() { RemoteCondition condition; @@ -1309,6 +1326,68 @@ HWTEST_F(DistributedDBRelationalMultiUserTest, RDBSyncOpt006, TestSize.Level0) g_communicatorAggregator->ResetSendDelayInfo(); } +/** + * @tc.name: SubUserAutoLaunchTest001 + * @tc.desc: Test auto launch with sub user + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBRelationalMultiUserTest, SubUserAutoLaunchTest001, TestSize.Level0) +{ + /** + * @tc.steps: step1. Prepare db1 and db2 with subUser + * @tc.expected: step1. success. + */ + RelationalStoreManager subUserMgr2(APP_ID, USER_ID_1, SUB_USER_1); + RelationalStoreDelegate::Option option; + subUserMgr2.OpenStore(g_storePath2, STORE_ID, option, g_rdbDelegatePtr2); + PrepareEnvironment(g_tableName, g_storePath2, g_rdbDelegatePtr2); + subUserMgr2.SetAutoLaunchRequestCallback(g_callback2); + RelationalStoreManager subUserMgr1(APP_ID, USER_ID_1, SUB_USER_1); + PrepareEnvironment(g_tableName, g_storePath1, g_rdbDelegatePtr1); + CloseStore(); + + /** + * @tc.steps: step2. Prepare data in deviceB + * @tc.expected: step2. success. + */ + VirtualRowData virtualRowData; + DataValue d1; + d1 = (int64_t)1; + virtualRowData.objectData.PutDataValue("id", d1); + DataValue d2; + d2.SetText("hello"); + virtualRowData.objectData.PutDataValue("name", d2); + virtualRowData.logInfo.timestamp = 1; + g_deviceB->PutData(g_tableName, {virtualRowData}); + + std::vector remoteDev; + remoteDev.push_back(g_deviceB); + PrepareVirtualDeviceEnv(g_tableName, g_storePath1, remoteDev); + + /** + * @tc.steps: step3. Set label in deviceB and sync + * @tc.expected: step3. success. + */ + Query query = Query::Select(g_tableName); + g_identifier = subUserMgr1.GetRelationalStoreIdentifier(USER_ID_1, SUB_USER_1, APP_ID, STORE_ID); + std::vector label(g_identifier.begin(), g_identifier.end()); + g_communicatorAggregator->SetCurrentUserId(USER_ID_1); + g_communicatorAggregator->RunCommunicatorLackCallback(label); + std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_TIME)); + EXPECT_EQ(g_deviceB->GenericVirtualDevice::Sync(SYNC_MODE_PUSH_ONLY, query, true), E_OK); + + /** + * @tc.steps: step4. Check result + * @tc.expected: step4. deviceA have data from deviceB. + */ + CheckDataInRealDevice(); + + RuntimeConfig::SetAutoLaunchRequestCallback(nullptr, DBType::DB_RELATION); + RuntimeConfig::ReleaseAutoLaunch(USER_ID_1, SUB_USER_1, APP_ID, STORE_ID, DBType::DB_RELATION); +} + /** * @tc.name: DropDistributedTableTest001 * @tc.desc: Test sync after drop distributed table. @@ -1316,7 +1395,7 @@ HWTEST_F(DistributedDBRelationalMultiUserTest, RDBSyncOpt006, TestSize.Level0) * @tc.require: * @tc.author: liaoyonghuang */ -HWTEST_F(DistributedDBRelationalMultiUserTest, DropDistributedTableTest001, TestSize.Level1) +HWTEST_F(DistributedDBRelationalMultiUserTest, DropDistributedTableTest001, TestSize.Level0) { /** * @tc.steps: step1. Prepare db1 and db2. @@ -1362,4 +1441,62 @@ HWTEST_F(DistributedDBRelationalMultiUserTest, DropDistributedTableTest001, Test CheckDataInRealDevice(); g_currentStatus = 0; CloseStore(); +} + +/** + * @tc.name: DeleteTest001 + * @tc.desc: Test insert update and delete + * @tc.type: FUNC + * @tc.require: + * @tc.author: zqq + */ +HWTEST_F(DistributedDBRelationalMultiUserTest, DeleteTest001, TestSize.Level0) +{ + /** + * @tc.steps: step1. Prepare db2. + * @tc.expected: step1. success. + */ + OpenStore2(); + PrepareEnvironment(g_tableName, g_storePath2, g_rdbDelegatePtr2); + /** + * @tc.steps: step2. Do 1st sync to create distributed table + * @tc.expected: step2. success. + */ + std::vector remoteDev; + remoteDev.push_back(g_deviceB); + PrepareVirtualDeviceEnv(g_tableName, g_storePath2, remoteDev); + /** + * @tc.steps: step3. Do sync and check result. + * @tc.expected: step3. success. + */ + VirtualRowData virtualRowData; + DataValue d1; + d1 = static_cast(1); + virtualRowData.objectData.PutDataValue("id", d1); + DataValue d2; + d2.SetText("hello"); + virtualRowData.objectData.PutDataValue("name", d2); + virtualRowData.logInfo.timestamp = 1; + virtualRowData.logInfo.hashKey = {'1'}; + g_deviceB->PutData(g_tableName, {virtualRowData}); + Query query = Query::Select(g_tableName); + EXPECT_EQ(g_deviceB->GenericVirtualDevice::Sync(SYNC_MODE_PUSH_ONLY, query, true), E_OK); + /** + * @tc.steps: step4. Update data and sync again. + * @tc.expected: step4. success. + */ + virtualRowData.logInfo.timestamp++; + g_deviceB->PutData(g_tableName, {virtualRowData}); + EXPECT_EQ(g_deviceB->GenericVirtualDevice::Sync(SYNC_MODE_PUSH_ONLY, query, true), E_OK); + /** + * @tc.steps: step5. Delete data and sync again. + * @tc.expected: step5. success. + */ + virtualRowData.logInfo.timestamp++; + virtualRowData.logInfo.flag = static_cast(LogInfoFlag::FLAG_DELETE); + g_deviceB->PutData(g_tableName, {virtualRowData}); + EXPECT_EQ(g_deviceB->GenericVirtualDevice::Sync(SYNC_MODE_PUSH_ONLY, query, true), E_OK); + CheckDataInRealDevice(); + g_currentStatus = 0; + CloseStore(); } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_multi_sub_user_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_multi_sub_user_test.cpp index 184559e97bff9f902fdebf8308b7c936e23a37b0..54982e13536729da52bd65e6587274c27418fcf7 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_multi_sub_user_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_multi_sub_user_test.cpp @@ -428,6 +428,73 @@ HWTEST_F(DistributedDBSingleVerMultiSubUserTest, KvDelegateInvalidParamTest001, CloseDelegate(delegatePtr3, mgr3, STORE_ID_1); } +/** + * @tc.name: SubUserPermissionCheck + * @tc.desc: permission check subuser + * @tc.type: FUNC + * @tc.require: + * @tc.author: luoguo + */ +HWTEST_F(DistributedDBSingleVerMultiSubUserTest, SubUserPermissionCheck, TestSize.Level1) +{ + /** + * @tc.steps: step1. set permission check callback + * @tc.expected: step1. set OK. + */ + std::string subUser1 = std::string(128, 'a'); + KvStoreDelegateManager mgr1(APP_ID, USER_ID, subUser1, INSTANCE_ID_1); + auto permissionCheckCallback = [] (const PermissionCheckParamV4 ¶m, uint8_t flag) -> bool { + if (param.deviceId == g_deviceB->GetDeviceId() && (flag && CHECK_FLAG_SPONSOR)) { + LOGD("in RunPermissionCheck callback func, check not pass, flag:%d", flag); + return false; + } else { + LOGD("in RunPermissionCheck callback func, check pass, flag:%d", flag); + return true; + } + }; + EXPECT_EQ(mgr1.SetPermissionCheckCallback(permissionCheckCallback), OK); + + /** + * @tc.steps: step2. deviceB put {1,1} + * @tc.expected: step2. put success + */ + KvStoreNbDelegate *delegatePtr1 = nullptr; + EXPECT_EQ(OpenDelegate("/subUser1", delegatePtr1, mgr1), OK); + ASSERT_NE(delegatePtr1, nullptr); + + DBStatus status = OK; + std::vector devices; + devices.push_back(g_deviceB->GetDeviceId()); + + Key key = {'1'}; + Value value = {'1'}; + g_deviceB->PutData(key, value, 0, 0); + ASSERT_TRUE(status == OK); + + /** + * @tc.steps: step3. deviceB push data + * @tc.expected: step3. return PERMISSION_CHECK_FORBID_SYNC. + */ + std::map result; + status = g_tool.SyncTest(delegatePtr1, devices, SYNC_MODE_PUSH_ONLY, result); + ASSERT_TRUE(status == OK); + std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_TIME)); + + ASSERT_TRUE(result.size() == devices.size()); + for (const auto &pair : result) { + LOGD("dev %s, status %d", pair.first.c_str(), pair.second); + if (g_deviceB->GetDeviceId() == pair.first) { + EXPECT_TRUE(pair.second == PERMISSION_CHECK_FORBID_SYNC); + } else { + EXPECT_TRUE(pair.second == OK); + } + } + + PermissionCheckCallbackV4 nullCallback = nullptr; + EXPECT_EQ(mgr1.SetPermissionCheckCallback(nullCallback), OK); + CloseDelegate(delegatePtr1, mgr1, STORE_ID_1); +} + /** * @tc.name: RDBDelegateInvalidParamTest001 * @tc.desc: Test rdb delegate open with invalid subUser. @@ -609,6 +676,7 @@ HWTEST_F(DistributedDBSingleVerMultiSubUserTest, SubUserDelegateCRUDTest002, Tes CloseDelegate(delegatePtr1, mgr1, STORE_ID_1); } +#ifdef USE_DISTRIBUTEDDB_CLOUD /** * @tc.name: SubUserDelegateCloudSyncTest001 * @tc.desc: Test subUser kv delegate cloud sync function. @@ -685,6 +753,7 @@ HWTEST_F(DistributedDBSingleVerMultiSubUserTest, SubUserDelegateCloudSyncTest002 CloseDelegate(rdbDelegatePtr1, mgr1, db1); CloseDelegate(rdbDelegatePtr2, mgr2, db2); } +#endif /** * @tc.name: MultiSubUserDelegateSync001 diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_multi_user_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_multi_user_test.cpp index c9a8c64814a488d49c3732bd5d2f25fd7cee9875..b76eebe2e7bc65ac2617941843c7c8b7a5646595 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_multi_user_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_multi_user_test.cpp @@ -255,7 +255,7 @@ void TestSyncWithUserChange(bool wait) CipherPassword passwd; bool startSync = false; std::condition_variable cv; - thread subThread([&]() { + thread subThread([&startSync, &cv]() { std::mutex notifyLock; std::unique_lock lck(notifyLock); cv.wait(lck, [&startSync]() { return startSync; }); @@ -906,3 +906,73 @@ HWTEST_F(DistributedDBSingleVerMultiUserTest, MultiUser014, TestSize.Level1) EXPECT_EQ(callCount, 0u); CloseStore(); } + +/** + * @tc.name: MultiUser015 + * @tc.desc: Test auto launch with sub user. + * @tc.type: FUNC + * @tc.require: + * @tc.author: liaoyonghuang + */ +HWTEST_F(DistributedDBSingleVerMultiUserTest, MultiUser015, TestSize.Level0) +{ + /** + * @tc.steps: step1. create sub user KvStoreDelegateManager + * @tc.expected: step1. OK. + */ + std::string subUser = "001"; + KvStoreDelegateManager subUserMgr(APP_ID, USER_ID_1, subUser); + std::string subUserPath = g_testDir + "/" + subUser; + ASSERT_TRUE(OS::MakeDBDirectory(subUserPath) == 0); + KvStoreConfig config; + config.dataDir = subUserPath; + subUserMgr.SetKvStoreConfig(config); + KvStoreNbDelegate::Option option; + /** + * @tc.steps: step2. Enable auto launch of sub user + * @tc.expected: step2. success. + */ + AutoLaunchNotifier notifier = nullptr; + KvStoreObserverUnitTest *observer = new (std::nothrow) KvStoreObserverUnitTest; + EXPECT_TRUE(observer != nullptr); + AutoLaunchOption autoLaunchOption; + CipherPassword passwd; + autoLaunchOption = {true, false, CipherType::DEFAULT, passwd, "", false, subUserPath, observer, + 0, nullptr}; + autoLaunchOption.notifier = nullptr; + autoLaunchOption.observer = observer; + autoLaunchOption.syncDualTupleMode = false; + EXPECT_TRUE(subUserMgr.EnableKvStoreAutoLaunch( + {USER_ID_1, APP_ID, STORE_ID, autoLaunchOption, notifier, "", subUser}) == OK); + DistributedDBToolsUnitTest::Dump(); + /** + * @tc.steps: step3. Device B put data and sync + * @tc.expected: step3. success. + */ + Key key = {'1'}; + Value value = {'1'}; + Timestamp currentTime; + (void)OS::GetCurrentSysTimeInMicrosecond(currentTime); + EXPECT_TRUE(g_deviceB->PutData(key, value, currentTime, 0) == E_OK); + EXPECT_TRUE(g_deviceB->Sync(SYNC_MODE_PUSH_ONLY, true) == E_OK); + /** + * @tc.steps: step4. Open kv store of sub user and check data + * @tc.expected: step4. Check data success. + */ + subUserMgr.GetKvStore(STORE_ID, option, g_kvDelegateCallback1); + ASSERT_TRUE(g_kvDelegateStatus1 == OK); + ASSERT_TRUE(g_kvDelegatePtr1 != nullptr); + Value actualValue; + EXPECT_EQ(g_kvDelegatePtr1->Get(key, actualValue), E_OK); + EXPECT_EQ(actualValue, value); + /** + * @tc.steps: step5. Disable auto launch and close kv store. + * @tc.expected: step5. success. + */ + EXPECT_TRUE(subUserMgr.DisableKvStoreAutoLaunch(USER_ID_1, subUser, APP_ID, STORE_ID) == OK); + ASSERT_EQ(subUserMgr.CloseKvStore(g_kvDelegatePtr1), OK); + g_kvDelegatePtr1 = nullptr; + DBStatus status = subUserMgr.DeleteKvStore(STORE_ID); + ASSERT_TRUE(status == OK); + delete observer; +} diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_query_sync_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_query_sync_test.cpp index 29ee0ceced9b5e9457113f21bcc07eb48060b5de..9d35a56d63c3bd17d1bfee039f09da12907c9b75 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_query_sync_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_query_sync_test.cpp @@ -1142,6 +1142,51 @@ HWTEST_F(DistributedDBSingleVerP2PQuerySyncTest, GetQueryLastTimestamp001, TestS EXPECT_EQ(meta.GetQueryLastTimestamp("D1", "Q2"), static_cast(INT64_MAX)); } +/** + * @tc.name: GetQueryLastTimestamp002 + * @tc.desc: Test Metadata::GetQueryLastTimestamp when timestamp out of INT64 range. + * @tc.type: FUNC + * @tc.author: liuhongyang + */ +HWTEST_F(DistributedDBSingleVerP2PQuerySyncTest, GetQueryLastTimestamp002, TestSize.Level1) +{ + /** + * @tc.steps: step1. initialize storage with fake meta data + * @tc.expected: step1. E_OK + */ + const int64_t validInt64Num1 = 3000000000000000000; // a random valid int64 number + const int64_t validInt64Num2 = 3000000000000000001; // a random valid int64 number + // key is queryId, value is: [stored timestamp in db, expect return value of GetQueryLastTimestamp] + std::map> idValueMap = { + {"regular1", {"3000000000000000000", validInt64Num1}}, + {"max", {"9223372036854775807", INT64_MAX}}, + {"min", {"-9223372036854775808", INT64_MIN}}, + {"overMax", {"9223372036854775808", INT64_MAX}}, + {"underMin", {"-9223372036854775809", INT64_MIN}}, + {"regular2", {"3000000000000000001", validInt64Num2}}}; + Key metaKey; + Value value; + VirtualSingleVerSyncDBInterface storage; + for (auto &pair : idValueMap) { + std::string keyStr = DBConstant::SUBSCRIBE_QUERY_PREFIX + DBCommon::TransferHashString(pair.first); + DBCommon::StringToVector(keyStr, metaKey); + DBCommon::StringToVector(pair.second.first, value); + EXPECT_EQ(storage.PutMetaData(metaKey, value, false), E_OK); + } + /** + * @tc.steps: step2. call GetQueryLastTimestamp with different query id + * @tc.expected: step2. get the correct return value + */ + Metadata meta; + int errCode = meta.Initialize(&storage); + ASSERT_EQ(errCode, E_OK); + for (auto &pair : idValueMap) { + auto &queryId = pair.first; + auto &expectVal = pair.second.second; + EXPECT_EQ(meta.GetQueryLastTimestamp("any", queryId), static_cast(expectVal)); + } +} + /** * @tc.name: MetaDataExceptionBranch001 * @tc.desc: Test execption branch of meata data. diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_simple_sync_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_simple_sync_test.cpp index 24e96e430c3b6fe97a928c9c7d23781491be4ba1..2fb3f81123dfbebcec05ea95474a9fb23230b4d6 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_simple_sync_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_simple_sync_test.cpp @@ -838,6 +838,66 @@ HWTEST_F(DistributedDBSingleVerP2PSimpleSyncTest, NormalSync011, TestSize.Level0 CheckWatermark(checkDev, g_kvDelegatePtr, info, false); } +/** + * @tc.name: Normal Sync 012 + * @tc.desc: Test sync with max data. + * @tc.type: FUNC + * @tc.require: + * @tc.author: wangxiangdong + */ +HWTEST_F(DistributedDBSingleVerP2PSimpleSyncTest, NormalSync012, TestSize.Level0) +{ + /** + * @tc.steps: step1. prepare env + */ + DBStatus status = OK; + std::vector devices; + devices.push_back(g_deviceB->GetDeviceId()); + uint32_t maxValueSize = 64 * 1024 * 1024; + Value maxValue; + DistributedDBToolsUnitTest::GetRandomKeyValue(maxValue, maxValueSize); // 64M + PragmaData input = static_cast(&maxValueSize); + status = g_kvDelegatePtr->Pragma(SET_MAX_VALUE_SIZE, input); + /** + * @tc.steps: step2. deviceA put {k1, v1} + */ + Key key = {'1'}; + status = g_kvDelegatePtr->Put(key, maxValue); + Key key2 = {'2'}; + Value value2 = {'2'}; + status = g_kvDelegatePtr->Put(key2, value2); + ASSERT_TRUE(status == OK); + + /** + * @tc.steps: step3. ori dev will be append test + * @tc.expected: step3. sync should return OK. + */ + RuntimeConfig::SetTranslateToDeviceIdCallback([](const std::string &oriDevId, const StoreInfo &) { + std::string dev = oriDevId + "test"; + LOGI("translate %s to %s", oriDevId.c_str(), dev.c_str()); + return dev; + }); + std::map result; + status = g_tool.SyncTest(g_kvDelegatePtr, devices, SYNC_MODE_PUSH_PULL, result); + ASSERT_TRUE(status == OK); + RuntimeConfig::SetTranslateToDeviceIdCallback(nullptr); + + /** + * @tc.expected: step4. onComplete should be called, deviceB should get same data + */ + ASSERT_TRUE(result.size() == devices.size()); + for (const auto &pair : result) { + LOGD("dev %s, status %d", pair.first.c_str(), pair.second); + EXPECT_TRUE(pair.second == OK); + } + VirtualDataItem item; + g_deviceB->GetData(key, item); + EXPECT_TRUE(item.value == maxValue); + VirtualDataItem item2; + g_deviceB->GetData(key2, item2); + EXPECT_TRUE(item2.value == value2); +} + /** * @tc.name: Limit Data Sync 001 * @tc.desc: Test sync limit key and value data diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_sync_check_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_sync_check_test.cpp index ea7a7c983376b5296abcfc017472e4f4cac769a6..6b44a01c2b8e26207392823e7a0900a4cc56c613 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_sync_check_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_sync_check_test.cpp @@ -1156,7 +1156,16 @@ void SyncWithQuery(vector &devices, const Query &query, const SyncM DBStatus status = g_tool.SyncTest(g_kvDelegatePtr, devices, mode, result, query); EXPECT_TRUE(status == OK); for (const auto &deviceId : devices) { - ASSERT_EQ(result[deviceId], targetStatus); + if (targetStatus == COMM_FAILURE) { + // If syncTaskContext of deviceB is scheduled to be executed first, ClearAllSyncTask is + // invoked when OfflineHandleByDevice is triggered, and SyncOperation::Finished() is triggered in advance. + // The returned status is COMM_FAILURE. + // If syncTaskContext of deviceB is not executed first, the error code is transparently transmitted. + EXPECT_TRUE((result[deviceId] == static_cast(-E_PERIPHERAL_INTERFACE_FAIL)) || + (result[deviceId] == COMM_FAILURE)); + } else { + ASSERT_EQ(result[deviceId], targetStatus); + } } } @@ -2488,4 +2497,52 @@ HWTEST_F(DistributedDBSingleVerP2PSyncCheckTest, KVTimeChange001, TestSize.Level EXPECT_EQ(messageCount, 0); g_communicatorAggregator->RegOnDispatch(nullptr); } + +/** + * @tc.name: KVTimeChange002 + * @tc.desc: test NotifyTimestampChanged will not stuck when notify delegate with no metadata + * @tc.type: FUNC + * @tc.require: + * @tc.author: liuhongyang + */ +HWTEST_F(DistributedDBSingleVerP2PSyncCheckTest, KVTimeChange002, TestSize.Level0) +{ + /** + * @tc.steps: step1. open a new store with STORE_ID_3 + * @tc.expected: step1. open success + */ + KvStoreNbDelegate::Option option; + option.secOption.securityLabel = SecurityLabel::S3; + option.secOption.securityFlag = SecurityFlag::SECE; + KvStoreNbDelegate *delegate2 = nullptr; + g_mgr.GetKvStore(STORE_ID_3, option, [&delegate2](DBStatus status, KvStoreNbDelegate *delegate) { + delegate2 = delegate; + EXPECT_EQ(status, OK); + }); + ASSERT_TRUE(delegate2 != nullptr); + /** + * @tc.steps: step2. STORE_ID_3 sync once so that it will be notified when time change + * @tc.expected: step2. sync should return OK. + */ + std::vector devices; + devices.push_back(g_deviceB->GetDeviceId()); + std::map result; + EXPECT_EQ(g_tool.SyncTest(delegate2, devices, SYNC_MODE_PULL_ONLY, result, true), OK); + /** + * @tc.steps: step3. deviceA call sync and wait + * @tc.expected: step3. sync should return OK. + */ + Sync(devices, OK); + /** + * @tc.steps: step4. call NotifyTimestampChanged + * @tc.expected: step4. expect no deadlock + */ + RuntimeContext::GetInstance()->NotifyTimestampChanged(100); + /** + * @tc.steps: step5. clean up the created db + */ + ASSERT_EQ(g_mgr.CloseKvStore(delegate2), OK); + delegate2 = nullptr; + ASSERT_TRUE(g_mgr.DeleteKvStore(STORE_ID_3) == OK); +} } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_time_sync_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_time_sync_test.cpp index 2a3725ff3498f5e41bb1e9e15c71f085f84ce5b6..306d796a737a6da92822092aeb0017aa3a61cd1a 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_time_sync_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_time_sync_test.cpp @@ -525,4 +525,34 @@ HWTEST_F(DistributedDBTimeSyncTest, SetTimeSyncFinish001, TestSize.Level0) g_timeSyncA->SetTimeSyncFinishIfNeed(); EXPECT_FALSE(g_metadataA->IsTimeSyncFinish(DEVICE_B)); RuntimeContext::GetInstance()->ClearAllDeviceTimeInfo(); +} + +/** + * @tc.name: TimeHelper001 + * @tc.desc: Verify init time helper will not record offset into db. + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBTimeSyncTest, TimeHelper001, TestSize.Level0) +{ + /** + * @tc.steps: step1. Initialize the metadata + * @tc.expected: step1. Initialize successfully + */ + EXPECT_EQ(g_metadataA->Initialize(g_syncInterfaceA), E_OK); + /** + * @tc.steps: step2. Record INT64_MAX as timestamp and init time helper + * @tc.expected: step2. Init without recording offset into db + */ + ASSERT_EQ(g_syncInterfaceA->PutData({'k'}, {'v'}, INT64_MAX, 0), E_OK); + std::string keyStr(DBConstant::LOCALTIME_OFFSET_KEY); + Key key(keyStr.begin(), keyStr.end()); + Value before; + g_syncInterfaceA->GetMetaData(key, before); + TimeHelper timeHelper; + EXPECT_EQ(timeHelper.Initialize(g_syncInterfaceA, g_metadataA), E_OK); + Value after; + g_syncInterfaceA->GetMetaData(key, after); + EXPECT_EQ(after, before); } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_communicator.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_communicator.h index aab37dff664551735ea66bb2c2ab23787a3cd19d..d0340cf87e2d440e04e80d8dc5f2a692ab029c36 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_communicator.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_communicator.h @@ -33,7 +33,7 @@ public: MOCK_METHOD2(RegOnConnectCallback, int(const OnConnectCallback &, const Finalizer &)); MOCK_METHOD2(RegOnSendableCallback, int(const std::function &, const Finalizer &)); MOCK_METHOD2(RegOnMessageCallback, int(const OnMessageCallback &, const Finalizer &)); - MOCK_METHOD0(Activate, void(void)); + MOCK_METHOD1(Activate, void(const std::string &)); MOCK_CONST_METHOD1(IsDeviceOnline, bool(const std::string &)); }; } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/relational_virtual_device.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/relational_virtual_device.cpp index 816795b6c99c9ae00020b23dc9d97758d39599b8..9cdcae6d3b9a478afe839fe0c4c1bfb3e5000717 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/relational_virtual_device.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/relational_virtual_device.cpp @@ -59,5 +59,10 @@ void RelationalVirtualDevice::SetTableInfo(const TableInfo &tableInfo) { static_cast(storage_)->SetTableInfo(tableInfo); } + +void RelationalVirtualDevice::SetDistributedSchema(const DistributedDB::DistributedSchema &schema) +{ + static_cast(storage_)->SetDistributedSchema(schema); +} } // DistributedDB #endif \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/relational_virtual_device.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/relational_virtual_device.h index 9fe74d4975e1a52533f12d3f7654b8d5ec4da1b9..bdc89991ad50cfc5e54d20757e4b47b71e3621e1 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/relational_virtual_device.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/relational_virtual_device.h @@ -35,6 +35,7 @@ public: void SetTableInfo(const TableInfo &tableInfo); int Sync(SyncMode mode, bool wait) override; void EraseSyncData(const std::string &tableName); + void SetDistributedSchema(const DistributedSchema &schema); template void PutDeviceData(const std::string &tableName, const std::vector &data) diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator.cpp index 6386e80cbecfd8adf215ea68dd30bf146bcb7139..9d6df07de1fd1977100c2c61aace5d0e6ff8210d 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator.cpp @@ -41,7 +41,7 @@ int VirtualCommunicator::RegOnSendableCallback(const std::function & return E_OK; } -void VirtualCommunicator::Activate() +void VirtualCommunicator::Activate(const std::string &userId) { } diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator.h index 7da559fd883eae7788eb6bcb0edbaf9f5f0daae7..f904df09802d88e359ae68ddc2ed7aeea6960c3d 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator.h @@ -43,7 +43,7 @@ public: int RegOnConnectCallback(const OnConnectCallback &onConnect, const Finalizer &inOper) override; int RegOnSendableCallback(const std::function &onSendable, const Finalizer &inOper) override; - void Activate() override; + void Activate(const std::string &userId = "") override; uint32_t GetCommunicatorMtuSize() const override; uint32_t GetCommunicatorMtuSize(const std::string &target) const override; diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator_aggregator.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator_aggregator.cpp index 4626a323f5e4242288bc46052675c3478f752224..66f1f92453ade482e262bf4587226fe758174f0e 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator_aggregator.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator_aggregator.cpp @@ -35,7 +35,8 @@ void VirtualCommunicatorAggregator::Finalize() } // If not success, return nullptr and set outErrorNo -ICommunicator *VirtualCommunicatorAggregator::AllocCommunicator(uint64_t commLabel, int &outErrorNo) +ICommunicator *VirtualCommunicatorAggregator::AllocCommunicator(uint64_t commLabel, int &outErrorNo, + const std::string &userId) { if (isEnable_) { return AllocCommunicator(remoteDeviceId_, outErrorNo); @@ -43,9 +44,13 @@ ICommunicator *VirtualCommunicatorAggregator::AllocCommunicator(uint64_t commLab return nullptr; } -ICommunicator *VirtualCommunicatorAggregator::AllocCommunicator(const LabelType &commLabel, int &outErrorNo) +ICommunicator *VirtualCommunicatorAggregator::AllocCommunicator(const LabelType &commLabel, int &outErrorNo, + const std::string &userId) { LOGI("[VirtualCommunicatorAggregator][Alloc] Label=%.6s.", VEC_TO_STR(commLabel)); + if (allocCommunicatorCallback_) { + allocCommunicatorCallback_(userId); + } if (commLabel.size() != COMM_LABEL_LENGTH) { outErrorNo = -E_INVALID_ARGS; return nullptr; @@ -57,8 +62,11 @@ ICommunicator *VirtualCommunicatorAggregator::AllocCommunicator(const LabelType return nullptr; } -void VirtualCommunicatorAggregator::ReleaseCommunicator(ICommunicator *inCommunicator) +void VirtualCommunicatorAggregator::ReleaseCommunicator(ICommunicator *inCommunicator, const std::string &userId) { + if (releaseCommunicatorCallback_) { + releaseCommunicatorCallback_(userId); + } // Called in main thread only VirtualCommunicator *communicator = static_cast(inCommunicator); OfflineDevice(communicator->GetDeviceId()); @@ -375,6 +383,17 @@ void VirtualCommunicatorAggregator::MockGetLocalDeviceRes(int mockRes) getLocalDeviceRet_ = mockRes; } +void VirtualCommunicatorAggregator::SetAllocCommunicatorCallback(AllocCommunicatorCallback allocCommunicatorCallback) +{ + allocCommunicatorCallback_ = allocCommunicatorCallback; +} + +void VirtualCommunicatorAggregator::SetReleaseCommunicatorCallback( + ReleaseCommunicatorCallback releaseCommunicatorCallback) +{ + releaseCommunicatorCallback_ = releaseCommunicatorCallback; +} + void VirtualCommunicatorAggregator::MockCommErrCode(int mockErrCode) { std::lock_guard lock(localDeviceIdMutex_); diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator_aggregator.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator_aggregator.h index 64812feb908e9cf3233e01e74dca0184a095135a..4bd4ed5865e6b31b4610b5fbf2ea4ed66cb888a7 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator_aggregator.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator_aggregator.h @@ -24,7 +24,8 @@ namespace DistributedDB { class ICommunicator; // Forward Declaration - +using AllocCommunicatorCallback = std::function; +using ReleaseCommunicatorCallback = std::function; class VirtualCommunicatorAggregator : public ICommunicatorAggregator { public: // Return 0 as success. Return negative as error @@ -33,10 +34,11 @@ public: void Finalize() override; // If not success, return nullptr and set outErrorNo - ICommunicator *AllocCommunicator(uint64_t commLabel, int &outErrorNo) override; - ICommunicator *AllocCommunicator(const LabelType &commLabel, int &outErrorNo) override; + ICommunicator *AllocCommunicator(uint64_t commLabel, int &outErrorNo, const std::string &userId = "") override; + ICommunicator *AllocCommunicator(const LabelType &commLabel, int &outErrorNo, + const std::string &userId = "") override; - void ReleaseCommunicator(ICommunicator *inCommunicator) override; + void ReleaseCommunicator(ICommunicator *inCommunicator, const std::string &userId = "") override; int RegCommunicatorLackCallback(const CommunicatorLackCallback &onCommLack, const Finalizer &inOper) override; int RegOnConnectCallback(const OnConnectCallback &onConnect, const Finalizer &inOper) override; @@ -93,6 +95,10 @@ public: void MockGetLocalDeviceRes(int mockRes); + void SetAllocCommunicatorCallback(AllocCommunicatorCallback allocCommunicatorCallback); + + void SetReleaseCommunicatorCallback(ReleaseCommunicatorCallback releaseCommunicatorCallback); + void MockCommErrCode(int mockErrCode); void MockDirectEndFlag(bool isDirectEnd); @@ -130,6 +136,9 @@ private: int getLocalDeviceRet_ = E_OK; int commErrCodeMock_ = E_OK; bool isDirectEnd_ = true; + + AllocCommunicatorCallback allocCommunicatorCallback_; + ReleaseCommunicatorCallback releaseCommunicatorCallback_; }; } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_relational_ver_sync_db_interface.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_relational_ver_sync_db_interface.cpp index 8ba5145cb18f8fd7c60fb446a5388abaf73269dd..946c833158a1c465dda533511a4b03b1c2698e24 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_relational_ver_sync_db_interface.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_relational_ver_sync_db_interface.cpp @@ -336,8 +336,10 @@ int VirtualRelationalVerSyncDBInterface::ExecuteQuery(const PreparedStmt &prepSt } int VirtualRelationalVerSyncDBInterface::SaveRemoteDeviceSchema(const std::string &deviceId, - const std::string &remoteSchema, uint8_t type) + const std::string &remoteSchema, [[gnu::unused]] uint8_t type) { + std::lock_guard autoLock(remoteSchemaMutex_); + remoteSchema_[deviceId] = remoteSchema; return E_OK; } @@ -347,9 +349,18 @@ int VirtualRelationalVerSyncDBInterface::GetSchemaFromDB(RelationalSchemaObject } int VirtualRelationalVerSyncDBInterface::GetRemoteDeviceSchema(const std::string &deviceId, - RelationalSchemaObject &schemaObj) + RelationalSchemaObject &schemaObj) const { - return E_OK; + if (schemaObj.IsSchemaValid()) { + LOGE("schema is already valid"); + return -E_INVALID_ARGS; + } + std::lock_guard autoLock(remoteSchemaMutex_); + auto schema = remoteSchema_.find(deviceId); + if (schema == remoteSchema_.end()) { + return -E_NOT_FOUND; + } + return schemaObj.ParseFromSchemaString(schema->second); } void VirtualRelationalVerSyncDBInterface::SetPermitCreateDistributedTable(bool permitCreateDistributedTable) @@ -385,5 +396,11 @@ void VirtualRelationalVerSyncDBInterface::ReleaseRemoteQueryContinueToken(Contin remoteToken = nullptr; token = nullptr; } + +void VirtualRelationalVerSyncDBInterface::SetDistributedSchema(const DistributedDB::DistributedSchema &schema) +{ + schemaObj_.SetTableMode(DistributedTableMode::COLLABORATION); + schemaObj_.SetDistributedSchema(schema); +} } #endif diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_relational_ver_sync_db_interface.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_relational_ver_sync_db_interface.h index 3bf32632d6bd5e0970006824601ca5a44e6416e9..db6ae341e4c2b35845a09c51318e53a9504e5d64 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_relational_ver_sync_db_interface.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_relational_ver_sync_db_interface.h @@ -113,7 +113,7 @@ public: int SaveRemoteDeviceSchema(const std::string &deviceId, const std::string &remoteSchema, uint8_t type) override; - int GetRemoteDeviceSchema(const std::string &deviceId, RelationalSchemaObject &schemaObj) override; + int GetRemoteDeviceSchema(const std::string &deviceId, RelationalSchemaObject &schemaObj) const override; int GetSchemaFromDB(RelationalSchemaObject &schema) override; @@ -122,6 +122,8 @@ public: int GetSecurityOption(SecurityOption &option) const override; void ReleaseRemoteQueryContinueToken(ContinueToken &token) const override; + + void SetDistributedSchema(const DistributedSchema &schema); private: mutable std::map, std::vector> metadata_; std::map, CaseInsensitiveComparator> syncData_; @@ -134,6 +136,8 @@ private: SecurityOption secOption_; bool permitCreateDistributedTable_ = true; uint64_t dbCreateTime_; + mutable std::mutex remoteSchemaMutex_; + std::map remoteSchema_; }; } #endif diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_time_sync_communicator.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_time_sync_communicator.cpp index 4049dbac4f77d25dc7ddb42f0c74acd7324d589a..6890e94b4d16fb4d9a1994c6aecc99ad02af73c8 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_time_sync_communicator.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_time_sync_communicator.cpp @@ -46,7 +46,7 @@ int VirtualTimeSyncCommunicator::RegOnSendableCallback(const std::function &onSendable, const Finalizer &inOper) override; - void Activate() override; + void Activate(const std::string &userId = "") override; // return maximum allowed data size uint32_t GetCommunicatorMtuSize() const override; diff --git a/kv_store/interfaces/innerkits/distributeddata/BUILD.gn b/kv_store/interfaces/innerkits/distributeddata/BUILD.gn index 96917de5c10369b9adeeb833790ce3f86da746c6..e12f42c62d8625f037e8ad57240b40cd846f5490 100644 --- a/kv_store/interfaces/innerkits/distributeddata/BUILD.gn +++ b/kv_store/interfaces/innerkits/distributeddata/BUILD.gn @@ -175,3 +175,42 @@ ohos_shared_library("distributeddata_client_sync") { subsystem_name = "distributeddatamgr" part_name = "kv_store" } + +config("kvdb_inner_lite_config") { + visibility = [ ":*" ] + + include_dirs = [ + "${kv_store_base_path}/frameworks/innerkitsimpl/kvdb/include", + "${kv_store_base_path}/frameworks/innerkitsimpl/distributeddatafwk/include", + "${kv_store_base_path}/frameworks/common", + "${kv_store_base_path}/interfaces/innerkits/distributeddata/include", + ] +} + +ohos_static_library("kvdb_inner_lite") { + branch_protector_ret = "pac_ret" + sanitize = { + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + + sources = [ + "${kv_store_base_path}/frameworks/innerkitsimpl/distributeddatafwk/src/blob.cpp", + "${kv_store_base_path}/frameworks/innerkitsimpl/distributeddatafwk/src/change_notification.cpp", + "${kv_store_base_path}/frameworks/innerkitsimpl/kvdb/src/kv_types_util.cpp", + ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_single", + ] + + public_configs = [ ":kvdb_inner_lite_config" ] + + subsystem_name = "distributeddatamgr" + part_name = "kv_store" +} diff --git a/kv_store/interfaces/innerkits/distributeddata/include/pool.h b/kv_store/interfaces/innerkits/distributeddata/include/pool.h index acb9f65c411d09ba70bab8ee834a3e6329af283c..063158bf8b4c38a2824ebc6893e4ac9f9d9a9d97 100644 --- a/kv_store/interfaces/innerkits/distributeddata/include/pool.h +++ b/kv_store/interfaces/innerkits/distributeddata/include/pool.h @@ -16,6 +16,7 @@ #ifndef OHOS_DISTRIBUTED_DATA_KV_STORE_FRAMEWORKS_COMMON_POOL_H #define OHOS_DISTRIBUTED_DATA_KV_STORE_FRAMEWORKS_COMMON_POOL_H #include +#include #include namespace OHOS { template diff --git a/kv_store/interfaces/innerkits/distributeddata/include/store_errno.h b/kv_store/interfaces/innerkits/distributeddata/include/store_errno.h index 5fa5c94b2b0ac515f2f3cb5490cf98a9ca03f86a..45cfe48e641e2f59f89696432a1c2f780adaf503 100644 --- a/kv_store/interfaces/innerkits/distributeddata/include/store_errno.h +++ b/kv_store/interfaces/innerkits/distributeddata/include/store_errno.h @@ -204,7 +204,7 @@ enum Status : int32_t { * Cloud disabled. */ CLOUD_DISABLED = DISTRIBUTEDDATAMGR_ERR_OFFSET + 41, - + /** * database can not open. */ diff --git a/kv_store/interfaces/innerkits/distributeddata/include/types.h b/kv_store/interfaces/innerkits/distributeddata/include/types.h index dda871da414a329bf5e4e1bba9bd195a68035bd6..0c6e322fd5408be49129228e31b66986ae3a0a88 100644 --- a/kv_store/interfaces/innerkits/distributeddata/include/types.h +++ b/kv_store/interfaces/innerkits/distributeddata/include/types.h @@ -571,6 +571,10 @@ struct Options { * Application sdk version. */ int32_t apiVersion = 9; + /** + * Sub user config for system ability. + */ + int32_t subUser = 0; }; /** diff --git a/kv_store/kv_store.gni b/kv_store/kv_store.gni index 53071fb36425a284991ce7ec02aab420c7ed1b08..8f687980edcafd6a1828b1f7bb54afc9519ada21 100644 --- a/kv_store/kv_store.gni +++ b/kv_store/kv_store.gni @@ -31,7 +31,7 @@ declare_args() { dms_service_enable = false } - if (product_name != "qemu-arm-linux-min") { + if (device_company != "qemu") { qemu_disable = true } else { qemu_disable = false diff --git a/kv_store/kvstoremock/distributeddb/BUILD.gn b/kv_store/kvstoremock/distributeddb/BUILD.gn index ef7e998521fb413c02015fc2f499f1bf99e2352c..98c04b5957d518ead634f52f79baaf7e4a6f536b 100644 --- a/kv_store/kvstoremock/distributeddb/BUILD.gn +++ b/kv_store/kvstoremock/distributeddb/BUILD.gn @@ -88,6 +88,7 @@ group("build_module") { } } distrdb_sources = distributeddb_src +distrdb_sources += distributeddb_cloud_src config("distrdb_config") { visibility = [ ":*" ] diff --git a/kv_store/kvstoremock/frameworks/cj/distributed_kv_store_mock.cpp b/kv_store/kvstoremock/frameworks/cj/distributed_kv_store_mock.cpp index bee9e10ef331e0611de7892a2a6d73ea2fa21686..72317874b2b30ce625e378dcede458e9e9df44f4 100644 --- a/kv_store/kvstoremock/frameworks/cj/distributed_kv_store_mock.cpp +++ b/kv_store/kvstoremock/frameworks/cj/distributed_kv_store_mock.cpp @@ -33,7 +33,7 @@ extern "C" { FFI_EXPORT int FfiOHOSDistributedKVStoreSingleKVStoreDelete = 0; FFI_EXPORT int FfiOHOSDistributedKVStoreSingleKVStoreDeleteBatch = 0; - + FFI_EXPORT int FfiOHOSDistributedKVStoreSingleKVStoreGet = 0; FFI_EXPORT int FfiOHOSDistributedKVStoreSingleKVStoreBackup = 0; diff --git a/kv_store/kvstoremock/frameworks/innerkitsimpl/distributeddatafwk/src/distributed_kv_data_manager.cpp b/kv_store/kvstoremock/frameworks/innerkitsimpl/distributeddatafwk/src/distributed_kv_data_manager.cpp index f594ed27da59072c5d6289f496589b35c7d15654..ff529a0dc5b9fde9676c3a1383b4f6d773755766 100644 --- a/kv_store/kvstoremock/frameworks/innerkitsimpl/distributeddatafwk/src/distributed_kv_data_manager.cpp +++ b/kv_store/kvstoremock/frameworks/innerkitsimpl/distributeddatafwk/src/distributed_kv_data_manager.cpp @@ -63,7 +63,7 @@ Status DistributedKvDataManager::CloseKvStore(const AppId &appId, const StoreId Status DistributedKvDataManager::CloseKvStore(const AppId &appId, std::shared_ptr &kvStorePtr) { if (kvStorePtr == nullptr) { - ZLOGE("kvStorePtr is nullptr."); + ZLOGE("This kvStorePtr is nullptr."); return Status::INVALID_ARGUMENT; } StoreId storeId = kvStorePtr->GetStoreId(); @@ -116,7 +116,7 @@ Status DistributedKvDataManager::DeleteAllKvStore(const AppId &appId, const std: void DistributedKvDataManager::RegisterKvStoreServiceDeathRecipient( std::shared_ptr kvStoreDeathRecipient) { - ZLOGD("begin"); + ZLOGD("Begin"); if (kvStoreDeathRecipient == nullptr) { ZLOGW("Register KvStoreService Death Recipient input is null."); return; @@ -126,7 +126,7 @@ void DistributedKvDataManager::RegisterKvStoreServiceDeathRecipient( void DistributedKvDataManager::UnRegisterKvStoreServiceDeathRecipient( std::shared_ptr kvStoreDeathRecipient) { - ZLOGD("begin"); + ZLOGD("Begin"); if (kvStoreDeathRecipient == nullptr) { ZLOGW("UnRegister KvStoreService Death Recipient input is null."); return; diff --git a/kv_store/kvstoremock/frameworks/innerkitsimpl/distributeddatafwk/src/kv_utils.cpp b/kv_store/kvstoremock/frameworks/innerkitsimpl/distributeddatafwk/src/kv_utils.cpp index 0b3269c2b7bd9b52801454ceda7ce81bf1dddb39..c8e68d8febf21ee5a830818acb51a4866c869d96 100644 --- a/kv_store/kvstoremock/frameworks/innerkitsimpl/distributeddatafwk/src/kv_utils.cpp +++ b/kv_store/kvstoremock/frameworks/innerkitsimpl/distributeddatafwk/src/kv_utils.cpp @@ -31,7 +31,7 @@ constexpr KvUtils::QueryHandler KvUtils::HANDLERS[LAST_TYPE]; std::shared_ptr KvUtils::ToResultSetBridge(std::shared_ptr resultSet) { if (resultSet == nullptr) { - ZLOGE("param error, kvResultSet nullptr"); + ZLOGE("Param error, kvResultSet nullptr"); return nullptr; } return nullptr; @@ -42,7 +42,7 @@ Status KvUtils::ToQuery(const DataShareAbsPredicates &predicates, DataQuery &que const auto &operations = predicates.GetOperationList(); for (const auto &oper : operations) { if (oper.operation < 0 || oper.operation >= LAST_TYPE) { - ZLOGE("operation param error"); + ZLOGE("The operation param error"); return Status::NOT_SUPPORT; } (*HANDLERS[oper.operation])(oper, query); @@ -64,7 +64,7 @@ Entry KvUtils::ToEntry(const DataShareValuesBucket &valueBucket) { const auto &values = valueBucket.valuesMap; if (values.empty()) { - ZLOGE("valuesMap is null"); + ZLOGE("This valuesMap is null"); return {}; } Entry entry; @@ -85,14 +85,14 @@ Status KvUtils::GetKeys(const DataShareAbsPredicates &predicates, std::vector myKeys; for (const auto &oper : operations) { if (oper.operation != IN_KEY) { - ZLOGE("find operation failed"); + ZLOGE("This find operation failed"); return Status::NOT_SUPPORT; } auto *val = std::get_if>(&oper.multiParams[0]); @@ -111,7 +111,7 @@ Status KvUtils::ToEntryKey(const std::map(&it->second)) { @@ -129,7 +129,7 @@ Status KvUtils::ToEntryValue(const std::map &files, const std::string &baseDir, std::map &status) override; - // IPC interface + // IPC interface Status Sync(const std::vector &devices, SyncMode mode, uint32_t delay) override; Status Sync(const std::vector &devices, SyncMode mode, const DataQuery &query, std::shared_ptr syncCallback, uint32_t delay) override; diff --git a/kv_store/kvstoremock/frameworks/innerkitsimpl/kvdb/src/dev_manager.cpp b/kv_store/kvstoremock/frameworks/innerkitsimpl/kvdb/src/dev_manager.cpp index 6507be8f52858f3a9d37c60131fdd4ddbe3e4ed1..bf755b4561a80e9caa6cb4a549091cd0dcd770f9 100644 --- a/kv_store/kvstoremock/frameworks/innerkitsimpl/kvdb/src/dev_manager.cpp +++ b/kv_store/kvstoremock/frameworks/innerkitsimpl/kvdb/src/dev_manager.cpp @@ -37,7 +37,7 @@ void DevManager::RegisterDevCallback() { int32_t errNo = Init(); if (errNo != DM_OK) { - ZLOGE("register device failed, try again"); + ZLOGE("Register device failed, try again"); } } diff --git a/kv_store/kvstoremock/frameworks/innerkitsimpl/kvdb/src/single_store_impl.cpp b/kv_store/kvstoremock/frameworks/innerkitsimpl/kvdb/src/single_store_impl.cpp index 0aca6b7fe6bc193b74c217b3bf9bb9bd0b7b0a14..755aba0e52e1047665b9d963c055f2368d37e324 100644 --- a/kv_store/kvstoremock/frameworks/innerkitsimpl/kvdb/src/single_store_impl.cpp +++ b/kv_store/kvstoremock/frameworks/innerkitsimpl/kvdb/src/single_store_impl.cpp @@ -42,7 +42,7 @@ Status SingleStoreImpl::Put(const Key &key, const Value &value) DBKey dbKey = convertor_.ToLocalDBKey(key); if (dbKey.empty() || value.Size() > MAX_VALUE_LENGTH) { - ZLOGE("invalid key:%{public}s size:[k:%{public}zu v:%{public}zu]", + ZLOGE("Invalid key:%{public}s size:[k:%{public}zu v:%{public}zu]", StoreUtil::Anonymous(key.ToString()).c_str(), key.Size(), value.Size()); return INVALID_ARGUMENT; } @@ -69,7 +69,7 @@ Status SingleStoreImpl::PutBatch(const std::vector &entries) DBEntry dbEntry; dbEntry.key = convertor_.ToLocalDBKey(entry.key); if (dbEntry.key.empty() || entry.value.Size() > MAX_VALUE_LENGTH) { - ZLOGE("invalid key:%{public}s size:[k:%{public}zu v:%{public}zu]", + ZLOGE("Invalid key:%{public}s size:[k:%{public}zu v:%{public}zu]", StoreUtil::Anonymous(entry.key.ToString()).c_str(), entry.key.Size(), entry.value.Size()); return INVALID_ARGUMENT; } @@ -94,7 +94,7 @@ Status SingleStoreImpl::Delete(const Key &key) DBKey dbKey = convertor_.ToLocalDBKey(key); if (dbKey.empty()) { - ZLOGE("invalid key:%{public}s size:%{public}zu", StoreUtil::Anonymous(key.ToString()).c_str(), key.Size()); + ZLOGE("Invalid key:%{public}s size:%{public}zu", StoreUtil::Anonymous(key.ToString()).c_str(), key.Size()); return INVALID_ARGUMENT; } @@ -118,7 +118,7 @@ Status SingleStoreImpl::DeleteBatch(const std::vector &keys) for (const auto &key : keys) { DBKey dbKey = convertor_.ToLocalDBKey(key); if (dbKey.empty()) { - ZLOGE("invalid key:%{public}s size:%{public}zu", StoreUtil::Anonymous(key.ToString()).c_str(), key.Size()); + ZLOGE("Invalid key:%{public}s size:%{public}zu", StoreUtil::Anonymous(key.ToString()).c_str(), key.Size()); return INVALID_ARGUMENT; } dbKeys.push_back(std::move(dbKey)); @@ -200,7 +200,7 @@ Status SingleStoreImpl::Get(const Key &key, Value &value) DBKey dbKey = convertor_.ToWholeDBKey(key); if (dbKey.empty()) { - ZLOGE("invalid key:%{public}s size:%{public}zu", StoreUtil::Anonymous(key.ToString()).c_str(), key.Size()); + ZLOGE("Invalid key:%{public}s size:%{public}zu", StoreUtil::Anonymous(key.ToString()).c_str(), key.Size()); return INVALID_ARGUMENT; } @@ -234,7 +234,7 @@ Status SingleStoreImpl::GetEntries(const Key &prefix, std::vector &entrie { DBKey dbPrefix = convertor_.GetPrefix(prefix); if (dbPrefix.empty() && !prefix.Empty()) { - ZLOGE("invalid prefix:%{public}s size:%{public}zu", StoreUtil::Anonymous(prefix.ToString()).c_str(), + ZLOGE("Invalid prefix:%{public}s size:%{public}zu", StoreUtil::Anonymous(prefix.ToString()).c_str(), prefix.Size()); return INVALID_ARGUMENT; } @@ -262,7 +262,7 @@ Status SingleStoreImpl::GetResultSet(const Key &prefix, std::shared_ptr &resultSet) { if (resultSet == nullptr) { - ZLOGE("input is nullptr"); + ZLOGE("Input is nullptr"); return INVALID_ARGUMENT; } diff --git a/kv_store/kvstoremock/frameworks/innerkitsimpl/kvdb/src/store_factory.cpp b/kv_store/kvstoremock/frameworks/innerkitsimpl/kvdb/src/store_factory.cpp index 306e32a0e3a8fc50d066384a0e04a6956a6d00d2..ef5cdd969d44e3bee23f0ea770dea4a84836b911 100644 --- a/kv_store/kvstoremock/frameworks/innerkitsimpl/kvdb/src/store_factory.cpp +++ b/kv_store/kvstoremock/frameworks/innerkitsimpl/kvdb/src/store_factory.cpp @@ -64,7 +64,7 @@ std::shared_ptr StoreFactory::GetOrOpenStore(const AppId &appId, }); status = StoreUtil::ConvertStatus(dbStatus); if (kvStore == nullptr) { - ZLOGE("failed! status:%{public}d appId:%{public}s storeId:%{public}s path:%{public}s", dbStatus, + ZLOGE("Failed! status:%{public}d appId:%{public}s storeId:%{public}s path:%{public}s", dbStatus, appId.appId.c_str(), StoreUtil::Anonymous(storeId.storeId).c_str(), options.baseDir.c_str()); return !stores.empty(); } diff --git a/kv_store/kvstoremock/frameworks/innerkitsimpl/kvdb/src/store_util.cpp b/kv_store/kvstoremock/frameworks/innerkitsimpl/kvdb/src/store_util.cpp index e774099f1479c8a0fd46b43413e3db6816077bf4..f08d93cfa3adee161ae57c50ac5ce51b4e42cc5d 100644 --- a/kv_store/kvstoremock/frameworks/innerkitsimpl/kvdb/src/store_util.cpp +++ b/kv_store/kvstoremock/frameworks/innerkitsimpl/kvdb/src/store_util.cpp @@ -187,7 +187,7 @@ bool StoreUtil::CreateFile(const std::string &name) umask(DEFAULT_UMASK); int fp = open(name.c_str(), (O_WRONLY | O_CREAT)); if (fp < 0) { - ZLOGE("fopen error:%{public}d, path:%{public}s", errno, name.c_str()); + ZLOGE("The fopen error:%{public}d, path:%{public}s", errno, name.c_str()); return false; } close(fp); @@ -199,7 +199,7 @@ std::vector StoreUtil::GetSubPath(const std::string &path) std::vector subPaths; DIR *dirp = opendir(path.c_str()); if (dirp == nullptr) { - ZLOGE("opendir error:%{public}d, path:%{public}s", errno, path.c_str()); + ZLOGE("The opendir error:%{public}d, path:%{public}s", errno, path.c_str()); return subPaths; } struct dirent *dp; @@ -215,7 +215,7 @@ std::vector StoreUtil::GetFiles(const std::string &path) std::vector fileInfos; DIR *dirp = opendir(path.c_str()); if (dirp == nullptr) { - ZLOGE("opendir error:%{public}d, path:%{public}s", errno, path.c_str()); + ZLOGE("The opendir error:%{public}d, path:%{public}s", errno, path.c_str()); return fileInfos; } struct dirent *dp; @@ -241,7 +241,7 @@ bool StoreUtil::Rename(const std::string &oldName, const std::string &newName) return false; } if (rename(oldName.c_str(), newName.c_str()) != 0) { - ZLOGE("rename error:%{public}d, file:%{public}s->%{public}s", errno, oldName.c_str(), newName.c_str()); + ZLOGE("The rename error:%{public}d, file:%{public}s->%{public}s", errno, oldName.c_str(), newName.c_str()); return false; } return true; @@ -264,7 +264,7 @@ bool StoreUtil::Remove(const std::string &path) return true; } if (remove(path.c_str()) != 0) { - ZLOGE("remove error:%{public}d, path:%{public}s", errno, path.c_str()); + ZLOGE("The remove error:%{public}d, path:%{public}s", errno, path.c_str()); return false; } return true; diff --git a/kv_store/kvstoremock/frameworks/jskitsimpl/distributedkvstore/src/js_util_mock.cpp b/kv_store/kvstoremock/frameworks/jskitsimpl/distributedkvstore/src/js_util_mock.cpp index 0999f1ac55470f34a7a3c516bfa7a520ff57b8ef..b755e287cef99cc5fc650269da76ddb4996ec96c 100644 --- a/kv_store/kvstoremock/frameworks/jskitsimpl/distributedkvstore/src/js_util_mock.cpp +++ b/kv_store/kvstoremock/frameworks/jskitsimpl/distributedkvstore/src/js_util_mock.cpp @@ -42,27 +42,27 @@ constexpr int32_t API_VERSION = 9; class AbilityMock { public: - + AbilityMock() = default; ~AbilityMock() = default; - + struct ModuleInfo { std::string moduleName = "com.example.myapplication"; }; - + struct ApplicationInfo { bool isSystemApp = true; int32_t apiTargetVersion = API_VERSION; }; - + class ContextMock { public: int GetArea() { return OHOS::DistributedKv::Area::EL1; }; - + std::string GetDatabaseDir() { #ifdef _WIN32 @@ -75,7 +75,7 @@ public: mkdir(baseDir.c_str(), MODE); return baseDir; } - + std::shared_ptr GetHapModuleInfo() { return std::make_shared(); diff --git a/kv_store/test/fuzztest/distributedkvdataservice_fuzzer/BUILD.gn b/kv_store/test/fuzztest/distributedkvdataservice_fuzzer/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..d494dd5e662e0273ba5839fed710bcec72193e82 --- /dev/null +++ b/kv_store/test/fuzztest/distributedkvdataservice_fuzzer/BUILD.gn @@ -0,0 +1,57 @@ +# Copyright (c) 2024 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. + +#####################hydra-fuzz################### +import("//build/config/features.gni") +import("//build/test.gni") + +##############################fuzztest########################################## +ohos_fuzztest("DistributedKvDataServiceFuzzTest") { + module_out_path = "kv_store/kv_store" + + include_dirs = [ + "../../../frameworks/common", + "../../../frameworks/innerkitsimpl/distributeddatafwk/include", + "../../../frameworks/innerkitsimpl/distributeddatafwk/src", + "../../../interfaces/innerkits/distributeddata/include", + ] + + fuzz_config_file = "../../../test/fuzztest/distributedkvdataservice_fuzzer" + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + sources = [ "distributedkvdataservice_fuzzer.cpp" ] + + deps = [] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "kv_store:distributeddata_inner", + ] +} + +############################################################################### +group("fuzztest") { + testonly = true + deps = [] + deps += [ + # deps file + ":DistributedKvDataServiceFuzzTest", + ] +} +############################################################################### diff --git a/kv_store/test/fuzztest/distributedkvdataservice_fuzzer/corpus/init b/kv_store/test/fuzztest/distributedkvdataservice_fuzzer/corpus/init new file mode 100644 index 0000000000000000000000000000000000000000..6198079a28e860189d4294f6598f8ac6804c0dff --- /dev/null +++ b/kv_store/test/fuzztest/distributedkvdataservice_fuzzer/corpus/init @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 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. + */ + +FUZZ \ No newline at end of file diff --git a/kv_store/test/fuzztest/distributedkvdataservice_fuzzer/distributedkvdataservice_fuzzer.cpp b/kv_store/test/fuzztest/distributedkvdataservice_fuzzer/distributedkvdataservice_fuzzer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..60ae617fffd2b4b0ff020819fbe9d8814f93daf6 --- /dev/null +++ b/kv_store/test/fuzztest/distributedkvdataservice_fuzzer/distributedkvdataservice_fuzzer.cpp @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2021 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 "distributedkvdataservice_fuzzer.h" + +#include "distributed_kv_data_manager.h" +#include "kvstore_death_recipient.h" +#include "kvstore_observer.h" +#include "types.h" +#include +#include + +using namespace OHOS; +using namespace OHOS::DistributedKv; + +class DistributedKvDataServiceFuzzer { + /* Keep C++ file names the same as the class name */ +}; + +namespace OHOS { + +static std::shared_ptr singleKvStore = nullptr; +static distributedkvdataservice service; +static AppId appIdTest; +static StoreId storeIdTest; +static Options createTest; +static Options noCreate; +static UserId userId; + +class MyDeathRecipient : public KvStoreDeathRecipient { +public: + MyDeathRecipient() { } + virtual ~MyDeathRecipient() { } + void OnRemoteDied() override { } +}; + +class SwitchDataObserver : public KvStoreObserver { +public: + void OnSwitchChange(const SwitchNotification ¬ification) override + { + blockData_.SetValue(notification); + } + + SwitchNotification Get() + { + return blockData_.GetValue(); + } + +private: + BlockData blockData_ { 1, SwitchNotification() }; +}; + +void SetUpTestCase(void) +{ + userId.userId = "account"; + appIdTest.appId = "distributedkvdataservicefuzzertest"; + createTest.createIfMissing = true; + createTest.encrypt = false; + createTest.autoSync = true; + createTest.kvStoreType = SINGLE_VERSION; + createTest.area = EL1; + createTest.baseDir = std::string("/data/service/el1/public/database/") + appIdTest.appId; + mkdir(createTest.baseDir.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); + + service.CloseAllKvStore(appIdTest); + service.DeleteAllKvStore(appIdTest, createTest.baseDir); +} + +void TearDown(void) +{ + service.CloseAllKvStore(appIdTest); + service.DeleteAllKvStore(appIdTest, createTest.baseDir); + (void)remove("/data/service/el1/public/database/distributedkvdataservicefuzzertest/key"); + (void)remove("/data/service/el1/public/database/distributedkvdataservicefuzzertest/kvdb"); + (void)remove("/data/service/el1/public/database/distributedkvdataservicefuzzertest"); +} + +void GetKvStoreFuzzTest(const uint8_t *data, size_t size) +{ + StoreId storeId; + storeId.storeId = std::string(data, data + size); + std::shared_ptr notExistKvStore; + service.GetSingleKvStore(createTest, appIdTest, storeId, notExistKvStore); + std::shared_ptr existKvStore; + service.GetSingleKvStore(noCreate, appIdTest, storeId, existKvStore); + service.CloseKvStore(appIdTest, storeId); + service.DeleteKvStore(appIdTest, storeId); +} + +void GetAllKvStoreFuzzTest(const uint8_t *data, size_t size) +{ + std::vector storeIds; + service.GetAllKvStoreId(appIdTest, storeIds); + + std::shared_ptr KvStore; + std::string storeIdBase(data, data + size); + int sum = 10; + + for (int i = 0; i < sum; i++) { + StoreId storeId; + storeId.storeId = storeIdBase + "_" + std::to_string(i); + service.GetSingleKvStore(createTest, appIdTest, storeId, KvStore); + } + service.GetAllKvStoreId(appIdTest, storeIds); + service.CloseAllKvStore(appIdTest); + + service.GetAllKvStoreId(appIdTest, storeIds); +} + +void CloseKvStoreFuzzTest(const uint8_t *data, size_t size) +{ + StoreId storeId; + storeId.storeId = std::string(data, data + size); + service.CloseKvStore(appIdTest, storeId); + std::shared_ptr kvStoreImpl; + service.GetSingleKvStore(createTest, appIdTest, storeId, kvStoreImpl); + service.CloseKvStore(appIdTest, storeId); + service.CloseKvStore(appIdTest, storeId); +} + +void DeleteKvStoreFuzzTest(const uint8_t *data, size_t size) +{ + StoreId storeId; + storeId.storeId = std::string(data, data + size); + service.DeleteKvStore(appIdTest, storeId, createTest.baseDir); + + std::shared_ptr kvStoreImpl; + service.GetSingleKvStore(createTest, appIdTest, storeId, kvStoreImpl); + service.CloseKvStore(appIdTest, storeId); + service.DeleteKvStore(appIdTest, storeId, createTest.baseDir); + + service.CloseKvStore(appIdTest, storeId); +} + +void DeleteAllKvStoreFuzz1Test(const uint8_t *data, size_t size) +{ + std::vector storeIds; + service.GetAllKvStoreId(appIdTest, storeIds); + + service.DeleteAllKvStore(appIdTest, createTest.baseDir); + std::shared_ptr KvStore; + std::string storeIdBase(data, data + size); + + int sum = 10; + for (int i = 0; i < sum; i++) { + StoreId storeId; + storeId.storeId = storeIdBase + "_" + std::to_string(i); + service.GetSingleKvStore(createTest, appIdTest, storeId, KvStore); + + service.CloseKvStore(appIdTest, storeId); + } + service.DeleteAllKvStore(appIdTest, createTest.baseDir); +} + +void DeleteAllKvStoreFuzz2Test(const uint8_t *data, size_t size) +{ + std::vector storeIds; + service.GetAllKvStoreId(appIdTest, storeIds); + + std::shared_ptr KvStore; + std::string storeIdBase(data, data + size); + service.GetSingleKvStore(create, appIdTest, storeIdTest, KvStore); + service.CloseKvStore(appIdTest, storeIdTest); + int sum = 10; + + for (int i = 0; i < sum; i++) { + StoreId storeId; + storeId.storeId = storeIdBase + "_" + std::to_string(i); + service.GetSingleKvStore(create, appIdTest, storeId, KvStore); + } + service.DeleteAllKvStore(appIdTest, createTest.baseDir); +} + +void DeleteAllKvStoreFuzz3Test(const uint8_t *data, size_t size) +{ + std::vector storeIds; + service.GetAllKvStoreId(appIdTest, storeIds); + + std::shared_ptr KvStore; + std::string storeIdBase(data, data + size); + int sum = 10; + for (int i = 0; i < sum; i++) { + StoreId storeId; + storeId.storeId = storeIdBase + "_" + std::to_string(i); + service.GetSingleKvStore(create, appIdTest, storeId, KvStore); + } + service.DeleteAllKvStore(appIdTest, createTest.baseDir); +} + +void RegisterKvStoreServiceDeathRecipientFuzzTest() +{ + std::shared_ptr kvStoreDeathRecipientImpl = std::make_shared(); + service.RegisterKvStoreServiceDeathRecipient(kvStoreDeathRecipientImpl); + kvStoreDeathRecipientImpl->OnRemoteDied(); +} + +void UnRegisterKvStoreServiceDeathRecipientFuzzTest() +{ + std::shared_ptr kvStoreDeathRecipientImpl = std::make_shared(); + + service.UnRegisterKvStoreServiceDeathRecipient(kvStoreDeathRecipientImpl); + kvStoreDeathRecipientImpl->OnRemoteDied(); +} + +void PutSwitchFuzzTest(const uint8_t *data, size_t size) +{ + std::string appIds(data, data + size); + uint32_t input = static_cast(size); + SwitchData switchData11; + switchData11.value = input; + switchData11.length = input & 0xFFFF; + + service.PutSwitch({ appIds }, switchData11); + service.PutSwitch({ "distributed_device_profile_service" }, switchData11); +} + +void GetSwitchFuzzTest(const uint8_t *data, size_t size) +{ + std::string appIds(data, data + size); + std::string networkId(data, data + size); + + service.GetSwitch({ appIds }, networkId); + service.GetSwitch({ "distributed_device_profile_service" }, networkId); +} + +void SubscribeSwitchDataFuzzTest(const uint8_t *data, size_t size) +{ + std::string appIds(data, data + size); + std::shared_ptr dataObserver = std::make_shared(); + + service.SubscribeSwitchData({ appIds }, dataObserver); +} + +void UnsubscribeSwitchDataFuzzTest(const uint8_t *data, size_t size) +{ + std::string appIds(data, data + size); + std::shared_ptr dataObserver = std::make_shared(); + + service.SubscribeSwitchData({ appIds }, dataObserver); + service.UnsubscribeSwitchData({ appIds }, dataObserver); +} +} // namespace OHOS + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + /* Run your code on data */ + OHOS::SetUpTestCase(); + OHOS::GetKvStoreFuzzTest(data, size); + OHOS::GetAllKvStoreFuzzTest(data, size); + OHOS::CloseKvStoreFuzzTest(data, size); + OHOS::DeleteKvStoreFuzzTest(data, size); + OHOS::DeleteAllKvStoreFuzz1Test(data, size); + OHOS::DeleteAllKvStoreFuzz2Test(data, size); + OHOS::DeleteAllKvStoreFuzz3Test(data, size); + OHOS::RegisterKvStoreServiceDeathRecipientFuzzTest(); + OHOS::UnRegisterKvStoreServiceDeathRecipientFuzzTest(); + OHOS::PutSwitchFuzzTest(data, size); + OHOS::GetSwitchFuzzTest(data, size); + OHOS::SubscribeSwitchDataFuzzTest(data, size); + OHOS::UnsubscribeSwitchDataFuzzTest(data, size); + OHOS::TearDown(); + return 0; +} \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/data_share/common/base64_utils.h b/kv_store/test/fuzztest/distributedkvdataservice_fuzzer/distributedkvdataservice_fuzzer.h similarity index 64% rename from datamgr_service/services/distributeddataservice/service/data_share/common/base64_utils.h rename to kv_store/test/fuzztest/distributedkvdataservice_fuzzer/distributedkvdataservice_fuzzer.h index 4593bd0efd84ecd6a215cc5281ed6de95d8a563f..37eb9ac9f9bdc8d7032e75b7e79ab7a1d42b7ff1 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/common/base64_utils.h +++ b/kv_store/test/fuzztest/distributedkvdataservice_fuzzer/distributedkvdataservice_fuzzer.h @@ -13,15 +13,10 @@ * limitations under the License. */ -#ifndef DATASHARESERVICE_BASE64_H -#define DATASHARESERVICE_BASE64_H +#ifndef DISTRIBUTEDKVDATASERVICE_FUZZER_H +#define DISTRIBUTEDKVDATASERVICE_FUZZER_H -#include -#include +#define FUZZ_PROJECT_NAME "distributedkvdataservice_fuzzer" -namespace OHOS::DataShare::Base64 { -std::string Encode(const std::vector &source); -std::vector Decode(const std::string &encoded); -} // namespace OHOS::DataShare::Base64 +#endif // DISTRIBUTEDKVDATASERVICE_FUZZER_H -#endif /* DATASHARESERVICE_BASE64_H */ diff --git a/kv_store/test/fuzztest/distributedkvdataservice_fuzzer/project.xml b/kv_store/test/fuzztest/distributedkvdataservice_fuzzer/project.xml new file mode 100644 index 0000000000000000000000000000000000000000..7133b2b92440904a5ed04b838733acea0f97486a --- /dev/null +++ b/kv_store/test/fuzztest/distributedkvdataservice_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + diff --git a/kv_store/test/fuzztest/jsonservice_fuzzer/BUILD.gn b/kv_store/test/fuzztest/jsonservice_fuzzer/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..eeae1c0937fd46743874e2cc9125c00410706645 --- /dev/null +++ b/kv_store/test/fuzztest/jsonservice_fuzzer/BUILD.gn @@ -0,0 +1,147 @@ +# Copyright (c) 2024 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. + +import("//build/config/features.gni") +import("//build/test.gni") + +module_output_path = "kv_store/kv_store" + +############################################################################### +config("module_private_config") { + visibility = [ ":*" ] + + include_dirs = [ + "../../../gaussdb_rd/include", + "../../../gaussdb_rd/src/common/include", + "../../../gaussdb_rd/src/executor/include", + "../../../gaussdb_rd/src/executor/document", + "../../../gaussdb_rd/src/oh_adapter/include", + "../../../gaussdb_rd/src/oh_adapter/src", + "../../../gaussdb_rd/src/interface/include", + ] + + defines = [ + "SQLITE_ENABLE_SNAPSHOT", + "SQLITE_HAS_CODEC", + "SQLITE_ENABLE_JSON1", + "USING_HILOG_LOGGER", + "USE_SQLITE_SYMBOLS", + "SQLITE_ENABLE_DROPTABLE_CALLBACK", + ] +} + +############################################################################### +ohos_source_set("src_file") { + testonly = true + + sources = [ + "../../../gaussdb_rd/src/common/src/collection_option.cpp", + "../../../gaussdb_rd/src/common/src/db_config.cpp", + "../../../gaussdb_rd/src/common/src/grd_api_manager.cpp", + "../../../gaussdb_rd/src/common/src/json_common.cpp", + "../../../gaussdb_rd/src/common/src/os_api.cpp", + "../../../gaussdb_rd/src/common/src/rd_log_print.cpp", + "../../../gaussdb_rd/src/executor/base/grd_db_api.cpp", + "../../../gaussdb_rd/src/executor/document/check_common.cpp", + "../../../gaussdb_rd/src/executor/document/grd_document_api.cpp", + "../../../gaussdb_rd/src/executor/document/grd_document_api_inner.cpp", + "../../../gaussdb_rd/src/executor/document/grd_resultset_api.cpp", + "../../../gaussdb_rd/src/executor/document/grd_resultset_api_inner.cpp", + "../../../gaussdb_rd/src/executor/kv/grd_kv_api.cpp", + "../../../gaussdb_rd/src/executor/kv/grd_kv_api_inner.cpp", + "../../../gaussdb_rd/src/interface/src/collection.cpp", + "../../../gaussdb_rd/src/interface/src/doc_errno.cpp", + "../../../gaussdb_rd/src/interface/src/document_key.cpp", + "../../../gaussdb_rd/src/interface/src/document_store.cpp", + "../../../gaussdb_rd/src/interface/src/document_store_manager.cpp", + "../../../gaussdb_rd/src/interface/src/projection_tree.cpp", + "../../../gaussdb_rd/src/interface/src/result_set.cpp", + "../../../gaussdb_rd/src/interface/src/result_set_common.cpp", + "../../../gaussdb_rd/src/oh_adapter/src/kv_store_manager.cpp", + "../../../gaussdb_rd/src/oh_adapter/src/rd_json_object.cpp", + "../../../gaussdb_rd/src/oh_adapter/src/rd_sqlite_utils.cpp", + "../../../gaussdb_rd/src/oh_adapter/src/sqlite_store_executor_impl.cpp", + ] + + configs = [ ":module_private_config" ] + + deps = [ "//third_party/sqlite:sqlite" ] + + configs += [ "//third_party/cJSON:cJSON_config" ] + ldflags = [ "-Wl,--exclude-libs,ALL" ] + deps += [ "//third_party/cJSON:cjson" ] + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + ] + + subsystem_name = "distributeddatamgr" + part_name = "kv_store" +} + +ohos_fuzztest("JsonServiceFuzzTest") { + module_out_path = module_output_path + fuzz_config_file = "../jsonservice_fuzzer" + + if (!defined(deps)) { + deps = [] + } + if (!defined(external_deps)) { + external_deps = [] + } + configs = [ ":module_private_config" ] + deps += [ + ":src_file", + "//third_party/sqlite:sqlite", + ] + configs += [ "//third_party/cJSON:cJSON_config" ] + ldflags = [ "-Wl,--exclude-libs,ALL" ] + deps += [ + "//third_party/cJSON:cjson", + "//third_party/openssl:libcrypto_shared", + ] + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + ] + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + "--coverage", + ] + + ldflags += [ "--coverage" ] + + cflags_cc = [ "--coverage" ] + + sources = [ "jsonservice_fuzzer.cpp" ] +} + +############################################################################### + +group("fuzztest") { + testonly = true + deps = [] + deps += [ + # deps file + ":JsonServiceFuzzTest", + ] +} +############################################################################### diff --git a/kv_store/test/fuzztest/jsonservice_fuzzer/corpus/init b/kv_store/test/fuzztest/jsonservice_fuzzer/corpus/init new file mode 100644 index 0000000000000000000000000000000000000000..e7c3fecd8d4d4816e40088113a2316bb9eb2e13f --- /dev/null +++ b/kv_store/test/fuzztest/jsonservice_fuzzer/corpus/init @@ -0,0 +1,14 @@ +# Copyright (c) 2024 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. + +FUZZ \ No newline at end of file diff --git a/kv_store/test/fuzztest/jsonservice_fuzzer/jsonservice_fuzzer.cpp b/kv_store/test/fuzztest/jsonservice_fuzzer/jsonservice_fuzzer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2650f0747128ccf85cb4ca533a44e88a65253abd --- /dev/null +++ b/kv_store/test/fuzztest/jsonservice_fuzzer/jsonservice_fuzzer.cpp @@ -0,0 +1,1671 @@ +/* + * Copyright (c) 2024 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 "jsonservice_fuzzer.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "grd_base/grd_db_api.h" +#include "grd_base/grd_error.h" +#include "grd_base/grd_resultset_api.h" +#include "grd_documentVirtual/grd_documentVirtual_api.h" +#include "grd_kv/grd_kv_api.h" +#include "grd_resultset_inner.h" +#include "securec.h" +#include +#include +#include +#include +#include + +const char *TEST_DB = "./data"; +const char *TEST_FILE = "./data/testfile"; +const char *COLLECT_NAME = "collectionname"; +const char *OPTION_STRING = "{ \"maxdoc\" : 1000}"; +const char *CONFIG_STRING = "{}"; +const char *DB_DIR_PATH = "./data/"; +const char *NO_EXIST_COLLECTION_NAME = "no_exisit"; +const int NUM_THREE = 3; +const int SMALL_PREFIX_LENGTH = 5; +const int NUM_FIFTEEN = 15; +const int NUM_NINETY_EIGHT = 98; +const int BATCH_COUNT = 100; +const int LESS_HALF_BYTES = 511; +const int HALF_BYTES = 512; +const int MORE_HALF_BYTES = 513; +const int HALF_HALF_BYTES = 256; +const int MORE_HALF_HALF_BYTES = 257; +const int MAX_LEN_NUM = 600; +const int LESS_MIDDLE_SIZE_TEST = 899; +const int MIDDLE_SIZE_TEST = 900; +const int MAX_SIZE_NUM_TEST = 1000; +const int ONE_BYTES = 1024; +const int CURSOR_COUNT_TEST = 50000; +const int VECTOR_SIZE = 100000; + +static GRD_DB *g_datatest = nullptr; + +namespace OHOS { +namespace { +int RemoveDirTest(const char *dirTest) +{ + if (dirTest == nullptr) { + return -1; + } + struct stat dirStatus; + if (stat(dirTest, &dirStatus) < 0) { + return -1; + } + if (access(dirTest, F_OK) != 0) { + return 0; + } + char dirNameVirtual[PATH_MAX]; + DIR *dirPtrTest = nullptr; + struct dirent *dr = nullptr; + if (S_ISREG(dirStatus.st_mode)) { // normal file + remove(dirTest); + } else if (S_ISDIR(dirStatus.st_mode)) { + dirPtrTest = opendir(dirTest); + while ((dr = readdir(dirPtrTest)) != nullptr) { + // ignore . and .. + if ((strcmp(".", dr->d_name) == 0) || (strcmp("..", dr->d_name) == 0)) { + continue; + } + if (sprintf_s(dirNameVirtual, sizeof(dirNameVirtual), "%s / %s", dirTest, dr->d_name) < 0) { + (void)RemoveDirTest(dirNameVirtual); + closedir(dirPtrTest); + rmdir(dirTest); + return -1; + } + (void)RemoveDirTest(dirNameVirtual); + } + closedir(dirPtrTest); + rmdir(dirTest); // remove empty dirTest + } else { + return -1; + } + return 0; +} + +void MakeDirctionary(const char *dirTest) +{ + std::string tmpPathVirtual; + const char *pcur = dirTest; + + while (*pcur++ != '\0') { + tmpPathVirtual.push_back(*(pcur - 1)); + if ((*pcur == '/' || *pcur == '\0') && access(tmpPathVirtual.c_str(), 0) != 0 && !tmpPathVirtual.empty()) { + if (mkdir(tmpPathVirtual.c_str(), (S_IRUSR | S_IWUSR | S_IXUSR)) != 0) { + return; + } + } + } +} + +std::string GetMaxString() +{ + std::string str = "{"; + for (int i = 0; i <= MAX_SIZE_NUM_TEST; i++) { + for (int j = 0; j <= MAX_LEN_NUM; j++) { + str += "a"; + } + } + return str + "}"; +} +} // namespace + +void InsertDocOneFuzzTest(const std::string &documentVirtualData) +{ + std::string documentVirtual2 = "{\"id\":2,\"field\":\"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual2.c_str(), 0); + std::string documentVirtual3 = "{\"id\":true,\"field\":\"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual3.c_str(), 0); + std::string documentVirtual4 = "{\"id\" : null, \"name\" : \"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual4.c_str(), 0); + std::string documentVirtual5 = "{\"id\" : [\"2\"], \"name\" : \"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual5.c_str(), 0); + std::string documentVirtual6 = "{\"id\" : {\"val\" : \"2\"}, \"name\" : \"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual6.c_str(), 0); + std::string documentVirtual7 = "{\"id\" : \"3\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual7.c_str(), 0); + std::string documentVirtual9 = "{\"id\" : \"4\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_InsertDocument(NULL, COLLECT_NAME, documentVirtual9.c_str(), 0); + std::string documentVirtual10 = "{\"id\" : \"5\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, NULL, documentVirtual10.c_str(), 0); + std::string documentVirtual12 = "{\"id\" : \"6\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual12.c_str(), 1); + std::string documentVirtual13 = "{\"id\" : \"7\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual13.c_str(), INT_MAX); + std::string documentVirtual14 = "{\"id\" : \"8\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual14.c_str(), INT_MIN); + GRD_InsertDocument(g_datatest, NULL, NULL, 0); + std::string documentVirtual15 = "{\"id\" : \"9\", \"name\" : \"" + documentVirtualData + "\"}"; + std::string collectName2(HALF_BYTES, 'a'); + GRD_InsertDocument(g_datatest, collectName2.c_str(), documentVirtual15.c_str(), 0); + const char *collectName = "collection@!#"; + std::string documentVirtual18 = "{\"id\" : \"18\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual18.c_str(), 0); + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual19.c_str(), 0); + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual20.c_str(), 0); + std::string documentVirtual21 = "{\"id\" : \"21\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, collectName, documentVirtual21.c_str(), GRD_OK); + std::string collectName1(HALF_HALF_BYTES, 'k'); +} + +void InsertDocTwoFuzzTest(const std::string &documentVirtualData) +{ + std::string documentVirtualPart1 = "{ \"id\" : \"15\", \"textVal\" : \" "; + std::string documentVirtualPart2 = "\" }"; + std::string jsonVal = + std::string(HALF_BYTES * ONE_BYTES - documentVirtualPart1.size() - documentVirtualPart2.size(), 'k'); + std::string documentVirtual = documentVirtualPart1 + jsonVal + documentVirtualPart2; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual.c_str(), 0); + std::string jsonVal2 = + std::string(HALF_BYTES * ONE_BYTES - 1 - documentVirtualPart1.size() - documentVirtualPart2.size(), 'k'); + std::string documentVirtual21 = documentVirtualPart1 + jsonVal2 + documentVirtualPart2; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual21.c_str(), 0); + std::string documentVirtual22 = "{\"id\" : \"16\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual22.c_str(), 0); + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual23.c_str(), 0); + std::string documentVirtual24 = documentVirtualData; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual24.c_str(), 0); + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual25.c_str(), 0); + std::string collectName3 = std::string(HALF_HALF_BYTES, 'k'); + std::string documentVirtual26 = "{\"id\" : \"22\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, collectName3.c_str(), documentVirtual26.c_str(), GRD_OK); + std::string collectName4 = "Aads_sd__23Asb_"; + std::string documentVirtual27 = "{\"id\" : \"23\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, collectName4.c_str(), documentVirtual27.c_str(), GRD_OK); + std::string collectName5 = "GRD_collectName"; + std::string documentVirtual28 = "{\"id\" : \"24\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_CreateCollect(g_datatest, collectName5.c_str(), "", 0); + GRD_InsertDocument(g_datatest, collectName5.c_str(), documentVirtual28.c_str(), 0); + collectName5 = "GM_SYS__collectName"; + std::string documentVirtual29 = "{\"id\" : \"24_2\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_CreateCollect(g_datatest, collectName5.c_str(), "", 0); + GRD_InsertDocument(g_datatest, collectName5.c_str(), documentVirtual29.c_str(), 0); + + collectName5 = "grd_collectName"; + std::string documentVirtual30 = "{\"id\" : \"24_3\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_CreateCollect(g_datatest, collectName5.c_str(), "", 0); + GRD_InsertDocument(g_datatest, collectName5.c_str(), documentVirtual30.c_str(), 0); +} + +void InsertDocThreeFuzzTest(const std::string &documentVirtualData) +{ + std::string collectName5 = "gm_sys_collectName"; + std::string documentVirtual31 = "{\"id\" : \"24_4\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_CreateCollect(g_datatest, collectName5.c_str(), "", 0); + GRD_InsertDocument(g_datatest, collectName5.c_str(), documentVirtual31.c_str(), 0); + + collectName5 = "gM_sYs_collectName"; + std::string documentVirtual32 = "{\"id\" : \"24_5\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_CreateCollect(g_datatest, collectName5.c_str(), "", 0); + GRD_InsertDocument(g_datatest, collectName5.c_str(), documentVirtual32.c_str(), 0); + + collectName5 = "gRd_collectName"; + std::string documentVirtual33 = "{\"id\" : \"24_6\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_CreateCollect(g_datatest, collectName5.c_str(), "", 0); + GRD_InsertDocument(g_datatest, collectName5.c_str(), documentVirtual33.c_str(), 0); + + collectName5 = "gRd@collectName"; + std::string documentVirtual34 = "{\"id\" : \"24_7\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_CreateCollect(g_datatest, collectName5.c_str(), "", 0); + GRD_InsertDocument(g_datatest, collectName5.c_str(), documentVirtual34.c_str(), 0); + + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual35.c_str(), 0); + + std::string documentVirtual36 = "{\"id\" : \"36_4\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_CreateCollect(g_datatest, collectName5.c_str(), "", 0); + GRD_InsertDocument(g_datatest, collectName5.c_str(), documentVirtual36.c_str(), 0); + + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual36.c_str(), 0); + std::string documentVirtual37 = "{\"id\" : \"37_4\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual37.c_str(), 0); + std::string documentVirtual38 = "{\"id\" : \"38_8\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual38.c_str(), 0); +} + +void InsertDocFourFuzzTest(const std::string &longId, const std::string &documentVirtualData) +{ + std::string documentVirtual39 = + "{\"id\" : \"35\", \"A_aBdk_324_\" : \"" + documentVirtualData + + "\", \"name\" : \"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual39.c_str(), 0); + + std::string documentVirtual40 = "{\"id\" : \"35_2\", \"1A_aBdk_324_\" : \"" + documentVirtualData + + "\", " + "\"name\" : \"" + + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual40.c_str(), 0); + std::string documentVirtual41 = "{\"id\" : \"36_0\", \"stringType\" : \"" + documentVirtualData + + documentVirtualData + ", \"objectType\" : {\"A\" : 3}}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual41.c_str(), 0); + + std::string documentVirtual42 = "({\"id\" : \"38_0\", \"field2\" : 1.7693" + longId + "13486232e308})"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual42.c_str(), 0); + std::string documentVirtual43 = + "({\"id\" : \"38_1\", \"t1\" : {\"field2\" : 1.797" + longId + "693134862e308}})"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual43.c_str(), 0); + std::string documentVirtual44 = "({\"id\" : \"38_2\", \"t1\" : [1, 2, 1.797313486" + longId + "232e308]})"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual44.c_str(), 0); + std::string documentVirtual45 = "({\"id\" : \"38_3\", \"t1\" : [1, 2, -1.79763486167" + longId + "E+308]})"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual45.c_str(), 0); + std::string documentVirtual46 = + "({\"id\" : \"38_4\", \"t1\" : [1, 2, -1." + longId + "79763486231570E+308]})"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual46.c_str(), 0); + std::string documentVirtual47 = + "({\"id\" : \"38_5\", \"t1\" : [1, 2, 1.79769313486" + longId + "2370E+308]})"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual47.c_str(), 0); + + std::string doc1 = "{\"id\" : "; + std::string doc2 = "\""; + std::string doc4 = "\""; + std::string doc5 = ", \"name\" : \"" + documentVirtualData + "\"}"; + std::string documentVirtualMiddle(MIDDLE_SIZE_TEST, 'k'); + std::string documentVirtual48 = doc1 + doc2 + documentVirtualMiddle + doc4 + doc5; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual48.c_str(), 0); + std::string documentVirtualMiddle2(MAX_SIZE_NUM_TEST, 'k'); + documentVirtual48 = doc1 + doc2 + documentVirtualMiddle2 + doc4 + doc5; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual48.c_str(), 0); + + std::string documentVirtual49 = "({\"id\":\"0123\", \"num\":\"" + documentVirtualData + "\"})"; + std::string documentVirtual50 = "({\"id\":\"0123\", \"NUM\":\"" + documentVirtualData + "\"})"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual49.c_str(), 0); + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual50.c_str(), 0); + + std::string documentVirtual51 = "({\"id\":\"0123\", \"num.\":\"" + documentVirtualData + "\"})"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual51.c_str(), 0); + + const char *documentVirtual52 = R""({})""; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual52, 0); +} + +void InsertDocFuzzTest(const uint8_t *data, size_t size) +{ + std::string collectNameData(reinterpret_cast(data), size); + const char *collectNameVal = collectNameData.data(); + std::string optionStrData(reinterpret_cast(data), size); + const char *optionStrVal = optionStrData.data(); + GRD_CreateCollect(g_datatest, collectNameVal, optionStrVal, 0); + std::string documentVirtualData(reinterpret_cast(data), size); + const char *documentVirtualVal = documentVirtualData.data(); + GRD_InsertDocument(g_datatest, collectNameVal, documentVirtualVal, 0); + GRD_InsertDocument(g_datatest, collectNameVal, documentVirtualVal, 0); + std::string strJson = "{" + documentVirtualData + "}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, strJson.c_str(), 0); + GRD_InsertDocument(g_datatest, COLLECT_NAME, strJson.c_str(), 0); + std::string stringJson2 = "{\"id\":\"1\",\"field\":\"" + documentVirtualData + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, stringJson2.c_str(), 0); + GRD_InsertDocument(g_datatest, COLLECT_NAME, stringJson2.c_str(), 0); + std::string longId = "1"; + for (int i = 0; i < MAX_SIZE_NUM_TEST; i++) { + longId += "1"; + } + longId = "{\"id\":\"" + longId + "\",\"field\":\"field_id\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, longId.c_str(), 0); + GRD_InsertDocument(g_datatest, COLLECT_NAME, "{\"id\":123}", 0); + GRD_InsertDocument(g_datatest, COLLECT_NAME, "{\"field1.field2.field&*^&3\":\"anc\"}", 0); + InsertDocOneFuzzTest(documentVirtualData); + InsertDocTwoFuzzTest(documentVirtualData); + InsertDocThreeFuzzTest(documentVirtualData); + InsertDocFourFuzzTest(longId, documentVirtualData); + + const char *documentVirtual53 = R""({"empty" : null})""; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual53, 0); + GRD_DropCollect(g_datatest, collectNameVal, 0); + GRD_DropCollect(g_datatest, COLLECT_NAME, 0); + + std::string documentVirtualNew1 = "{\"id\" : "; + std::string documentVirtualNew2 = "\""; + std::string documentVirtualNew3 = "\""; + std::string documentVirtualNew4 = ", \"name\" : \"Ori\"}"; + std::string documentVirtual = documentVirtualNew1 + + documentVirtualNew2 + documentVirtualData + documentVirtualNew3 + documentVirtualNew4; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual.c_str(), 0); +} + +static const char *DOCU1 = "{\"id\" : \"1\", \"name\":\"doc1\",\"item\":\"journal\",\"person\":\ + {\"school\":\"AB\", \"age\" : 51}}"; +static const char *DOCU2 = "{\"id\" : \"2\", \"name\":\"doc2\",\"item\": 1, \"person\":\ + [1, \"my string\", {\"school\":\"AB\", \"age\" : 51}, true, {\"school\":\"CD\", \"age\" : 15}, false]}"; +static const char *DOCU3 = "{\"id\" : \"3\", \"name\":\"doc3\",\"item\":\"notebook\",\"person\":\ + [{\"school\":\"C\", \"age\" : 5}]}"; +static const char *DOCU4 = "{\"id\" : \"4\", \"name\":\"doc4\",\"item\":\"paper\",\"person\":\ + {\"grade\" : 1, \"school\":\"A\", \"age\" : 18}}"; +static const char *DOCU5 = "{\"id\" : \"5\", \"name\":\"doc5\",\"item\":\"journal\",\"person\":\ + [{\"sex\" : \"woma\", \"school\" : \"B\", \"age\" : 15}, {\"school\":\"C\", \"age\" : 35}]}"; +static const char *DOCU6 = "{\"id\" : \"6\", \"name\":\"doc6\",\"item\":false,\"person\":\ + [{\"school\":\"B\", \"teacher\" : \"mike\", \"age\" : 15},\ + {\"school\":\"C\", \"teacher\" : \"moon\", \"age\" : 20}]}"; + +static const char *DOCU7 = "{\"id\" : \"7\", \"name\":\"doc7\",\"item\":\"fruit\",\"other_Info\":\ + [{\"school\":\"BX\", \"age\" : 15}, {\"school\":\"C\", \"age\" : 35}]}"; +static const char *DOCU8 = "{\"id\" : \"8\", \"name\":\"doc8\",\"item\":true,\"person\":\ + [{\"school\":\"B\", \"age\" : 15}, {\"school\":\"C\", \"age\" : 35}]}"; +static const char *DOCU9 = "{\"id\" : \"9\", \"name\":\"doc9\",\"item\": true}"; +static const char *DOCU10 = "{\"id\" : \"10\", \"name\":\"doc10\", \"parent\" : \"kate\"}"; +static const char *DOCU11 = "{\"id\" : \"11\", \"name\":\"doc11\", \"other\" : \"null\"}"; +static const char *DOCU12 = "{\"id\" : \"12\", \"name\":\"doc12\",\"other\" : null}"; +static const char *DOCU13 = "{\"id\" : \"13\", \"name\":\"doc13\",\"item\" : \"shoes\",\"person\":\ + {\"school\":\"AB\", \"age\" : 15}}"; +static const char *DOCU14 = "{\"id\" : \"14\", \"name\":\"doc14\",\"item\" : true,\"person\":\ + [{\"school\":\"B\", \"age\" : 15}, {\"school\":\"C\", \"age\" : 85}]}"; +static const char *DOCU15 = "{\"id\" : \"15\", \"name\":\"doc15\",\"person\":[{\"school\":\"C\", \"age\" : " + "5}]}"; +static const char *DOCU16 = "{\"id\" : \"16\", \"name\":\"doc16\", \"nested1\":{\"nested2\":{\"nested3\":\ + {\"nested4\":\"ABC\", \"field2\":\"CCC\"}}}}"; +static const char *DOCU17 = "{\"id\" : \"17\", \"name\":\"doc17\",\"person\":\"oh,ok\"}"; +static const char *DOCU18 = "{\"id\" : \"18\", \"name\":\"doc18\",\"item\" : \"mobile phone\",\"person\":\ + {\"school\":\"DD\", \"age\":66}, \"color\":\"blue\"}"; +static const char *DOCU19 = "{\"id\" : \"19\", \"name\":\"doc19\",\"ITEM\" : true,\"PERSONINFO\":\ + {\"school\":\"AB\", \"age\":15}}"; +static const char *DOCU20 = "{\"id\" : \"20\", \"name\":\"doc20\",\"ITEM\" : true,\"person\":\ + [{\"SCHOOL\":\"B\", \"AGE\":15}, {\"SCHOOL\":\"C\", \"AGE\":35}]}"; +static const char *DOCU23 = "{\"id\" : \"23\", \"name\":\"doc22\",\"ITEM\" : " + "true,\"person\":[{\"school\":\"b\", \"age\":15}, [{\"school\":\"doc23\"}, 10, " + "{\"school\":\"doc23\"}, true, {\"school\":\"y\"}], {\"school\":\"b\"}]}"; +static std::vector g_datatest = { DOCU1, DOCU2, DOCU3, DOCU4, DOCU5, + DOCU6, DOCU7, DOCU8, DOCU9, DOCU10, DOCU11, DOCU12, DOCU13, + DOCU14, DOCU15, DOCU16, DOCU17, DOCU18, DOCU19, DOCU20, DOCU23 }; + +namespace { +static void InsertData(GRD_DB *g_datatest, const char *collectName) +{ + for (const auto &item : g_datatest) { + GRD_InsertDocument(g_datatest, collectName, item, 0); + } +} + +void SetUpTestCase() +{ + (void)RemoveDirTest(TEST_DB); + MakeDirctionary(TEST_DB); + GRD_DBOpen(TEST_FILE, CONFIG_STRING, GRD_OPEN_CREATE, &g_datatest); + InsertData(g_datatest, COLLECT_NAME); + GRD_CreateCollect(g_datatest, COLLECT_NAME, OPTION_STRING, 0); +} + +void TearDownTestCase() +{ + GRD_DropCollect(g_datatest, COLLECT_NAME, 0); + GRD_DBClose(g_datatest, GRD_CLOSE); + (void)RemoveDirTest(TEST_DB); + g_datatest = nullptr; +} + +void FindDocumentResultSetFuzzTest(const char *colName, const std::string &filt, const std::string &projectInfo) +{ + GRD_ResultSet *reSet = nullptr; + Query query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, colName, query, 1, &reSet); + if (reSet != nullptr) { + GRD_Next(reSet); + char *valueResult = nullptr; + GRD_GetVal(reSet, &valueResult); + } + GRD_FreeRe(reSet); +} + +void FindDocumentWithFlagFuzzTest(const std::string &filt, const std::string &projectInfo, int flag) +{ + GRD_ResultSet *reSet = nullptr; + Query query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, flag, &reSet); + GRD_Next(reSet); + char *value = nullptr; + GRD_GetVal(reSet, &value); + GRD_FreeVal(value); + GRD_FreeRe(reSet); +} + +void FindDocumentNextTwiceFuzzTest(const std::string &filt, const std::string &projectInfo) +{ + GRD_ResultSet *reSet = nullptr; + Query query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 1, &reSet); + GRD_Next(reSet); + GRD_Next(reSet); + char *value = nullptr; + GRD_GetVal(reSet, &value); + GRD_FreeVal(value); + GRD_FreeRe(reSet); +} + +void FindDocumentZeroFuzzTest(const std::string &input) +{ + std::string filt = "{\"id\" : \"6\"}"; + FindDocumentResultSetFuzzTest(COLLECT_NAME, filt, R"({})"); + + filt = "{\"id\" : \"6\", \"name\":\"" + input + "\"}"; + FindDocumentResultSetFuzzTest(COLLECT_NAME, filt, R"({})"); + + filt = "{\"name\":\"" + input + "\"}"; + FindDocumentResultSetFuzzTest(COLLECT_NAME, filt, R"({})"); + + filt = "{\"id\" : \"" + input + "\"}"; + FindDocumentResultSetFuzzTest(COLLECT_NAME, filt, R"({})"); + + filt = "{\"id\" : 1}"; + FindDocumentResultSetFuzzTest(COLLECT_NAME, filt, R"({})"); + + filt = "{\"id\" : [\"" + input + "\", 1]}"; + FindDocumentResultSetFuzzTest(COLLECT_NAME, filt, R"({})"); + + filt = "{\"id\" : {\"" + input + "\" : \"1\"}}"; + FindDocumentResultSetFuzzTest(COLLECT_NAME, filt, R"({})"); + + filt = "{\"id\" : true}"; + FindDocumentResultSetFuzzTest(COLLECT_NAME, filt, R"({})"); + + filt = "{\"id\" : null}"; + FindDocumentResultSetFuzzTest(COLLECT_NAME, filt, R"({})"); + + const char *colName1 = "grd_type"; + const char *colName2 = "GM_SYS_sysfff"; + filt = "{\"id\" : \"1\"}"; + FindDocumentResultSetFuzzTest(colName1, filt, R"({})"); + FindDocumentResultSetFuzzTest(colName2, filt, R"({})"); + + filt = "{\"id\" : \"100\"}"; + FindDocumentResultSetFuzzTest(COLLECT_NAME, filt, R"({})"); +} + +void FindDocumentOneFuzzTest() +{ + std::string filt = "{\"id\" : \"6\"}"; + GRD_ResultSet *reSet = nullptr; + GRD_ResultSet *reSet2 = nullptr; + Query query = { filt.c_str(), "{}" }; + const char *collectName = "DocumentDBFindTest024"; + GRD_CreateCollect(g_datatest, collectName, "", 0); + InsertData(g_datatest, collectName); + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 1, &reSet); + GRD_FindDocument(g_datatest, collectName, query, 1, &reSet2); + + GRD_Next(reSet); + char *value = nullptr; + GRD_GetVal(reSet, &value); + GRD_FreeVal(value); + + GRD_Next(reSet2); + char *value2 = nullptr; + GRD_GetVal(reSet2, &value2); + GRD_FreeVal(value2); + + GRD_Next(reSet); + GRD_Next(reSet2); + GRD_GetVal(reSet, &value); + GRD_GetVal(reSet2, &value); + GRD_FreeRe(reSet); + GRD_FreeRe(reSet2); + GRD_DropCollect(g_datatest, collectName, 0); + + filt = "{\"id\" : \"16\"}"; + reSet = nullptr; + std::string projectInfo = "{\"name\": true, \"nested1.nested2.nested3.nested4\":true}"; + query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); + GRD_Next(reSet); + value = nullptr; + GRD_GetVal(reSet, &value); + GRD_FreeVal(value); + GRD_Next(reSet); + GRD_GetVal(reSet, &value); + GRD_FreeRe(reSet); + + projectInfo = "{\"name\": true, \"nested1\":{\"nested2\":{\"nested3\":{\"nested4\":true}}}}"; + query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); + GRD_Next(reSet); + GRD_GetVal(reSet, &value); + GRD_FreeVal(value); + GRD_Next(reSet); + GRD_GetVal(reSet, &value); + GRD_FreeRe(reSet); +} + +void FindDocumentTwoFuzzTest(const std::string &input) +{ + GRD_ResultSet *reSet = nullptr; + std::string projectInfo = "{\"name\": 0, \"nested1.nested2.nested3.nested4\":0}"; + std::string filt = "{\"id\" : \"16\"}"; + Query query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); + GRD_Next(reSet); + char *value = nullptr; + GRD_GetVal(reSet, &value); + GRD_FreeVal(value); + GRD_FreeRe(reSet); + + projectInfo = "{\"name\": \"" + input + "\", \"nested1.nested2.nested3.nested4\":\"" + input + "\"}"; + FindDocumentResultSetFuzzTest(COLLECT_NAME, filt, projectInfo); + + filt = "{\"id\" : \"7\"}"; + reSet = nullptr; + projectInfo = "{\"name\": true, \"other_Info\":true, \"non_exist_field\":true}"; + query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); + GRD_Next(reSet); + value = nullptr; + GRD_GetVal(reSet, &value); + GRD_FreeVal(value); + GRD_FreeRe(reSet); + + projectInfo = "{\"name\": true, \"other_Info\":true, \" item \":true}"; + FindDocumentResultSetFuzzTest(COLLECT_NAME, filt, projectInfo); +} + +void FindDocumentThreeFuzzTest(const std::string &input) +{ + std::string filt = "{\"id\" : \"7\"}"; + GRD_ResultSet *reSet = nullptr; + std::string projectInfo = "{\"name\": true, \"other_Info.non_exist_field\":true}"; + Query query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); + GRD_Next(reSet); + char *value = nullptr; + GRD_GetVal(reSet, &value); + GRD_FreeVal(value); + GRD_FreeRe(reSet); + projectInfo = "{\"name\": true, \"other_Info\":{\"non_exist_field\":true}}"; + FindDocumentResultSetFuzzTest(COLLECT_NAME, filt, projectInfo); + projectInfo = "{\"name\": true, \"other_Info.0\": true}"; + FindDocumentResultSetFuzzTest(COLLECT_NAME, filt, projectInfo); + filt = "{\"id\" : \"4\"}"; + reSet = nullptr; + projectInfo = "{\"person\": true, \"person.grade\": true}"; + query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); + + filt = "{\"id\" : \"7\"}"; + projectInfo = "{\"non_exist_field\":true}"; + int flag = 0; + FindDocumentWithFlagFuzzTest(filt, projectInfo, flag); + flag = 1; + FindDocumentWithFlagFuzzTest(filt, projectInfo, flag); + filt = "{\"id\" : \"7\"}"; + projectInfo = "{\"name\":true, \"item\":true}"; + flag = 0; + FindDocumentWithFlagFuzzTest(filt, projectInfo, flag); + flag = 1; + projectInfo = "{\"name\": " + input + ", \"item\": " + input + "}"; + FindDocumentWithFlagFuzzTest(filt, projectInfo, flag); + filt = "{\"id\" : \"7\"}"; + projectInfo = "{\"name\":false, \"item\":false}"; + flag = 0; + FindDocumentWithFlagFuzzTest(filt, projectInfo, flag); + flag = 1; + projectInfo = "{\"name\": " + input + ", \"item\": " + input + "}"; + FindDocumentWithFlagFuzzTest(filt, projectInfo, flag); + filt = "{\"id\" : \"4\"}"; + flag = 0; + FindDocumentWithFlagFuzzTest(filt, projectInfo, flag); + projectInfo = "{\"name\": false, \"person.grade1\": false, \ + \"person.shool1\": false, \"person.age1\": false}"; + FindDocumentResultSetFuzzTest(COLLECT_NAME, filt, projectInfo); +} + +void FindDocumentFourFuzzTest(const std::string &input) +{ + std::string filt = "{\"id\" : \"4\"}"; + std::string projectInfo = + "{\"name\": " + input + ", \"person.school\": " + input + ", \"person.age\": " + input + "}"; + FindDocumentResultSetFuzzTest(COLLECT_NAME, filt, projectInfo); + + filt = "{\"id\" : \"17\"}"; + GRD_ResultSet *reSet = nullptr; + Query query = { filt.c_str(), "{}" }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, GRD_DOC_ID_DISPLAY, &reSet); + GRD_Next(reSet); + char *value = nullptr; + GRD_GetVal(reSet, &value); + GRD_FreeVal(value); + GRD_Next(reSet); + GRD_GetVal(reSet, &value); + GRD_FreeRe(reSet); + + reSet = nullptr; + query = { filt.c_str(), "{}" }; + GRD_FindDocument(g_datatest, "", query, 0, &reSet); + GRD_FindDocument(g_datatest, nullptr, query, 0, &reSet); + + filt = "{\"id\" : \"4\"}"; + reSet = nullptr; + projectInfo = "{\"name\":" + input + ", \"person\":0, \"item\":" + input + "}"; + query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); + + projectInfo = "{\"name\":true, \"person\":0, \"item\":true}"; + query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); + + projectInfo = "{\"name\":\"\", \"person\":0, \"item\":\"\"}"; + query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); + + projectInfo = "{\"name\":false, \"person\":1, \"item\":false"; + query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); + + projectInfo = "{\"name\":false, \"person\":-1.123, \"item\":false"; + query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); + + projectInfo = "{\"name\":false, \"person\":true, \"item\":false"; + query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); +} + +void FindDocumentFiveFuzzTest(const std::string &input) +{ + std::string filt = "{\"id\" : \"6\"}"; + std::string projectInfo = "{\"name\":false, \"person\": 0, \"item\":0}"; + int flag = 0; + FindDocumentWithFlagFuzzTest(filt, projectInfo, flag); + + filt = "{\"id\" : \"18\"}"; + projectInfo = "{\"name\":true, \"person.age\": \"\", \"item\":1, \"color\":10, \"nonExist\" : " + "-100}"; + flag = 0; + FindDocumentWithFlagFuzzTest(filt, projectInfo, flag); + + GRD_ResultSet *reSet = nullptr; + projectInfo = "{\"person\":[true, " + input + "]}"; + flag = 1; + Query query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, flag, &reSet); + projectInfo = "{\"person\":null}"; + query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, flag, &reSet); + reSet = nullptr; + projectInfo = "{\"Name\":true, \"person.age\": \"\", \"item\":" + input + ", \"COLOR\":" + input + + ", \"nonExist\" : " + "" + + input + "}"; + flag = 0; + query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, flag, &reSet); + GRD_Next(reSet); + GRD_FreeRe(reSet); + + reSet = nullptr; + projectInfo = "{\"Name\":" + input + ", \"person.age\": false, \"person.SCHOOL\": false, \"item\":\ + false, \"COLOR\":false, \"nonExist\" : false}"; + query = { filt.c_str(), projectInfo.c_str() }; + char *value = nullptr; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 1, &reSet); + GRD_Next(reSet); + GRD_GetVal(reSet, &value); + GRD_FreeVal(value); + GRD_Next(reSet); + GRD_FreeRe(reSet); + + filt = "{\"id\" : \"18\"}"; + reSet = nullptr; + query = { filt.c_str(), "{}" }; + std::string collectName1(LESS_HALF_BYTES, 'a'); + GRD_FindDocument(g_datatest, collectName1.c_str(), query, 1, &reSet); + GRD_FreeRe(reSet); +} + +void FindDocumentSixFuzzTest(const std::string &input) +{ + std::string collectName2(HALF_BYTES, 'a'); + std::string filt = "{\"id\" : \"18\"}"; + Query query = { filt.c_str(), "{}" }; + GRD_ResultSet *reSet = nullptr; + GRD_FindDocument(g_datatest, collectName2.c_str(), query, 1, &reSet); + GRD_FindDocument(g_datatest, "", query, 1, &reSet); + + reSet = nullptr; + std::string projectInfo = "{}"; + query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, NUM_THREE, &reSet); + GRD_FindDocument(g_datatest, COLLECT_NAME, query, INT_MAX, &reSet); + GRD_FindDocument(g_datatest, COLLECT_NAME, query, INT_MIN, &reSet); + GRD_FindDocument(nullptr, COLLECT_NAME, query, 0, &reSet); + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, nullptr); + query = { nullptr, nullptr }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); + + std::string documentVirtual1 = "{\"id\" : "; + std::string documentVirtual2 = "\""; + std::string documentVirtual4 = "\""; + std::string documentVirtual5 = "}"; + std::string documentVirtualMiddle(MIDDLE_SIZE_TEST, 'k'); + filt = documentVirtual1 + documentVirtual2 + documentVirtualMiddle + documentVirtual4 + documentVirtual5; + reSet = nullptr; + query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); + std::string documentVirtualMiddle2(LESS_MIDDLE_SIZE_TEST, 'k'); + filt = documentVirtual1 + documentVirtual2 + documentVirtualMiddle2 + documentVirtual4 + documentVirtual5; + query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); + GRD_FreeRe(reSet); + + filt = "{\"person\" : {\"school\":\"" + input + "\"}}"; + FindDocumentNextTwiceFuzzTest(filt, R"({})"); + + projectInfo = "{\"version\": " + input + "}"; + FindDocumentNextTwiceFuzzTest(filt, projectInfo); + + projectInfo = "({\"a00001\":" + input + ", \"a00001\":" + input + "})"; + FindDocumentNextTwiceFuzzTest(filt, projectInfo); + + projectInfo = "({\"abc123_.\":" + input + "})"; + FindDocumentNextTwiceFuzzTest(filt, projectInfo); + + filt = "({\"abc123_.\":" + input + "})"; + FindDocumentNextTwiceFuzzTest(filt, projectInfo); +} + +void FindDocumentSevenFuzzTest(const std::string &input) +{ + std::string documentVirtual064 = "{\"id\" : \"64\", \"a\":" + input + ", \"doc64\" : " + input + "}"; + std::string documentVirtual063 = "{\"id\" : \"63\", \"a\":" + input + ", \"doc63\" : " + input + "}"; + std::string documentVirtual062 = "{\"id\" : \"62\", \"a\":" + input + ", \"doc62\" : " + input + "}"; + std::string documentVirtual061 = "{\"id\" : \"61\", \"a\":" + input + ", \"doc61\" : " + input + "}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual064.c_str(), 0); + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual063.c_str(), 0); + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual062.c_str(), 0); + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual061.c_str(), 0); + std::string filt = "{\"a\":" + input + "}"; + GRD_ResultSet *reSet = nullptr; + std::string projectInfo = R"({})"; + Query query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 1, &reSet); + GRD_Next(reSet); + char *value = nullptr; + GRD_GetVal(reSet, &value); + + GRD_Next(reSet); + GRD_GetVal(reSet, &value); + + GRD_Next(reSet); + GRD_GetVal(reSet, &value); + + GRD_Next(reSet); + GRD_GetVal(reSet, &value); + GRD_FreeVal(value); + GRD_FreeRe(reSet); +} + +void FindDocumentFuzzTestPlus(const std::string &input) +{ + FindDocumentZeroFuzzTest(input); + std::string filt = "{\"id\" : \"6\"}"; + FindDocumentResultSetFuzzTest(COLLECT_NAME, filt, R"({})"); + FindDocumentOneFuzzTest(); + FindDocumentTwoFuzzTest(input); + FindDocumentThreeFuzzTest(input); + FindDocumentFourFuzzTest(input); + FindDocumentFiveFuzzTest(input); + FindDocumentSixFuzzTest(input); + FindDocumentSevenFuzzTest(input); + + std::string documentVirtual = "{\"a\":" + input + ", \"doc64\" : " + input + "}"; + filt = "{\"b\":" + input + "}"; + GRD_Upsert(g_datatest, COLLECT_NAME, filt.c_str(), documentVirtual.c_str(), 0); + GRD_Upsert(g_datatest, COLLECT_NAME, filt.c_str(), documentVirtual.c_str(), 0); + GRD_Upsert(g_datatest, COLLECT_NAME, filt.c_str(), documentVirtual.c_str(), 0); + GRD_Upsert(g_datatest, COLLECT_NAME, filt.c_str(), documentVirtual.c_str(), 0); + GRD_Upsert(g_datatest, COLLECT_NAME, filt.c_str(), documentVirtual.c_str(), 0); + GRD_Upsert(g_datatest, COLLECT_NAME, filt.c_str(), documentVirtual.c_str(), 0); + GRD_Upsert(g_datatest, COLLECT_NAME, filt.c_str(), documentVirtual.c_str(), 0); + GRD_Upsert(g_datatest, COLLECT_NAME, filt.c_str(), documentVirtual.c_str(), 0); + filt = "{\"a\":" + input + "}"; + GRD_ResultSet *reSet = nullptr; + std::string projectInfo = R"({})"; + Query query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 1, &reSet); + GRD_Next(reSet); + GRD_Next(reSet); + GRD_Next(reSet); + GRD_Next(reSet); + GRD_Next(reSet); + GRD_Next(reSet); + GRD_Next(reSet); + GRD_Next(reSet); + GRD_Next(reSet); + GRD_FreeRe(reSet); + filt = "{\"a\":" + input + "}"; + reSet = nullptr; + projectInfo = R"({})"; + query = { filt.c_str(), projectInfo.c_str() }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 1, &reSet); + GRD_DropCollect(g_datatest, COLLECT_NAME, 0); + GRD_Next(reSet); + char *valueNew = nullptr; + GRD_GetVal(reSet, &valueNew); + GRD_FreeVal(valueNew); + GRD_FreeRe(reSet); + filt = "{\"person\" : {\"school\":" + input + "}" + "}"; + FindDocumentNextTwiceFuzzTest(filt, R"({})"); +} +} // namespace + +void FindDocumentFuzzTest(const uint8_t *data, size_t size) +{ + GRD_CreateCollect(g_datatest, COLLECT_NAME, OPTION_STRING, 0); + std::string input(reinterpret_cast(data), size); + std::string inputJson11 = "{\"field\":\"" + input + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, inputJson11.c_str(), 0); + Query query = { inputJson11.c_str(), inputJson11.c_str() }; + GRD_ResultSet *reSet = nullptr; + // ResultSet conflict + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 1, &reSet); + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 1, &reSet); + GRD_FreeRe(reSet); + reSet = nullptr; + GRD_FindDocument(g_datatest, input.c_str(), query, size, &reSet); + GRD_FreeRe(reSet); + GRD_FindDocument(nullptr, input.c_str(), query, 1, &reSet); + query.filt = nullptr; + GRD_FindDocument(g_datatest, input.c_str(), query, 1, &reSet); + inputJson11 = "{\"field\": 0, \"field2\":" + input + "}"; + query.filt = "{}"; + query.project = inputJson11.c_str(); + reSet = nullptr; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 1, &reSet); + GRD_FreeRe(reSet); + inputJson11 = "{\"" + input + "\": 0}"; + query.project = inputJson11.c_str(); + reSet = nullptr; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 1, &reSet); + GRD_FreeRe(reSet); + inputJson11 = "{\"field\":[\"aaa\"," + input + "]}"; + reSet = nullptr; + query.project = inputJson11.c_str(); + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 1, &reSet); + GRD_FreeRe(reSet); + query.filt = "{\"field\": false}"; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 1, &reSet); + GRD_FreeRe(reSet); + FindDocumentFuzzTestPlus(input); + GRD_DropCollect(g_datatest, COLLECT_NAME, 0); +} + +void UpdateDocOneFuzzTest(std::string s, const std::string &input) +{ + std::string inputJson11 = "{\"field5\": \"" + s + "\"}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field5\": \"" + s + s + "\"}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field1\": [\"field2\", {\"field3\":\"" + input + "\"}]}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"name\":\"doc6\", \"c0\" : {\"c1\" : true } }"; + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"name\":\"doc6\"}", inputJson11.c_str(), 1); + inputJson11 = "{\"name\":\"doc7\", \"c0\" : {\"c1\" : null } }"; + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"name\":\"doc7\"}", inputJson11.c_str(), 1); + inputJson11 = "{\"name\":\"doc8\", \"c0\" : [\"" + input + "\", 123]}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"name\":\"doc8\"}", inputJson11.c_str(), 1); + + GRD_InsertDocument(g_datatest, COLLECT_NAME, inputJson11.c_str(), 0); + GRD_UpDoc(g_datatest, inputJson11.c_str(), "{}", "{}", 0); + GRD_UpDoc(g_datatest, COLLECT_NAME, input.c_str(), "{}", 0); + GRD_UpDoc(g_datatest, COLLECT_NAME, "{}", input.c_str(), 0); + GRD_UpDoc(nullptr, COLLECT_NAME, "{}", "{}", 0); + inputJson11 = "{\"id\":\"2\", \"field\":" + input + "}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field\":" + input + "}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field1.field2.field3.field4.field5.field6\":" + input + "}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field1\": {\"field2\": {\"field3\": {\"field4\": {\"field5\":" + input + "}}}}}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + s.clear(); + for (int i = 0; i < ((ONE_BYTES * ONE_BYTES) - 1) - NUM_FIFTEEN; i++) { + s += 'a'; + } + inputJson11 = "{\"field5\": \"" + s + "\"}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field5\": \"" + s + s + "\"}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field1\": [\"field2\", {\"field3\":\"" + input + "\"}]}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"name\":\"doc6\", \"c0\" : {\"c1\" : true } }"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, inputJson11.c_str(), 0); + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"name\":\"doc6\"}", "{\"c0.c1\":false}", 1); + inputJson11 = "{\"name\":\"doc7\", \"c0\" : {\"c1\" : null } }"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, inputJson11.c_str(), 0); + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"name\":\"doc7\"}", "{\"c0.c1\":null}", 1); + inputJson11 = "{\"name\":\"doc8\", \"c0\" : [\"" + input + "\", 123]}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, inputJson11.c_str(), 0); + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"name\":\"doc8\"}", "{\"c0.0\":\"ac\"}", 1); +} + +void UpdateDocTwoFuzzTest(const char *newCollName, std::string s, const std::string &input) +{ + std::string inputJson11 = "{\"field5\": \"" + s + "\"}"; + GRD_UpDoc(g_datatest, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field5\": \"" + s + s + "\"}"; + GRD_UpDoc(g_datatest, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field1\": [\"field2\", {\"field3\":\"" + input + "\"}]}"; + GRD_UpDoc(g_datatest, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"name\":\"doc6\", \"c0\" : {\"c1\" : true } }"; + GRD_UpDoc(g_datatest, newCollName, "{\"name\":\"doc6\"}", inputJson11.c_str(), 1); + inputJson11 = "{\"name\":\"doc7\", \"c0\" : {\"c1\" : null } }"; + GRD_UpDoc(g_datatest, newCollName, "{\"name\":\"doc7\"}", inputJson11.c_str(), 1); + inputJson11 = "{\"name\":\"doc8\", \"c0\" : [\"" + input + "\", 123]}"; + GRD_UpDoc(g_datatest, newCollName, "{\"name\":\"doc8\"}", inputJson11.c_str(), 1); + + GRD_InsertDocument(g_datatest, COLLECT_NAME, inputJson11.c_str(), 0); + GRD_UpDoc(g_datatest, inputJson11.c_str(), "{}", "{}", 0); + GRD_UpDoc(g_datatest, newCollName, input.c_str(), "{}", 0); + GRD_UpDoc(g_datatest, newCollName, "{}", input.c_str(), 0); + GRD_UpDoc(nullptr, newCollName, "{}", "{}", 0); + inputJson11 = "{\"id\":\"2\", \"field\":" + input + "}"; + GRD_UpDoc(g_datatest, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field\":" + input + "}"; + GRD_UpDoc(g_datatest, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field1.field2.field3.field4.field5.field6\":" + input + "}"; + GRD_UpDoc(g_datatest, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field1\": {\"field2\": {\"field3\": {\"field4\": {\"field5\":" + input + "}}}}}"; + GRD_UpDoc(g_datatest, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + s.clear(); + for (int i = 0; i < ((ONE_BYTES * ONE_BYTES) - 1) - NUM_FIFTEEN; i++) { + s += 'a'; + } + inputJson11 = "{\"field5\": \"" + s + "\"}"; + GRD_UpDoc(g_datatest, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field5\": \"" + s + s + "\"}"; + GRD_UpDoc(g_datatest, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field1\": [\"field2\", {\"field3\":\"" + input + "\"}]}"; + GRD_UpDoc(g_datatest, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"name\":\"doc6\", \"c0\" : {\"c1\" : true } }"; + GRD_InsertDocument(g_datatest, newCollName, inputJson11.c_str(), 0); + GRD_UpDoc(g_datatest, newCollName, "{\"name\":\"doc6\"}", "{\"c0.c1\":false}", 1); + inputJson11 = "{\"name\":\"doc7\", \"c0\" : {\"c1\" : null } }"; + GRD_InsertDocument(g_datatest, newCollName, inputJson11.c_str(), 0); + GRD_UpDoc(g_datatest, newCollName, "{\"name\":\"doc7\"}", "{\"c0.c1\":null}", 1); + inputJson11 = "{\"name\":\"doc8\", \"c0\" : [\"" + input + "\", 123]}"; + GRD_InsertDocument(g_datatest, newCollName, inputJson11.c_str(), 0); + GRD_UpDoc(g_datatest, newCollName, "{\"name\":\"doc8\"}", "{\"c0.0\":\"ac\"}", 1); +} + +void UpdateDocFilterFuzzTest() +{ + const char *filt = "{\"id\" : \"1\"}"; + const char *updata2 = "{\"objectInfo.child.child\" : {\"child\":{\"child\":null}}}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, filt, updata2, 0); + + const char *filt1 = "{\"id\" : \"1\"}"; + const char *updata1 = "{\"id\" : \"6\"}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, filt1, updata1, 0); + + const char *filt2 = "{\"id\" : \"1\"}"; + const char *updata3 = "{\"age$\" : \"21\"}"; + const char *updata4 = "{\"bonus..traffic\" : 100}"; + const char *updata5 = "{\"0item\" : 100}"; + const char *updata6 = "{\"item\" : 1.79769313486232e308}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, filt2, updata3, 0); + GRD_UpDoc(g_datatest, COLLECT_NAME, filt2, updata4, 0); + GRD_UpDoc(g_datatest, COLLECT_NAME, filt2, updata5, 0); + GRD_UpDoc(g_datatest, COLLECT_NAME, filt2, updata6, 0); + + const char *filt3 = "{\"id\" : \"1\"}"; + const char *updata7 = "{\"age\" : 21}"; + GRD_UpDoc(g_datatest, NULL, filt3, updata7, 0); + GRD_UpDoc(g_datatest, "", filt3, updata7, 0); + GRD_UpDoc(NULL, COLLECT_NAME, filt3, updata7, 0); + GRD_UpDoc(g_datatest, COLLECT_NAME, NULL, updata7, 0); + GRD_UpDoc(g_datatest, COLLECT_NAME, filt3, NULL, 0); + GRD_DropCollect(g_datatest, COLLECT_NAME, 0); +} + +void UpdateDocFuzzTest(const uint8_t *data, size_t size) +{ + GRD_CreateCollect(g_datatest, COLLECT_NAME, OPTION_STRING, 0); + std::string input(reinterpret_cast(data), size); + std::string inputJson11 = "{\"id\":\"2\", \"field\": \"aaa\", " + "\"subject\":\"aaaaaaaaaaa\", \"test1\": true, " + "\"test2\": null}"; + + GRD_UpDoc(g_datatest, inputJson11.c_str(), "{}", "{}", 0); + GRD_UpDoc(g_datatest, COLLECT_NAME, input.c_str(), "{}", 0); + GRD_UpDoc(g_datatest, COLLECT_NAME, "{}", input.c_str(), 0); + GRD_UpDoc(nullptr, COLLECT_NAME, "{}", "{}", 0); + inputJson11 = "{\"id\":\"2\", \"field\":" + input + "}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field\":" + input + "}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field1.field2.field3.field4.field5.field6\":" + input + "}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field1\": {\"field2\": {\"field3\": {\"field4\": {\"field5\":" + input + "}}}}}"; + GRD_UpDoc(g_datatest, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + std::string s; + for (int i = 0; i < ((ONE_BYTES * ONE_BYTES) - 1) - NUM_FIFTEEN; i++) { + s += 'a'; + } + UpdateDocOneFuzzTest(s, input); + + const char *newCollName = "./student"; + GRD_UpDoc(g_datatest, inputJson11.c_str(), "{}", "{}", 0); + GRD_UpDoc(g_datatest, newCollName, input.c_str(), "{}", 0); + GRD_UpDoc(g_datatest, newCollName, "{}", input.c_str(), 0); + GRD_UpDoc(nullptr, newCollName, "{}", "{}", 0); + inputJson11 = "{\"id\":\"2\", \"field\":" + input + "}"; + GRD_UpDoc(g_datatest, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field\":" + input + "}"; + GRD_UpDoc(g_datatest, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field1.field2.field3.field4.field5.field6\":" + input + "}"; + GRD_UpDoc(g_datatest, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field1\": {\"field2\": {\"field3\": {\"field4\": {\"field5\":" + input + "}}}}}"; + GRD_UpDoc(g_datatest, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + s.clear(); + for (int i = 0; i < ((ONE_BYTES * ONE_BYTES) - 1) - NUM_FIFTEEN; i++) { + s += 'a'; + } + + UpdateDocTwoFuzzTest(newCollName, s, input); + UpdateDocFilterFuzzTest(); +} + +void UpsertNewFuzzTest(const std::string &input, GRD_DB *db1) +{ + GRD_CreateCollect(g_datatest, "student", "", 0); + std::string documentVirtualNew = + "{\"name\": {\"first\":[\"XXX\", \"BBB\", \"CCC\"], \"last\":\"moray\", \"field\":" + input + "}"; + std::string updateDocNew = R""({"name.last.AA.B":"Mnado"})""; + GRD_Upsert(g_datatest, "student", R""({"id":"10001"})"", documentVirtualNew.c_str(), 0); + GRD_Upsert(db1, "student", R""({"id":"10001"})"", updateDocNew.c_str(), 1); + GRD_DropCollect(g_datatest, "student", 0); + + GRD_CreateCollect(g_datatest, "student", "", 0); + documentVirtualNew = "{\"name\":[\"Tmn\", \"BB\", \"Alice\"], \"field\":" + input + "}"; + updateDocNew = R""({"name.first":"GG"})""; + GRD_Upsert(g_datatest, "student", R""({"id":"10002"})"", documentVirtualNew.c_str(), 0); + GRD_Upsert(db1, "student", R""({"id":"10002"})"", updateDocNew.c_str(), 1); +} + +void UpsertFuzzTest(const uint8_t *data, size_t size) +{ + GRD_CreateCollect(g_datatest, COLLECT_NAME, OPTION_STRING, 0); + std::string input(reinterpret_cast(data), size); + std::string inputJson11NoId = "{\"name\":\"doc8\", \"c0\" : [\"" + input + "\", 123]}"; + std::string inputJson11 = "{\"id\":\"1\", \"field\": " + input + "}"; + + GRD_InsertDocument(g_datatest, COLLECT_NAME, inputJson11.c_str(), 0); + GRD_Upsert(g_datatest, input.c_str(), "{}", "{}", 0); + GRD_Upsert(g_datatest, COLLECT_NAME, inputJson11.c_str(), "{}", 0); + inputJson11 = "{\"id\":\"1\", \"field\":" + input + "}"; + GRD_Upsert(g_datatest, COLLECT_NAME, "{\"id\":\"1\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"id\":\"1\", \"field\":\"" + input + "\"}"; + GRD_Upsert(g_datatest, COLLECT_NAME, "{\"id\":\"1\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field\":" + input + "}"; + GRD_Upsert(g_datatest, COLLECT_NAME, "{\"id\":\"1\"}", inputJson11.c_str(), 0); + GRD_Upsert(g_datatest, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + GRD_Upsert(g_datatest, COLLECT_NAME, "{\"id\":\"1\"}", inputJson11.c_str(), 1); + GRD_Upsert(g_datatest, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), 1); + GRD_Upsert(nullptr, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), 1); + GRD_Upsert(g_datatest, COLLECT_NAME, nullptr, inputJson11.c_str(), 1); + GRD_Upsert(g_datatest, COLLECT_NAME, "{\"id\":\"2\"}", inputJson11.c_str(), BATCH_COUNT); + + const char *newCollName = "./student"; + GRD_DB *db1 = nullptr; + GRD_CreateCollect(db1, newCollName, "", 0); + GRD_InsertDocument(db1, newCollName, inputJson11.c_str(), 0); + GRD_Upsert(db1, input.c_str(), "{}", "{}", 0); + GRD_Upsert(db1, newCollName, inputJson11.c_str(), "{}", 0); + inputJson11 = "{\"id\":\"1\", \"field\":" + input + "}"; + GRD_Upsert(db1, newCollName, "{\"id\":\"1\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"id\":\"1\", \"field\":\"" + input + "\"}"; + GRD_Upsert(db1, newCollName, "{\"id\":\"1\"}", inputJson11.c_str(), 0); + inputJson11 = "{\"field\":" + input + "}"; + GRD_Upsert(db1, newCollName, "{\"id\":\"1\"}", inputJson11.c_str(), 0); + GRD_Upsert(db1, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), 0); + GRD_Upsert(db1, newCollName, "{\"id\":\"1\"}", inputJson11.c_str(), 1); + GRD_Upsert(db1, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), 1); + GRD_Upsert(db1, newCollName, "{\"id\":\"newID1999\"}", inputJson11NoId.c_str(), 0); + GRD_Upsert(db1, newCollName, "{\"id\":\"newID1999a\"}", inputJson11NoId.c_str(), 1); + GRD_Upsert(nullptr, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), 1); + GRD_Upsert(db1, newCollName, nullptr, inputJson11.c_str(), 1); + GRD_Upsert(db1, newCollName, "{\"id\":\"2\"}", inputJson11.c_str(), BATCH_COUNT); + GRD_DropCollect(db1, newCollName, 0); + GRD_DropCollect(g_datatest, COLLECT_NAME, 0); + + UpsertNewFuzzTest(input, db1); +} + +void DelDocResultFuzzTest(const std::string &input) +{ + const char *filt = "{\"age\" : 15}"; + GRD_DelDoc(g_datatest, COLLECT_NAME, filt, 0); + const char *filt1 = "{\"id\" : \"1\", \"age\" : 15}"; + GRD_DelDoc(g_datatest, COLLECT_NAME, filt1, 0); + std::string filt2 = "{\"id\" : \"1\", \"name\" : " + input + "}"; + GRD_DelDoc(g_datatest, COLLECT_NAME, filt2.c_str(), 1); + GRD_DelDoc(g_datatest, NULL, filt2.c_str(), 0); + GRD_DelDoc(g_datatest, "", filt2.c_str(), 1); + GRD_DelDoc(g_datatest, COLLECT_NAME, filt2.c_str(), 0); + + const char *filt3 = "{\"id\" : \"1\"}"; + GRD_ResultSet *reSet = nullptr; + Query query = { filt3, "{}" }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); + GRD_DelDoc(g_datatest, COLLECT_NAME, filt3, 0); + + const char *filt4 = "{\"id\" : \"1\"}"; + std::string collectName1(LESS_HALF_BYTES, 'a'); + GRD_CreateCollect(g_datatest, collectName1.c_str(), "", 0); + GRD_DelDoc(g_datatest, collectName1.c_str(), filt4, 0); + GRD_DropCollect(g_datatest, collectName1.c_str(), 0); + GRD_FreeRe(reSet); + + GRD_DelDoc(NULL, COLLECT_NAME, filt2.c_str(), 0); + GRD_DelDoc(g_datatest, NULL, filt2.c_str(), 0); + GRD_DelDoc(g_datatest, "", filt2.c_str(), 0); + GRD_DelDoc(g_datatest, COLLECT_NAME, NULL, 0); + GRD_DelDoc(g_datatest, COLLECT_NAME, "", 0); + GRD_DelDoc(g_datatest, "notExisted", filt2.c_str(), 0); + + std::vector filtVec = { R"({"id" : 1})", R"({"id":[1, 2]})", R"({"id" : {"t1" : 1}})", + R"({"id":null})", R"({"id":true})", R"({"id" : 1.333})", R"({"id" : -2.0})" }; + for (const auto &item : filtVec) { + GRD_DelDoc(g_datatest, COLLECT_NAME, item.c_str(), 0); + } + GRD_DelDoc(g_datatest, COLLECT_NAME, filt2.c_str(), 0); + + std::string filt5 = "{\"subject.info\" : \"" + input + "\"}"; + reSet = nullptr; + query = { filt2.c_str(), "{}" }; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); + GRD_DelDoc(g_datatest, COLLECT_NAME, filt5.c_str(), 0); + GRD_DropCollect(g_datatest, COLLECT_NAME, 0); + GRD_FreeRe(reSet); +} + +void DelDocFuzzTest(const uint8_t *data, size_t size) +{ + GRD_CreateCollect(g_datatest, COLLECT_NAME, OPTION_STRING, 0); + std::string input(reinterpret_cast(data), size); + std::string inputJson11 = "{\"field\":" + input + "}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, inputJson11.c_str(), 0); + GRD_DelDoc(g_datatest, input.c_str(), "{}", 0); + GRD_DelDoc(g_datatest, nullptr, "{}", 0); + std::string longName = ""; + for (int i = 0; i < MORE_HALF_BYTES; i++) { + longName += 'a'; + } + GRD_DelDoc(g_datatest, "grd_name", "{}", 0); + GRD_DelDoc(g_datatest, longName.c_str(), "{}", 0); + GRD_DelDoc(g_datatest, COLLECT_NAME, inputJson11.c_str(), 0); + inputJson11 = "{\"field1\":" + input + "}"; + GRD_DelDoc(g_datatest, COLLECT_NAME, inputJson11.c_str(), 0); + inputJson11 = "{\"field\":\"" + input + "\"}"; + GRD_DelDoc(g_datatest, COLLECT_NAME, inputJson11.c_str(), 0); + inputJson11 = "{\"field1\":\"" + input + "\"}"; + GRD_DelDoc(g_datatest, COLLECT_NAME, inputJson11.c_str(), 0); + + const char *documentVirtual1 = "{ \ + \"id\" : \"1\", \ + \"name\": \"xiaoming\", \ + \"address\": \"beijing\", \ + \"age\" : 15, \ + \"friend\" : {\"name\" : \"David\", \"sex\" : \"female\", \"age\" : 90}, \ + \"subject\": [\"math\", \"English\", \"music\", {\"info\" : \"exam\"}] \ + }"; + const char *documentVirtual2 = "{ \ + \"id\" : \"2\", \ + \"name\": \"ori\", \ + \"address\": \"beijing\", \ + \"age\" : 15, \ + \"friend\" : {\"name\" : \"David\", \"sex\" : \"female\", \"age\" : 90}, \ + \"subject\": [\"math\", \"English\", \"music\"] \ + }"; + const char *documentVirtual3 = "{ \ + \"id\" : \"3\", \ + \"name\": \"David\", \ + \"address\": \"beijing\", \ + \"age\" : 15, \ + \"friend\" : {\"name\" : \"David\", \"sex\" : \"female\", \"age\" : 90}, \ + \"subject\": [\"Sing\", \"Jump\", \"Rap\", \"BasketBall\"] \ + }"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual1, 0); + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual2, 0); + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual3, 0); + GRD_DelDoc(g_datatest, COLLECT_NAME, "{}", 0); + + DelDocResultFuzzTest(input); +} + +namespace { +void FindAndRelease(Query query) +{ + GRD_ResultSet *reSet = nullptr; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 1, &reSet); + GRD_Next(reSet); + char *value = nullptr; + GRD_GetVal(reSet, &value); + GRD_FreeVal(value); + GRD_FreeRe(reSet); + reSet = nullptr; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 0, &reSet); + GRD_Next(reSet); + value = nullptr; + GRD_GetVal(reSet, &value); + GRD_FreeVal(value); + GRD_FreeRe(reSet); + + const char *newCollName = "./student"; + reSet = nullptr; + GRD_FindDocument(g_datatest, newCollName, query, 1, &reSet); + GRD_Next(reSet); + value = nullptr; + GRD_GetVal(reSet, &value); + GRD_FreeVal(value); + GRD_FreeRe(reSet); + reSet = nullptr; + GRD_FindDocument(g_datatest, newCollName, query, 0, &reSet); + GRD_Next(reSet); + value = nullptr; + GRD_GetVal(reSet, &value); + GRD_FreeVal(value); + GRD_FreeRe(reSet); +} +} // namespace + +void FindAndReleaseFuzzTest(std::string documentVirtual, std::string filt, Query query, const std::string &input) +{ + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual.c_str(), 0); + query.filt = filt.c_str(); + query.project = "{\"field\": 0}"; + FindAndRelease(query); + documentVirtual = "{\"field1.field2\" [false], \"field1.field2.field3\": [3], " + "\"field1.field4\": [null]}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual.c_str(), 0); + query.filt = documentVirtual.c_str(); + query.project = "{\"field\": 0}"; + FindAndRelease(query); + query.project = "{\"field\": 1}"; + FindAndRelease(query); + query.project = "{\"field.field2\": 1}"; + FindAndRelease(query); + documentVirtual = "{\"field1\": {\"field2\": [{\"field3\":\"" + input + "\"}]}}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, documentVirtual.c_str(), 0); + filt = "{\"field1.field2.field3\":\"" + input + "\"}"; + query.filt = filt.c_str(); + query.project = "{\"field1.field2\": 1}"; + FindAndRelease(query); + query.project = "{\"field1.field2\": 0}"; + FindAndRelease(query); + query.project = "{\"field1.field3\": 1}"; + FindAndRelease(query); + query.project = "{\"field1.field3\": 0}"; + FindAndRelease(query); + query.project = "{\"field1.field2.field3\": 0, \"field1.field2.field3\": 0}"; + FindAndRelease(query); + std::string project = "{\"field1\": \"" + input + "\"}"; + query.project = project.c_str(); + FindAndRelease(query); + project = "{\"" + input + "\": true, \"" + input + "\": false}"; + query.project = project.c_str(); + FindAndRelease(query); +} + +void NextFuzzTest(const uint8_t *data, size_t size) +{ + GRD_CreateCollect(g_datatest, COLLECT_NAME, OPTION_STRING, 0); + std::string input(reinterpret_cast(data), size); + std::string inputJson11 = "{" + input + "}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, inputJson11.c_str(), 0); + Query query = { inputJson11.c_str(), "{}" }; + FindAndRelease(query); + std::string stringJson2 = "{ \"id\":\"1\", \"field\":\"" + input + "\"}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, stringJson2.c_str(), 0); + query.filt = "{\"id\": \"1\"}"; + FindAndRelease(query); + std::string filt2 = "{ \"id\":\"1\", \"field\":\"" + input + " invalid\"}"; + query.filt = filt2.c_str(); + FindAndRelease(query); + query.filt = "{\"id\": \"3\"}"; + FindAndRelease(query); + std::string stringJson3 = "{ \"id\":\"2\", \"field\": [\"field2\", null, \"abc\", 123]}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, stringJson3.c_str(), 0); + query.filt = "{\"field\": [\"field2\", null, \"abc\", 123]}"; + FindAndRelease(query); + std::string documentVirtual = "{\"field\": [\"" + input + "\",\"" + input + "\",\"" + input + "\"]}"; + std::string filt = "{\"field." + std::to_string(size) + "\":\"" + input + "\"}"; + FindAndReleaseFuzzTest(documentVirtual, filt, query, input); + GRD_DropCollect(g_datatest, COLLECT_NAME, 0); +} + +void GetValueFuzzTest(const uint8_t *data, size_t size) +{ + GRD_CreateCollect(g_datatest, COLLECT_NAME, OPTION_STRING, 0); + std::string input(reinterpret_cast(data), size); + std::string inputJson11 = "{" + input + "}"; + GRD_InsertDocument(g_datatest, COLLECT_NAME, inputJson11.c_str(), 0); + char *value = nullptr; + Query query = { inputJson11.c_str(), "{}" }; + GRD_ResultSet *reSet = nullptr; + GRD_FindDocument(g_datatest, COLLECT_NAME, query, 1, &reSet); + GRD_GetVal(reSet, &value); + GRD_Next(reSet); + GRD_GetVal(reSet, &value); + GRD_FreeVal(value); + GRD_FreeRe(reSet); + GRD_DropCollect(g_datatest, COLLECT_NAME, 0); +} + +void FreeReFuzzTest() +{ + GRD_ResultSet *reSet = nullptr; + GRD_FreeRe(reSet); + reSet = new GRD_ResultSet; + reSet->reSet_ = DocumentDB::ResultSet(); + GRD_FreeRe(reSet); + GRD_DropCollect(g_datatest, COLLECT_NAME, 0); +} + +void DbOpenCloseFuzzTest(const char *dbFileVal, const char *configStr, GRD_DB *dbVal) +{ + int ret = GRD_DBOpen(dbFileVal, configStr, GRD_OPEN_CREATE, &dbVal); + if (ret == GRD_OK) { + GRD_DBClose(dbVal, GRD_CLOSE); + } +} + +void DbOpenOneFuzzTest(GRD_DB *dbVal) +{ + std::string path = "./documentVirtualFuzzTest.db"; + int ret = GRD_DBOpen(path.c_str(), "", GRD_DB_OPEN_ONLY, &dbVal); + if (ret == GRD_OK) { + GRD_DBClose(dbVal, GRD_CLOSE); + } + (void)remove(path.c_str()); + + path = "./documentVirtual.db"; + DbOpenCloseFuzzTest(path.c_str(), R""({"pageSize":64, "redopubbufsize":4033})"", dbVal); + DbOpenCloseFuzzTest(path.c_str(), R""({"pageSize":64, "redopubbufsize":4032})"", dbVal); + DbOpenCloseFuzzTest(path.c_str(), R""({"redopubbufsize":255})"", dbVal); + DbOpenCloseFuzzTest(path.c_str(), R""({"redopubbufsize":16385})"", dbVal); +} + +void DbOpenFuzzTestTest(const uint8_t *data, size_t size) +{ + std::string dbFileData(reinterpret_cast(data), size); + std::string realDbFileData = DB_DIR_PATH + dbFileData; + const char *dbFileVal = realDbFileData.data(); + std::string configStrData(reinterpret_cast(data), size); + const char *configStrVal = configStrData.data(); + GRD_DB *dbVal = nullptr; + + GRD_DropCollect(g_datatest, COLLECT_NAME, 0); + std::string stringMax = getMaxString(); + const char *configStrMaxLen = stringMax.data(); + DbOpenCloseFuzzTest(dbFileVal, configStrMaxLen, dbVal); + + std::string fieldStringValue = "{\"bufferPoolSize\": \"1024.5\"}"; + const char *configStrStringValue = fieldStringValue.data(); + DbOpenCloseFuzzTest(dbFileVal, configStrStringValue, dbVal); + + std::string fieldBoolValue = "{\"bufferPoolSize\":}"; + const char *configStrBool = fieldBoolValue.data(); + DbOpenCloseFuzzTest(dbFileVal, configStrBool, dbVal); + + std::string fieldStringValueAppend = "{\"bufferPoolSize\":\"8192\"}"; + const char *configStrStr = fieldStringValueAppend.data(); + DbOpenCloseFuzzTest(dbFileVal, configStrStr, dbVal); + + std::string fieldStringValueFlush = "{\"bufferPoolSize\":\"8192\",\"redoFlushBtTrx\":\"1\"}"; + const char *configStrFlush = fieldStringValueFlush.data(); + DbOpenCloseFuzzTest(dbFileVal, configStrFlush, dbVal); + + std::string fieldStringValueRedoBufsize = "{\"bufferPoolSize\":\"8192\",\"redoBufSize\":\"16384\"}"; + const char *configStrBs = fieldStringValueRedoBufsize.data(); + DbOpenCloseFuzzTest(dbFileVal, configStrBs, dbVal); + + std::string fieldStringValueMaxConnNum = "{\"bufferPoolSize\":\"8192\",\"maxConnNum\":\"1024\"}"; + const char *configStrMcn = fieldStringValueMaxConnNum.data(); + DbOpenCloseFuzzTest(dbFileVal, configStrMcn, dbVal); + + GRD_DropCollect(g_datatest, COLLECT_NAME, 0); + std::string fieldStringValueAll = "{\"bufferPoolSize\":\"8192\",\"redoFlushBtTrx\":\"1\",\"redoBufSize\":" + "\"16384\",\"maxConnNum\":\"1024\"}"; + const char *configStrAll = fieldStringValueAll.data(); + DbOpenCloseFuzzTest(dbFileVal, configStrAll, dbVal); + + std::string fieldLowNumber = "{\"bufferPoolSize\": 102}"; + const char *configStrLowNumber = fieldLowNumber.data(); + DbOpenCloseFuzzTest(dbFileVal, configStrLowNumber, dbVal); + + int ret = GRD_DBOpen(nullptr, configStrVal, GRD_OPEN_CREATE, &dbVal); + if (ret == GRD_OK) { + GRD_DBClose(nullptr, GRD_CLOSE); + } + DbOpenCloseFuzzTest(dbFileVal, configStrVal, dbVal); + + DbOpenOneFuzzTest(dbVal); +} + +void DbCloseFuzzTest(const uint8_t *data, size_t size) +{ + std::string dbFileData(reinterpret_cast(data), size); + std::string realDbFileData = DB_DIR_PATH + dbFileData; + const char *dbFileVal = realDbFileData.data(); + std::string configStrData(reinterpret_cast(data), size); + const char *configStrVal = configStrData.data(); + GRD_DB *dbVal = nullptr; + DbOpenCloseFuzzTest(dbFileVal, configStrVal, dbVal); +} + +void DbCloseResultSetFuzzTest() +{ + GRD_DB *db = nullptr; + GRD_DB *db2 = nullptr; + int ret = GRD_DBOpen(TEST_FILE, CONFIG_STRING, GRD_OPEN_CREATE, &db); + int errCode = GRD_DBOpen(TEST_FILE, CONFIG_STRING, GRD_OPEN_CREATE, &db2); + if (ret == GRD_OK) { + GRD_CreateCollect(db, "collection1", "{\"maxdoc\" : 5}", 0); + + GRD_ResultSet *reSet = nullptr; + Query query = { "{}", "{}" }; + GRD_FindDocument(db, "collection1", query, 0, &reSet); + + GRD_FreeRe(reSet); + + GRD_DBClose(db, GRD_CLOSE); + } + + if (errCode == GRD_OK) { + GRD_DBClose(db2, GRD_CLOSE); + } +} + +void CreateCollectionFuzzTest(const uint8_t *data, size_t size) +{ + std::string collectNameData(reinterpret_cast(data), size); + const char *collectNameVal = collectNameData.data(); + std::string optionStrData(reinterpret_cast(data), size); + const char *optionStrVal = optionStrData.data(); + GRD_CreateCollect(nullptr, collectNameVal, optionStrVal, 0); + GRD_CreateCollect(g_datatest, collectNameVal, optionStrVal, 0); + const char *optionStr = nullptr; + GRD_CreateCollect(g_datatest, COLLECT_NAME, optionStr, 0); + GRD_CreateCollect(g_datatest, COLLECT_NAME, "{\"maxdoc\":5, \"unexpected_max_doc\":32}", 0); + GRD_CreateCollect(g_datatest, COLLECT_NAME, "{}", 0); + GRD_DropCollect(g_datatest, COLLECT_NAME, 0); + std::string optStr = "{\"maxdoc\":" + optionStrData + "}"; + GRD_CreateCollect(g_datatest, COLLECT_NAME, optStr.c_str(), 0); + GRD_DropCollect(g_datatest, COLLECT_NAME, 0); + GRD_CreateCollect(g_datatest, COLLECT_NAME, optStr.c_str(), MAX_SIZE_NUM_TEST); + optStr = "{\"maxdoc\": 5}"; + GRD_CreateCollect(g_datatest, COLLECT_NAME, optStr.c_str(), 0); + GRD_CreateCollect(g_datatest, COLLECT_NAME, optStr.c_str(), 1); + GRD_DropCollect(g_datatest, COLLECT_NAME, 0); + GRD_DropCollect(g_datatest, COLLECT_NAME, MAX_SIZE_NUM_TEST); + GRD_DropCollect(g_datatest, collectNameVal, 0); +} + +void DropCollectFuzzTest(const uint8_t *data, size_t size) +{ + std::string collectNameData(reinterpret_cast(data), size); + const char *collectNameVal = collectNameData.data(); + std::string optionStrData(reinterpret_cast(data), size); + const char *optionStrVal = optionStrData.data(); + GRD_CreateCollect(g_datatest, collectNameVal, optionStrVal, 0); + GRD_DropCollect(nullptr, collectNameVal, 0); + GRD_DropCollect(g_datatest, collectNameVal, 0); +} + +void DbFlushFuzzTest(const uint8_t *data, size_t size) +{ + if (data == nullptr) { + return; + } + GRD_DB *db = nullptr; + GRD_DB *db2 = nullptr; + const uint32_t flags = *data; + int ret = GRD_DBOpen(TEST_FILE, CONFIG_STRING, GRD_OPEN_CREATE, &db); + if (ret == GRD_OK) { + GRD_Flush(db, flags); + GRD_DBClose(db, GRD_CLOSE); + } + GRD_Flush(db2, flags); +} + +void TestGrdDbApGrdGetItem002FuzzTest() +{ + const char *config = CONFIG_STRING; + GRD_DB *db = nullptr; + DbOpenCloseFuzzTest(TEST_FILE, config, db); + GRD_Preload(nullptr, COLLECT_NAME); + GRD_Preload(nullptr, "invalid_name"); + GRD_Preload(g_datatest, COLLECT_NAME); + std::string smallPrefix = std::string(SMALL_PREFIX_LENGTH, 'a'); + for (uint32_t i = 0; i < NUM_NINETY_EIGHT; ++i) { + std::string v = smallPrefix + std::to_string(i); + GRD_KVItem key = { &i, sizeof(uint32_t) }; + GRD_KVItem value = { reinterpret_cast(v.data()), static_cast(v.size()) + 1 }; + GRD_KVPut(g_datatest, COLLECT_NAME, &key, &value); + + GRD_KVItem getValue = { nullptr, 0 }; + GRD_KVGet(g_datatest, COLLECT_NAME, &key, &getValue); + GRD_KVFreeItem(&getValue); + + GRD_KVDel(g_datatest, COLLECT_NAME, &key); + } + GRD_Flush(g_datatest, 1); + + uint32_t begin = 0, end = MAX_SIZE_NUM_TEST; + GRD_FilterOptionT option = {}; + option.mode = KV_SCAN_RANGE; + option.begin = { &begin, sizeof(uint32_t) }; + option.end = { &end, sizeof(uint32_t) }; + GRD_ResultSet *reSet = nullptr; + GRD_KVFilter(g_datatest, COLLECT_NAME, &option, &reSet); + + uint32_t keySize, valueSize; + GRD_KVGetSize(reSet, &keySize, &valueSize); + + reSet = nullptr; + uint32_t i = 32; + GRD_KVItem key = { &i, sizeof(uint32_t) }; + GRD_KVScan(g_datatest, COLLECT_NAME, &key, KV_SCAN_EQUAL_OR_LESS_KEY, &reSet); + + GRD_Prev(reSet); + GRD_Next(reSet); + + GRD_FreeRe(reSet); +} + +void TestGrdKvBatchCoupling003FuzzTest() +{ + const char *config = CONFIG_STRING; + GRD_DB *db = nullptr; + DbOpenCloseFuzzTest(TEST_FILE, config, db); + + GRD_ResultSet *reSet = nullptr; + GRD_KVScan(g_datatest, COLLECT_NAME, nullptr, KV_SCAN_PREFIX, &reSet); + + for (uint32_t i = 0; i < CURSOR_COUNT_TEST; i++) { + GRD_Next(reSet); + } + + GRD_KVBatchT *batchDel = nullptr; + std::vector keySet; + std::vector valueSet; + for (uint32_t i = 0; i < VECTOR_SIZE; i++) { + std::string key(MAX_SIZE_NUM_TEST, 'a'); + key += std::to_string(i); + keySet.emplace_back(key); + std::string value = std::to_string(i); + valueSet.emplace_back(value); + } + + for (int j = 0; j < BATCH_COUNT; j++) { + GRD_KVBatchPrepare(BATCH_COUNT, &batchDel); + GRD_KVBatchPut(g_datatest, COLLECT_NAME, batchDel); + for (uint16_t i = 0; i < BATCH_COUNT; i++) { + char *batchKey = const_cast(keySet[CURSOR_COUNT_TEST + j * BATCH_COUNT + i].c_str()); + char *batchValue = const_cast(valueSet[CURSOR_COUNT_TEST + j * BATCH_COUNT + i].c_str()); + GRD_KVBatchPushback(static_cast(batchKey), + static_cast(keySet[CURSOR_COUNT_TEST + j * BATCH_COUNT + i].length()) + 1, + static_cast(batchValue), + static_cast(valueSet[CURSOR_COUNT_TEST + j * BATCH_COUNT + i].length()) + 1, + batchDel); + } + + GRD_KVBatchDel(g_datatest, COLLECT_NAME, batchDel); + + GRD_KVBatchDestroy(batchDel); + } + + GRD_Next(reSet); + GRD_KVItem keyItem = { nullptr, 0 }; + GRD_KVItem valueItem = { nullptr, 0 }; + GRD_Fetch(reSet, &keyItem, &valueItem); + GRD_KVFreeItem(&keyItem); + GRD_KVFreeItem(&valueItem); + GRD_FreeRe(reSet); +} +} // namespace OHOS + +/* FuzzTester entry point */ +extern "C" { +int LLVMFuzzTesterTestOneInput(const uint8_t *data, size_t size) +{ + /* Run your code on data */ + OHOS::SetUpTestCase(); + + OHOS::DbOpenFuzzTestTest(data, size); + OHOS::CreateCollectionFuzzTest(data, size); + OHOS::DropCollectFuzzTest(data, size); + OHOS::InsertDocFuzzTest(data, size); + OHOS::FindDocumentFuzzTest(data, size); + OHOS::UpdateDocFuzzTest(data, size); + OHOS::UpsertFuzzTest(data, size); + OHOS::DelDocFuzzTest(data, size); + OHOS::NextFuzzTest(data, size); + OHOS::GetValueFuzzTest(data, size); + OHOS::FreeReFuzzTest(); + OHOS::TestGrdDbApGrdGetItem002FuzzTest(); + OHOS::TestGrdKvBatchCoupling003FuzzTest(); + OHOS::DbCloseFuzzTest(data, size); + OHOS::DbCloseResultSetFuzzTest(); + OHOS::DbFlushFuzzTest(data, size); + + OHOS::TearDownTestCase(); + return 0; +} +} diff --git a/kv_store/test/fuzztest/jsonservice_fuzzer/jsonservice_fuzzer.h b/kv_store/test/fuzztest/jsonservice_fuzzer/jsonservice_fuzzer.h new file mode 100644 index 0000000000000000000000000000000000000000..af5feb8c9cef1cfedaea4faa2da7f8a02d0e38e7 --- /dev/null +++ b/kv_store/test/fuzztest/jsonservice_fuzzer/jsonservice_fuzzer.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 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 JSON_FUZZER_H +#define JSON_FUZZER_H + +#define FUZZ_PROJECT_NAME "Json_fuzzer" + +#endif // JSON_FUZZER_H \ No newline at end of file diff --git a/kv_store/test/fuzztest/jsonservice_fuzzer/project.xml b/kv_store/test/fuzztest/jsonservice_fuzzer/project.xml new file mode 100644 index 0000000000000000000000000000000000000000..73736f01a8820f5deb20590a5655e6fbe62b6aa6 --- /dev/null +++ b/kv_store/test/fuzztest/jsonservice_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 1800 + + 4096 + + diff --git a/kv_store/test/fuzztest/kvsync_fuzzer/BUILD.gn b/kv_store/test/fuzztest/kvsync_fuzzer/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..7e65b4a2b28c6dd42c1b22824edfe990edb87068 --- /dev/null +++ b/kv_store/test/fuzztest/kvsync_fuzzer/BUILD.gn @@ -0,0 +1,130 @@ +# Copyright (c) 2024 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. + +#####################hydra-fuzz################### +import("//build/config/features.gni") +import("//build/test.gni") +import("../../../distributeddb.gni") + +##############################fuzztest########################################## +ohos_fuzztest("KvsyncFuzzTest") { + module_out_path = "kv_store/kv_store" + + include_dirs = [ + "../../../test/fuzztest/common", + "../../../test/unittest/common/common", + "../../../test/unittest/common/syncer", + "../../../test/unittest/common/syncer/kv", + "../../../test/unittest/common/storage", + "../../../include", + "../../../interfaces/include", + "../../../interfaces/include/kv", + "../../../interfaces/include/relational", + "../../../interfaces/src", + "../../../interfaces/src/relational", + "../../../storage/include", + "../../../storage/src", + "../../../storage/src/kv", + "../../../storage/src/kv", + "../../../storage/src/gaussdb_rd", + "../../../storage/src/multiver", + "../../../storage/src/operation", + "../../../storage/src/relational", + "../../../storage/src/sqlite", + "../../../storage/src/sqlite/kv", + "../../../storage/src/sqlite/relational", + "../../../storage/src/upgrader", + "../../../common/include", + "../../../common/include/kv", + "../../../common/include/relational", + "../../../common/src", + "../../../common/src/kv", + "../../../communicator/include", + "../../../communicator/src", + "../../../syncer/include", + "../../../syncer/src", + "../../../syncer/src/kv", + "../../../syncer/src/device", + "../../../syncer/src/device/multiver", + "../../../syncer/src/device/singlever", + ] + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + "--coverage", + ] + + ldflags = [ "--coverage" ] + + cflags_cc = [ "--coverage" ] + + fuzz_config_file = "../kvsync_fuzzer" + + sources = distributeddb_src + sources += [ + "../../../test/fuzztest/common/distributeddb_tools_test.cpp", + "../../../test/fuzztest/common/fuzzer_data.cpp", + "../../../test/fuzztest/kvsync_fuzzer/kvsync_fuzzer.cpp", + "../../../test/unittest/common/common/distributeddb_data_generate_unit_test.cpp", + "../../../test/unittest/common/syncer/kv/virtual_asset_loader.cpp", + "../../../test/unittest/common/syncer/kv/virtual_kv_data_translate.cpp", + "../../../test/unittest/common/syncer/kv/virtual_kv_db.cpp", + ] + + defines = [ + "SQLITE_ENABLE_SNAPSHOT", + "_LARGEFILE64_SOURCE", + "_FILE_OFFSET_BITS=64", + "SQLITE_HAS_CODEC", + "SQLITE_ENABLE_JSON1", + "USING_HILOG_LOGGER", + "USE_SQLITE_SYMBOLS", + "USING_DB_JSON_EXTRACT_AUTOMATICALLY", + "LOW_LEVEL_MEM_DEV", + "JSONCPP_USE_BUILDER", + "OMIT_FLATBUFFER", + "OMIT_MULTI_VER", + "RELATIONAL_STORE", + "SQLITE_DISTRIBUTE_RELATIONAL", + "SQLITE_EXPORT_SYMBOLS", + "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "OPENSSL_SUPPRESS_DEPRECATED", + ] + + deps = [ + "../../../../distributeddb:distributeddb", + "//third_party/jsoncpp:jsoncpp", + "//third_party/openssl:libcrypto_shared", + "//third_party/sqlite:sqlite", + ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "zlib:shared_libz", + ] +} + +############################################################################### + +group("fuzztest") { + testonly = true + deps = [] + deps += [ + # deps file + ":KvsyncFuzzTest", + ] +} diff --git a/kv_store/test/fuzztest/kvsync_fuzzer/corpus/init b/kv_store/test/fuzztest/kvsync_fuzzer/corpus/init new file mode 100644 index 0000000000000000000000000000000000000000..e4ceac1bcd4e3b3427eb63cea0c28304064333cc --- /dev/null +++ b/kv_store/test/fuzztest/kvsync_fuzzer/corpus/init @@ -0,0 +1,14 @@ +# 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. + +FUZZ \ No newline at end of file diff --git a/kv_store/test/fuzztest/kvsync_fuzzer/kvsync_fuzzer.cpp b/kv_store/test/fuzztest/kvsync_fuzzer/kvsync_fuzzer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..239478304543430b8acd92552922ffd4e7533d9b --- /dev/null +++ b/kv_store/test/fuzztest/kvsync_fuzzer/kvsync_fuzzer.cpp @@ -0,0 +1,561 @@ +/* + * 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 "kvsync_fuzzer.h" +#include "kv/kv_dbtypes.h" +#include "kv/kv_dbconstant.h" +#include "distributeddbvData_generate_unit_test.h" +#include "distributeddbtools_test.h" +#include "fuzzer_vData.h" +#include "kv_store_nb_kvDelegate.h" +#include "logprint.h" +#include "relational_store_kvDelegate.h" +#include "relational_store_manager.h" +#include "runtime_kvConfig.h" +#include "time_helper.h" +#include "virtual_assetTest_loader.h" +#include "virtual_kv_vData_translate.h" +#include "virtual_kv_db.h" + +namespace OHOS { +using namespace DistributedDB; +using namespace DistributedDBTest; + +static constexpr const int MOD = 1000; // 1000 is mod +class KvSyncContext { +public: + void WaitForFinishTest() + { + std::unique_lock unique(mutex); + LOGI("begin wait"); + cv.wait_for(unique, std::chrono::milliseconds(DBConstant::MAX_TIMEOUT), [this]() { + return finished; + }); + LOGI("end wait"); + } + + void FinishAndNotifyTest() + { + { + std::lock_guard autoLock(mutex); + finished = true; + } + cv.notify_one(); + } + +private: + std::condition_variable cv; + std::mutex mutex; + bool finished = false; +}; +class KvSyncTest { +public: + static void ExecSqlFuzz(sqlite3 *db, const std::string &sql) + { + if (db == nullptr || sql.empty()) { + return; + } + int errCodeTest = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, nullptr); + if (errCodeTest != SQLITE_OK) { + LOGE("Execute sql failed. err: %d", errCodeTest); + } + } + + static void CreateTableFuzz(sqlite3 *&db) + { + ExecSqlFuzz(db, "PRAGMA journal_modeTest=WAL;"); + ExecSqlFuzz(db, gcreateLocalTableSql); + } + + static void SetKvDbSchemaFuzz(RelationalStoreDelegate *kvDelegate) + { + DataBaseSchema vDataSchema; + const std::vector kvFiled = { + {"name", TYPE_INDEX, true}, {"height", TYPE_INDEX}, + {"married", TYPE_INDEX}, {"photoTest", TYPE_INDEX, false, false}, + {"assert", TYPE_INDEX}, {"asserts", TYPE_INDEX}, {"age", TYPE_INDEX} + }; + TableSchema tableSchemaTest = { + .name = gtable, + .fieldTests = kvFiled + }; + vDataSchema.tables.push_back(tableSchemaTest); + kvDelegate->SetKvDbSchemaFuzz(vDataSchema); + kvDelegate->CreateDistributedTable(gtable, CLOUD_COOPERATION); + } + + static void InitDbData(sqlite3 *&db, const uint8_t *vData, size_t size) + { + sqlite3_stmt *stmt = nullptr; + int errCodeTest = SQLiteUtils::GetStatement(db, ginsertLocalDataSql, stmt); + if (errCodeTest != E_OK) { + return; + } + FuzzerData fuzzerDataTest(vData, size); + uint32_t len = fuzzerDataTest.GetUInt32() % MOD; + for (size_t i = 0; i <= size; ++i) { + std::string idStr = fuzzerDataTest.GetString(len); + errCodeTest = SQLiteUtils::BindTextToStatement(stmt, 1, idStr); + if (errCodeTest != E_OK) { + break; + } + std::vector photoTest = fuzzerDataTest.GetSequence(fuzzerDataTest.GetInt()); + errCodeTest = SQLiteUtils::BindBlobToStatement(stmt, 2, photoTest); // 2 is index of photoTest + if (errCodeTest != E_OK) { + break; + } + errCodeTest = SQLiteUtils::StepWithRetry(stmt); + if (errCodeTest != SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + break; + } + SQLiteUtils::ResetStatement(stmt, false, errCodeTest); + } + SQLiteUtils::ResetStatement(stmt, true, errCodeTest); + } + + static Asset GenAsset(const std::string &name, const std::string &hash) + { + Asset assetTest; + assetTest.name = name; + assetTest.hash = hash; + return assetTest; + } + + void InitDbAssetFuzz(const uint8_t *vData, size_t size) + { + if (vData == nullptr || size == 0) { + return; + } + sqlite3_stmt *stmt = nullptr; + int errCodeTest = SQLiteUtils::GetStatement(db, ginsertLocalAssetSql, stmt); + if (errCodeTest != E_OK) { + return; + } + FuzzerData fuzzerDataTest(vData, size); + uint32_t len = fuzzerDataTest.GetUInt32() % MOD; + for (size_t i = 0; i <= size; ++i) { + std::string idStr = fuzzerDataTest.GetString(len); + errCodeTest = SQLiteUtils::BindTextToStatement(stmt, 1, idStr); + if (errCodeTest != E_OK) { + break; + } + std::vector photoTest = fuzzerDataTest.GetSequence(fuzzerDataTest.GetInt()); + errCodeTest = SQLiteUtils::BindBlobToStatement(stmt, 2, photoTest); // 2 is index of photoTest + if (errCodeTest != E_OK) { + break; + } + std::vector assetTest; + RuntimeContext::GetInstance()->AssetToBlob(localAssets[i % size], assetTest); + errCodeTest = SQLiteUtils::BindBlobToStatement(stmt, 3, assetTest); // 3 is index of assert + if (errCodeTest != E_OK) { + break; + } + + std::vector assetTestVec(localAssets.begin() + (i % size), localAssets.end()); + RuntimeContext::GetInstance()->AssetsToBlob(assetTestVec, assetTest); + errCodeTest = SQLiteUtils::BindBlobToStatement(stmt, 4, assetTest); // 4 is index of asserts + if (errCodeTest != E_OK) { + break; + } + errCodeTest = SQLiteUtils::StepWithRetry(stmt); + if (errCodeTest != SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + break; + } + SQLiteUtils::ResetStatement(stmt, false, errCodeTest); + } + SQLiteUtils::ResetStatement(stmt, true, errCodeTest); + } + + void InsertKvTableRecordFuzz(int64_t begin, int64_t count, int64_t photoTestSize, bool assetTestIsNull) + { + std::vector photoTest(photoTestSize, 'v'); + std::vector record1; + std::vector extend1; + double randomHeight = 166.0; // 166.0 is random double value + int64_t randomAge = 13L; // 13 is random int64_t value + Timestamp now = TimeHelper::GetSysCurrentTime(); + for (int64_t i = begin; i < begin + count; ++i) { + VBucket vData; + vData.insert_or_assign("name", "Kv" + std::to_string(i)); + vData.insert_or_assign("height", randomHeight); + vData.insert_or_assign("married", false); + vData.insert_or_assign("photoTest", photoTest); + vData.insert_or_assign("age", randomAge); + Asset assetTest = gkvAsset; + assetTest.name = assetTest.name + std::to_string(i); + assetTestIsNull ? vData.insert_or_assign("assert", Nil()) : vData.insert_or_assign("assert", assetTest); + record1.push_back(vData); + VBucket log; + log.insert_or_assign(KvDbConstant::CREATE_FIELD, + static_cast(now / KvDbConstant::TEN_THOUSAND + i)); + log.insert_or_assign(KvDbConstant::MODIFY_FIELD, + static_cast(now / KvDbConstant::TEN_THOUSAND + i)); + log.insert_or_assign(KvDbConstant::DELETE_FIELD, false); + extend1.push_back(log); + } + examKvDb->BatchInsert(gtable, std::move(record1), extend1); + LOGD("insert kv record worker1[primary key]:[kv%" PRId64 " - kv%" PRId64 ")", begin, count); + std::this_thread::sleep_for(std::chrono::milliseconds(count)); + } + + void SetUp() + { + DistributedDBToolsTest::TestDirInit(testDir); + storePathTest = testDir + "/" + gstoreId + gdbSuffix; + LOGI("The test db is:%s", testDir.c_str()); + RuntimeConfig::SetKvTranslate(std::make_shared()); + LOGD("Test dir is %s", testDir.c_str()); + db = RdbTestUtils::CreateDataBase(storePathTest); + if (db == nullptr) { + return; + } + CreateTableFuzz(db); + mgr = std::make_shared("APP_ID", "USER_ID"); + RelationalStoreDelegate::Option optionTest; + mgr->OpenStore(storePathTest, "STORE_ID", optionTest, kvDelegate); + gKvSyncOption.modeTest = SyncMode::SYNC_MODE_CLOUD_MERGE; + gKvSyncOption.users.push_back(DistributedDBUnitTest::USER_ID); + gKvSyncOption.devices.push_back("kv"); + kvConfig.vDataDir = testDir; + gmgr.SetKvStoreConfig(kvConfig); + KvStoreNbDelegate::Option optionTest1; + GetKvStoreFuzz(kvDelegatePtrS1, DistributedDBUnitTest::STORE_ID_1, optionTest1); + KvStoreNbDelegate::Option optionTest2; + GetKvStoreFuzz(kvDelegatePtrS2, DistributedDBUnitTest::STORE_ID_2, optionTest2); + examKvDb = std::make_shared(); + examKvDb1 = std::make_shared(); + examKvDb2 = std::make_shared(); + virtualAssetLoader = std::make_shared(); + kvDelegate->SetKvDB(examKvDb); + kvDelegate->SetIAssetLoader(virtualAssetLoader); + } + + void TearDown() + { + if (kvDelegate != nullptr) { + DBStatus errCodeTest = mgr->CloseStore(kvDelegate); + LOGI("kvDelegate close with errCodeTest %d", static_cast(errCodeTest)); + kvDelegate = nullptr; + } + if (db != nullptr) { + int errCodeTest = sqlite3_close_v2(db); + LOGI("sqlite close with errCodeTest %d", errCodeTest); + } + examKvDb = nullptr; + CloseKvStoreFuzz(kvDelegatePtrS1, DistributedDBUnitTest::STORE_ID_1); + CloseKvStoreFuzz(kvDelegatePtrS2, DistributedDBUnitTest::STORE_ID_2); + examKvDb1 = nullptr; + examKvDb2 = nullptr; + virtualAssetLoader = nullptr; + if (DistributedDBToolsTest::RemoveTestDbFiles(testDir) != 0) { + LOGE("rm test db files error."); + } + } + + void KvBlockSyncFuzz(KvStoreNbDelegate *kvDelegate, DBStatus expectDBStatus, KvSyncOption optionTest, + int expectSyncResult = OK) + { + if (kvDelegate == nullptr) { + return; + } + std::mutex virDataMutex; + std::condition_variable cv; + bool finish = false; + SyncProcess last; + auto callback = [expectDBStatus, &last, &cv, &virDataMutex, &finish, &optionTest]( + const std::map &process) { + size_t notifyCnt = 0; + for (const auto &item : process) { + LOGD("user = %s, dbStatus = %d", item.first.c_str(), item.second.process); + if (item.second.process != DistributedDB::FINISHED) { + continue; + } + { + std::lock_guard autoLock(virDataMutex); + notifyCnt++; + std::set userSet(optionTest.users.begin(), optionTest.users.end()); + if (notifyCnt == userSet.size()) { + finish = true; + last = item.second; + cv.notify_one(); + } + } + } + }; + auto result = kvDelegate->Sync(optionTest, callback); + if (result == OK) { + std::unique_lock unique(virDataMutex); + cv.wait(unique, [&finish]() { + return finish; + }); + } + lastProcess = last; + } + + static DataBaseSchema GetDataBaseSchema(bool invalidSchema) + { + DataBaseSchema schemaTest; + TableSchema tableSchemaTest; + tableSchemaTest.name = invalidSchema ? "invalid_schemaTest_name" : KvDbConstant::CLOUD_KV_TABLE_NAME; + Field fieldTest; + fieldTest.colName = KvDbConstant::CLOUD_KV_FIELD_KEY; + fieldTest.type = TYPE_INDEX; + fieldTest.primary = true; + fieldTest.colName = KvDbConstant::CLOUD_KV_FIELD_DEVICE; + fieldTest.primary = false; + tableSchemaTest.fieldTests.push_back(fieldTest); + tableSchemaTest.fieldTests.push_back(fieldTest); + fieldTest.colName = KvDbConstant::CLOUD_KV_FIELD_ORI_DEVICE; + tableSchemaTest.fieldTests.push_back(fieldTest); + fieldTest.colName = KvDbConstant::CLOUD_KV_FIELD_VALUE; + tableSchemaTest.fieldTests.push_back(fieldTest); + fieldTest.colName = KvDbConstant::CLOUD_KV_FIELD_DEVICE_CREATE_TIME; + fieldTest.type = TYPE_INDEX; + tableSchemaTest.fieldTests.push_back(fieldTest); + schemaTest.tables.push_back(tableSchemaTest); + return schemaTest; + } + + void GetKvStoreFuzz(KvStoreNbDelegate *&kvDelegate, const std::string &storeId, KvDelegate::Option optionTest, + int securityLabel = NOT_SET, bool invalidSchema = false) + { + DBStatus openRet = OK; + optionTest.secOption.securityLabel = securityLabel; + gmgr.GetKvStoreFuzz(storeId, optionTest, [&openRet, &kvDelegate](KvStoreNbDelegate *openDelegate) { + openRet = dbStatus; + kvDelegate = openDelegate; + }); + if (kvDelegate == nullptr) { + return; + } + std::map schemaTests; + schemaTests[DistributedDBUnitTest::USER_ID] = GetDataBaseSchema(invalidSchema); + schemaTests[USER_ID] = GetDataBaseSchema(invalidSchema); + kvDelegate->SetKvDbSchemaFuzz(schemaTests); + std::map> kvDbs; + kvDbs[DistributedDBUnitTest::USER_ID] = examKvDb1; + kvDbs[USER_ID] = examKvDb2; + kvDelegate->SetKvDB(kvDbs); + } + + static void CloseKvStoreFuzz(KvStoreNbDelegate *&kvDelegate, const std::string &storeId) + { + if (kvDelegate != nullptr) { + gmgr.CloseKvStoreFuzz(kvDelegate); + kvDelegate = nullptr; + DBStatus dbStatus = gmgr.DeleteKvStore(storeId); + LOGD("delete kv store dbStatus %d store %s", dbStatus, storeId.c_str()); + } + } + + void BlockSyncFuzz(SyncMode modeTest = SYNC_MODE_CLOUD_MERGE) + { + Query dbQuery = Query::Select().FromTable({ gtable }); + auto kvContext = std::make_shared(); + auto callback = [kvContext](const std::map &onProcess) { + for (const auto &item : onProcess) { + if (item.second.process == ProcessStatus::FINISHED) { + kvContext->FinishAndNotifyTest(); + } + } + }; + DBStatus dbStatus = kvDelegate->Sync({gdeviceKv}, modeTest, dbQuery, callback, DBConstant::MAX_TIMEOUT); + if (dbStatus != OK) { + return; + } + kvContext->WaitForFinishTest(); + } + + void OptionBlockSyncFuzz(const std::vector &devices, SyncMode modeTest = SYNC_MODE_CLOUD_MERGE) + { + Query dbQuery = Query::Select().FromTable({ gtable }); + auto kvContext = std::make_shared(); + auto callback = [kvContext](const std::map &onProcess) { + for (const auto &item : onProcess) { + if (item.second.process == ProcessStatus::FINISHED) { + kvContext->FinishAndNotifyTest(); + } + } + }; + KvSyncOption optionTest; + optionTest.modeTest = modeTest; + optionTest.devices = devices; + optionTest.dbQuery = dbQuery; + optionTest.waitTime = DBConstant::MAX_TIMEOUT; + DBStatus dbStatus = kvDelegate->Sync(optionTest, callback); + if (dbStatus != OK) { + return; + } + kvContext->WaitForFinishTest(); + } + + void NormalSync() + { + BlockSyncFuzz(); + SetKvDbSchemaFuzz(kvDelegate); + BlockSyncFuzz(); + } + + void KvNormalSync() + { + Key key = {'k'}; + Value expectValue = {'v'}; + kvDelegatePtrS1->Put(key, expectValue); + KvBlockSyncFuzz(kvDelegatePtrS1, OK, gKvSyncOption); + KvBlockSyncFuzz(kvDelegatePtrS2, OK, gKvSyncOption); + Value actualValue; + kvDelegatePtrS2->Get(key, actualValue); + } + + void RandomModeSyncFuzz(const uint8_t *vData, size_t size) + { + if (size == 0) { + BlockSyncFuzz(); + return; + } + auto modeTest = static_cast(vData[0]); + LOGI("[RandomModeSyncFuzz] select modeTest %d", static_cast(modeTest)); + BlockSyncFuzz(modeTest); + } + + void DataChangeSyncFuzz(const uint8_t *vData, size_t size) + { + SetKvDbSchemaFuzz(kvDelegate); + if (size == 0) { + return; + } + InitDbData(db, vData, size); + BlockSyncFuzz(); + FuzzerData fuzzerDataTest(vData, size); + KvSyncConfig kvConfig; + int maxUploadSize11 = fuzzerDataTest.GetInt(); + int maxUploadCount = fuzzerDataTest.GetInt(); + kvConfig.maxUploadSize11 = maxUploadSize11; + kvConfig.maxUploadCount = maxUploadCount; + kvDelegate->SetKvSyncConfig(kvConfig); + kvDelegatePtrS1->SetKvSyncConfig(kvConfig); + uint32_t len = fuzzerDataTest.GetUInt32() % MOD; + std::string version = fuzzerDataTest.GetString(len); + kvDelegatePtrS1->SetGenKvVersionCallback([version](const std::string &origin) { + return origin + version; + }); + KvNormalSync(); + int count = fuzzerDataTest.GetInt(); + kvDelegatePtrS1->GetCount(Query::Select(), count); + std::string device = fuzzerDataTest.GetString(len); + kvDelegatePtrS1->GetKvVersion(device); + std::vector devices = fuzzerDataTest.GetStringVector(len); + OptionBlockSyncFuzz(devices); + } + + void InitAssetsFuzz(const uint8_t *vData, size_t size) + { + FuzzerData fuzzerDataTest(vData, size); + uint32_t len = fuzzerDataTest.GetUInt32() % MOD; + for (size_t i = 0; i <= size; ++i) { + std::string nameStr = fuzzerDataTest.GetString(len); + localAssets.push_back(GenAsset(nameStr, std::to_string(vData[0]))); + } + } + + void AssetChangeSyncFuzz(const uint8_t *vData, size_t size) + { + SetKvDbSchemaFuzz(kvDelegate); + if (size == 0) { + return; + } + InitAssetsFuzz(vData, size); + InitDbAssetFuzz(vData, size); + BlockSyncFuzz(); + } + + void RandomModeRemoveDeviceDataFuzz(const uint8_t *vData, size_t size) + { + if (size == 0) { + return; + } + SetKvDbSchemaFuzz(kvDelegate); + int64_t kvCount = 10; + int64_t paddingSize = 10; + InsertKvTableRecordFuzz(0, kvCount, paddingSize, false); + BlockSyncFuzz(); + auto modeTest = static_cast(vData[0]); + LOGI("[RandomModeRemoveDeviceDataFuzz] select modeTest %d", static_cast(modeTest)); + if (modeTest == DEFAULT) { + return; + } + std::string device = ""; + kvDelegate->RemoveDeviceData(device, modeTest); + } +private: + std::string testDir; + std::string storePathTest; + sqlite3 *db = nullptr; + RelationalStoreDelegate *kvDelegate = nullptr; + KvStoreNbDelegate* kvDelegatePtrS1 = nullptr; + KvStoreNbDelegate* kvDelegatePtrS2 = nullptr; + std::shared_ptr examKvDb; + std::shared_ptr examKvDb1 = nullptr; + std::shared_ptr examKvDb2 = nullptr; + std::shared_ptr virtualAssetLoader; + std::shared_ptr mgr; + KvStoreConfig kvConfig; + SyncProcess lastProcess; + Assets localAssets; +}; +KvSyncTest *g_kvSyncFuzzTest = nullptr; + +void Setup() +{ + LOGI("Set up"); + g_kvSyncFuzzTest = new(std::nothrow) KvSyncTest(); + if (g_kvSyncFuzzTest == nullptr) { + return; + } + g_kvSyncFuzzTest->SetUp(); +} + +void TearDown() +{ + LOGI("Tear down"); + g_kvSyncFuzzTest->TearDown(); + if (g_kvSyncFuzzTest != nullptr) { + delete g_kvSyncFuzzTest; + g_kvSyncFuzzTest = nullptr; + } +} + +void CombineFuzzTest(const uint8_t *vData, size_t size) +{ + if (g_kvSyncFuzzTest == nullptr) { + return; + } + g_kvSyncFuzzTest->NormalSync(); + g_kvSyncFuzzTest->KvNormalSync(); + g_kvSyncFuzzTest->RandomModeSyncFuzz(vData, size); + g_kvSyncFuzzTest->DataChangeSyncFuzz(vData, size); + g_kvSyncFuzzTest->AssetChangeSyncFuzz(vData, size); + g_kvSyncFuzzTest->RandomModeRemoveDeviceDataFuzz(vData, size); +} +} + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *vData, size_t size) +{ + OHOS::Setup(); + OHOS::CombineFuzzTest(vData, size); + OHOS::TearDown(); + return 0; +} diff --git a/kv_store/test/fuzztest/kvsync_fuzzer/kvsync_fuzzer.h b/kv_store/test/fuzztest/kvsync_fuzzer/kvsync_fuzzer.h new file mode 100644 index 0000000000000000000000000000000000000000..77a42ea30656fe03b593db536c1ee6f3b4bd4c4d --- /dev/null +++ b/kv_store/test/fuzztest/kvsync_fuzzer/kvsync_fuzzer.h @@ -0,0 +1,21 @@ +/* + * 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 KV_SYNC_FUZZER_H +#define KV_SYNC_FUZZER_H + +#define FUZZ_PROJECT_NAME "KvSync_fuzzer" + +#endif // KV_SYNC_FUZZER_H \ No newline at end of file diff --git a/kv_store/test/fuzztest/kvsync_fuzzer/project.xml b/kv_store/test/fuzztest/kvsync_fuzzer/project.xml new file mode 100644 index 0000000000000000000000000000000000000000..1bd6e94e384a119569cdd3efa9503d51f6612fe4 --- /dev/null +++ b/kv_store/test/fuzztest/kvsync_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 600 + + 4096 + + diff --git a/kv_store/test/fuzztest/singlekvstorestub_fuzzer/BUILD.gn b/kv_store/test/fuzztest/singlekvstorestub_fuzzer/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..39487e589b2121bb78a29094c180d56117b0272a --- /dev/null +++ b/kv_store/test/fuzztest/singlekvstorestub_fuzzer/BUILD.gn @@ -0,0 +1,58 @@ +# Copyright (c) 2024 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. + +#####################hydra-fuzz################### +import("//build/config/features.gni") +import("//build/test.gni") + +##############################fuzztest########################################## +ohos_fuzztest("SingleKvStoreStubFuzzTest") { + module_out_path = "kv_store/kv_store" + + include_dirs = [ + "../../../frameworks/common", + "../../../frameworks/innerkitsimpl/distributeddatafwk/include", + "../../../frameworks/innerkitsimpl/distributeddatafwk/src", + "../../../interfaces/innerkits/distributeddata/include", + ] + + fuzz_config_file = "../../../test/fuzztest/singlekvstorestub_fuzzer" + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + + sources = [ "singlekvstorestub_fuzzer.cpp" ] + + deps = [] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "kv_store:distributeddata_inner", + ] +} + +############################################################################### +group("fuzztest") { + testonly = true + deps = [] + deps += [ + # deps file + ":SingleKvStoreStubFuzzTest", + ] +} +############################################################################### diff --git a/kv_store/test/fuzztest/singlekvstorestub_fuzzer/corpus/init b/kv_store/test/fuzztest/singlekvstorestub_fuzzer/corpus/init new file mode 100644 index 0000000000000000000000000000000000000000..6198079a28e860189d4294f6598f8ac6804c0dff --- /dev/null +++ b/kv_store/test/fuzztest/singlekvstorestub_fuzzer/corpus/init @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 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. + */ + +FUZZ \ No newline at end of file diff --git a/kv_store/test/fuzztest/singlekvstorestub_fuzzer/project.xml b/kv_store/test/fuzztest/singlekvstorestub_fuzzer/project.xml new file mode 100644 index 0000000000000000000000000000000000000000..7133b2b92440904a5ed04b838733acea0f97486a --- /dev/null +++ b/kv_store/test/fuzztest/singlekvstorestub_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + diff --git a/kv_store/test/fuzztest/singlekvstorestub_fuzzer/singlekvstorestub_fuzzer.cpp b/kv_store/test/fuzztest/singlekvstorestub_fuzzer/singlekvstorestub_fuzzer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..475038cdd28576c58b555b8a59b70a11eb7d0767 --- /dev/null +++ b/kv_store/test/fuzztest/singlekvstorestub_fuzzer/singlekvstorestub_fuzzer.cpp @@ -0,0 +1,545 @@ +/* + * Copyright (c) 2024 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 "singlekvstorestub_fuzzer.h" + +#include "distributed_kv_data_manager.h" +#include "store_errno.h" +#include +#include +#include + +using namespace OHOS; +using namespace OHOS::DistributedKv; + +namespace OHOS { +static std::shared_ptr singleKvStoreStub = nullptr; + +class DeviceObserverTestVirtual : public KvStoreObserver { +public: + DeviceObserverTestVirtual(); + ~DeviceObserverTestVirtual() + { + } + DeviceObserverTestVirtual(const DeviceObserverTestVirtual &) = delete; + DeviceObserverTestVirtual &operator=(const DeviceObserverTestVirtual &) = delete; + DeviceObserverTestVirtual(DeviceObserverTestVirtual &&) = delete; + DeviceObserverTestVirtual &operator=(DeviceObserverTestVirtual &&) = delete; + + void OnChange(const ChangeNotification &changeNotification); +}; + +DeviceObserverTestVirtual::DeviceObserverTestVirtual() +{ +} + +void DeviceObserverTestVirtual::OnChange(const ChangeNotification &changeNotification) +{ +} + +class DeviceSyncCallbackTestImpl : public KvStoreSyncCallback { +public: + void DeviceSyncCompleted(const std::map &result); +}; + +void DeviceSyncCallbackTestImpl::DeviceSyncCompleted(const std::map &result) +{ +} + +void SetUpTestCase(void) +{ + DistributedKvDataManager dataManager; + Options optionsItem = { + .createIfMissing = true, + .encrypt = false, + .autoSync = true, + .securityLevelTest = S1, + .kvStoreType = KvStoreType::SINGLE_VERSION + }; + optionsItem.area = EL1; + AppId appIdTest = { "kvstorefuzzertest" }; + optionsItem.baseDir = std::string("/data/service/el1/public/database/") + appIdTest.appId; + /* define kvstore(database) name. */ + StoreId storeId = { "fuzzer_single" }; + mkdir(optionsItem.baseDir.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); + /* [create and] open and initialize kvstore instance. */ + dataManager.GetSingleKvStore(optionsItem, appIdTest, storeId, singleKvStoreStub); +} + +void TearDown(void) +{ + (void)remove("/data/service/el1/public/database/singlekvstorestubfuzzertest/kvdb"); + (void)remove("/data/service/el1/public/database/singlekvstorestubfuzzertest/keyTest"); + (void)remove("/data/service/el1/public/database/singlekvstorestubfuzzertest"); +} + +void PutFuzzTest(const uint8_t *data, size_t size) +{ + std::string dataKey(data, data + size); + std::string dataValue(data, data + size); + Key keyTest = { dataKey }; + Value value = { dataValue }; + singleKvStoreStub->Put(keyTest, value); + singleKvStoreStub->Delete(keyTest); +} + +void PutBatchFuzzTest(const uint8_t *data, size_t size) +{ + std::string dataKey(data, data + size); + std::string dataValue(data, data + size); + std::vector entriesItem; + std::vector keysString; + Entry entry1; + Entry entry2; + Entry entry3; + entry1.keyTest = { dataKey + "test_key1" }; + entry1.value = { dataValue + "test_val1" }; + entry2.keyTest = { dataKey + "test_key2" }; + entry2.value = { dataValue + "test_val2" }; + entry3.keyTest = { dataKey + "test_key3" }; + entry3.value = { dataValue + "test_val3" }; + entriesItem.push_back(entry1); + entriesItem.push_back(entry2); + entriesItem.push_back(entry3); + keysString.push_back(entry1.keyTest); + keysString.push_back(entry2.keyTest); + keysString.push_back(entry3.keyTest); + singleKvStoreStub->PutBatch(entriesItem); + singleKvStoreStub->DeleteBatch(keysString); +} + +void GetFuzzTest(const uint8_t *data, size_t size) +{ + std::string dataKey(data, data + size); + std::string dataValue(data, data + size); + Key keyTest = { dataKey }; + Value value = { dataValue }; + Value val1; + singleKvStoreStub->Put(keyTest, value); + singleKvStoreStub->Get(keyTest, val1); + singleKvStoreStub->Delete(keyTest); +} + +void GetEntriesFuzz1Test(const uint8_t *data, size_t size) +{ + std::string prefixTest(data, data + size); + std::string keysString = "testString_"; + size_t count = 10; + std::vector result; + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Put(prefixTest + keysString + std::to_string(i), { keysString + std::to_string(i) }); + } + singleKvStoreStub->GetEntries(prefixTest, result); + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Delete(prefixTest + keysString + std::to_string(i)); + } +} + +void GetEntriesFuzz2Test(const uint8_t *data, size_t size) +{ + std::string prefixTest(data, data + size); + DataQuery dataQueryTest; + dataQueryTest.KeyPrefix(prefixTest); + std::string keysString = "testString_"; + std::vector entriesItem; + size_t count = 10; + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Put(prefixTest + keysString + std::to_string(i), keysString + std::to_string(i)); + } + singleKvStoreStub->GetEntries(dataQueryTest, entriesItem); + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Delete(prefixTest + keysString + std::to_string(i)); + } +} + +void SubscribeKvStoreFuzzTest(const uint8_t *data, size_t size) +{ + std::string prefixTest(data, data + size); + DataQuery dataQueryTest; + dataQueryTest.KeyPrefix(prefixTest); + std::string keysString = "testString_"; + size_t count = 10; + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Put(prefixTest + keysString + std::to_string(i), keysString + std::to_string(i)); + } + auto observer = std::make_shared(); + singleKvStoreStub->SubscribeKvStore(SubscribeType::SUBSCRIBE_TYPE_ALL, observer); + singleKvStoreStub->UnSubscribeKvStore(SubscribeType::SUBSCRIBE_TYPE_ALL, observer); + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Delete(prefixTest + keysString + std::to_string(i)); + } +} + +void SyncCallbackFuzzTest(const uint8_t *data, size_t size) +{ + auto syncCallback = std::make_shared(); + singleKvStoreStub->RegisterSyncCallback(syncCallback); + + std::string prefixTest(data, data + size); + DataQuery dataQueryTest; + dataQueryTest.KeyPrefix(prefixTest); + std::string keysString = "testString_"; + size_t count = 10; + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Put(prefixTest + keysString + std::to_string(i), keysString + std::to_string(i)); + } + + std::map result; + syncCallback->DeviceSyncCompleted(result); + + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Delete(prefixTest + keysString + std::to_string(i)); + } + singleKvStoreStub->UnRegisterSyncCallback(); +} + +void GetResultSetFuzz1Test(const uint8_t *data, size_t size) +{ + std::string prefixTest(data, data + size); + std::string keysString = "testString_"; + int position = static_cast(size); + std::shared_ptr kvResultSet; + size_t count = 10; + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Put(prefixTest + keysString + std::to_string(i), keysString + std::to_string(i)); + } + auto status = singleKvStoreStub->GetResultSet(prefixTest, kvResultSet); + if (status != Status::SUCCESS || kvResultSet == nullptr) { + return; + } + kvResultSet->Move(position); + kvResultSet->MoveToPosition(position); + Entry entry; + kvResultSet->GetEntry(entry); + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Delete(prefixTest + keysString + std::to_string(i)); + } +} + +void GetResultSetFuzz2Test(const uint8_t *data, size_t size) +{ + std::string prefixTest(data, data + size); + DataQuery dataQueryTest; + dataQueryTest.KeyPrefix(prefixTest); + std::string keysString = "testString_"; + std::shared_ptr kvResultSet; + size_t count = 10; + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Put(prefixTest + keysString + std::to_string(i), keysString + std::to_string(i)); + } + singleKvStoreStub->GetResultSet(dataQueryTest, kvResultSet); + singleKvStoreStub->CloseResultSet(kvResultSet); + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Delete(prefixTest + keysString + std::to_string(i)); + } +} + +void GetResultSetFuzz3Test(const uint8_t *data, size_t size) +{ + std::string prefixTest(data, data + size); + DataQuery dataQueryTest; + dataQueryTest.KeyPrefix(prefixTest); + std::string keysString = "testString_"; + std::shared_ptr kvResultSet; + size_t count = 10; + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Put(prefixTest + keysString + std::to_string(i), keysString + std::to_string(i)); + } + singleKvStoreStub->GetResultSet(dataQueryTest, kvResultSet); + auto status = singleKvStoreStub->GetResultSet(prefixTest, kvResultSet); + if (status != Status::SUCCESS || kvResultSet == nullptr) { + return; + } + int cnt = kvResultSet->GetCount(); + if (static_cast(size) != cnt) { + return; + } + kvResultSet->GetPosition(); + kvResultSet->IsBeforeFirst(); + kvResultSet->IsFirst(); + kvResultSet->IsBeforeFirst(); + kvResultSet->IsFirst(); + kvResultSet->MoveToPrevious(); + while (kvResultSet->MoveToNext()) { + Entry entry; + kvResultSet->GetEntry(entry); + } + Entry entry; + kvResultSet->GetEntry(entry); + kvResultSet->IsLast(); + kvResultSet->IsAfterLast(); + kvResultSet->MoveToNext(); + kvResultSet->IsLast(); + kvResultSet->IsAfterLast(); + kvResultSet->MoveToFirst(); + kvResultSet->GetEntry(entry); + kvResultSet->MoveToLast(); + kvResultSet->IsAfterLast(); + kvResultSet->Move(1); + kvResultSet->IsLast(); + kvResultSet->GetEntry(entry); + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Delete(prefixTest + keysString + std::to_string(i)); + } +} + +void GetCountFuzz1Test(const uint8_t *data, size_t size) +{ + int count; + std::string prefixTest(data, data + size); + DataQuery query11; + query11.KeyPrefix(prefixTest); + std::string keysString = "testString_"; + size_t count = 10; + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Put(prefixTest + keysString + std::to_string(i), keysString + std::to_string(i)); + } + singleKvStoreStub->GetCount(query11, count); + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Delete(prefixTest + keysString + std::to_string(i)); + } +} + +void GetCountFuzz2Test(const uint8_t *data, size_t size) +{ + int count; + size_t count = 10; + std::vector keysString; + std::string prefixTest(data, data + size); + for (size_t i = 0; i < count; i++) { + keysString.push_back(prefixTest); + } + DataQuery query11; + query11.InKeys(keysString); + std::string dataKey = "testString_"; + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Put(prefixTest + dataKey + std::to_string(i), dataKey + std::to_string(i)); + } + singleKvStoreStub->GetCount(query11, count); + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Delete(prefixTest + dataKey + std::to_string(i)); + } +} + +void RemoveDeviceDataFuzzTest(const uint8_t *data, size_t size) +{ + size_t count = 10; + std::string deviceId01(data, data + size); + std::vector input; + auto cmp = [](const Key &entry, const Key &sentry) { return entry.Data() < sentry.Data(); }; + std::map dictionary(cmp); + for (size_t i = 0; i < count; ++i) { + Entry entry; + entry.keyTest = std::to_string(i).append("_k"); + entry.value = std::to_string(i).append("_v"); + dictionary[entry.keyTest] = entry.value; + input.push_back(entry); + } + singleKvStoreStub->PutBatch(input); + singleKvStoreStub->RemoveDeviceData(deviceId01); + singleKvStoreStub->RemoveDeviceData(""); + + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Delete(std::to_string(i).append("_k")); + } +} + +void GetSecurityLevelFuzzTest(const uint8_t *data, size_t size) +{ + size_t count = 10; + std::vector keysString; + std::string prefixTest(data, data + size); + for (size_t i = 0; i < count; i++) { + keysString.push_back(prefixTest); + } + std::string dataKey = "testString_"; + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Put(prefixTest + dataKey + std::to_string(i), dataKey + std::to_string(i)); + } + SecurityLevel securityLevelTest; + singleKvStoreStub->GetSecurityLevel(securityLevelTest); + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Delete(prefixTest + dataKey + std::to_string(i)); + } +} + +void SyncFuzz1Test(const uint8_t *data, size_t size) +{ + size_t count = 10; + std::string dataKey = "testString_"; + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Put(dataKey + std::to_string(i), dataKey + std::to_string(i)); + } + std::string deviceId01(data, data + size); + std::vector deviceIdItem = { deviceId01 }; + uint32_t allowedDelay = 200; + singleKvStoreStub->Sync(deviceIdItem, SyncMode::PUSH, allowedDelay); + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Delete(dataKey + std::to_string(i)); + } +} + +void SyncFuzz2Test(const uint8_t *data, size_t size) +{ + size_t count = 10; + std::string dataKey = "testString_"; + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Put(dataKey + std::to_string(i), dataKey + std::to_string(i)); + } + std::string deviceId01(data, data + size); + std::vector deviceIdItem = { deviceId01 }; + DataQuery dataQueryTest; + dataQueryTest.KeyPrefix("name"); + singleKvStoreStub->Sync(deviceIdItem, SyncMode::PULL, dataQueryTest, nullptr); + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Delete(dataKey + std::to_string(i)); + } +} + +void SyncParamFuzzTest(const uint8_t *data, size_t size) +{ + size_t count = 10; + std::vector keysString; + std::string prefixTest(data, data + size); + for (size_t i = 0; i < count; i++) { + keysString.push_back(prefixTest); + } + std::string dataKey = "testString_"; + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Put(prefixTest + dataKey + std::to_string(i), dataKey + std::to_string(i)); + } + + KvSyncParam syncParam { 500 }; + singleKvStoreStub->SetSyncParam(syncParam); + + KvSyncParam syncParam; + singleKvStoreStub->GetSyncParam(syncParam); + + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Delete(prefixTest + dataKey + std::to_string(i)); + } +} + +void SetCapabilityRangeFuzzTest(const uint8_t *data, size_t size) +{ + std::string label(data, data + size); + std::vector local = { label + "_local1", label + "_local2" }; + std::vector remote = { label + "_remote1", label + "_remote2" }; + singleKvStoreStub->SetCapabilityRange(local, remote); +} + +void SetCapabilityEnabledFuzzTest(const uint8_t *data, size_t size) +{ + size_t count = 10; + std::vector keysString; + std::string prefixTest(data, data + size); + for (size_t i = 0; i < count; i++) { + keysString.push_back(prefixTest); + } + std::string dataKey = "testString_"; + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Put(prefixTest + dataKey + std::to_string(i), dataKey + std::to_string(i)); + } + + singleKvStoreStub->SetCapabilityEnable(true); + singleKvStoreStub->SetCapabilityEnable(false); + + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Delete(prefixTest + dataKey + std::to_string(i)); + } +} + +void SubscribeWithQueryFuzzTest(const uint8_t *data, size_t size) +{ + std::string deviceId01(data, data + size); + std::vector deviceIdItem = { deviceId01 + "_1", deviceId01 + "_2" }; + DataQuery dataQueryTest; + dataQueryTest.KeyPrefix("name"); + singleKvStoreStub->SubscribeWithQuery(deviceIdItem, dataQueryTest); + singleKvStoreStub->UnsubscribeWithQuery(deviceIdItem, dataQueryTest); +} + +void UnSubscribeWithQueryFuzzTest(const uint8_t *data, size_t size) +{ + std::string deviceId01(data, data + size); + std::vector deviceIdItem = { deviceId01 + "_1", deviceId01 + "_2" }; + DataQuery dataQueryTest; + dataQueryTest.KeyPrefix("name"); + singleKvStoreStub->UnsubscribeWithQuery(deviceIdItem, dataQueryTest); +} + +void AsyncGetFuzzTest(const uint8_t *data, size_t size) +{ + std::string strKey(data, data + size); + std::string strValue(data, data + size); + Key keyTest = { strKey }; + Value value = { strValue }; + singleKvStoreStub->Put(keyTest, value); + Value out; + std::function call = [](Status status, Value &&value) {}; + std::string networkIdTest(data, data + size); + singleKvStoreStub->Get(keyTest, networkIdTest, call); + singleKvStoreStub->Delete(keyTest); +} + +void AsyncGetEntriesFuzzTest(const uint8_t *data, size_t size) +{ + std::string prefixTest(data, data + size); + std::string keysString = "testString_"; + size_t count = 10; + std::vector result; + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Put(prefixTest + keysString + std::to_string(i), { keysString + std::to_string(i) }); + } + std::function &&)> call = [](Status status, std::vector &&entry) {}; + std::string networkIdTest(data, data + size); + singleKvStoreStub->GetEntries(prefixTest, networkIdTest, call); + for (size_t i = 0; i < count; i++) { + singleKvStoreStub->Delete(prefixTest + keysString + std::to_string(i)); + } +} +} // namespace OHOS + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + /* Run your code on data */ + OHOS::SetUpTestCase(); + OHOS::PutFuzzTest(data, size); + OHOS::PutBatchFuzzTest(data, size); + OHOS::GetFuzzTest(data, size); + OHOS::GetEntriesFuzz1Test(data, size); + OHOS::GetEntriesFuzz2Test(data, size); + OHOS::GetResultSetFuzz1Test(data, size); + OHOS::GetResultSetFuzz2Test(data, size); + OHOS::GetResultSetFuzz3Test(data, size); + OHOS::GetCountFuzz1Test(data, size); + OHOS::GetCountFuzz2Test(data, size); + OHOS::SyncFuzz1Test(data, size); + OHOS::SyncFuzz2Test(data, size); + OHOS::SubscribeKvStoreFuzzTest(data, size); + OHOS::RemoveDeviceDataFuzzTest(data, size); + OHOS::GetSecurityLevelFuzzTest(data, size); + OHOS::SyncCallbackFuzzTest(data, size); + OHOS::SyncParamFuzzTest(data, size); + OHOS::SetCapabilityEnabledFuzzTest(data, size); + OHOS::SetCapabilityRangeFuzzTest(data, size); + OHOS::SubscribeWithQueryFuzzTest(data, size); + OHOS::UnSubscribeWithQueryFuzzTest(data, size); + OHOS::AsyncGetFuzzTest(data, size); + OHOS::AsyncGetEntriesFuzzTest(data, size); + OHOS::TearDown(); + return 0; +} \ No newline at end of file diff --git a/kv_store/test/fuzztest/singlekvstorestub_fuzzer/singlekvstorestub_fuzzer.h b/kv_store/test/fuzztest/singlekvstorestub_fuzzer/singlekvstorestub_fuzzer.h new file mode 100644 index 0000000000000000000000000000000000000000..b2652170a3aa9922d6cd4b5c11abc4fc675e96b9 --- /dev/null +++ b/kv_store/test/fuzztest/singlekvstorestub_fuzzer/singlekvstorestub_fuzzer.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 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 SINGLEKVSTORESTUB_FUZZER_H +#define SINGLEKVSTORESTUB_FUZZER_H + +#define FUZZ_PROJECT_NAME "singlekvstorestub_fuzzer" + +#endif // SINGLEKVSTORESTUB_FUZZER_H + diff --git a/kv_store/test/unittest/distributedKVStore/config.json b/kv_store/test/unittest/distributedKVStore/config.json index b73d03107a541b930fc6b659244d69e851c786f2..a98b5dc3e83ebc22f78c548a1c215294967f2377 100644 --- a/kv_store/test/unittest/distributedKVStore/config.json +++ b/kv_store/test/unittest/distributedKVStore/config.json @@ -19,7 +19,8 @@ "default", "tablet", "phone", - "2in1" + "2in1", + "wearable" ], "distro": { "deliveryWithInstall": true, diff --git a/kv_store/test/unittest/distributeddata/config.json b/kv_store/test/unittest/distributeddata/config.json index b73d03107a541b930fc6b659244d69e851c786f2..a98b5dc3e83ebc22f78c548a1c215294967f2377 100644 --- a/kv_store/test/unittest/distributeddata/config.json +++ b/kv_store/test/unittest/distributeddata/config.json @@ -19,7 +19,8 @@ "default", "tablet", "phone", - "2in1" + "2in1", + "wearable" ], "distro": { "deliveryWithInstall": true, diff --git a/mock/CMakeLists.txt b/mock/CMakeLists.txt index ce20853e0491a326ddb44e14ac7b57aeddcdf0b8..8fffca1996e9bb575411237a4bf5e4533b9098f2 100644 --- a/mock/CMakeLists.txt +++ b/mock/CMakeLists.txt @@ -157,6 +157,7 @@ target_include_directories(mock PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/innerkits/abi target_include_directories(mock PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/innerkits/ability_runtime/ability_manager/include/continuation) target_include_directories(mock PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/innerkits/ability_runtime/abilitykit_native/include) target_include_directories(mock PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/innerkits/ability_runtime/app_manager/include/appmgr) +target_include_directories(mock PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/innerkits/ability_runtime/common/include) target_include_directories(mock PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/innerkits/ability_runtime/dataobs_manager/include) target_include_directories(mock PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/innerkits/ability_runtime/extension_manager/include) target_include_directories(mock PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/innerkits/ability_runtime/mock) diff --git a/mock/innerkits/ability_runtime/ability_manager/include/ability_manager_proxy.h b/mock/innerkits/ability_runtime/ability_manager/include/ability_manager_proxy.h new file mode 100644 index 0000000000000000000000000000000000000000..4cf3cc6fc93a53ce424681ccaef0c2343a15e894 --- /dev/null +++ b/mock/innerkits/ability_runtime/ability_manager/include/ability_manager_proxy.h @@ -0,0 +1,1613 @@ +/* + * Copyright (c) 2023-2024 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_ABILITY_RUNTIME_ABILITY_MANAGER_PROXY_H +#define OHOS_ABILITY_RUNTIME_ABILITY_MANAGER_PROXY_H + +#include "ability_manager_interface.h" +//#include "auto_startup_info.h" +#include "iremote_proxy.h" +#include "mission_info.h" +//#include "intent_exemption_info.h" + +namespace OHOS { +namespace AAFwk { +//using AutoStartupInfo = AbilityRuntime::AutoStartupInfo; +/** + * @class AbilityManagerProxy + * AbilityManagerProxy. + */ +class AbilityManagerProxy : public IRemoteProxy { +public: + explicit AbilityManagerProxy(const sptr &impl) : IRemoteProxy(impl) + {} + + virtual ~AbilityManagerProxy() + {} + + /** + * StartSelfUIAbility with want, start self uiability only on 2-in-1 devices. + * + * @param want, the want of the ability to start. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StartSelfUIAbility(const Want &want) override; + + /** + * StartAbility with want, send want to ability manager service. + * + * @param want, the want of the ability to start. + * @param requestCode, Ability request code. + * @param userId, Designation User ID. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StartAbility( + const Want &want, + int32_t userId = DEFAULT_INVAL_VALUE, + int requestCode = DEFAULT_INVAL_VALUE) override; + + /** + * StartAbility with want, send want to ability manager service. + * + * @param want, the want of the ability to start. + * @param callerToken, caller ability token. + * @param requestCode the resultCode of the ability to start. + * @param userId, Designation User ID. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StartAbility( + const Want &want, + const sptr &callerToken, + int32_t userId = DEFAULT_INVAL_VALUE, + int requestCode = DEFAULT_INVAL_VALUE) override; + + /** + * StartAbilityWithSpecifyTokenId with want and specialId, send want to ability manager service. + * + * @param want, the want of the ability to start. + * @param callerToken, caller ability token. + * @param specialId the caller Id. + * @param userId, Designation User ID. + * @param requestCode the resultCode of the ability to start. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StartAbilityWithSpecifyTokenId( + const Want &want, + const sptr &callerToken, + uint32_t specifyTokenId, + int32_t userId = DEFAULT_INVAL_VALUE, + int requestCode = DEFAULT_INVAL_VALUE) override; + + /** + * StartAbility by insight intent, send want to ability manager service. + * + * @param want Ability want. + * @param callerToken caller ability token. + * @param intentId insight intent id. + * @param userId userId of target ability. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t StartAbilityByInsightIntent( + const Want &want, + const sptr &callerToken, + uint64_t intentId, + int32_t userId = DEFAULT_INVAL_VALUE) override; + + /** + * Starts a new ability with specific start settings. + * + * @param want Indicates the ability to start. + * @param callerToken caller ability token. + * @param abilityStartSetting Indicates the setting ability used to start. + * @param userId, Designation User ID. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StartAbility( + const Want &want, + const AbilityStartSetting &abilityStartSetting, + const sptr &callerToken, + int32_t userId = DEFAULT_INVAL_VALUE, + int requestCode = DEFAULT_INVAL_VALUE) override; + + /** + * Starts a new ability with specific start options. + * + * @param want, the want of the ability to start. + * @param startOptions Indicates the options used to start. + * @param callerToken, caller ability token. + * @param userId, Designation User ID. + * @param requestCode the resultCode of the ability to start. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StartAbility( + const Want &want, + const StartOptions &startOptions, + const sptr &callerToken, + int32_t userId = DEFAULT_INVAL_VALUE, + int requestCode = DEFAULT_INVAL_VALUE) override; + + /** + * Starts a new ability using the original caller information. + * + * @param want the want of the ability to start. + * @param callerToken current caller ability token. + * @param asCallerSourceToken source caller ability token. + * @param userId Designation User ID. + * @param requestCode the resultCode of the ability to start. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StartAbilityAsCaller( + const Want &want, + const sptr &callerToken, + sptr asCallerSourceToken, + int32_t userId = DEFAULT_INVAL_VALUE, + int requestCode = DEFAULT_INVAL_VALUE) override; + + /** + * Starts a new ability using the original caller information. + * + * @param want the want of the ability to start. + * @param startOptions Indicates the options used to start. + * @param callerToken current caller ability token. + * @param asCallerSourceToken source caller ability token. + * @param userId Designation User ID. + * @param requestCode the resultCode of the ability to start. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StartAbilityAsCaller( + const Want &want, + const StartOptions &startOptions, + const sptr &callerToken, + sptr asCallerSourceToken, + int32_t userId = DEFAULT_INVAL_VALUE, + int requestCode = DEFAULT_INVAL_VALUE) override; + + /** + * Starts a new ability for result using the original caller information. + * + * @param want the want of the ability to start. + * @param callerToken current caller ability token. + * @param requestCode the resultCode of the ability to start. + * @param userId Designation User ID. + * @return Returns ERR_OK on success, others on failure. + */ + int StartAbilityForResultAsCaller( + const Want &want, + const sptr &callerToken, + int requestCode = DEFAULT_INVAL_VALUE, + int32_t userId = DEFAULT_INVAL_VALUE) override; + + /** + * Starts a new ability for result using the original caller information. + * + * @param want the want of the ability to start. + * @param startOptions Indicates the options used to start. + * @param callerToken current caller ability token. + * @param requestCode the resultCode of the ability to start. + * @param userId Designation User ID. + * @return Returns ERR_OK on success, others on failure. + */ + int StartAbilityForResultAsCaller( + const Want &want, + const StartOptions &startOptions, + const sptr &callerToken, + int requestCode = DEFAULT_INVAL_VALUE, + int32_t userId = DEFAULT_INVAL_VALUE) override; + + /** + * Start ui session ability with extension session info, send session info to ability manager service. + * + * @param want, the want of the ability to start. + * @param callerToken, caller ability token. + * @param sessionInfo the information of UIExtensionContentSession. + * @param userId, Designation User ID. + * @param requestCode, Ability request code. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StartAbilityByUIContentSession( + const Want &want, + const sptr &callerToken, + const sptr &sessionInfo, + int32_t userId = DEFAULT_INVAL_VALUE, + int requestCode = DEFAULT_INVAL_VALUE) override; + + /** + * Start ui session ability with extension session info, send session info to ability manager service. + * + * @param want, the want of the ability to start. + * @param startOptions Indicates the options used to start. + * @param callerToken, caller ability token. + * @param sessionInfo the information of UIExtensionContentSession. + * @param userId, Designation User ID. + * @param requestCode the resultCode of the ability to start. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StartAbilityByUIContentSession( + const Want &want, + const StartOptions &startOptions, + const sptr &callerToken, + const sptr &sessionInfo, + int32_t userId = DEFAULT_INVAL_VALUE, + int requestCode = DEFAULT_INVAL_VALUE) override; + + /** + * Start ui ability + * + * @param want the want of the ability to start. + * @param callerToken caller ability token. + * @param specifyTokenId The Caller ID. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StartAbilityOnlyUIAbility( + const Want &want, + const sptr &callerToken, + uint32_t specifyTokenId) override; + + /** + * Start extension ability with want, send want to ability manager service. + * + * @param want, the want of the ability to start. + * @param callerToken, caller ability token. + * @param userId, Designation User ID. + * @param extensionType If an ExtensionAbilityType is set, only extension of that type can be started. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t StartExtensionAbility( + const Want &want, + const sptr &callerToken, + int32_t userId = DEFAULT_INVAL_VALUE, + AppExecFwk::ExtensionAbilityType extensionType = AppExecFwk::ExtensionAbilityType::UNSPECIFIED) override; + + /** + * Create UIExtension with want, send want to ability manager service. + * + * @param want, the want of the ability to start. + * @return Returns ERR_OK on success, others on failure. + */ + int RequestModalUIExtension(const Want &want) override; + + /** + * Preload UIExtension with want, send want to ability manager service. + * + * @param want, the want of the ability to start. + * @param hostBundleName, the caller application bundle name. + * @param userId, the extension runs in. + * @return Returns ERR_OK on success, others on failure. + */ + int PreloadUIExtensionAbility(const Want &want, std::string &hostBundleName, + int32_t userId = DEFAULT_INVAL_VALUE, int32_t hostPid = DEFAULT_INVAL_VALUE) override; + + int ChangeAbilityVisibility(sptr token, bool isShow) override; + + int ChangeUIAbilityVisibilityBySCB(sptr sessionInfo, bool isShow) override; + /** + * Start ui extension ability with extension session info, send extension session info to ability manager service. + * + * @param extensionSessionInfo the extension session info of the ability to start. + * @param userId, Designation User ID. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StartUIExtensionAbility( + const sptr &extensionSessionInfo, + int32_t userId = DEFAULT_INVAL_VALUE) override; + + /** + * Start ui ability with want, send want to ability manager service. + * + * @param sessionInfo the session info of the ability to start. + * @param isColdStart the session info of the ability is or not cold start. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StartUIAbilityBySCB(sptr sessionInfo, bool &isColdStart, uint32_t sceneFlag = 0) override; + + /** + * Stop extension ability with want, send want to ability manager service. + * + * @param want, the want of the ability to stop. + * @param callerToken, caller ability token. + * @param userId, Designation User ID. + * @param extensionType If an ExtensionAbilityType is set, only extension of that type can be stopped. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StopExtensionAbility( + const Want& want, + const sptr& callerToken, + int32_t userId = DEFAULT_INVAL_VALUE, + AppExecFwk::ExtensionAbilityType extensionType = AppExecFwk::ExtensionAbilityType::UNSPECIFIED) override; + /** + * TerminateAbility, terminate the special ability. + * + * @param token, the token of the ability to terminate. + * @param resultCode, the resultCode of the ability to terminate. + * @param resultWant, the Want of the ability to return. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int TerminateAbility( + const sptr &token, int resultCode, const Want *resultWant = nullptr) override; + + /** + * BackToCallerAbilityWithResult, return to the caller ability. + * + * @param token, the token of the ability to terminate. + * @param resultCode, the resultCode of the ability to terminate. + * @param resultWant, the Want of the ability to return. + * @param callerRequestCode, the requestCode of caller ability. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int BackToCallerAbilityWithResult(const sptr &token, int resultCode, + const Want *resultWant, int64_t callerRequestCode) override; + + /** + * TerminateUIServiceExtensionAbility, terminate UIServiceExtensionAbility. + * + * @param token, the token of the UIServiceExtensionAbility to terminate. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t TerminateUIServiceExtensionAbility(const sptr &token) override; + + /** + * TerminateUIExtensionAbility, terminate the special ui extension ability. + * + * @param extensionSessionInfo the extension session info of the ability to terminate. + * @param resultCode resultCode. + * @param Want Ability want returned. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int TerminateUIExtensionAbility(const sptr &extensionSessionInfo, int resultCode, + const Want *resultWant) override; + + /** + * CloseUIExtensionAbilityBySCB, terminate the specified ui extension ability by SCB. + * + * @param token the ability token. + * @return Returns ERR_OK on success, others on failure. + */ + int CloseUIExtensionAbilityBySCB(const sptr token) override; + + /** + * CloseUIAbilityBySCB, close the special ability by scb. + * + * @param sessionInfo the session info of the ability to terminate. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int CloseUIAbilityBySCB(const sptr &sessionInfo) override; + + /** + * SendResultToAbility with want, return want from ability manager service.(Only used for dms) + * + * @param requestCode, request code. + * @param resultCode, resultCode to return. + * @param resultWant, the Want of the ability to return. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int SendResultToAbility(int32_t requestCode, int32_t resultCode, Want& resultWant) override; + + /** + * MoveAbilityToBackground. + * + * @param token, the token of the ability to move. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int MoveAbilityToBackground(const sptr &token) override; + + /** + * Move the UIAbility to background, called by app self. + * + * @param token the token of the ability to move. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t MoveUIAbilityToBackground(const sptr token) override; + + /** + * CloseAbility, close the special ability. + * + * @param token, the token of the ability to terminate. + * @param resultCode, the resultCode of the ability to terminate. + * @param resultWant, the Want of the ability to return. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int CloseAbility( + const sptr &token, int resultCode, const Want *resultWant = nullptr) override; + + /** + * MinimizeAbility, minimize the special ability. + * + * @param token, ability token. + * @param fromUser mark the minimize operation source. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int MinimizeAbility(const sptr &token, bool fromUser = false) override; + + /** + * MinimizeUIExtensionAbility, minimize the special ui extension ability. + * + * @param extensionSessionInfo the extension session info of the ability to minimize. + * @param fromUser mark the minimize operation source. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int MinimizeUIExtensionAbility(const sptr &extensionSessionInfo, + bool fromUser = false) override; + + /** + * MinimizeUIAbilityBySCB, minimize the special ability by scb. + * + * @param sessionInfo the session info of the ability to minimize. + * @param fromUser, Whether form user. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int MinimizeUIAbilityBySCB(const sptr &sessionInfo, bool fromUser = false, + uint32_t sceneFlag = 0) override; + + /** + * ConnectAbility, connect session with service ability. + * + * @param want, Special want for service type's ability. + * @param connect, Callback used to notify caller the result of connecting or disconnecting. + * @param callerToken, caller ability token. + * @param userId, Designation User ID. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int ConnectAbility( + const Want &want, + const sptr &connect, + const sptr &callerToken, + int32_t userId = DEFAULT_INVAL_VALUE) override; + + virtual int ConnectAbilityCommon( + const Want &want, + const sptr &connect, + const sptr &callerToken, + AppExecFwk::ExtensionAbilityType extensionType, + int32_t userId = DEFAULT_INVAL_VALUE, + bool isQueryExtensionOnly = false) override; + + virtual int ConnectUIExtensionAbility( + const Want &want, + const sptr &connect, + const sptr &sessionInfo, + int32_t userId = DEFAULT_INVAL_VALUE, + sptr connectInfo = nullptr) override; + + /** + * DisconnectAbility, connect session with service ability. + * + * @param connect, Callback used to notify caller the result of connecting or disconnecting. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int DisconnectAbility(sptr connect) override; + + /** + * AcquireDataAbility, acquire a data ability by its authority, if it not existed, + * AMS loads it synchronously. + * + * @param uri, data ability uri. + * @param isKill, true: when a data ability is died, ams will kill this client, or do nothing. + * @param callerToken, specifies the caller ability token. + * @return returns the data ability ipc object, or nullptr for failed. + */ + virtual sptr AcquireDataAbility( + const Uri &uri, bool isKill, const sptr &callerToken) override; + + /** + * ReleaseDataAbility, release the data ability that referenced by 'dataAbilityToken'. + * + * @param dataAbilityScheduler, specifies the data ability that will be released. + * @param callerToken, specifies the caller ability token. + * @return returns ERR_OK if succeeded, or error codes for failed. + */ + virtual int ReleaseDataAbility( + sptr dataAbilityScheduler, const sptr &callerToken) override; + + /** + * AttachAbilityThread, ability call this interface after loaded. + * + * @param scheduler,.the interface handler of kit ability. + * @param token,.ability's token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int AttachAbilityThread( + const sptr &scheduler, const sptr &token) override; + + /** + * AbilityTransitionDone, ability call this interface after lift cycle was changed. + * + * @param token,.ability's token. + * @param state,.the state of ability lift cycle. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int AbilityTransitionDone(const sptr &token, int state, const PacMap &saveData) override; + + /** + * AbilityWindowConfigTransitionDone, ability call this interface after lift cycle was changed. + * + * @param token,.ability's token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int AbilityWindowConfigTransitionDone( + const sptr &token, const WindowConfig &windowConfig) override; + + /** + * ScheduleConnectAbilityDone, service ability call this interface while session was connected. + * + * @param token,.service ability's token. + * @param remoteObject,.the session proxy of service ability. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int ScheduleConnectAbilityDone( + const sptr &token, const sptr &remoteObject) override; + + /** + * ScheduleDisconnectAbilityDone, service ability call this interface while session was disconnected. + * + * @param token,.service ability's token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int ScheduleDisconnectAbilityDone(const sptr &token) override; + + /** + * ScheduleCommandAbilityDone, service ability call this interface while session was commanded. + * + * @param token,.service ability's token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int ScheduleCommandAbilityDone(const sptr &token) override; + + virtual int ScheduleCommandAbilityWindowDone( + const sptr &token, + const sptr &sessionInfo, + WindowCommand winCmd, + AbilityCommand abilityCmd) override; + + /** + * dump ability stack info, about userID, mission stack info, + * mission record info and ability info. + * + * @param state Ability stack info. + * @return Returns ERR_OK on success, others on failure. + */ + virtual void DumpState(const std::string &args, std::vector &state) override; + virtual void DumpSysState( + const std::string& args, std::vector& state, bool isClient, bool isUserID, int UserID) override; + + /** + * Destroys this Service ability by Want. + * + * @param want, Special want for service type's ability. + * @param token ability's token. + * @return Returns true if this Service ability will be destroyed; returns false otherwise. + */ + virtual int StopServiceAbility(const Want &want, int32_t userId = DEFAULT_INVAL_VALUE, + const sptr &token = nullptr) override; + + /** + * Get top ability. + * + * @param isNeedLocalDeviceId is need local device id. + * @return Returns front desk focus ability elementName. + */ + virtual AppExecFwk::ElementName GetTopAbility(bool isNeedLocalDeviceId = true) override; + + /** + * Get element name by token. + * + * @param token ability's token. + * @param isNeedLocalDeviceId is need local device id. + * @return Returns front desk focus ability elementName by token. + */ + virtual AppExecFwk::ElementName GetElementNameByToken(sptr token, + bool isNeedLocalDeviceId = true) override; + + /** + * Kill the process immediately. + * + * @param bundleName. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int KillProcess(const std::string &bundleName, bool clearPageStack = false, int32_t appIndex = 0) override; + + #ifdef ABILITY_COMMAND_FOR_TEST + /** + * force timeout ability. + * + * @param abilityName. + * @param state. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int ForceTimeoutForTest(const std::string &abilityName, const std::string &state) override; + #endif + + /** + * Uninstall app + * + * @param bundleName bundle name of uninstalling app. + * @param uid uid of bundle. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int UninstallApp(const std::string &bundleName, int32_t uid) override; + + /** + * Uninstall app + * + * @param bundleName bundle name of uninstalling app. + * @param uid uid of bundle. + * @param appIndex the app index of app clone. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t UninstallApp(const std::string &bundleName, int32_t uid, int32_t appIndex) override; + + /** + * Upgrade app, record exit reason and kill application + * + * @param bundleName bundle name of upgrading app. + * @param uid uid of bundle. + * @param exitMsg the exit reason message. + * @param appIndex the app index of app clone. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t UpgradeApp(const std::string &bundleName, const int32_t uid, const std::string &exitMsg, + int32_t appIndex = 0) override; + + virtual sptr GetWantSender( + const WantSenderInfo &wantSenderInfo, const sptr &callerToken, int32_t uid = -1) override; + + virtual int SendWantSender(sptr target, const SenderInfo &senderInfo) override; + + virtual void CancelWantSender(const sptr &sender) override; + + virtual int GetPendingWantUid(const sptr &target) override; + + virtual int GetPendingWantUserId(const sptr &target) override; + + virtual std::string GetPendingWantBundleName(const sptr &target) override; + + virtual int GetPendingWantCode(const sptr &target) override; + + virtual int GetPendingWantType(const sptr &target) override; + + virtual void RegisterCancelListener(const sptr &sender, const sptr &receiver) override; + + virtual void UnregisterCancelListener( + const sptr &sender, const sptr &receiver) override; + + virtual int GetPendingRequestWant(const sptr &target, std::shared_ptr &want) override; + + virtual int GetWantSenderInfo(const sptr &target, std::shared_ptr &info) override; + + virtual int GetAppMemorySize() override; + + virtual bool IsRamConstrainedDevice() override; + virtual int ContinueMission(const std::string &srcDeviceId, const std::string &dstDeviceId, + int32_t missionId, const sptr &callBack, AAFwk::WantParams &wantParams) override; + + virtual int ContinueMission(AAFwk::ContinueMissionInfo continueMissionInfo, + const sptr &callback) override; + + virtual int ContinueAbility(const std::string &deviceId, int32_t missionId, uint32_t versionCode) override; + + virtual int StartContinuation(const Want &want, const sptr &abilityToken, int32_t status) override; + + virtual void NotifyCompleteContinuation(const std::string &deviceId, int32_t sessionId, bool isSuccess) override; + + virtual int NotifyContinuationResult(int32_t missionId, int32_t result) override; + + virtual int StartSyncRemoteMissions(const std::string& devId, bool fixConflict, int64_t tag) override; + + virtual int StopSyncRemoteMissions(const std::string& devId) override; + + virtual int LockMissionForCleanup(int32_t missionId) override; + + virtual int UnlockMissionForCleanup(int32_t missionId) override; + + virtual void SetLockedState(int32_t sessionId, bool lockedState) override; + + /** + * @brief Register mission listener to ability mgr. + * @param listener The handler of listener. + * + * @return Returns ERR_OK on success, others on failure. + */ + virtual int RegisterMissionListener(const sptr &listener) override; + + /** + * @brief UnRegister mission listener from ability mgr. + * @param listener The handler of listener. + * + * @return Returns ERR_OK on success, others on failure. + */ + virtual int UnRegisterMissionListener(const sptr &listener) override; + + /** + * @brief Get mission infos from ability mgr. + * @param deviceId local or remote deviceId. + * @param numMax max number of missions. + * @param missionInfos mission info result. + * + * @return Returns ERR_OK on success, others on failure. + */ + virtual int GetMissionInfos(const std::string& deviceId, int32_t numMax, + std::vector &missionInfos) override; + + /** + * @brief Get mission info by id. + * @param deviceId local or remote deviceId. + * @param missionId Id of target mission. + * @param missionInfo mission info of target mission. + * + * @return Returns ERR_OK on success, others on failure. + */ + virtual int GetMissionInfo(const std::string& deviceId, int32_t missionId, + MissionInfo &missionInfos) override; + + /** + * @brief Clean mission by id. + * @param missionId Id of target mission. + * + * @return Returns ERR_OK on success, others on failure. + */ + virtual int CleanMission(int32_t missionId) override; + + /** + * @brief Clean all missions in system. + * + * @return Returns ERR_OK on success, others on failure. + */ + virtual int CleanAllMissions() override; + + virtual int MoveMissionToFront(int32_t missionId) override; + + /** + * @brief Move a mission to front. + * @param missionId Id of target mission. + * @param startOptions Special startOptions for target mission. + * + * @return Returns ERR_OK on success, others on failure. + */ + virtual int MoveMissionToFront(int32_t missionId, const StartOptions &startOptions) override; + + /** + * Move missions to front + * @param missionIds Ids of target missions + * @param topMissionId Indicate which mission will be moved to top, if set to -1, missions' order won't change + * @return Returns ERR_OK on success, others on failure. + */ + virtual int MoveMissionsToForeground(const std::vector& missionIds, int32_t topMissionId) override; + + /** + * Move missions to background + * @param missionIds Ids of target missions + * @param result The result of move missions to background, and the array is sorted by zOrder + * @return Returns ERR_OK on success, others on failure. + */ + virtual int MoveMissionsToBackground(const std::vector& missionIds, + std::vector& result) override; + + /** + * Start Ability, connect session with common ability. + * + * @param want, Special want for service type's ability. + * @param connect, Callback used to notify caller the result of connecting or disconnecting. + * @param accountId Indicates the account to start. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StartAbilityByCall(const Want &want, const sptr &connect, + const sptr &callerToken, int32_t accountId = DEFAULT_INVAL_VALUE) override; + + /** + * CallRequestDone, after invoke callRequest, ability will call this interface to return callee. + * + * @param token, ability's token. + * @param callStub, ability's callee. + */ + void CallRequestDone(const sptr &token, const sptr &callStub) override; + + /** + * Release the call between Ability, disconnect session with common ability. + * + * @param connect, Callback used to notify caller the result of connecting or disconnecting. + * @param element, the element of target service. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int ReleaseCall( + const sptr &connect, const AppExecFwk::ElementName &element) override; + + /** + * @brief start user. + * @param accountId accountId. + * @param isAppRecovery is appRecovery or not. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StartUser(int userId, sptr callback, bool isAppRecovery = false) override; + + /** + * @brief stop user. + * @param accountId accountId. + * @param callback callback. + * + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StopUser(int userId, const sptr &callback) override; + + /** + * @brief logout user. + * @param accountId accountId. + * + * @return Returns ERR_OK on success, others on failure. + */ + virtual int LogoutUser(int32_t userId) override; + + virtual int SetMissionContinueState(const sptr &token, const AAFwk::ContinueState &state) override; + +#ifdef SUPPORT_SCREEN + virtual int SetMissionLabel(const sptr &abilityToken, const std::string &label) override; + + virtual int SetMissionIcon(const sptr &token, + const std::shared_ptr &icon) override; + + virtual int RegisterWindowManagerServiceHandler(const sptr& handler, + bool animationEnabled) override; + + virtual void CompleteFirstFrameDrawing(const sptr &abilityToken) override; + + virtual void CompleteFirstFrameDrawing(int32_t sessionId) override; + + virtual int PrepareTerminateAbility( + const sptr &token, sptr &callback) override; + + virtual int GetDialogSessionInfo(const std::string &dialogSessionId, sptr &info) override; + + virtual int SendDialogResult(const Want &want, const std::string &dialogSessionId, bool isAllow) override; + + virtual int RegisterAbilityFirstFrameStateObserver(const sptr &observer, + const std::string &targetBundleName) override; + + virtual int UnregisterAbilityFirstFrameStateObserver( + const sptr &observer) override; +#endif + /** + * @brief Get the ability running information. + * + * @param info Ability running information. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int GetAbilityRunningInfos(std::vector &info) override; + + /** + * @brief Get the extension running information. + * + * @param upperLimit The maximum limit of information wish to get. + * @param info Extension running information. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int GetExtensionRunningInfos(int upperLimit, std::vector &info) override; + + /** + * @brief Get running process information. + * + * @param info Running process information. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int GetProcessRunningInfos(std::vector &info) override; + + /** + * @brief Register mission listener to ability manager service. + * @param deviceId The remote device Id. + * @param listener The handler of listener. + * + * @return Returns ERR_OK on success, others on failure. + */ + virtual int RegisterMissionListener(const std::string &deviceId, + const sptr &listener) override; + + virtual int RegisterOnListener(const std::string &type, + const sptr &listener) override; + + virtual int RegisterOffListener(const std::string &deviceId, + const sptr &listener) override; + + virtual int UnRegisterMissionListener(const std::string &deviceId, + const sptr &listener) override; + + /** + * Set ability controller. + * + * @param abilityController, The ability controller. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int SetAbilityController(const sptr &abilityController, + bool imAStabilityTest) override; + + /** + * Is user a stability test. + * + * @return Returns true if user is a stability test. + */ + virtual bool IsRunningInStabilityTest() override; + + /** + * @brief Register the snapshot handler + * @param handler snapshot handler + * @return ErrCode Returns ERR_OK on success, others on failure. + */ + virtual int RegisterSnapshotHandler(const sptr& handler) override; + + /** + * @brief Get the Mission Snapshot Info object + * @param deviceId local or remote deviceId. + * @param missionId Id of target mission. + * @param snapshot snapshot of target mission. + * @param isLowResolution get low resolution snapshot. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int GetMissionSnapshot(const std::string& deviceId, int32_t missionId, + MissionSnapshot& snapshot, bool isLowResolution) override; + + /** + * @brief start user test. + * @param want the want of the ability user test to start. + * @param observer test observer callback. + * + * @return Returns ERR_OK on success, others on failure. + */ + virtual int StartUserTest(const Want &want, const sptr &observer) override; + + /** + * @brief Finish user test. + * @param msg user test message. + * @param resultCode user test result Code. + * @param bundleName user test bundleName. + * + * @return Returns ERR_OK on success, others on failure. + */ + virtual int FinishUserTest( + const std::string &msg, const int64_t &resultCode, const std::string &bundleName) override; + + /** + * GetTopAbility, get the token of top ability. + * + * @param token, the token of top ability. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int GetTopAbility(sptr &token) override; + + virtual int CheckUIExtensionIsFocused(uint32_t uiExtensionTokenId, bool& isFocused) override; + + /** + * The delegator calls this interface to move the ability to the foreground. + * + * @param token, ability's token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int DelegatorDoAbilityForeground(const sptr &token) override; + + /** + * The delegator calls this interface to move the ability to the background. + * + * @param token, ability's token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int DelegatorDoAbilityBackground(const sptr &token) override; + + /** + * Calls this interface to move the ability to the foreground. + * + * @param token, ability's token. + * @param flag, use for lock or unlock flag and so on. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int DoAbilityForeground(const sptr &token, uint32_t flag) override; + + /** + * Calls this interface to move the ability to the background. + * + * @param token, ability's token. + * @param flag, use for lock or unlock flag and so on. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int DoAbilityBackground(const sptr &token, uint32_t flag) override; + + /** + * Get mission id by ability token. + * + * @param token The token of ability. + * @return Returns -1 if do not find mission, otherwise return mission id. + */ + virtual int32_t GetMissionIdByToken(const sptr &token) override; + + /** + * Get ability token by connect. + * + * @param token The token of ability. + * @param callStub The callee object. + */ + void GetAbilityTokenByCalleeObj(const sptr &callStub, sptr &token) override; + + /** + * Call free install from remote. + * + * @param want, the want of the ability to start. + * @param userId, Designation User ID. + * @param requestCode, Ability request code. + * @param callback, Callback from remote. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int FreeInstallAbilityFromRemote(const Want &want, const sptr &callback, + int32_t userId, int requestCode = DEFAULT_INVAL_VALUE) override; + + /** + * Add FreeInstall Observer + * + * @param observer the observer of ability free install start. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int AddFreeInstallObserver(const sptr &callerToken, + const sptr &observer) override; + + /** + * Called when client complete dump. + * + * @param infos The dump info. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int DumpAbilityInfoDone(std::vector &infos, const sptr &callerToken) override; + + /** + * Called to update mission snapshot. + * @param token The target ability. + * @param pixelMap The snapshot. + */ +#ifdef SUPPORT_SCREEN + virtual void UpdateMissionSnapShot(const sptr &token, + const std::shared_ptr &pixelMap) override; +#endif // SUPPORT_SCREEN + virtual void EnableRecoverAbility(const sptr& token) override; + virtual void SubmitSaveRecoveryInfo(const sptr& token) override; + virtual void ScheduleRecoverAbility(const sptr &token, int32_t reason, + const Want *want = nullptr) override; + + /** + * @brief Schedule clear recovery page stack. + * + * @param bundleName application bundleName. + */ + virtual void ScheduleClearRecoveryPageStack() override; + + /** + * Called to verify that the MissionId is valid. + * @param missionIds Query mission list. + * @param results Output parameters, return results up to 20 query results. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t IsValidMissionIds( + const std::vector &missionIds, std::vector &results) override; + + /** + * Query whether the application of the specified PID and UID has been granted a certain permission + * @param permission + * @param pid Process id + * @param uid + * @return Returns ERR_OK if the current process has the permission, others on failure. + */ + virtual int VerifyPermission(const std::string &permission, int pid, int uid) override; + + /** + * Request dialog service with want, send want to ability manager service. + * + * @param want, the want of the dialog service to start. + * @param callerToken, caller ability token. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t RequestDialogService(const Want &want, const sptr &callerToken) override; + + int32_t ReportDrawnCompleted(const sptr &callerToken) override; + + virtual int32_t AcquireShareData( + const int32_t &missionId, const sptr &shareData) override; + virtual int32_t ShareDataDone(const sptr &token, + const int32_t &resultCode, const int32_t &uniqueId, WantParams &wantParam) override; + + /** + * Force app exit and record exit reason. + * @param pid Process id . + * @param exitReason The reason of app exit. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t ForceExitApp(const int32_t pid, const ExitReason &exitReason) override; + + /** + * Record app exit reason. + * @param exitReason The reason of app exit. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t RecordAppExitReason(const ExitReason &exitReason) override; + + /** + * Record the process exit reason before the process being killed. + * @param pid The process id. + * @param exitReason The reason of process exit. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t RecordProcessExitReason(const int32_t pid, const ExitReason &exitReason) override; + + /** + * Set rootSceneSession by SCB. + * + * @param rootSceneSession Indicates root scene session of SCB. + */ + virtual void SetRootSceneSession(const sptr &rootSceneSession) override; + + /** + * Call UIAbility by SCB. + * + * @param sessionInfo the session info of the ability to be called. + * @param isColdStart the session of the ability is or not cold start. + */ + virtual void CallUIAbilityBySCB(const sptr &sessionInfo, bool &isColdStart) override; + + /** + * Start specified ability by SCB. + * + * @param want Want information. + */ + void StartSpecifiedAbilityBySCB(const Want &want) override; + + /** + * Notify sandbox app the result of saving file. + * @param want Result of saving file, which contains the file's uri if success. + * @param resultCode Indicates the action's result. + * @param requestCode Pass the requestCode to match request. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t NotifySaveAsResult(const Want &want, int resultCode, int requestCode) override; + + /** + * Set sessionManagerService + * @param sessionManagerService the point of sessionManagerService. + * + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t SetSessionManagerService(const sptr &sessionManagerService) override; + + /** + * @brief Register collaborator. + * @param type collaborator type. + * @param impl collaborator. + * @return 0 or else. + */ + virtual int32_t RegisterIAbilityManagerCollaborator( + int32_t type, const sptr &impl) override; + + /** + * @brief Unregister collaborator. + * @param type collaborator type. + * @return 0 or else. + */ + virtual int32_t UnregisterIAbilityManagerCollaborator(int32_t type) override; + + virtual int32_t RegisterStatusBarDelegate(sptr delegate) override; + + virtual int32_t KillProcessWithPrepareTerminate(const std::vector& pids) override; + + /** + * @brief the process with reason + * @param pid id of process. + * @param reason, kill process reason. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t KillProcessWithReason(int32_t pid, const ExitReason &reason) override; + + /** + * @brief Register auto start up callback for system api. + * @param callback The point of JsAbilityAutoStartupCallBack. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t RegisterAutoStartupSystemCallback(const sptr &callback) override; + + /** + * @brief Unregister auto start up callback for system api. + * @param callback The point of JsAbilityAutoStartupCallBack. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t UnregisterAutoStartupSystemCallback(const sptr &callback) override; + + /** + * @brief Set every application auto start up state. + * @param info The auto startup info,include bundle name, module name, ability name. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t SetApplicationAutoStartup(const AutoStartupInfo &info) override; + + /** + * @brief Cancel every application auto start up . + * @param info The auto startup info,include bundle name, module name, ability name. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t CancelApplicationAutoStartup(const AutoStartupInfo &info) override; + + /** + * @brief Query auto startup state all application. + * @param infoList Output parameters, return auto startup info list. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t QueryAllAutoStartupApplications(std::vector &infoList) override; + + /** + * PrepareTerminateAbilityBySCB, prepare to terminate ability by scb. + * + * @param sessionInfo the session info of the ability to start. + * @param isPrepareTerminate the result of ability onPrepareToTerminate. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int PrepareTerminateAbilityBySCB(const sptr &sessionInfo, bool &isPrepareTerminate) override; + + /** + * @brief Register session handler. + * @param object The handler. + * + * @return Returns ERR_OK on success, others on failure. + */ + virtual int RegisterSessionHandler(const sptr &object) override; + + /** + * @brief Register app debug listener. + * @param listener App debug listener. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t RegisterAppDebugListener(sptr listener) override; + + /** + * @brief Unregister app debug listener. + * @param listener App debug listener. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t UnregisterAppDebugListener(sptr listener) override; + + /** + * @brief Attach app debug. + * @param bundleName The application bundle name. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t AttachAppDebug(const std::string &bundleName) override; + + /** + * @brief Detach app debug. + * @param bundleName The application bundle name. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t DetachAppDebug(const std::string &bundleName) override; + + /** + * @brief Execute intent. + * @param key The key of intent executing client. + * @param callerToken Caller ability token. + * @param param The Intent execute param. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t ExecuteIntent(uint64_t key, const sptr &callerToken, + const InsightIntentExecuteParam ¶m) override; + + /** + * @brief Check if ability controller can start. + * @param want The want of ability to start. + * @return Return true to allow ability to start, or false to reject. + */ + virtual bool IsAbilityControllerStart(const Want &want) override; + + /** + * @brief Called when insight intent execute finished. + * + * @param token ability's token. + * @param intentId insight intent id. + * @param result insight intent execute result. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t ExecuteInsightIntentDone(const sptr &token, uint64_t intentId, + const InsightIntentExecuteResult &result) override; + + /** + * @brief Set application auto start up state by EDM. + * @param info The auto startup info, include bundle name, module name, ability name. + * @param flag Indicate whether to allow the application to change the auto start up state. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t SetApplicationAutoStartupByEDM(const AutoStartupInfo &info, bool flag) override; + + /** + * @brief Cancel application auto start up state by EDM. + * @param info The auto startup info, include bundle name, module name, ability name. + * @param flag Indicate whether to allow the application to change the auto start up state. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t CancelApplicationAutoStartupByEDM(const AutoStartupInfo &info, bool flag) override; + + /** + * @brief Get foreground ui abilities. + * @param list Foreground ui abilities. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t GetForegroundUIAbilities(std::vector &list) override; + + /** + * @brief Open file by uri. + * @param uri The file uri. + * @param flag Want::FLAG_AUTH_READ_URI_PERMISSION or Want::FLAG_AUTH_WRITE_URI_PERMISSION. + * @return int The file descriptor. + */ + virtual int32_t OpenFile(const Uri& uri, uint32_t flag) override; + + /** + * @brief Update session info. + * @param sessionInfos The vector of session info. + */ + virtual int32_t UpdateSessionInfoBySCB(std::list &sessionInfos, int32_t userId, + std::vector &sessionIds) override; + + /** + * @brief Restart app self. + * @param want The ability type must be UIAbility. + * @param isAppRecovery True indicates that the app is restarted because of recovery. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t RestartApp(const AAFwk::Want &want, bool isAppRecovery = false) override; + + /** + * @brief Get host info of root caller. + * + * @param token The ability token. + * @param hostInfo The host info of root caller. + * @param userId The user id. + * @return int32_t Returns 0 on success, others on failure. + */ + int32_t GetUIExtensionRootHostInfo(const sptr token, UIExtensionHostInfo &hostInfo, + int32_t userId = DEFAULT_INVAL_VALUE) override; + + /** + * @brief Get ui extension session info + * + * @param token The ability token. + * @param uiExtensionSessionInfo The ui extension session info. + * @param userId The user id. + * @return int32_t Returns ERR_OK on success, others on failure. + */ + int32_t GetUIExtensionSessionInfo(const sptr token, UIExtensionSessionInfo &uiExtensionSessionInfo, + int32_t userId = DEFAULT_INVAL_VALUE) override; + + /** + * @brief Pop-up launch of full-screen atomic service. + * @param want The want with parameters. + * @param callerToken caller ability token. + * @param requestCode Ability request code. + * @param userId The User ID. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t OpenAtomicService(Want& want, const StartOptions &options, sptr callerToken, + int32_t requestCode = DEFAULT_INVAL_VALUE, int32_t userId = DEFAULT_INVAL_VALUE) override; + + /** + * @brief Querying whether to allow embedded startup of atomic service. + * + * @param token The caller UIAbility token. + * @param appId The ID of the application to which this bundle belongs. + * @return Returns true to allow ability to start, or false to reject. + */ + virtual bool IsEmbeddedOpenAllowed(sptr callerToken, const std::string &appId) override; + + /** + * Set the enable status for starting and stopping resident processes. + * The caller application can only set the resident status of the configured process. + * @param bundleName The bundle name of the resident process. + * @param enable Set resident process enable status. + * @return Returns ERR_OK on success, others on failure. + */ + int32_t SetResidentProcessEnabled(const std::string &bundleName, bool enable) override; + + /** + * @brief Request to display assert fault dialog. + * @param callback Listen for user operation callbacks. + * @param wantParams Assert dialog box display information. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t RequestAssertFaultDialog( + const sptr &callback, const AAFwk::WantParams &wantParams) override; + + /** + * @brief Notify the operation status of the user. + * @param assertFaultSessionId Indicates the request ID of AssertFault. + * @param userStatus Operation status of the user. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t NotifyDebugAssertResult(uint64_t assertFaultSessionId, AAFwk::UserStatus userStatus) override; + + /** + * Starts a new ability with specific start options. + * + * @param want, the want of the ability to start. + * @param startOptions Indicates the options used to start. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t StartShortcut(const Want &want, const StartOptions &startOptions) override; + + /** + * Get ability state by persistent id. + * + * @param persistentId, the persistentId of the session. + * @param state Indicates the ability state. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t GetAbilityStateByPersistentId(int32_t persistentId, bool &state) override; + + /** + * Transfer resultCode & want to ability manager service. + * + * @param callerToken caller ability token. + * @param requestCode the resultCode of the ability to start. + * @param want Indicates the ability to start. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t TransferAbilityResultForExtension(const sptr &callerToken, int32_t resultCode, + const Want &want) override; + + /** + * Notify ability manager service frozen process. + * + * @param pidList, the pid list of the frozen process. + * @param uid, the uid of the frozen process. + */ + virtual void NotifyFrozenProcessByRSS(const std::vector &pidList, int32_t uid) override; + + /** + * Open atomic service window prior to finishing free install. + * + * @param bundleName, the bundle name of the atomic service. + * @param moduleName, the module name of the atomic service. + * @param abilityName, the ability name of the atomic service. + * @param startTime, the starting time of the free install task. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t PreStartMission(const std::string& bundleName, const std::string& moduleName, + const std::string& abilityName, const std::string& startTime) override; + + /** + * Request to clean UIAbility from user. + * + * @param sessionInfo the session info of the ability to clean. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t CleanUIAbilityBySCB(const sptr &sessionInfo) override; + + /** + * Open link of ability and atomic service. + * + * @param want Ability want. + * @param callerToken Caller ability token. + * @param userId User ID. + * @param requestCode Ability request code. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t OpenLink(const Want& want, sptr callerToken, + int32_t userId = DEFAULT_INVAL_VALUE, int requestCode = DEFAULT_INVAL_VALUE) override; + + /** + * Terminate the mission. + * + * @param missionId, The mission id of the UIAbility need to be terminated. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t TerminateMission(int32_t missionId) override; + + /** + * Notify ability manager to set the flag to block all apps from starting. + * Needs to apply for ohos.permission.BLOCK_ALL_APP_START. + * @param flag, The flag to block all apps from starting + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t BlockAllAppStart(bool flag) override; + + /** + * update associate config list by rss. + * + * @param configs The rss config info. + * @param exportConfigs The rss export config info. + * @param flag UPDATE_CONFIG_FLAG_COVER is cover config, UPDATE_CONFIG_FLAG_APPEND is append config. + */ + virtual int32_t UpdateAssociateConfigList(const std::map>& configs, + const std::list& exportConfigs, int32_t flag) override; + + /** + * Set keep-alive flag for application under a specific user. + * @param bundleName Bundle name. + * @param userId User Id. + * @param flag Keep-alive flag. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t SetApplicationKeepAlive(const std::string &bundleName, int32_t userId, bool flag) override; + + /** + * Get keep-alive applications. + * @param appType Application type. + * @param userId User Id. + * @param list List of Keep-alive information. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t QueryKeepAliveApplications(int32_t appType, int32_t userId, + std::vector &list) override; + + /** + * Set keep-alive flag for application under a specific user by EDM. + * @param bundleName Bundle name. + * @param userId User Id. + * @param flag Keep-alive flag. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t SetApplicationKeepAliveByEDM(const std::string &bundleName, int32_t userId, bool flag) override; + + /** + * Get keep-alive applications by EDM. + * @param appType Application type. + * @param userId User Id. + * @param list List of Keep-alive information. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t QueryKeepAliveApplicationsByEDM(int32_t appType, int32_t userId, + std::vector &list) override; + + /** + * Get intent exemption info. + * @param list List of intent exemption info. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t GetAllIntentExemptionInfo(std::vector &info) override; + + /** + * Add query ERMS observer. + * + * @param callerToken, The caller ability token. + * @param observer, The observer of the ability to query ERMS. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t AddQueryERMSObserver(sptr callerToken, + sptr observer) override; + + /** + * Query atomic service ERMS rule. + * + * @param callerToken, The caller ability token. + * @param appId, The appId of the atomic service. + * @param startTime, The startTime of the query. + * @param rule, The returned ERMS rule. + * @return Returns ERR_OK on success, others on failure. + */ + virtual int32_t QueryAtomicServiceStartupRule(sptr callerToken, + const std::string &appId, const std::string &startTime, AtomicServiceStartupRule &rule) override; + +private: + template + int GetParcelableInfos(MessageParcel &reply, std::vector &parcelableInfos); + bool WriteInterfaceToken(MessageParcel &data); + // flag = true : terminate; flag = false : close + int TerminateAbility(const sptr &token, int resultCode, const Want *resultWant, bool flag); + ErrCode SendRequest(AbilityManagerInterfaceCode code, MessageParcel &data, MessageParcel &reply, + MessageOption& option); + int CheckUISessionParams(MessageParcel &data, const sptr &callerToken, + const sptr &sessionInfo, int32_t userId, int requestCode); + bool UpdateAssociateConfigInner(const std::map>& configs, + MessageParcel& data); + bool ExtendMaxIpcCapacityForWant(const Want &want, MessageParcel &data); + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace AAFwk +} // namespace OHOS +#endif diff --git a/mock/innerkits/ability_runtime/common/BUILD.gn b/mock/innerkits/ability_runtime/common/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..c5fcef0bd917cc4b7aaa44d1821594ad7c469c9b --- /dev/null +++ b/mock/innerkits/ability_runtime/common/BUILD.gn @@ -0,0 +1,188 @@ +# +# Copyright (c) 2024 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. +# + +import("//build/ohos.gni") +import("//foundation/ability/ability_runtime/ability_runtime.gni") + +group("ams_common_target") { + deps = [ + ":event_report", + ":perm_verification", + ":task_handler_wrap", + ] +} + +config("common_config") { + visibility = [ ":*" ] + visibility += [ + "${ability_runtime_innerkits_path}/*", + "${ability_runtime_napi_path}/*", + "${ability_runtime_native_path}/ability/native/*", + "${ability_runtime_native_path}/child_process/*", + "${ability_runtime_path}/frameworks/c/ability_runtime/*", + "${ability_runtime_path}/frameworks/simulator/ability_simulator/*", + "${ability_runtime_path}/tools/aa/*", + "${ability_runtime_services_path}/common/*", + "${ability_runtime_services_path}/quickfixmgr/*", + "${ability_runtime_services_path}/uripermmgr/*", + "${ability_runtime_test_path}/*", + "${hiebpf_path}/*", + "${power_manager_path}/utils/*", + "${request_path}/common/*", + ] + include_dirs = [ + "include", + "${ability_runtime_innerkits_path}/ability_manager/include", + ] + cflags = [] + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } +} + +#build so +ohos_shared_library("perm_verification") { + branch_protector_ret = "pac_ret" + + include_dirs = [ "${ability_runtime_utils_path}/server/constant" ] + + public_configs = [ ":common_config" ] + + sources = [ "src/permission_verification.cpp" ] + + external_deps = [ + "ability_base:want", + "access_token:libaccesstoken_sdk", + "access_token:libtokenid_sdk", + "c_utils:utils", + "hilog:libhilog", + "hitrace:hitrace_meter", + "init:libbegetutil", + "ipc:ipc_core", + ] + + cflags_cc = [] + if (os_dlp_part_enabled) { + cflags_cc += [ "-DWITH_DLP" ] + } + + subsystem_name = "ability" + innerapi_tags = [ "platformsdk_indirect" ] + part_name = "ability_runtime" +} + +ohos_shared_library("event_report") { + branch_protector_ret = "pac_ret" + + public_configs = [ ":common_config" ] + + sources = [ "src/event_report.cpp" ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + ] + + innerapi_tags = [ "platformsdk_indirect" ] + subsystem_name = "ability" + part_name = "ability_runtime" +} + +ohos_shared_library("task_handler_wrap") { + branch_protector_ret = "pac_ret" + + public_configs = [ ":common_config" ] + include_dirs = [ "include" ] + + sources = [ + "src/event_handler_wrap.cpp", + "src/ffrt_task_handler_wrap.cpp", + "src/queue_task_handler_wrap.cpp", + "src/task_handler_wrap.cpp", + ] + + external_deps = [ + "ffrt:libffrt", + "hilog:libhilog", + ] + + subsystem_name = "ability" + part_name = "ability_runtime" +} + +ohos_shared_library("app_util") { + branch_protector_ret = "pac_ret" + + public_configs = [ ":common_config" ] + include_dirs = [ "include" ] + + sources = [ + "src/ability_manager_radar.cpp", + "src/app_utils.cpp", + "src/json_utils.cpp", + ] + + external_deps = [ + "c_utils:utils", + "config_policy:configpolicy_util", + "hilog:libhilog", + "hisysevent:libhisysevent", + "init:libbegetutil", + "json:nlohmann_json_static", + ] + + if (ability_runtime_graphics) { + defines = [ "SUPPORT_GRAPHICS" ] + external_deps += [ "window_manager:libwsutils" ] + } + + subsystem_name = "ability" + part_name = "ability_runtime" +} + +ohos_shared_library("res_sched_util") { + sanitize = { + integer_overflow = true + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + branch_protector_ret = "pac_ret" + + public_configs = [ ":common_config" ] + include_dirs = [ "include" ] + + sources = [ "src/res_sched_util.cpp" ] + + external_deps = [ + "bundle_framework:appexecfwk_base", + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_core", + "samgr:samgr_proxy", + ] + + if (resource_schedule_service_enable) { + defines = [ "RESOURCE_SCHEDULE_SERVICE_ENABLE" ] + external_deps += [ "resource_schedule_service:ressched_client" ] + } + + subsystem_name = "ability" + part_name = "ability_runtime" +} diff --git a/mock/innerkits/ability_runtime/common/include/ability_manager_radar.h b/mock/innerkits/ability_runtime/common/include/ability_manager_radar.h new file mode 100644 index 0000000000000000000000000000000000000000..665356ecfca1c5e547b16d15d94db7b1dcdae99d --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/ability_manager_radar.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024 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_ABILITY_MANAGER_RADAR_H +#define OHOS_ABILITY_MANAGER_RADAR_H + +#include +#include +#include +#include + +namespace OHOS { +namespace AAFWK { +enum class BizScene : int32_t { + CLICK_ICON = 10, + SAVE_DATA = 11, +}; + +enum class StageRes : int32_t { + STAGE_IDLE = 0, + STAGE_SUCC = 1, + STAGE_FAIL = 2, + STAGE_CANCEL = 3, + STAGE_UNKNOW = 4, +}; + +enum class BizState : int32_t { + BIZ_STATE_START = 1, + BIZ_STATE_END = 2, +}; + +enum class ClickIcon : int32_t { + CLICKICON_CONTINUE = 3, + CLICKICON_STARTABILITY = 6, + CLICKICON_RECV_OVER = 9, +}; + +enum class SaveData : int32_t { + SAVEDATA_CONTINUE = 2, + SAVEDATA_RES = 3, + SAVEDATA_REMOTE_WANT = 4, +}; + +class ContinueRadar { +public: + static ContinueRadar &GetInstance(); + + bool ClickIconContinue(const std::string& func); + bool ClickIconStartAbility(const std::string& func, unsigned int flags, int32_t errCode); + bool ClickIconRecvOver(const std::string& func); + bool SaveDataContinue(const std::string& func); + bool SaveDataRes(const std::string& func); + bool SaveDataRemoteWant(const std::string& func); +}; +} // namespace AAFWK +} // namespace OHOS +#endif // OHOS_ABILITY_MANAGER_RADAR_H \ No newline at end of file diff --git a/mock/innerkits/ability_runtime/common/include/app_utils.h b/mock/innerkits/ability_runtime/common/include/app_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..a4bd58743b2310b518d73a3c82f288dd338eee47 --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/app_utils.h @@ -0,0 +1,328 @@ +/* + * 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_ABILITY_RUNTIME_APP_UTILS_H +#define OHOS_ABILITY_RUNTIME_APP_UTILS_H + +#include +#include + +#include "nocopyable.h" + +namespace OHOS { +namespace AAFwk { +constexpr const int32_t DEFAULT_MAX_EXT_PER_PROC = 10; +constexpr const int32_t DEFAULT_MAX_EXT_PER_DEV = 100; +constexpr const int32_t DEFAULT_INVALID_VALUE = -1; +constexpr const int32_t DEFAULT_MAX_CHILD_PROCESS = 0; +template +class DeviceConfiguration { +public: + bool isLoaded = false; + T value; +}; + +/** + * @class AppUtils + * provides app utils. + */ +class AppUtils { +public: + /** + * GetInstance, get an instance of AppUtils. + * + * @return An instance of AppUtils. + */ + static AppUtils &GetInstance(); + + /** + * AppUtils, destructor. + * + */ + ~AppUtils(); + + /** + * IsLauncher, check if it is a launcher. + * + * @param bundleName The bundle name. + * @return Whether it is a launcher. + */ + bool IsLauncher(const std::string &bundleName) const; + + /** + * IsLauncherAbility, check if it is a launcher ability. + * + * @param abilityName The ability name. + * @return Whether it is a launcher ability. + */ + bool IsLauncherAbility(const std::string &abilityName) const; + + /** + * IsInheritWindowSplitScreenMode, check if it is inherit window split screen mode. + * + * @return Whether it is inherit window split screen mode. + */ + bool IsInheritWindowSplitScreenMode(); + + /** + * IsSupportAncoApp, check if it supports anco app. + * + * @return Whether it supports anco app. + */ + bool IsSupportAncoApp(); + + /** + * GetTimeoutUnitTimeRatio, get timeout unit time ratio. + * + * @return Timeout unit time ratio. + */ + int32_t GetTimeoutUnitTimeRatio(); + + /** + * IsSelectorDialogDefaultPossion, check if selector dialog is on the default position. + * + * @return Whether selector dialog is on the default position. + */ + bool IsSelectorDialogDefaultPossion(); + + /** + * IsStartSpecifiedProcess, check whether or not to start specified process. + * + * @return Whether or not to start specified process. + */ + bool IsStartSpecifiedProcess(); + + /** + * IsUseMultiRenderProcess, check whether uses multi-render process. + * + * @return Whether uses multi-render process. + */ + bool IsUseMultiRenderProcess(); + + /** + * IsLimitMaximumOfRenderProcess, check limit maximum of render process. + * + * @return Whether limit maximum of render process. + */ + bool IsLimitMaximumOfRenderProcess(); + + /** + * IsGrantPersistUriPermission, check whether to grant persist uri permission. + * + * @return Whether to grant persist uri permission. + */ + bool IsGrantPersistUriPermission(); + + /** + * IsStartOptionsWithAnimation, check whether the start options have animation. + * + * @return Whether the start options have animation. + */ + bool IsStartOptionsWithAnimation(); + + /** + * IsStartOptionsWithAnimation, check whether it is a multi-process model. + * + * @return Whether it is a multi-process model. + */ + bool IsMultiProcessModel(); + + /** + * IsStartOptionsWithProcessOptions, check whether the start options have process options. + * + * @return Whether the start options have process options. + */ + bool IsStartOptionsWithProcessOptions(); + + /** + * EnableMoveUIAbilityToBackgroundApi, enable move ui-ability to background api. + * + * @return Whether the enable move ui-ability to background api is successful. + */ + bool EnableMoveUIAbilityToBackgroundApi(); + + /** + * IsLaunchEmbededUIAbility, check if it is to launch embedded ui-ability. + * + * @return Whether it is to launch embedded ui-ability. + */ + bool IsLaunchEmbededUIAbility(); + + /** + * IsSupportNativeChildProcess, check if it supports native child process. + * + * @return Whether it supports native child process. + */ + bool IsSupportNativeChildProcess(); + + /** + * IsSupportMultiInstance, check if it supports multi-instance. + * + * @return Whether it supports multi-instance. + */ + bool IsSupportMultiInstance(); + + /** + * IsAllowResidentInExtremeMemory, check if it allows resident in extrem low memory. + * + * @param bundleName The bundle name. + * @param abilityName The ability name. + * @return Whether it allows resident in extrem low memory. + */ + bool IsAllowResidentInExtremeMemory(const std::string& bundleName, const std::string& abilityName = ""); + + /** + * IsAllowNativeChildProcess, check if it allows native child process. + * + * @param appIdentifier The app identifier. + * @return Whether it allows native child process. + */ + bool IsAllowNativeChildProcess(const std::string &appIdentifier); + + /** + * GetLimitMaximumExtensionsPerProc, get limit max extensions per proc. + * + * @return Limit max extensions per proc. + */ + int32_t GetLimitMaximumExtensionsPerProc(); + + /** + * GetLimitMaximumExtensionsPerDevice, get limit max extensions per device. + * + * @return Limit max extensions per device. + */ + int32_t GetLimitMaximumExtensionsPerDevice(); + + /** + * GetCacheExtensionTypeList, get cache extension type list. + * + * @return Cache extension type list. + */ + std::string GetCacheExtensionTypeList(); + + /** + * IsAllowStartAbilityWithoutCallerToken, check if it allows start ability without caller token. + * + * @param bundleName The bundle name. + * @param abilityName The ability name. + * @return Whether it allows start ability without caller token. + */ + bool IsAllowStartAbilityWithoutCallerToken(const std::string& bundleName, const std::string& abilityName); + + /** + * GetBrokerDelegateBundleName, get broker delegate bundle name. + * + * @return Broker delegate bundle name. + */ + std::string GetBrokerDelegateBundleName(); + + /** + * GetCollaboratorBrokerUID, get collaborator broker id. + * + * @return Collaborator broker id. + */ + int32_t GetCollaboratorBrokerUID(); + + /** + * GetCollaboratorBrokerReserveUID, get collaborator broker reserve uid. + * + * @return Collaborator broker reserve uid. + */ + int32_t GetCollaboratorBrokerReserveUID(); + + /** + * MaxChildProcess, get max child process. + * + * @return Max child process. + */ + int32_t MaxChildProcess(); + + /** + * GetMigrateClientBundleName, get migrate client bundle name. + * + * @return Migrate client bundle name. + */ + std::string GetMigrateClientBundleName(); + + /** + * IsConnectSupportCrossUser, check if it support cross-user. + * + * @return Whether it supports cross-user. + */ + bool IsConnectSupportCrossUser(); + +private: + /** + * LoadResidentProcessInExtremeMemory, load resident process in extreme low memory. + * + */ + void LoadResidentProcessInExtremeMemory(); + + /** + * LoadAllowNativeChildProcessApps, load allow native child process apps. + * + */ + void LoadAllowNativeChildProcessApps(); + + /** + * LoadStartAbilityWithoutCallerToken, load start ability without caller token. + * + */ + void LoadStartAbilityWithoutCallerToken(); + + /** + * AppUtils, private constructor. + * + */ + AppUtils(); + + volatile bool isSceneBoard_ = false; + volatile DeviceConfiguration isInheritWindowSplitScreenMode_ = {false, true}; + volatile DeviceConfiguration isSupportAncoApp_ = {false, false}; + volatile DeviceConfiguration timeoutUnitTimeRatio_ = {false, 1}; + volatile DeviceConfiguration isSelectorDialogDefaultPossion_ = {false, true}; + volatile DeviceConfiguration isStartSpecifiedProcess_ = {false, false}; + volatile DeviceConfiguration isUseMultiRenderProcess_ = {false, true}; + volatile DeviceConfiguration isLimitMaximumOfRenderProcess_ = {false, true}; + volatile DeviceConfiguration isGrantPersistUriPermission_ = {false, false}; + volatile DeviceConfiguration isStartOptionsWithAnimation_ = {false, false}; + volatile DeviceConfiguration isMultiProcessModel_ = {false, false}; + volatile DeviceConfiguration isStartOptionsWithProcessOptions_ = {false, false}; + volatile DeviceConfiguration enableMoveUIAbilityToBackgroundApi_ = {false, true}; + volatile DeviceConfiguration isLaunchEmbededUIAbility_ = {false, false}; + volatile DeviceConfiguration isSupportNativeChildProcess_ = {false, false}; + volatile DeviceConfiguration isSupportMultiInstance_ = {false, false}; + std::mutex isConnectSupportCrossUserMutex_; + volatile DeviceConfiguration isConnectSupportCrossUser_ = {false, false}; + DeviceConfiguration>> + residentProcessInExtremeMemory_ = {false, {}}; + std::mutex residentProcessInExtremeMemoryMutex_; + DeviceConfiguration> + allowStartNativeProcessApps_ = {false, {}}; + volatile DeviceConfiguration limitMaximumExtensionsPerProc_ = {false, DEFAULT_MAX_EXT_PER_PROC}; + volatile DeviceConfiguration limitMaximumExtensionsPerDevice_ = {false, DEFAULT_MAX_EXT_PER_DEV}; + DeviceConfiguration>> + startAbilityWithoutCallerToken_ = {false, {}}; + std::mutex startAbilityWithoutCallerTokenMutex_; + DeviceConfiguration brokerDelegateBundleName_ = {false, ""}; + volatile DeviceConfiguration collaboratorBrokerUid_ = {false, DEFAULT_INVALID_VALUE}; + volatile DeviceConfiguration collaboratorBrokerReserveUid_ = {false, DEFAULT_INVALID_VALUE}; + volatile DeviceConfiguration maxChildProcess_ = {false, DEFAULT_MAX_CHILD_PROCESS}; + DeviceConfiguration migrateClientBundleName_ = {true, "com.huwei.hmos.migratecilent"}; + DISALLOW_COPY_AND_MOVE(AppUtils); +}; +} // namespace AAFwk +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_APP_UTILS_H diff --git a/mock/innerkits/ability_runtime/common/include/cache_extension_utils.h b/mock/innerkits/ability_runtime/common/include/cache_extension_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..bb4d44344bc378a40145a7e1aef5684b5b4ed051 --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/cache_extension_utils.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024-2024 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_AAFWK_CACHE_EXTENSION_UTILS_H +#define OHOS_AAFWK_CACHE_EXTENSION_UTILS_H + +#include + +#include "app_utils.h" +#include "extension_ability_info.h" + +namespace OHOS { +namespace AAFwk { +namespace CacheExtensionUtils { +constexpr const int32_t BASE_TEN = 10; + +// cache extension type list +std::unordered_set GetCacheExtensionTypeList() +{ + std::unordered_set cacheExtTypeList; + auto cacheExtTypeListStr = AppUtils::GetInstance().GetCacheExtensionTypeList(); + if (cacheExtTypeListStr.empty()) { + return cacheExtTypeList; + } + std::vector cacheExtTypeListVec; + SplitStr(cacheExtTypeListStr, ";", cacheExtTypeListVec); + for (auto it = cacheExtTypeListVec.begin(); it != cacheExtTypeListVec.end(); it++) { + cacheExtTypeList.insert( + static_cast(std::strtol((*it).c_str(), nullptr, BASE_TEN))); + } + return cacheExtTypeList; +} + +inline bool IsCacheExtensionType(const AppExecFwk::ExtensionAbilityType type) +{ + return GetCacheExtensionTypeList().count(type) > 0; +} +} // namespace CacheExtensionUtils +} // namespace AAFwk +} // namespace OHOS +#endif // OHOS_AAFWK_CACHE_EXTENSION_UTILS_H diff --git a/mock/innerkits/ability_runtime/common/include/display_util.h b/mock/innerkits/ability_runtime/common/include/display_util.h new file mode 100644 index 0000000000000000000000000000000000000000..eb22fda5f3d69897e2021d4c83be8020b54a2ebe --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/display_util.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 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_ABILITY_RUNTIME_DISPLAY_UTIL_H +#define OHOS_ABILITY_RUNTIME_DISPLAY_UTIL_H + +#include "hilog_tag_wrapper.h" +#ifdef SUPPORT_GRAPHICS +#include "display_manager.h" +#include "scene_board_judgement.h" +#endif // SUPPORT_GRAPHICS + +namespace OHOS { +namespace AAFwk { +namespace DisplayUtil { +#ifdef SUPPORT_GRAPHICS +static inline int32_t GetDefaultDisplayId() +{ + if (Rosen::SceneBoardJudgement::IsSceneBoardEnabled()) { + sptr display = Rosen::DisplayManager::GetInstance().GetPrimaryDisplaySync(); + if (display != nullptr) { + TAG_LOGD(AAFwkTag::DEFAULT, "displayId: %{public}d", static_cast(display->GetId())); + return static_cast(display->GetId()); + } + } + return static_cast(Rosen::DisplayManager::GetInstance().GetDefaultDisplayId()); +} +#endif +}; +} // namespace AAFwk +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_DISPLAY_UTIL_H \ No newline at end of file diff --git a/mock/innerkits/ability_runtime/common/include/event_handler_wrap.h b/mock/innerkits/ability_runtime/common/include/event_handler_wrap.h new file mode 100644 index 0000000000000000000000000000000000000000..46ef901b3649be0c95acd2b1572bcebd8bfbdf54 --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/event_handler_wrap.h @@ -0,0 +1,137 @@ +/* + * 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_ABILITY_RUNTIME_EVENT_HANDLER_WRAP_H +#define OHOS_ABILITY_RUNTIME_EVENT_HANDLER_WRAP_H + +#include +#include +#include +#include + +#include "task_handler_wrap.h" + +namespace OHOS { +namespace AAFwk { +class EventDataBase { +public: + virtual ~EventDataBase() = default; +}; +class EventWrap { +public: + EventWrap(uint32_t eventId) : EventWrap(eventId, 0) {} + EventWrap(uint32_t eventId, int64_t param) : eventId_(eventId), param_(param) + { + eventData_ = std::make_shared(); + } + EventWrap(uint32_t eventId, int64_t param, bool isExtension) : isExtension_(isExtension), eventId_(eventId), + param_(param) + { + eventData_ = std::make_shared(); + } + EventWrap(uint32_t eventId, std::shared_ptr data) + : eventId_(eventId), param_(0), eventData_(data) + { + if (!eventData_) { + eventData_ = std::make_shared(); + } + } + uint32_t GetEventId() const + { + return eventId_; + } + int64_t GetParam() const + { + return param_; + } + const std::shared_ptr& GetEventData() const + { + return eventData_; + } + const TaskHandle& GetEventTask() const + { + return eventTask_; + } + void SetEventTask(const TaskHandle &eventTask) + { + eventTask_ = eventTask; + } + std::string GetEventString() + { + return std::to_string(eventId_) + "_" + std::to_string(param_); + } + bool IsSame(const EventWrap &other) const + { + return eventData_ == other.eventData_; + } + void SetRunCount(int runCount) + { + runCount_ = runCount; + } + int GetRunCount() const + { + return runCount_; + } + void SetTimeout(uint32_t timeout) + { + timeout_ = timeout; + } + uint32_t GetTimeout() const + { + return timeout_; + } + bool IsExtension() const + { + return isExtension_; + } +private: + bool isExtension_ = false; + uint32_t eventId_; + uint32_t timeout_ = 0; + int runCount_ = 0; + int64_t param_; + std::shared_ptr eventData_; + TaskHandle eventTask_; +}; + +class EventHandlerWrap : public std::enable_shared_from_this { +public: + EventHandlerWrap(); + EventHandlerWrap(std::shared_ptr taskHandler); + EventHandlerWrap(EventHandlerWrap &) = delete; + void operator=(EventHandlerWrap &) = delete; + virtual ~EventHandlerWrap(); + virtual void ProcessEvent(const EventWrap &event); + bool SendEvent(uint32_t eventId); + bool SendEvent(uint32_t eventId, int64_t delayMillis); + bool SendEvent(EventWrap event); + bool SendEvent(EventWrap event, int64_t delayMillis, bool forceInsert = true); + bool RemoveEvent(uint32_t eventId, int64_t param = 0); + bool RemoveEvent(EventWrap event, bool force = true); + + void SetEventCallback(std::function eventCallback) + { + eventCallback_ = eventCallback; + } +protected: + std::shared_ptr taskHandler_; + std::function eventCallback_; + + std::unique_ptr eventMutex_; + std::unordered_map eventMap_; +}; +} // namespace AAFWK +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_EVENT_HANDLER_WRAP_H \ No newline at end of file diff --git a/mock/innerkits/ability_runtime/common/include/event_report.h b/mock/innerkits/ability_runtime/common/include/event_report.h new file mode 100644 index 0000000000000000000000000000000000000000..b666e4341d53391d3d8b48172b8fa9a8e690572e --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/event_report.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2022-2024 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_ABILITY_RUNTIME_EVENT_REPORT_H +#define OHOS_ABILITY_RUNTIME_EVENT_REPORT_H + +#include + +#include "hisysevent.h" + +using HiSysEventType = OHOS::HiviewDFX::HiSysEvent::EventType; +using HiSysEvent = OHOS::HiviewDFX::HiSysEvent; + +namespace OHOS { +namespace AAFwk { +struct EventInfo { + bool isPreload = false; + int32_t pid = -1; + int32_t userId = -1; + int32_t extensionType = -1; + int32_t abilityNumber = 0; + int32_t abilityType = -1; + int32_t callerUid = -1; + int32_t exitResult = -1; + int32_t bundleType = -1; + int32_t startType = 0; + int32_t startReason = 0; + int32_t appUid = -1; + int32_t errCode = -1; + int32_t callerState = -1; + int32_t processType = -1; + int32_t callerPid = -1; + int64_t duration = 0; + int32_t reason = -1; + int32_t subReason = -1; + int32_t exitReason = -1; + int32_t preloadMode = 0; + uint32_t versionCode = 0; + uint32_t callerVersionCode = -1; + int64_t time = 0; + std::string versionName; + std::string bundleName; + std::string moduleName; + std::string abilityName; + std::string processName; + std::string callerProcessName; + std::string callerBundleName; + std::string callerVersionName; + std::string uri; +}; + +enum class EventName { + // fault event + START_ABILITY_ERROR = 0, + TERMINATE_ABILITY_ERROR, + START_EXTENSION_ERROR, + STOP_EXTENSION_ERROR, + CONNECT_SERVICE_ERROR, + DISCONNECT_SERVICE_ERROR, + + // ability behavior event + START_ABILITY, + TERMINATE_ABILITY, + CLOSE_ABILITY, + ABILITY_ONFOREGROUND, + ABILITY_ONBACKGROUND, + ABILITY_ONACTIVE, + ABILITY_ONINACTIVE, + START_ABILITY_BY_APP_LINKING, + + // serviceExtensionAbility behavior event + START_SERVICE, + STOP_SERVICE, + CONNECT_SERVICE, + DISCONNECT_SERVICE, + START_ABILITY_OTHER_EXTENSION, + + // app behavior event + APP_ATTACH, + APP_LAUNCH, + APP_FOREGROUND, + APP_BACKGROUND, + APP_TERMINATE, + PROCESS_START, + PROCESS_EXIT, + DRAWN_COMPLETED, + APP_STARTUP_TYPE, + PROCESS_START_FAILED, + + // key behavior event + GRANT_URI_PERMISSION, + FA_SHOW_ON_LOCK, + START_PRIVATE_ABILITY, + RESTART_PROCESS_BY_SAME_APP, + START_STANDARD_ABILITIES, + + // atomic service event + CREATE_ATOMIC_SERVICE_PROCESS, + ATOMIC_SERVICE_DRAWN_COMPLETE, + + // uri permission + SHARE_UNPRIVILEGED_FILE_URI +}; + +class EventReport { +public: + static void SendAppEvent(const EventName &eventName, HiSysEventType type, const EventInfo &eventInfo); + static void SendAbilityEvent(const EventName &eventName, HiSysEventType type, const EventInfo &eventInfo); + static void SendAtomicServiceEvent(const EventName &eventName, HiSysEventType type, const EventInfo &eventInfo); + static void SendExtensionEvent(const EventName &eventName, HiSysEventType type, const EventInfo &eventInfo); + static void SendKeyEvent(const EventName &eventName, HiSysEventType type, const EventInfo &eventInfo); + static void SendAppLaunchEvent(const EventName &eventName, const EventInfo &eventInfo); + static void SendAppForegroundEvent(const EventName &eventName, const EventInfo &eventInfo); + static void SendAppBackgroundEvent(const EventName &eventName, const EventInfo &eventInfo); + static void SendProcessStartEvent(const EventName &eventName, const EventInfo &eventInfo); + static void SendProcessStartFailedEvent(const EventName &eventName, const EventInfo &eventInfo); + static void SendProcessExitEvent(const EventName &eventName, const EventInfo &eventInfo); + static void SendStartServiceEvent(const EventName &eventName, const EventInfo &eventInfo); + static void SendStopServiceEvent(const EventName &eventName, const EventInfo &eventInfo); + static void SendConnectServiceEvent(const EventName &eventName, const EventInfo &eventInfo); + static void SendDisconnectServiceEvent(const EventName &eventName, const EventInfo &eventInfo); + static void SendStartAbilityOtherExtensionEvent(const EventName &eventName, const EventInfo &eventInfo); + static void SendGrantUriPermissionEvent(const EventName &eventName, const EventInfo &eventInfo); + +private: + static std::string ConvertEventName(const EventName &eventName); + static void LogErrorEvent(const std::string &name, HiSysEventType type, const EventInfo &eventInfo); + static void LogStartAbilityEvent(const std::string &name, HiSysEventType type, const EventInfo &eventInfo); + static void LogTerminateAbilityEvent(const std::string &name, HiSysEventType type, const EventInfo &eventInfo); + static void LogAbilityOnForegroundEvent(const std::string &name, HiSysEventType type, const EventInfo &eventInfo); + static void LogAbilityOnBackgroundEvent(const std::string &name, HiSysEventType type, const EventInfo &eventInfo); + static void LogAbilityOnActiveEvent(const std::string &name, HiSysEventType type, const EventInfo &eventInfo); + static void LogStartStandardEvent(const std::string &name, HiSysEventType type, const EventInfo &eventInfo); + static void LogStartAbilityByAppLinking(const std::string &name, HiSysEventType type, const EventInfo &eventInfo); +}; +} // namespace AAFWK +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_EVENT_REPORT_H diff --git a/mock/innerkits/ability_runtime/common/include/fd_guard.h b/mock/innerkits/ability_runtime/common/include/fd_guard.h new file mode 100644 index 0000000000000000000000000000000000000000..4ccf98aafc5c198a3040f6b0a4ae104266d3d862 --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/fd_guard.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024 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_ABILITY_RUNTIME_FD_GUARD_H +#define OHOS_ABILITY_RUNTIME_FD_GUARD_H + +#include +#include + +namespace OHOS { +namespace AAFwk { +class FdGuard { +public: + FdGuard() = default; + explicit FdGuard(int32_t fd) : fd_(fd) {} + ~FdGuard() + { + if (fd_ > -1) { + close(fd_); + } + } + FdGuard(const FdGuard &) = delete; + FdGuard(FdGuard &&other) : fd_(other.fd_) + { + other.fd_ = -1; + } + void operator=(const FdGuard &) = delete; + FdGuard &operator=(FdGuard &&other) + { + if (fd_ > -1) { + close(fd_); + } + fd_ = other.fd_; + other.fd_ = -1; + return *this; + } + + int32_t Get() const + { + return fd_; + } + + int32_t Release() + { + auto ret = fd_; + fd_ = -1; + return ret; + } + + void Reset() + { + if (fd_ > -1) { + close(fd_); + } + fd_ = -1; + } + +private: + int32_t fd_ = -1; +}; +} // AAFwk +} // OHOS +#endif // OHOS_ABILITY_RUNTIME_FD_GUARD_H \ No newline at end of file diff --git a/mock/innerkits/ability_runtime/common/include/hilog_tag_wrapper.h b/mock/innerkits/ability_runtime/common/include/hilog_tag_wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..2914871157419b5fed0f9a08249971dd5f35735c --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/hilog_tag_wrapper.h @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2024 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_AAFWK_HILOG_TAG_WRAPPER_H +#define OHOS_AAFWK_HILOG_TAG_WRAPPER_H + +#include +#include + +#include "hilog/log.h" + +#ifndef AAFWK_FUNC_FMT +#define AAFWK_FUNC_FMT "[%{public}s:%{public}d]" +#endif + +#ifndef AAFWK_FILE_NAME +#define AAFWK_FILE_NAME \ + (__builtin_strrchr(__FILE_NAME__, '/') ? __builtin_strrchr(__FILE_NAME__, '/') + 1 : __FILE_NAME__) +#endif + +#ifndef AAFWK_FUNC_INFO +#define AAFWK_FUNC_INFO AAFWK_FILE_NAME, __LINE__ +#endif + + +namespace OHOS::AAFwk { +enum class AAFwkLogTag : uint32_t { + DEFAULT = 0xD001300, // 0XD001300 + ABILITY, + TEST, + AA_TOOL, + ABILITY_SIM, + + APPDFR = DEFAULT + 0x10, // 0xD001310 + APPMGR, + DBOBSMGR, + DIALOG, + QUICKFIX, + URIPERMMGR, + BUNDLEMGRHELPER, + APPKIT, + + JSENV = DEFAULT + 0x20, // 0xD001320 + JSRUNTIME, + FA, + INTENT, + JSNAPI, + CJRUNTIME, + + DELEGATOR = DEFAULT + 0x30, // 0xD001330 + CONTEXT, + UIABILITY, + WANT, + MISSION, + CONNECTION, + ABILITYMGR, + ECOLOGICAL_RULE, + DATA_ABILITY, + + EXT = DEFAULT + 0x40, // 0xD001340 + AUTOFILL_EXT, + SERVICE_EXT, + FORM_EXT, + SHARE_EXT, + UI_EXT, + ACTION_EXT, + EMBEDDED_EXT, + UISERVC_EXT, + FORM_EDIT_EXT, + + WANTAGENT = DEFAULT + 0x50, // 0xD001350 + AUTOFILLMGR, + EXTMGR, + SER_ROUTER, + AUTO_STARTUP, + STARTUP, + RECOVERY, + PROCESSMGR, + CONTINUATION, + DISTRIBUTED, + FREE_INSTALL, + KEEP_ALIVE, + QUERY_ERMS, + + LOCAL_CALL = DEFAULT + 0x60, // 0xD001360 + + END = 256, // N.B. never use it +}; + +inline uint32_t GetOffset(AAFwkLogTag tag, AAFwkLogTag base) +{ + return static_cast(tag) - static_cast(base); +} + +inline const char* GetDomainName0(AAFwkLogTag tag) +{ + const char* tagNames[] = { "AAFwk", "Ability", "Test", "AATool", "Simulator" }; + uint32_t offset = GetOffset(tag, AAFwkLogTag::DEFAULT); + if (offset >= sizeof(tagNames) / sizeof(const char*)) { + return "UN"; + } + return tagNames[offset]; +} + +inline const char* GetDomainName1(AAFwkLogTag tag) +{ + const char* tagNames[] = { "AppDfr", "AppMS", "DbObsMgr", "Dialog", "Quickfix", + "UriPermMgr", "BMSHelper", "AppKit" }; + uint32_t offset = GetOffset(tag, AAFwkLogTag::APPDFR); + if (offset >= sizeof(tagNames) / sizeof(const char*)) { + return "UN"; + } + return tagNames[offset]; +} + +inline const char* GetDomainName2(AAFwkLogTag tag) +{ + const char* tagNames[] = { "JsEnv", "JsRuntime", "FA", "Intent", "JsNapi" }; + uint32_t offset = GetOffset(tag, AAFwkLogTag::JSENV); + if (offset >= sizeof(tagNames) / sizeof(const char*)) { + return "UN"; + } + return tagNames[offset]; +} + +inline const char* GetDomainName3(AAFwkLogTag tag) +{ + const char* tagNames[] = { "Delegator", "Context", "UIAbility", "Want", "Mission", + "Connection", "AMS", "EcologicalRule", "DataAbility" }; + uint32_t offset = GetOffset(tag, AAFwkLogTag::DELEGATOR); + if (offset >= sizeof(tagNames) / sizeof(const char*)) { + return "UN"; + } + return tagNames[offset]; +} + +inline const char* GetDomainName4(AAFwkLogTag tag) +{ + const char* tagNames[] = { "Ext", "AutoFillExt", "ServiceExt", "FormExt", "ShareExt", + "UIExt", "ActionExt", "EmbeddedExt", "UIServiceExt" }; + uint32_t offset = GetOffset(tag, AAFwkLogTag::EXT); + if (offset >= sizeof(tagNames) / sizeof(const char*)) { + return "UN"; + } + return tagNames[offset]; +} + +inline const char* GetDomainName5(AAFwkLogTag tag) +{ + const char* tagNames[] = { "WantAgent", "AutoFillMgr", "ExtMgr", "ServiceRouter", + "AutoStartup", "Startup", "Recovery", "ProcessMgr", "Continuation", + "Distributed", "FreeInstall", "KeepAlive", "QueryERMS" }; + uint32_t offset = GetOffset(tag, AAFwkLogTag::WANTAGENT); + if (offset >= sizeof(tagNames) / sizeof(const char*)) { + return "UN"; + } + return tagNames[offset]; +} + +inline const char* GetDomainName6(AAFwkLogTag tag) +{ + const char* tagNames[] = { "LocalCall" }; + uint32_t offset = GetOffset(tag, AAFwkLogTag::LOCAL_CALL); + if (offset >= sizeof(tagNames) / sizeof(const char*)) { + return "UN"; + } + return tagNames[offset]; +} + +constexpr uint32_t BASE_DEFAULT = 0; +constexpr uint32_t BASE_APPDFR = 1; +constexpr uint32_t BASE_JSENV = 2; +constexpr uint32_t BASE_DELEGATOR = 3; +constexpr uint32_t BASE_EXT = 4; +constexpr uint32_t BASE_WANTAGENT = 5; +constexpr uint32_t BASE_LOCAL_CALL = 6; + +static inline const char* GetTagInfoFromDomainId(AAFwkLogTag tag) +{ + uint32_t offset = GetOffset(tag, AAFwkLogTag::DEFAULT); + uint32_t base = offset >> 4; + switch (base) { + case BASE_DEFAULT: return GetDomainName0(tag); + case BASE_APPDFR: return GetDomainName1(tag); + case BASE_JSENV: return GetDomainName2(tag); + case BASE_DELEGATOR: return GetDomainName3(tag); + case BASE_EXT: return GetDomainName4(tag); + case BASE_WANTAGENT: return GetDomainName5(tag); + case BASE_LOCAL_CALL: return GetDomainName6(tag); + default: return "UN"; + } +} +} // OHOS::AAFwk + +using AAFwkTag = OHOS::AAFwk::AAFwkLogTag; + +#define AAFWK_PRINT_LOG(level, tag, fmt, ...) \ + do { \ + AAFwkTag logTag = tag; \ + ((void)HILOG_IMPL(LOG_CORE, level, static_cast(logTag), \ + OHOS::AAFwk::GetTagInfoFromDomainId(logTag), AAFWK_FUNC_FMT fmt, AAFWK_FUNC_INFO, ##__VA_ARGS__)); \ + } while (0) + +#define TAG_LOGD(tag, fmt, ...) AAFWK_PRINT_LOG(LOG_DEBUG, tag, fmt, ##__VA_ARGS__) +#define TAG_LOGI(tag, fmt, ...) AAFWK_PRINT_LOG(LOG_INFO, tag, fmt, ##__VA_ARGS__) +#define TAG_LOGW(tag, fmt, ...) AAFWK_PRINT_LOG(LOG_WARN, tag, fmt, ##__VA_ARGS__) +#define TAG_LOGE(tag, fmt, ...) AAFWK_PRINT_LOG(LOG_ERROR, tag, fmt, ##__VA_ARGS__) +#define TAG_LOGF(tag, fmt, ...) AAFWK_PRINT_LOG(LOG_FATAL, tag, fmt, ##__VA_ARGS__) + +#endif // OHOS_AAFWK_HILOG_TAG_WRAPPER_H diff --git a/mock/innerkits/ability_runtime/common/include/hilog_wrapper.h b/mock/innerkits/ability_runtime/common/include/hilog_wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..60c04534b7f31fd5e89837cea7b029482d8b1b7f --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/hilog_wrapper.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2021 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 HILOG_WRAPPER_H +#define HILOG_WRAPPER_H + +#define CONFIG_HILOG +#ifdef CONFIG_HILOG +#include "hilog/log.h" + +#ifdef HILOG_FATAL +#undef HILOG_FATAL +#endif + +#ifdef HILOG_ERROR +#undef HILOG_ERROR +#endif + +#ifdef HILOG_WARN +#undef HILOG_WARN +#endif + +#ifdef HILOG_INFO +#undef HILOG_INFO +#endif + +#ifdef HILOG_DEBUG +#undef HILOG_DEBUG +#endif + +#ifndef AMS_LOG_DOMAIN +#define AMS_LOG_DOMAIN 0xD001304 +#endif + +#ifndef AMS_LOG_TAG +#define AMS_LOG_TAG "AbilityManagerService" +#endif + +#define __FILENAME__ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__) + +#define HILOG_FATAL(fmt, ...) \ + ((void)HILOG_IMPL(LOG_CORE, LOG_FATAL, AMS_LOG_DOMAIN, AMS_LOG_TAG, \ + "[%{public}s(%{public}s:%{public}d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__)) +#define HILOG_ERROR(fmt, ...) \ + ((void)HILOG_IMPL(LOG_CORE, LOG_ERROR, AMS_LOG_DOMAIN, AMS_LOG_TAG, \ + "[%{public}s(%{public}s:%{public}d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__)) +#define HILOG_WARN(fmt, ...) \ + ((void)HILOG_IMPL(LOG_CORE, LOG_WARN, AMS_LOG_DOMAIN, AMS_LOG_TAG, \ + "[%{public}s(%{public}s:%{public}d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__)) +#define HILOG_INFO(fmt, ...) \ + ((void)HILOG_IMPL(LOG_CORE, LOG_INFO, AMS_LOG_DOMAIN, AMS_LOG_TAG, \ + "[%{public}s(%{public}s:%{public}d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__)) +#define HILOG_DEBUG(fmt, ...) \ + ((void)HILOG_IMPL(LOG_CORE, LOG_DEBUG, AMS_LOG_DOMAIN, AMS_LOG_TAG, \ + "[%{public}s(%{public}s:%{public}d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__)) +#else + +#define HILOG_FATAL(...) +#define HILOG_ERROR(...) +#define HILOG_WARN(...) +#define HILOG_INFO(...) +#define HILOG_DEBUG(...) +#endif // CONFIG_HILOG + +#endif // HILOG_WRAPPER_H diff --git a/mock/innerkits/ability_runtime/common/include/in_process_call_wrapper.h b/mock/innerkits/ability_runtime/common/include/in_process_call_wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..a6b720f9f992e41c4985b64186f2bbb99a36941d --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/in_process_call_wrapper.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022 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_ABILITY_RUNTIME_IN_PROCESS_CALL_WRAPPER_H +#define OHOS_ABILITY_RUNTIME_IN_PROCESS_CALL_WRAPPER_H + +#include "ipc_skeleton.h" + +#define IN_PROCESS_CALL(theCall) \ + ([&]() { \ + std::string identity = IPCSkeleton::ResetCallingIdentity(); \ + auto retVal = theCall; \ + IPCSkeleton::SetCallingIdentity(identity); \ + return retVal; \ + }()) + +#define IN_PROCESS_CALL_WITHOUT_RET(theCall) \ + do { \ + std::string identity = IPCSkeleton::ResetCallingIdentity(); \ + theCall; \ + IPCSkeleton::SetCallingIdentity(identity); \ + } while (0) + +#endif // OHOS_ABILITY_RUNTIME_IN_PROCESS_CALL_WRAPPER_H diff --git a/mock/innerkits/ability_runtime/common/include/ipc_capacity_wrap.h b/mock/innerkits/ability_runtime/common/include/ipc_capacity_wrap.h new file mode 100644 index 0000000000000000000000000000000000000000..10ef07a8f9480746a01b0afa6d21ef1f054b34a2 --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/ipc_capacity_wrap.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 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_ABILITY_RUNTIME_IPC_CAPACITY_WRAP_H +#define OHOS_ABILITY_RUNTIME_IPC_CAPACITY_WRAP_H + +#include "ipc_types.h" + +namespace OHOS { +namespace AAFwk { +namespace { +constexpr int32_t MAX_IPC_CAPACITY_FOR_WANT = 216 * 1024; +} + +static inline void ExtendMaxIpcCapacityForInnerWant(MessageParcel &parcel) +{ + if ((parcel).GetMaxCapacity() < MAX_IPC_CAPACITY_FOR_WANT) { + (parcel).SetMaxCapacity(MAX_IPC_CAPACITY_FOR_WANT); + } +} + +} // namespace AAFwk +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_IPC_CAPACITY_WRAP_H diff --git a/mock/innerkits/ability_runtime/common/include/json_utils.h b/mock/innerkits/ability_runtime/common/include/json_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..8eed8db121070229ee32fa7890cf21ff840f0bd2 --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/json_utils.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024 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_ABILITY_RUNTIME_JSON_UTILS_H +#define OHOS_ABILITY_RUNTIME_JSON_UTILS_H + +#include +#include + +#include "nlohmann/json.hpp" +#include "singleton.h" + +namespace OHOS { +namespace AAFwk { +/** + * @class JsonUtils + * provides json utilities. + */ +class JsonUtils { +public: + /** + * GetInstance, get an instance of JsonUtils. + * + * @return an instance of JsonUtils. + */ + static JsonUtils &GetInstance() + { + static JsonUtils instance; + return instance; + } + + /** + * JsonUtils, destructor. + * + */ + ~JsonUtils() = default; + + /** + * LoadConfiguration, load configuration. + * + * @param path The json file path. + * @param jsonBuf The json buffer to be returned. + * @param defaultPath The default output path. + * @return Whether or not the load operation succeeds. + */ + bool LoadConfiguration(const std::string& path, nlohmann::json& jsonBuf, const std::string& defaultPath = ""); + + /** + * IsEqual, check if json object contains certain key. + * + * @param jsonObject The json object. + * @param key The key. + * @param value The string value. + * @param checkEmpty The flag indicates whether the value can be empty. + * @return Whether or not the json object contains certain key. + */ + bool IsEqual(nlohmann::json &jsonObject, const std::string &key, + const std::string &value, bool checkEmpty = false); + + /** + * IsEqual, check if json object contains certain key. + * + * @param jsonObject The json object. + * @param key The key. + * @param value The int32_t value. + * @return Whether or not the json object contains certain key. + */ + bool IsEqual(nlohmann::json &jsonObject, const std::string &key, int32_t value); + +private: + std::string GetConfigPath(const std::string& path, const std::string& defaultPath); + bool ReadFileInfoJson(const std::string &filePath, nlohmann::json &jsonBuf); + JsonUtils() = default; + DISALLOW_COPY_AND_MOVE(JsonUtils); +}; +} // namespace AAFwk +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_JSON_UTILS_H \ No newline at end of file diff --git a/mock/innerkits/ability_runtime/common/include/permission_constants.h b/mock/innerkits/ability_runtime/common/include/permission_constants.h new file mode 100644 index 0000000000000000000000000000000000000000..dfdf8339004270ee8d19bb1e5e1cfa9b9f1cd007 --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/permission_constants.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2022-2025 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_ABILITY_RUNTIME_PERMISSION_CONSTANTS_H +#define OHOS_ABILITY_RUNTIME_PERMISSION_CONSTANTS_H + +namespace OHOS { +namespace AAFwk { +namespace PermissionConstants { +constexpr const char* PERMISSION_ACCESS_DLP = "ohos.permission.ACCESS_DLP_FILE"; +constexpr const char* PERMISSION_CLEAN_APPLICATION_DATA = "ohos.permission.CLEAN_APPLICATION_DATA"; +constexpr const char* PERMISSION_CLEAN_BACKGROUND_PROCESSES = "ohos.permission.CLEAN_BACKGROUND_PROCESSES"; +constexpr const char* PERMISSION_GET_RUNNING_INFO = "ohos.permission.GET_RUNNING_INFO"; +constexpr const char* PERMISSION_INTERACT_ACROSS_LOCAL_ACCOUNTS = "ohos.permission.INTERACT_ACROSS_LOCAL_ACCOUNTS"; +constexpr const char* PERMISSION_MANAGE_MISSION = "ohos.permission.MANAGE_MISSIONS"; +constexpr const char* PERMISSION_RUNNING_STATE_OBSERVER = "ohos.permission.RUNNING_STATE_OBSERVER"; +constexpr const char* PERMISSION_SET_ABILITY_CONTROLLER = "ohos.permission.SET_ABILITY_CONTROLLER"; +constexpr const char* PERMISSION_UPDATE_CONFIGURATION = "ohos.permission.UPDATE_CONFIGURATION"; +constexpr const char* PERMISSION_UPDATE_APP_CONFIGURATION = "ohos.permission.UPDATE_APP_CONFIGURATION"; +constexpr const char* PERMISSION_INSTALL_BUNDLE = "ohos.permission.INSTALL_BUNDLE"; +constexpr const char* PERMISSION_GET_BUNDLE_INFO_PRIVILEGED = "ohos.permission.GET_BUNDLE_INFO_PRIVILEGED"; +constexpr const char* PERMISSION_START_INVISIBLE_ABILITY = "ohos.permission.START_INVISIBLE_ABILITY"; +constexpr const char* PERMISSION_START_ABILITIES_FROM_BACKGROUND = "ohos.permission.START_ABILITIES_FROM_BACKGROUND"; +constexpr const char* PERMISSION_START_ABILIIES_FROM_BACKGROUND = "ohos.permission.START_ABILIIES_FROM_BACKGROUND"; +constexpr const char* PERMISSION_ABILITY_BACKGROUND_COMMUNICATION = "ohos.permission.ABILITY_BACKGROUND_COMMUNICATION"; +constexpr const char* PERMISSION_MANAGER_ABILITY_FROM_GATEWAY = "ohos.permission.MANAGER_ABILITY_FROM_GATEWAY"; +constexpr const char* PERMISSION_PROXY_AUTHORIZATION_URI = "ohos.permission.PROXY_AUTHORIZATION_URI"; +constexpr const char* PERMISSION_FILE_ACCESS_MANAGER = "ohos.permission.FILE_ACCESS_MANAGER"; +constexpr const char* PERMISSION_WRITE_IMAGEVIDEO = "ohos.permission.WRITE_IMAGEVIDEO"; +constexpr const char* PERMISSION_READ_IMAGEVIDEO = "ohos.permission.READ_IMAGEVIDEO"; +constexpr const char* PERMISSION_WRITE_AUDIO = "ohos.permission.WRITE_AUDIO"; +constexpr const char* PERMISSION_READ_AUDIO = "ohos.permission.READ_AUDIO"; +constexpr const char* PERMISSION_GRANT_URI_PERMISSION_PRIVILEGED = "ohos.permission.GRANT_URI_PERMISSION_PRIVILEGED"; +constexpr const char* PERMISSION_READ_WRITE_DOWNLOAD = "ohos.permission.READ_WRITE_DOWNLOAD_DIRECTORY"; +constexpr const char* PERMISSION_READ_WRITE_DESKTON = "ohos.permission.READ_WRITE_DESKTOP_DIRECTORY"; +constexpr const char* PERMISSION_READ_WRITE_DOCUMENTS = "ohos.permission.READ_WRITE_DOCUMENTS_DIRECTORY"; +constexpr const char* PERMISSION_EXEMPT_AS_CALLER = "ohos.permission.EXEMPT_AS_CALLER"; +constexpr const char* PERMISSION_EXEMPT_AS_TARGET = "ohos.permission.EXEMPT_AS_TARGET"; +constexpr const char* PERMISSION_PREPARE_TERMINATE = "ohos.permission.PREPARE_APP_TERMINATE"; +constexpr const char* PERMISSION_START_RECENT_ABILITY = "ohos.permission.START_RECENT_ABILITY"; +constexpr const char* PERMISSION_MANAGE_APP_BOOT = "ohos.permission.MANAGE_APP_BOOT"; +constexpr const char* PERMISSION_START_ABILITY_WITH_ANIMATION = "ohos.permission.START_ABILITY_WITH_ANIMATION"; +constexpr const char* PERMISSION_MANAGE_APP_BOOT_INTERNAL = "ohos.permission.MANAGE_APP_BOOT_INTERNAL"; +constexpr const char* PERMISSION_CONNECT_UI_EXTENSION_ABILITY = "ohos.permission.CONNECT_UI_EXTENSION_ABILITY"; +constexpr const char* PERMISSION_NOTIFY_DEBUG_ASSERT_RESULT = "ohos.permission.NOTIFY_DEBUG_ASSERT_RESULT"; +constexpr const char* PERMISSION_START_SHORTCUT = "ohos.permission.START_SHORTCUT"; +constexpr const char* PERMISSION_PRELOAD_APPLICATION = "ohos.permission.PRELOAD_APPLICATION"; +constexpr const char* PERMISSION_SET_PROCESS_CACHE_STATE = "ohos.permission.SET_PROCESS_CACHE_STATE"; +constexpr const char* PERMISSION_PRELOAD_UI_EXTENSION_ABILITY = "ohos.permission.PRELOAD_UI_EXTENSION_ABILITY"; +constexpr const char* PERMISSION_KILL_APP_PROCESSES = "ohos.permission.KILL_APP_PROCESSES"; +constexpr const char* PERMISSION_KILL_PROCESS_DEPENDED_ON_WEB = "ohos.permission.KILL_PROCESS_DEPENDED_ON_ARKWEB"; +constexpr const char* PERMISSION_PRE_START_ATOMIC_SERVICE = "ohos.permission.PRE_START_ATOMIC_SERVICE"; +constexpr const char* PERMISSION_START_NATIVE_CHILD_PROCESS = "ohos.permission.START_NATIVE_CHILD_PROCESS"; +constexpr const char* PERMISSION_BLOCK_ALL_APP_START = "ohos.permission.BLOCK_ALL_APP_START"; +constexpr const char* PERMISSION_START_UIABILITY_TO_HIDDEN = "ohos.permission.START_UIABILITY_TO_HIDDEN"; +constexpr const char* PERMISSION_SUPERVISE_KIA_SERVICE = "ohos.permission.SUPERVISE_KIA_SERVICE"; +constexpr const char* PERMISSION_GET_TELEPHONY_STATE = "ohos.permission.GET_TELEPHONY_STATE"; +constexpr const char* PERMISSION_MANAGE_APP_KEEP_ALIVE = "ohos.permission.MANAGE_APP_KEEP_ALIVE"; +constexpr const char* PERMISSION_MANAGE_APP_KEEP_ALIVE_INTERNAL = "ohos.permission.MANAGE_APP_KEEP_ALIVE_INTERNAL"; +constexpr const char* PERMISSION_SET_LAUNCH_REASON_MESSAGE = "ohos.permission.SET_LAUNCH_REASON_MESSAGE"; +constexpr const char* PERMISSION_NDK_START_SELF_UI_ABILITY = "ohos.permission.NDK_START_SELF_UI_ABILITY"; +} // namespace PermissionConstants +} // namespace AAFwk +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_PERMISSION_CONSTANTS_H diff --git a/mock/innerkits/ability_runtime/common/include/permission_verification.h b/mock/innerkits/ability_runtime/common/include/permission_verification.h new file mode 100644 index 0000000000000000000000000000000000000000..e8b9e92fb7b98ab818d7059accd6e3bcce6f55bf --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/permission_verification.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2022 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_ABILITY_RUNTIME_PERMISSION_VERIFICATION_H +#define OHOS_ABILITY_RUNTIME_PERMISSION_VERIFICATION_H + +#include "ipc_skeleton.h" +#include "singleton.h" +#include "want.h" + +namespace OHOS { +namespace AAFwk { +class PermissionVerification : public DelayedSingleton { +public: +struct VerificationInfo { + bool visible = false; + bool isBackgroundCall = true; + bool associatedWakeUp = false; + bool withContinuousTask = false; + uint32_t accessTokenId = 0; + int32_t apiTargetVersion = 0; + uint32_t specifyTokenId = 0; +}; + + PermissionVerification() = default; + ~PermissionVerification() = default; + + bool VerifyPermissionByTokenId(const int &tokenId, const std::string &permissionName) const; + + bool VerifyCallingPermission(const std::string &permissionName, const uint32_t specifyTokenId = 0) const; + + bool IsSACall() const; + + bool IsSACallByTokenId(uint32_t callerTokenId) const; + + bool IsShellCall() const; + + bool IsShellCallByTokenId(uint32_t callerTokenId) const; + + bool CheckSpecificSystemAbilityAccessPermission(const std::string &processName) const; + + bool CheckObserverCallerPermission() const; + + bool VerifyRunningInfoPerm() const; + + bool VerifyControllerPerm() const; + + bool VerifyDlpPermission(Want &want) const; + + int VerifyAccountPermission() const; + + bool VerifyMissionPermission() const; + + int VerifyAppStateObserverPermission() const; + + int32_t VerifyUpdateConfigurationPerm() const; + + int32_t VerifyUpdateAPPConfigurationPerm() const; + + bool VerifyInstallBundlePermission() const; + + bool VerifyGetBundleInfoPrivilegedPermission() const; + + bool VerifyStartRecentAbilityPermission() const; + + int CheckCallDataAbilityPermission(const VerificationInfo &verificationInfo, bool isShell) const; + + int CheckCallServiceAbilityPermission(const VerificationInfo &verificationInfo) const; + + int CheckCallAbilityPermission(const VerificationInfo &verificationInfo, bool isCallByShortcut = false) const; + + /** + * Check if Caller is allowed to start ServiceExtension(Stage) or DataShareExtension(Stage) + * + * @param verificationInfo, verificationInfo. + * @return Returns ERR_OK on check success, others on check failure. + */ + int CheckCallServiceExtensionPermission(const VerificationInfo &verificationInfo) const; + + int CheckStartByCallPermission(const VerificationInfo &verificationInfo) const; + + bool JudgeCallerIsAllowedToUseSystemAPI() const; + + bool IsSystemAppCall() const; + + bool IsSystemAppCallByTokenId(uint32_t callerTokenId) const; + + bool VerifyPrepareTerminatePermission() const; + + bool VerifyPrepareTerminatePermission(const int &tokenId) const; + + bool VerifyShellStartExtensionType(int32_t type) const; + + bool VerifyPreloadApplicationPermission() const; + + bool VerifyPreStartAtomicServicePermission() const; + + bool VerifyKillProcessDependedOnWebPermission() const; + + bool VerifyBackgroundCallPermission(const bool isBackgroundCall) const; + + bool VerifyBlockAllAppStartPermission() const; + + bool VerifyStartUIAbilityToHiddenPermission() const; + + bool VerifySuperviseKiaServicePermission() const; + + bool VerifyStartSelfUIAbility(int tokenId) const; + +private: + DISALLOW_COPY_AND_MOVE(PermissionVerification); + + constexpr static int32_t API8 = 8; + + unsigned int GetCallingTokenID() const; + + bool JudgeStartInvisibleAbility(const uint32_t accessTokenId, const bool visible, + const uint32_t specifyTokenId = 0) const; + + bool JudgeStartAbilityFromBackground(const bool isBackgroundCall) const; + + bool JudgeAssociatedWakeUp(const uint32_t accessTokenId, const bool associatedWakeUp) const; + + int JudgeInvisibleAndBackground(const VerificationInfo &verificationInfo, bool isCallByShortcut = false) const; + + inline bool IsCallFromSameAccessToken(const uint32_t accessTokenId) const + { + return IPCSkeleton::GetCallingTokenID() == accessTokenId; + } +}; +} // namespace AAFwk +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_PERMISSION_VERIFICATION_H diff --git a/mock/innerkits/ability_runtime/common/include/res_sched_util.h b/mock/innerkits/ability_runtime/common/include/res_sched_util.h new file mode 100644 index 0000000000000000000000000000000000000000..aea8f1dc78296a044e9457323ac588a7f035f56f --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/res_sched_util.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 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_ABILITY_RUNTIME_RES_SCHED_UTIL_H +#define OHOS_ABILITY_RUNTIME_RES_SCHED_UTIL_H + +#include + +#include "nocopyable.h" + +namespace OHOS { +namespace AppExecFwk { +struct AbilityInfo; +} +namespace AAFwk { +namespace { +constexpr int32_t INTENT_EXEMPTION_DURATION = 10000; +} +using AbilityInfo = AppExecFwk::AbilityInfo; +constexpr int64_t RES_TYPE_SCB_START_ABILITY = 0; +constexpr int64_t RES_TYPE_EXTENSION_START_ABILITY = 1; +constexpr int64_t RES_TYPE_MISSION_LIST_START_ABILITY = 2; + +enum class LoadingStage : int32_t { + LOAD_BEGIN = 1, + LOAD_END, + FOREGROUND_BEGIN, + FOREGROUND_END, + CONNECT_BEGIN, + CONNECT_END, + DESTROY_BEGIN = 8, + DESTROY_END = 9, + PRELOAD_BEGIN, +}; + +class ResSchedUtil final { +public: + static ResSchedUtil &GetInstance(); + void ReportAbilityStartInfoToRSS(const AbilityInfo &abilityInfo, int32_t pid, bool isColdStart); + void ReportAbilityAssociatedStartInfoToRSS( + const AbilityInfo &abilityInfo, int64_t resSchedType, int32_t callerUid, int32_t callerPid); + void ReportEventToRSS(const int32_t uid, const std::string &bundleName, const std::string &reason, + const int32_t pid = -1, const int32_t callerPid = -1); + std::string GetThawReasonByAbilityType(const AbilityInfo &abilityInfo); + void GetAllFrozenPidsFromRSS(std::unordered_set &frozenPids); + bool CheckShouldForceKillProcess(int32_t pid); + void ReportLoadingEventToRss(LoadingStage stage, int32_t pid, int32_t uid, + int64_t timeDuration = 0, int64_t abilityRecordId = -1); + std::unordered_set GetNWebPreloadSet() const; + void ReportAbilityIntentExemptionInfoToRSS(int32_t callerUid, int32_t callerPid); +private: + ResSchedUtil() = default; + ~ResSchedUtil() = default; + DISALLOW_COPY_AND_MOVE(ResSchedUtil); + + int64_t convertType(int64_t resSchedType); +}; +} // namespace AAFwk +} // namespace OHOS + +#endif // OHOS_ABILITY_RUNTIME_RES_SCHED_UTIL_H diff --git a/mock/innerkits/ability_runtime/common/include/support_system_ability_permission.h b/mock/innerkits/ability_runtime/common/include/support_system_ability_permission.h new file mode 100644 index 0000000000000000000000000000000000000000..e59289d219baf2f624fd7b213f1d4598c8e5d24d --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/support_system_ability_permission.h @@ -0,0 +1,37 @@ +/* + * 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_ABILITY_SUPPORT_SYSTEM_ABILITY_PERMISSION_H +#define OHOS_ABILITY_SUPPORT_SYSTEM_ABILITY_PERMISSION_H + +#include +#include "hilog_tag_wrapper.h" +#include "parameters.h" + +namespace OHOS { +namespace AAFwk { +namespace SupportSystemAbilityPermission { +const std::string SUPPORT_SYSTEM_ABILITY_PERMISSION = "abilitymanagerservice.support.sa.call"; + +inline bool IsSupportSaCallPermission() +{ + TAG_LOGD(AAFwkTag::DEFAULT, "call"); + std::string ret = OHOS::system::GetParameter(SUPPORT_SYSTEM_ABILITY_PERMISSION, "true"); + return ret == "true"; +} +} // namespace SupportSystemAbilityPermission +} // namespace AAFwk +} // namespace OHOS +#endif // OHOS_ABILITY_SUPPORT_SYSTEM_ABILITY_PERMISSION_H \ No newline at end of file diff --git a/mock/innerkits/ability_runtime/common/include/task_handler_wrap.h b/mock/innerkits/ability_runtime/common/include/task_handler_wrap.h new file mode 100644 index 0000000000000000000000000000000000000000..89332e8d83a2e014af42ea81bd3bdf90ad24f192 --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/task_handler_wrap.h @@ -0,0 +1,146 @@ +/* + * 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_ABILITY_RUNTIME_TASK_HANDLER_WRAP_H +#define OHOS_ABILITY_RUNTIME_TASK_HANDLER_WRAP_H + +#include +#include +#include +#include +#include + +#include "task_utils_wrap.h" + +namespace ffrt { +class mutex; +}; + +namespace OHOS { +namespace AAFwk { +class TaskHandlerWrap; +class InnerTaskHandle; +class TaskHandle { +friend class TaskHandlerWrap; +public: + TaskHandle() = default; + TaskHandle(std::shared_ptr handler, std::shared_ptr InnerTaskHandle, + TaskStatus status = TaskStatus::PENDING) : handler_(handler), innerTaskHandle_(InnerTaskHandle) + { + status_ = std::make_shared(status); + } + bool Cancel() const; + void Sync() const; + bool IsSame(const TaskHandle &other) const + { + return innerTaskHandle_ == other.innerTaskHandle_; + } + explicit operator bool() const + { + return status_ && innerTaskHandle_; + } + uint64_t GetTaskId() const; + bool PrintTaskLog() const + { + return printTaskLog_; + } +private: + std::weak_ptr handler_; + std::shared_ptr innerTaskHandle_; + std::shared_ptr status_; + + bool printTaskLog_ = false; +}; + +class TaskHandlerWrap : public std::enable_shared_from_this { +friend class TaskHandle; +public: + static std::shared_ptr CreateQueueHandler(const std::string &queueName, + TaskQoS queueQos = TaskQoS::DEFAULT); + + static std::shared_ptr CreateConcurrentQueueHandler(const std::string &queueName, + int32_t concurrentNum, TaskQoS queueQos = TaskQoS::DEFAULT); + + static std::shared_ptr GetFfrtHandler(); + + TaskHandlerWrap(TaskHandlerWrap &) = delete; + void operator=(TaskHandlerWrap &) = delete; + virtual ~TaskHandlerWrap(); + /** + * Submit task to be scheduled and executed + * @return TaskHandle, could be used later + */ + TaskHandle SubmitTask(const std::function &task); + TaskHandle SubmitTask(const std::function &task, const std::string &name); + TaskHandle SubmitTask(const std::function &task, int64_t delayMillis); + TaskHandle SubmitTask(const std::function &task, TaskQoS taskQos); + TaskHandle SubmitTask(const std::function &task, const std::string &name, + int64_t delayMillis, bool forceSubmit = true); + TaskHandle SubmitTask(const std::function &task, const TaskAttribute &taskAttr); + // Task can't be canceled by name if submitted with this method + TaskHandle SubmitTaskJust(const std::function &task, const std::string &name, + int64_t delayMillis); + // This is only used for compatibility and could be be wrong if multi tasks with same name submitted. + // TaskHandle::Cancel is preferred. + bool CancelTask(const std::string &name); + void SetPrintTaskLog(bool printTaskLog) + { + printTaskLog_ = printTaskLog; + } +protected: + TaskHandlerWrap(const std::string &queueName); + virtual std::shared_ptr SubmitTaskInner(std::function &&task, + const TaskAttribute &taskAttr) = 0; + virtual bool CancelTaskInner(const std::shared_ptr &taskHandle) = 0; + virtual void WaitTaskInner(const std::shared_ptr &taskHandle) = 0; + virtual uint64_t GetTaskCount() + { + return 0; + } + bool RemoveTask(const std::string &name, const TaskHandle &taskHandle); +protected: + bool printTaskLog_ = false; + // this is used only for compatibility + std::unordered_map tasks_; + std::unique_ptr tasksMutex_; + + std::string queueName_; +}; + +class AutoSyncTaskHandle { +public: + explicit AutoSyncTaskHandle(const TaskHandle &handle) : handle_(handle) {} + ~AutoSyncTaskHandle() + { + Sync(); + } + + AutoSyncTaskHandle(AutoSyncTaskHandle&) = delete; + void operator=(AutoSyncTaskHandle&) = delete; + + void Sync() + { + auto handle = handle_; + handle_ = TaskHandle(); + if (handle) { + handle.Sync(); + } + } +private: + TaskHandle handle_; +}; +} // namespace AAFWK +} // namespace OHOS +#endif // OHOS_ABILITY_RUNTIME_TASK_HANDLER_WRAP_H \ No newline at end of file diff --git a/mock/innerkits/ability_runtime/common/include/task_utils_wrap.h b/mock/innerkits/ability_runtime/common/include/task_utils_wrap.h new file mode 100644 index 0000000000000000000000000000000000000000..0f3038a2a0c402e58564a995eec4d7446f7a067d --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/task_utils_wrap.h @@ -0,0 +1,57 @@ +/* + * 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_ABILITY_RUNTIME_TASK_UTILS_WRAP_H +#define OHOS_ABILITY_RUNTIME_TASK_UTILS_WRAP_H + +#include +namespace OHOS { +namespace AAFwk { +enum class TaskStatus { + PENDING, + EXECUTING, + FINISHED, + CANCELED +}; + +enum class TaskQoS { + INHERENT = 0, + BACKGROUND, + UTILITY, + DEFAULT, + USER_INITIATED, + DEADLINE_REQUEST, + USER_INTERACTIVE +}; + +enum class TaskQueuePriority { + IMMEDIATE = 0, + HIGH, + LOW, + IDLE +}; + +struct TaskAttribute { + std::string taskName_; + int64_t delayMillis_ = 0; + TaskQoS taskQos_ = TaskQoS::DEFAULT; + TaskQueuePriority taskPriority_ = TaskQueuePriority::LOW; + int64_t timeoutMillis_ = 0; // task should be started within timeout + bool insertHead_ = false; // insert into the head of the queue +}; +} // namespace AAFwk +} // namespace OHOS + +#endif // OHOS_ABILITY_RUNTIME_TASK_UTILS_WRAP_H \ No newline at end of file diff --git a/mock/innerkits/ability_runtime/common/include/ui_extension_utils.h b/mock/innerkits/ability_runtime/common/include/ui_extension_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..ec285532e4d411eaf688aac8e6720d2bd9a460e0 --- /dev/null +++ b/mock/innerkits/ability_runtime/common/include/ui_extension_utils.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2023-2024 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_AAFwk_UI_EXTENSION_UTILS_H +#define OHOS_AAFwk_UI_EXTENSION_UTILS_H + +#include + +#include "extension_ability_info.h" +#include "ipc_skeleton.h" + +namespace OHOS { +namespace AAFwk { +namespace { +constexpr int EDM_SA_UID = 3057; +} +namespace UIExtensionUtils { +// ui extension type list +inline std::unordered_set GetUiExtensionSet() +{ + return std::unordered_set { + AppExecFwk::ExtensionAbilityType::SHARE, + AppExecFwk::ExtensionAbilityType::ACTION, + AppExecFwk::ExtensionAbilityType::EMBEDDED_UI, + AppExecFwk::ExtensionAbilityType::INSIGHT_INTENT_UI, + AppExecFwk::ExtensionAbilityType::AUTO_FILL_PASSWORD, + AppExecFwk::ExtensionAbilityType::UI, + AppExecFwk::ExtensionAbilityType::SYSPICKER_MEDIACONTROL, + AppExecFwk::ExtensionAbilityType::SYSDIALOG_USERAUTH, + AppExecFwk::ExtensionAbilityType::SYSDIALOG_COMMON, + AppExecFwk::ExtensionAbilityType::SYSDIALOG_ATOMICSERVICEPANEL, + AppExecFwk::ExtensionAbilityType::SYSDIALOG_POWER, + AppExecFwk::ExtensionAbilityType::SYSPICKER_SHARE, + AppExecFwk::ExtensionAbilityType::HMS_ACCOUNT, + AppExecFwk::ExtensionAbilityType::ADS, + AppExecFwk::ExtensionAbilityType::VOIP, + AppExecFwk::ExtensionAbilityType::STATUS_BAR_VIEW, + AppExecFwk::ExtensionAbilityType::SYSDIALOG_MEETIMECALL, + AppExecFwk::ExtensionAbilityType::SYSDIALOG_MEETIMECONTACT, + AppExecFwk::ExtensionAbilityType::SYSDIALOG_MEETIMEMESSAGE, + AppExecFwk::ExtensionAbilityType::SYSDIALOG_PRINT, + AppExecFwk::ExtensionAbilityType::SYSPICKER_MEETIMECONTACT, + AppExecFwk::ExtensionAbilityType::SYSPICKER_MEETIMECALLLOG, + AppExecFwk::ExtensionAbilityType::SYSPICKER_PHOTOPICKER, + AppExecFwk::ExtensionAbilityType::SYS_COMMON_UI, + AppExecFwk::ExtensionAbilityType::SYSPICKER_NAVIGATION, + AppExecFwk::ExtensionAbilityType::SYSPICKER_APPSELECTOR, + AppExecFwk::ExtensionAbilityType::SYSPICKER_CAMERA, + AppExecFwk::ExtensionAbilityType::SYSPICKER_FILEPICKER, + AppExecFwk::ExtensionAbilityType::AUTO_FILL_SMART, + AppExecFwk::ExtensionAbilityType::LIVEVIEW_LOCKSCREEN, + AppExecFwk::ExtensionAbilityType::SYSPICKER_PHOTOEDITOR, + AppExecFwk::ExtensionAbilityType::PHOTO_EDITOR, + AppExecFwk::ExtensionAbilityType::SYSPICKER_AUDIOPICKER, + AppExecFwk::ExtensionAbilityType::SYS_VISUAL, + AppExecFwk::ExtensionAbilityType::RECENT_PHOTO, + AppExecFwk::ExtensionAbilityType::FORM_EDIT + }; +} + +inline bool IsUIExtension(const AppExecFwk::ExtensionAbilityType type) +{ + return GetUiExtensionSet().count(type) > 0; +} + +inline bool IsSystemUIExtension(const AppExecFwk::ExtensionAbilityType type) +{ + const std::unordered_set systemUiExtensionSet = { + AppExecFwk::ExtensionAbilityType::SYSDIALOG_COMMON, + AppExecFwk::ExtensionAbilityType::SYSDIALOG_ATOMICSERVICEPANEL, + AppExecFwk::ExtensionAbilityType::SYSDIALOG_POWER, + AppExecFwk::ExtensionAbilityType::SYSDIALOG_MEETIMECALL, + AppExecFwk::ExtensionAbilityType::SYSDIALOG_MEETIMECONTACT, + AppExecFwk::ExtensionAbilityType::SYSDIALOG_MEETIMEMESSAGE, + AppExecFwk::ExtensionAbilityType::SYSDIALOG_PRINT, + AppExecFwk::ExtensionAbilityType::SYSPICKER_MEDIACONTROL, + AppExecFwk::ExtensionAbilityType::SYSPICKER_SHARE, + AppExecFwk::ExtensionAbilityType::SYSPICKER_MEETIMECONTACT, + AppExecFwk::ExtensionAbilityType::SYSPICKER_MEETIMECALLLOG, + AppExecFwk::ExtensionAbilityType::SYSPICKER_PHOTOPICKER, + AppExecFwk::ExtensionAbilityType::SYSPICKER_NAVIGATION, + AppExecFwk::ExtensionAbilityType::SYSPICKER_APPSELECTOR, + AppExecFwk::ExtensionAbilityType::UI, + AppExecFwk::ExtensionAbilityType::SYS_COMMON_UI, + AppExecFwk::ExtensionAbilityType::SYSPICKER_PHOTOEDITOR, + AppExecFwk::ExtensionAbilityType::ADS, + AppExecFwk::ExtensionAbilityType::SYSPICKER_AUDIOPICKER, + AppExecFwk::ExtensionAbilityType::AUTO_FILL_PASSWORD, + AppExecFwk::ExtensionAbilityType::SYSPICKER_CAMERA, + AppExecFwk::ExtensionAbilityType::AUTO_FILL_SMART, + AppExecFwk::ExtensionAbilityType::SYSPICKER_FILEPICKER, + AppExecFwk::ExtensionAbilityType::SYSDIALOG_USERAUTH, + AppExecFwk::ExtensionAbilityType::HMS_ACCOUNT, + AppExecFwk::ExtensionAbilityType::SYS_VISUAL, + AppExecFwk::ExtensionAbilityType::RECENT_PHOTO, + AppExecFwk::ExtensionAbilityType::FORM_EDIT + }; + return systemUiExtensionSet.find(type) != systemUiExtensionSet.end(); +} + +// In this case, extension which be starting needs that caller should be the system app, otherwise not supported. +inline bool IsSystemCallerNeeded(const AppExecFwk::ExtensionAbilityType type) +{ + const std::unordered_set uiExtensionStartingSet = { + AppExecFwk::ExtensionAbilityType::PHOTO_EDITOR, + AppExecFwk::ExtensionAbilityType::INSIGHT_INTENT_UI, + AppExecFwk::ExtensionAbilityType::LIVEVIEW_LOCKSCREEN, + AppExecFwk::ExtensionAbilityType::SHARE, + AppExecFwk::ExtensionAbilityType::ACTION, + AppExecFwk::ExtensionAbilityType::STATUS_BAR_VIEW, + AppExecFwk::ExtensionAbilityType::VOIP, + AppExecFwk::ExtensionAbilityType::FORM_EDIT + }; + return uiExtensionStartingSet.find(type) != uiExtensionStartingSet.end(); +} + +// In this collection, extension can be embedded by public app, which requires vertical businesses to ensure security. +inline bool IsPublicForEmbedded(const AppExecFwk::ExtensionAbilityType type) +{ + const std::unordered_set publicForEmbeddedSet = { + AppExecFwk::ExtensionAbilityType::EMBEDDED_UI, // EMBEDDED_UI usage within the app + AppExecFwk::ExtensionAbilityType::ADS, + AppExecFwk::ExtensionAbilityType::SYSPICKER_MEDIACONTROL, + AppExecFwk::ExtensionAbilityType::SYS_VISUAL, + AppExecFwk::ExtensionAbilityType::AUTO_FILL_SMART, + AppExecFwk::ExtensionAbilityType::AUTO_FILL_PASSWORD + }; + return publicForEmbeddedSet.find(type) != publicForEmbeddedSet.end(); +} + +// In this collection, extension can be embedded by public app, which some UX effects are constrained +inline bool IsPublicForConstrainedEmbedded(const AppExecFwk::ExtensionAbilityType type) +{ + const std::unordered_set publicForConstrainedEmbeddedSet = { + AppExecFwk::ExtensionAbilityType::SYSPICKER_PHOTOPICKER, + AppExecFwk::ExtensionAbilityType::RECENT_PHOTO + }; + return publicForConstrainedEmbeddedSet.find(type) != publicForConstrainedEmbeddedSet.end(); +} + +inline bool IsEnterpriseAdmin(const AppExecFwk::ExtensionAbilityType type) +{ + bool enterpriseAdminSa = (IPCSkeleton::GetCallingUid() == EDM_SA_UID); + bool isEnterpriseAdmin = (type == AppExecFwk::ExtensionAbilityType::ENTERPRISE_ADMIN); + return enterpriseAdminSa && isEnterpriseAdmin; +} + +inline bool IsWindowExtension(const AppExecFwk::ExtensionAbilityType type) +{ + return type == AppExecFwk::ExtensionAbilityType::WINDOW; +} +} // namespace UIExtensionUtils +} // namespace AAFwk +} // namespace OHOS +#endif // OHOS_AAFwk_UI_EXTENSION_UTILS_H diff --git a/mock/innerkits/appexecfwk_base/include/bundle_info.h b/mock/innerkits/appexecfwk_base/include/bundle_info.h index 80e9a745ce343761161f4231a1f9dca37202e7a9..e2f62c445e9652696fb318272f4ea555fc55eccd 100644 --- a/mock/innerkits/appexecfwk_base/include/bundle_info.h +++ b/mock/innerkits/appexecfwk_base/include/bundle_info.h @@ -1,17 +1,17 @@ /* - * Copyright (c) 2021-2022 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. - */ +* Copyright (c) 2021-2024 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 FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_BUNDLE_INFO_H #define FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_BUNDLE_INFO_H @@ -19,13 +19,13 @@ #include #include -#include "parcel.h" - #include "ability_info.h" #include "application_info.h" #include "extension_ability_info.h" #include "hap_module_info.h" #include "message_parcel.h" +//#include "overlay/overlay_bundle_info.h" +#include "parcel.h" namespace OHOS { namespace AppExecFwk { @@ -40,11 +40,35 @@ enum BundleFlag { GET_BUNDLE_WITH_EXTENSION_INFO = 0x00000020, // get bundle info include hash value GET_BUNDLE_WITH_HASH_VALUE = 0x00000030, + // get bundle info inlcude menu, only for dump usage + GET_BUNDLE_WITH_MENU = 0x00000040, + // get bundle info inlcude router map, only for dump usage + GET_BUNDLE_WITH_ROUTER_MAP = 0x00000080, + // get bundle info include skill info + GET_BUNDLE_WITH_SKILL = 0x00000800, +}; + +enum class GetBundleInfoFlag { + GET_BUNDLE_INFO_DEFAULT = 0x00000000, + GET_BUNDLE_INFO_WITH_APPLICATION = 0x00000001, + GET_BUNDLE_INFO_WITH_HAP_MODULE = 0x00000002, + GET_BUNDLE_INFO_WITH_ABILITY = 0x00000004, + GET_BUNDLE_INFO_WITH_EXTENSION_ABILITY = 0x00000008, + GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION = 0x00000010, + GET_BUNDLE_INFO_WITH_METADATA = 0x00000020, + GET_BUNDLE_INFO_WITH_DISABLE = 0x00000040, + GET_BUNDLE_INFO_WITH_SIGNATURE_INFO = 0x00000080, + GET_BUNDLE_INFO_WITH_MENU = 0x00000100, + GET_BUNDLE_INFO_WITH_ROUTER_MAP = 0x00000200, + GET_BUNDLE_INFO_WITH_SKILL = 0x00000800, + GET_BUNDLE_INFO_ONLY_WITH_LAUNCHER_ABILITY = 0x00001000, + GET_BUNDLE_INFO_OF_ANY_USER = 0x00002000, + GET_BUNDLE_INFO_EXCLUDE_CLONE = 0x00004000, }; struct RequestPermissionUsedScene : public Parcelable { - std::vector abilities; std::string when; + std::vector abilities; bool ReadFromParcel(Parcel &parcel); virtual bool Marshalling(Parcel &parcel) const override; @@ -52,75 +76,107 @@ struct RequestPermissionUsedScene : public Parcelable { }; struct RequestPermission : public Parcelable { + uint32_t reasonId = 0; std::string name; + std::string moduleName; std::string reason; - int32_t reasonId = 0; RequestPermissionUsedScene usedScene; bool ReadFromParcel(Parcel &parcel); virtual bool Marshalling(Parcel &parcel) const override; static RequestPermission *Unmarshalling(Parcel &parcel); }; -// configuration information about a bundle -struct BundleInfo : public Parcelable { - std::string name; - uint32_t versionCode = 0; - std::string versionName; - uint32_t minCompatibleVersionCode = 0; +struct SignatureInfo : public Parcelable { + std::string appId; + std::string fingerprint; + std::string appIdentifier; + std::string certificate; - uint32_t compatibleVersion = 0; - uint32_t targetVersion = 0; + bool ReadFromParcel(Parcel &parcel); + virtual bool Marshalling(Parcel &parcel) const override; + static SignatureInfo *Unmarshalling(Parcel &parcel); +}; + +struct SimpleAppInfo : public Parcelable { + int32_t uid = -1; + std::string bundleName; + int32_t appIndex = -1; + int32_t ret = 0; + + bool ReadFromParcel(Parcel &parcel); + virtual bool Marshalling(Parcel &parcel) const override; + static SimpleAppInfo *Unmarshalling(Parcel &parcel); + std::string ToString() const; +}; +// configuration information about a bundle +struct BundleInfo : public Parcelable { + bool isNewVersion = false; bool isKeepAlive = false; bool singleton = false; bool isPreInstallApp = false; - std::string vendor; - std::string releaseType; bool isNativeApp = false; - std::string mainEntry; // modulePackage - std::string entryModuleName; // moduleName bool entryInstallationFree = false; // application : false; atomic service : true + bool isDifferentName = false; - std::string appId; + uint32_t versionCode = 0; + uint32_t minCompatibleVersionCode = 0; + + uint32_t compatibleVersion = 0; + uint32_t targetVersion = 0; + int32_t appIndex = 0; // index for sandbox app + int32_t minSdkVersion = -1; + int32_t maxSdkVersion = -1; +// int32_t overlayType = NON_OVERLAY_TYPE; // user related fields, assign when calling the get interface int uid = -1; int gid = -1; int64_t installTime = 0; int64_t updateTime = 0; + int64_t firstInstallTime = 0; + std::string name; + std::string versionName; + + std::string vendor; + std::string releaseType; + std::string mainEntry; // modulePackage + std::string entryModuleName; // moduleName + std::string appId; + + std::string cpuAbi; + std::string seInfo; + std::string label; + std::string description; + std::string jointUserId; + SignatureInfo signatureInfo; + std::vector oldAppIds; // used for appId changed - ApplicationInfo applicationInfo; std::vector abilityInfos; std::vector extensionInfos; std::vector hapModuleInfos; - std::vector hapModuleNames; // the "module.package" in each config.json - std::vector moduleNames; // the "module.name" in each config.json - std::vector modulePublicDirs; // the public paths of all modules of the application. - std::vector moduleDirs; // the paths of all modules of the application. - std::vector moduleResPaths; // the paths of all resources paths. + std::vector hapModuleNames; // the "module.package" in each config.json + std::vector moduleNames; // the "module.name" in each config.json + std::vector modulePublicDirs; // the public paths of all modules of the application. + std::vector moduleDirs; // the paths of all modules of the application. + std::vector moduleResPaths; // the paths of all resources paths. std::vector reqPermissions; std::vector defPermissions; std::vector reqPermissionStates; std::vector reqPermissionDetails; - - // unused - std::string cpuAbi; - std::string seInfo; - std::string label; - std::string description; - std::string jointUserId; - int32_t minSdkVersion = -1; - int32_t maxSdkVersion = -1; - bool isDifferentName = false; +// std::vector overlayBundleInfos; +// +// std::vector routerArray; + ApplicationInfo applicationInfo; bool ReadFromParcel(Parcel &parcel); virtual bool Marshalling(Parcel &parcel) const override; static BundleInfo *Unmarshalling(Parcel &parcel); }; -} // namespace AppExecFwk -} // namespace OHOS -#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_BUNDLE_INFO_H +} // namespace AppExecFwk +} // namespace OHOS +#endif // FOUNDATION_APPEXECFWK_INTERFACES_INNERKITS_APPEXECFWK_BASE_INCLUDE_BUNDLE_INFO_H diff --git a/mock/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_interface.h b/mock/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_interface.h index 95d83ff110df6a614634596abf8953fd90f76155..62ab7083e0a6051a1b244b38da6ec35fd3b86096 100644 --- a/mock/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_interface.h +++ b/mock/innerkits/appexecfwk_core/include/bundlemgr/bundle_mgr_interface.h @@ -43,23 +43,6 @@ enum class DumpFlag { DUMP_BUNDLE_INFO, // corresponse to option "-bundle [name]" DUMP_SHORTCUT_INFO, // corresponse to option "-bundle [name] -shortcut-info" }; -enum class GetBundleInfoFlag { - GET_BUNDLE_INFO_DEFAULT = 0x00000000, - GET_BUNDLE_INFO_WITH_APPLICATION = 0x00000001, - GET_BUNDLE_INFO_WITH_HAP_MODULE = 0x00000002, - GET_BUNDLE_INFO_WITH_ABILITY = 0x00000004, - GET_BUNDLE_INFO_WITH_EXTENSION_ABILITY = 0x00000008, - GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION = 0x00000010, - GET_BUNDLE_INFO_WITH_METADATA = 0x00000020, - GET_BUNDLE_INFO_WITH_DISABLE = 0x00000040, - GET_BUNDLE_INFO_WITH_SIGNATURE_INFO = 0x00000080, - GET_BUNDLE_INFO_WITH_MENU = 0x00000100, - GET_BUNDLE_INFO_WITH_ROUTER_MAP = 0x00000200, - GET_BUNDLE_INFO_WITH_SKILL = 0x00000800, - GET_BUNDLE_INFO_ONLY_WITH_LAUNCHER_ABILITY = 0x00001000, - GET_BUNDLE_INFO_OF_ANY_USER = 0x00002000, - GET_BUNDLE_INFO_EXCLUDE_CLONE = 0x00004000, -}; class IBundleMgr : public IRemoteBroker { public: diff --git a/mock/innerkits/dsoftbus/softbus_client/include/transport/trans_type.h b/mock/innerkits/dsoftbus/softbus_client/include/transport/trans_type.h index b7e642ad9545753353e339f7cb824b1b99879f9a..2a7c1e535c07ff1b794a1ea76e5725e6f73bf4ee 100644 --- a/mock/innerkits/dsoftbus/softbus_client/include/transport/trans_type.h +++ b/mock/innerkits/dsoftbus/softbus_client/include/transport/trans_type.h @@ -116,6 +116,7 @@ typedef enum { QOS_TYPE_FIRST_PACKAGE, /**< First packet size. */ QOS_TYPE_MAX_IDLE_TIMEOUT, /**< Maximum idle time. */ QOS_TYPE_TRANS_RELIABILITY, /**< Transmission reliability. */ + QOS_TYPE_REUSE_BE, QOS_TYPE_BUTT, } QosType; diff --git a/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/copy/distributed_file_fd_guard.h b/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/copy/distributed_file_fd_guard.h new file mode 100644 index 0000000000000000000000000000000000000000..8de06854b64dd9a1886638828ee98fc1c17062d6 --- /dev/null +++ b/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/copy/distributed_file_fd_guard.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025 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 DISTRIBUTED_FILE_FD_GUARD_H +#define DISTRIBUTED_FILE_FD_GUARD_H + +namespace OHOS { +namespace Storage { +namespace DistributedFile { +class FDGuard final { +public: + FDGuard() = default; + explicit FDGuard(int fd); + FDGuard(int fd, bool autoClose); + + FDGuard(const FDGuard &fdg) = delete; + FDGuard &operator=(const FDGuard &fdg) = delete; + + FDGuard(FDGuard &&fdg); + FDGuard &operator=(FDGuard &&fdg); + + operator bool() const; + + ~FDGuard(); + + int GetFD() const; + void SetFD(int fd, bool autoClose = true); + void ClearFD(); + +private: + int fd_ = -1; + bool autoClose_ = true; +}; +} // namespace DistributedFile +} // namespace Storage +} // namespace OHOS +#endif // DISTRIBUTED_FILE_FD_GUARD_H diff --git a/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/copy/file_copy_listener.h b/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/copy/file_copy_listener.h new file mode 100644 index 0000000000000000000000000000000000000000..91c4b0c3b8b6a1bc68c18d69a84731a5d9be9194 --- /dev/null +++ b/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/copy/file_copy_listener.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2025 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 DISTRIBUTED_FILE_COPY_LISTENER_H +#define DISTRIBUTED_FILE_COPY_LISTENER_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace OHOS { +namespace Storage { +namespace DistributedFile { + +struct ReceiveInfo { + std::string path; // dir name + std::map fileList; // filename, proceededSize +}; + +using ProcessCallback = std::function; +class FileCopyLocalListener { +public: + FileCopyLocalListener(const FileCopyLocalListener&) = delete; + FileCopyLocalListener& operator=(const FileCopyLocalListener&) = delete; + FileCopyLocalListener(const std::string &srcPath, + bool isFile, const ProcessCallback &processCallback); + ~FileCopyLocalListener(); + static std::shared_ptr GetLocalListener(const std::string &srcPath, + bool isFile, const ProcessCallback &processCallback); + +public: + void StartListener(); + void StopListener(); + void AddFile(const std::string &fileName); + void AddListenerFile(const std::string &destPath, uint32_t mode); + std::set GetFilePath() + { + std::lock_guard lock(filePathsMutex_); + return filePaths_; + } + int32_t GetResult() { return errorCode_; }; + +private: + void CloseNotifyFd(); + void GetNotifyEvent(); + void ReadNotifyEvent(); + std::tuple HandleProgress(inotify_event *event); + bool CheckFileValid(const std::string &filePath); + int UpdateProgressSize(const std::string &filePath, std::shared_ptr receivedInfo); + +private: + bool isFile_ = false; + int32_t notifyFd_ = -1; + int32_t eventFd_ = -1; + uint64_t totalSize_ = 0; + uint64_t progressSize_ = 0; + std::chrono::steady_clock::time_point notifyTime_; + std::mutex wdsMutex_; + std::map> wds_; + + std::thread notifyHandler_; + std::mutex filePathsMutex_; + std::set filePaths_; + ProcessCallback processCallback_; + int32_t errorCode_ = 0; +}; +} // namespace DistributedFile +} // namespace Storage +} // namespace OHOS + +#endif // DISTRIBUTED_FILE_COPY_LISTENER_H diff --git a/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/copy/file_copy_manager.h b/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/copy/file_copy_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..191a8562fb0c139c78eaeaebdde9f147f33eaa1c --- /dev/null +++ b/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/copy/file_copy_manager.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025 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 DISTRIBUTED_FILE_COPY_MANAGER_H +#define DISTRIBUTED_FILE_COPY_MANAGER_H + +#include +#include +#include +#include +#include + +#include "copy/distributed_file_fd_guard.h" +//#include "copy/file_copy_listener.h" +#include "copy/trans_listener.h" +#include "iremote_broker.h" +#include "refbase.h" +#include "uv.h" + +namespace OHOS { +namespace Storage { +namespace DistributedFile { + +class FileIoToken : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.fileio.open"); + + FileIoToken() = default; + virtual ~FileIoToken() noexcept = default; +}; + +struct FileInfos { + std::string srcUri; + std::string destUri; + std::string srcPath; + std::string destPath; + bool srcUriIsFile = false; +// std::shared_ptr localListener = nullptr; + sptr transListener = nullptr; + std::atomic_bool needCancel{ false }; + std::mutex subDirsMutex; + std::set subDirs; + + bool operator==(const FileInfos &infos) const + { + return (srcUri == infos.srcUri && destUri == infos.destUri); + } + bool operator<(const FileInfos &infos) const + { + if (srcUri == infos.srcUri) { + return destUri < infos.destUri; + } + return srcUri < infos.srcUri; + } +}; + +class FileCopyManager final { +public: + using ProcessCallback = std::function; + static std::shared_ptr GetInstance(); + int32_t Copy(const std::string &srcUri, const std::string &destUri, ProcessCallback &processCallback); + int32_t Cancel(const std::string &srcUri, const std::string &destUri); + int32_t Cancel(); + +private: + static std::shared_ptr instance_; + std::mutex FileInfosVecMutex_; + std::vector> FileInfosVec_; +}; +} // namespace DistributedFile +} // namespace Storage +} // namespace OHOS + +#endif // DISTRIBUTED_FILE_COPY_MANAGER_H diff --git a/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/copy/file_size_utils.h b/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/copy/file_size_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..fd999a00c07779f65952b55960b4d21e4d60b3f3 --- /dev/null +++ b/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/copy/file_size_utils.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025 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 DISTRIBUTED_FILE_SIZE_UTILS_H +#define DISTRIBUTED_FILE_SIZE_UTILS_H + +#include +#include +#include + + +namespace OHOS { +namespace Storage { +namespace DistributedFile { + +struct NameList { + struct dirent **namelist = { nullptr }; + int direntNum = 0; +}; + +class FileSizeUtils { +public: + static int32_t GetSize(const std::string &uri, bool isSrcUri, uint64_t &size); + static int32_t IsDirectory(const std::string &uri, bool isSrcUri, bool &isDirectory); + + static std::string GetPathFromUri(const std::string &uri, bool isSrcUri); + static int32_t GetFileSize(const std::string &path, uint64_t &size); + static int32_t GetDirSize(const std::string &path, uint64_t &size); + static void Deleter(struct NameList *arg); + static std::unique_ptr GetDirNameList(const std::string &path); + +private: +// static int FilterFunc(const struct dirent *filename); +// static std::string GetRealPath(const std::string &path); +// static int32_t IsFile(const std::string &path, bool &result); +// static int32_t IsDirectory(const std::string &path, bool &result); +}; +} // namespace DistributedFile +} // namespace Storage +} // namespace OHOS +#endif // DISTRIBUTED_FILE_SIZE_UTILS_H diff --git a/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/copy/trans_listener.h b/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/copy/trans_listener.h new file mode 100644 index 0000000000000000000000000000000000000000..907d0d2ac1e6771e63044ef6cdceb798f5d240e4 --- /dev/null +++ b/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/copy/trans_listener.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025 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 DISTRIBUTED_TRANS_LISTENER_H +#define DISTRIBUTED_TRANS_LISTENER_H + +#include + +#include "file_trans_listener_stub.h" +#include "hmdfs_info.h" + +constexpr int NONE = 0; +constexpr int SUCCESS = 1; +constexpr int FAILED = 2; +namespace OHOS { +namespace Storage { +namespace DistributedFile { +struct CopyEvent { + int copyResult = NONE; + int32_t errorCode = 0; +}; + +class TransListener : public Storage::DistributedFile::FileTransListenerStub { +public: + using ProcessCallback = std::function; + explicit TransListener(const std::string &destUri, ProcessCallback &processCallback); + virtual ~TransListener(); + + int32_t OnFileReceive(uint64_t totalBytes, uint64_t processedBytes) override; + int32_t OnFinished(const std::string &sessionName) override; + int32_t OnFailed(const std::string &sessionName, int32_t errorCode) override; + + int32_t WaitForCopyResult(); + int32_t CopyToSandBox(const std::string &srcUri); + std::string GetNetworkIdFromUri(const std::string &uri); + int32_t Cancel(); + int32_t GetErrCode() { return copyEvent_.errorCode; }; +public: + HmdfsInfo hmdfsInfo_{}; + +private: + int32_t CreateTmpDir(); + void RmTmpDir(); + std::string CreateDfsCopyPath(); + std::string GetFileName(const std::string &path); + +private: + std::string disSandboxPath_; + std::mutex cvMutex_; + std::condition_variable cv_; + ProcessCallback processCallback_; + + CopyEvent copyEvent_; +}; +} // namespace DistributedFile +} // namespace Storage +} // namespace OHOS +#endif // DISTRIBUTED_TRANS_LISTENER_H diff --git a/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/i_file_trans_listener.h b/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/i_file_trans_listener.h index ab27d4f901c1ac8a4749a0781c1b78f0d2baa4b5..4832a6f7302099b1f7ad8e4d144b5eaeb521eea5 100644 --- a/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/i_file_trans_listener.h +++ b/mock/innerkits/filemanagement/dfs_service/frameworks/native/distributed_file_inner/include/i_file_trans_listener.h @@ -29,7 +29,7 @@ public: File_Trans_Listener_DESCRIPTOR_IS_EMPTY, }; virtual int32_t OnFileReceive(uint64_t totalBytes, uint64_t processedBytes) = 0; - virtual int32_t OnFailed(const std::string &sessionName) = 0; + virtual int32_t OnFailed(const std::string &sessionName, int32_t errorCode) = 0; virtual int32_t OnFinished(const std::string &sessionName) = 0; DECLARE_INTERFACE_DESCRIPTOR(u"ohos.storage.distributedfile.translistener") }; diff --git a/mock/innerkits/napi/native_common.h b/mock/innerkits/napi/native_common.h index 5b753ed2e0b8182b365f3b4fcecf0a882ba5b40a..1d8e9b31c45ebdb5c4f196e0ba3d011a28766820 100644 --- a/mock/innerkits/napi/native_common.h +++ b/mock/innerkits/napi/native_common.h @@ -1,17 +1,17 @@ /* -* Copyright (c) 2021 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. -*/ + * Copyright (c) 2021 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 FOUNDATION_ACE_NAPI_INTERFACES_KITS_NAPI_NATIVE_COMMON_H #define FOUNDATION_ACE_NAPI_INTERFACES_KITS_NAPI_NATIVE_COMMON_H @@ -19,108 +19,145 @@ #define NAPI_RETVAL_NOTHING #define GET_AND_THROW_LAST_ERROR(env) \ - do { \ - const napi_extended_error_info* errorInfo = nullptr; \ - napi_get_last_error_info((env), &errorInfo); \ - bool isPending = false; \ - napi_is_exception_pending((env), &isPending); \ - if (!isPending && errorInfo != nullptr) { \ - const char* errorMessage = \ - errorInfo->error_message != nullptr ? errorInfo->error_message : "empty error message"; \ - napi_throw_error((env), nullptr, errorMessage); \ - } \ - } while (0) + do { \ + const napi_extended_error_info* errorInfo = nullptr; \ + napi_get_last_error_info((env), &errorInfo); \ + bool isPending = false; \ + napi_is_exception_pending((env), &isPending); \ + if (!isPending && errorInfo != nullptr) { \ + const char* errorMessage = \ + errorInfo->error_message != nullptr ? errorInfo->error_message : "empty error message"; \ + napi_throw_error((env), nullptr, errorMessage); \ + } \ + } while (0) #define NAPI_ASSERT_BASE(env, assertion, message, retVal) \ - do { \ - if (!(assertion)) { \ - napi_throw_error((env), nullptr, "assertion (" #assertion ") failed: " message); \ - return retVal; \ - } \ - } while (0) + do { \ + if (!(assertion)) { \ + napi_throw_error((env), nullptr, "assertion (" #assertion ") failed: " message); \ + return retVal; \ + } \ + } while (0) #define NAPI_ASSERT(env, assertion, message) NAPI_ASSERT_BASE(env, assertion, message, nullptr) #define NAPI_ASSERT_RETURN_VOID(env, assertion, message) NAPI_ASSERT_BASE(env, assertion, message, NAPI_RETVAL_NOTHING) #define NAPI_CALL_BASE(env, theCall, retVal) \ - do { \ - if ((theCall) != napi_ok) { \ - GET_AND_THROW_LAST_ERROR((env)); \ - return retVal; \ - } \ - } while (0) + do { \ + if ((theCall) != napi_ok) { \ + GET_AND_THROW_LAST_ERROR((env)); \ + return retVal; \ + } \ + } while (0) #define NAPI_CALL(env, theCall) NAPI_CALL_BASE(env, theCall, nullptr) #define NAPI_CALL_RETURN_VOID(env, theCall) NAPI_CALL_BASE(env, theCall, NAPI_RETVAL_NOTHING) +// W-writable E-enumerable C-configurable napi_default is not WEC #define DECLARE_NAPI_PROPERTY(name, val) \ - { \ - (name), nullptr, nullptr, nullptr, nullptr, val, napi_default, nullptr \ - } + { \ + (name), nullptr, nullptr, nullptr, nullptr, val, napi_default, nullptr \ + } +// W-writable E-enumerable C-configurable tihs define is W #define DECLARE_NAPI_INSTANCE_PROPERTY(name, val) \ - { \ - (name), nullptr, nullptr, nullptr, nullptr, val, \ - static_cast(NATIVE_INSTANCE | napi_writable), nullptr \ - } + { \ + (name), nullptr, nullptr, nullptr, nullptr, val, \ + static_cast(NATIVE_INSTANCE | napi_writable), nullptr \ + } +// W-writable E-enumerable C-configurable tihs define is W #define DECLARE_NAPI_INSTANCE_OBJECT_PROPERTY(name) \ - { \ - (name), nullptr, nullptr, nullptr, nullptr, nullptr, \ - static_cast(NATIVE_INSTANCE_OBJECT | napi_writable), nullptr \ - } + { \ + (name), nullptr, nullptr, nullptr, nullptr, nullptr, \ + static_cast(NATIVE_INSTANCE_OBJECT | napi_writable), nullptr \ + } +// W-writable E-enumerable C-configurable tihs define is W #define DECLARE_NAPI_INSTANCE_GENERIC_PROPERTY(name) \ - { \ - (name), nullptr, nullptr, nullptr, nullptr, nullptr, \ - static_cast(NATIVE_INSTANCE_GENERIC | napi_writable), nullptr \ - } + { \ + (name), nullptr, nullptr, nullptr, nullptr, nullptr, \ + static_cast(NATIVE_INSTANCE_GENERIC | napi_writable), nullptr \ + } +// W-writable E-enumerable C-configurable napi_default_jsproperty is WEC #define DECLARE_NAPI_DEFAULT_PROPERTY(name, val) \ - { \ - (name), nullptr, nullptr, nullptr, nullptr, val, napi_default_jsproperty, nullptr \ - } + { \ + (name), nullptr, nullptr, nullptr, nullptr, val, napi_default_jsproperty, nullptr \ + } +//static properties #define DECLARE_NAPI_STATIC_PROPERTY(name, val) \ - { \ - (name), nullptr, nullptr, nullptr, nullptr, val, napi_static, nullptr \ - } + { \ + (name), nullptr, nullptr, nullptr, nullptr, val, napi_static, nullptr \ + } +// W-writable E-enumerable C-configurable napi_default is not WEC #define DECLARE_NAPI_FUNCTION(name, func) \ - { \ - (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, nullptr \ - } + { \ + (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, nullptr \ + } +// W-writable E-enumerable C-configurable napi_default_jsproperty is WEC #define DECLARE_NAPI_DEFAULT_PROPERTY_FUNCTION(name, func) \ - { \ - (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default_jsproperty, nullptr \ - } + { \ + (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default_jsproperty, nullptr \ + } +// W-writable E-enumerable C-configurable napi_default is not WEC #define DECLARE_NAPI_FUNCTION_WITH_DATA(name, func, data) \ - { \ - (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, data \ - } - + { \ + (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, data \ + } + +// W-writable E-enumerable C-configurable napi_default_jsproperty is WEC +#define DECLARE_NAPI_FUNCTION_WITH_WEC(name, func) \ + { \ + (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default_jsproperty, nullptr \ + } + +// W-writable E-enumerable C-configurable napi_default_jsproperty is WEC +#define DECLARE_NAPI_FUNCTION_WITH_DATA_WITH_WEC(name, func, data) \ + { \ + (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default_jsproperty, data \ + } + +// W-writable E-enumerable C-configurable napi_default is not WEC +#define DECLARE_NAPI_FUNCTION_WITHOUT_WEC(name, func) \ + { \ + (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, nullptr \ + } + +// W-writable E-enumerable C-configurable napi_default is not WEC +#define DECLARE_NAPI_FUNCTION_WITH_DATA_WITHOUT_WEC(name, func) \ + { \ + (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, data \ + } + +//static properties #define DECLARE_NAPI_STATIC_FUNCTION(name, func) \ - { \ - (name), nullptr, (func), nullptr, nullptr, nullptr, napi_static, nullptr \ - } + { \ + (name), nullptr, (func), nullptr, nullptr, nullptr, napi_static, nullptr \ + } +// W-writable E-enumerable C-configurable napi_default is not WEC #define DECLARE_NAPI_GETTER(name, getter) \ - { \ - (name), nullptr, nullptr, (getter), nullptr, nullptr, napi_default, nullptr \ - } + { \ + (name), nullptr, nullptr, (getter), nullptr, nullptr, napi_default, nullptr \ + } +// W-writable E-enumerable C-configurable napi_default is not WEC #define DECLARE_NAPI_SETTER(name, setter) \ - { \ - (name), nullptr, nullptr, nullptr, (setter), nullptr, napi_default, nullptr \ - } + { \ + (name), nullptr, nullptr, nullptr, (setter), nullptr, napi_default, nullptr \ + } +// W-writable E-enumerable C-configurable napi_default is not WEC #define DECLARE_NAPI_GETTER_SETTER(name, getter, setter) \ - { \ - (name), nullptr, nullptr, (getter), (setter), nullptr, napi_default, nullptr \ - } + { \ + (name), nullptr, nullptr, (getter), (setter), nullptr, napi_default, nullptr \ + } #endif /* FOUNDATION_ACE_NAPI_INTERFACES_KITS_NAPI_NATIVE_COMMON_H */ diff --git a/mock/innerkits/napi/native_node_api.h b/mock/innerkits/napi/native_node_api.h index 231b81c8c16eb79343e910db72eb844a1cccd196..cc9506c0c79d7a32a226ed0b70bcee1cecb5fedf 100644 --- a/mock/innerkits/napi/native_node_api.h +++ b/mock/innerkits/napi/native_node_api.h @@ -16,43 +16,118 @@ #ifndef FOUNDATION_ACE_NAPI_INTERFACES_KITS_NAPI_NATIVE_NODE_API_H #define FOUNDATION_ACE_NAPI_INTERFACES_KITS_NAPI_NATIVE_NODE_API_H +#include #include +#include #include -#include +#include "js_native_api.h" +#include "native_common.h" +#include "node_api.h" -#include "innerkits/napi/ace_napi/include/napi/native_common.h" +typedef void (*NAPIGetJSCode)(const char **buf, int *bufLen); +typedef void (*NapiNativeFinalize)(napi_env env, void *data, void *hint); +typedef void *(*NapiDetachCallback)(napi_env env, void *nativeObject, void *hint); // hint: detach params +typedef napi_value (*NapiAttachCallback)(napi_env env, void *nativeObject, void *hint); // hint: attach params +typedef struct napi_fast_native_scope__ *napi_fast_native_scope; -NAPI_EXTERN napi_status napi_is_callable(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_create_runtime(napi_env env, napi_env* result_env); -NAPI_EXTERN napi_status napi_serialize(napi_env env, napi_value object, napi_value transfer_list, napi_value* result); -NAPI_EXTERN napi_status napi_deserialize(napi_env env, napi_value recorder, napi_value* object); -NAPI_EXTERN napi_status napi_delete_serialization_data(napi_env env, napi_value value); -NAPI_EXTERN napi_status napi_get_exception_info_for_worker(napi_env env, napi_value obj); -NAPI_EXTERN napi_status napi_run_buffer_script(napi_env env, std::vector& buffer, napi_value* result); -NAPI_EXTERN napi_status napi_run_actor(napi_env env, std::vector& buffer, - const char* descriptor, napi_value* result); +typedef struct napi_module_with_js { + int nm_version = 0; + unsigned int nm_flags = 0; + const char *nm_filename = nullptr; + napi_addon_register_func nm_register_func = nullptr; + const char *nm_modname = nullptr; + void *nm_priv = nullptr; + NAPIGetJSCode nm_get_abc_code = nullptr; + NAPIGetJSCode nm_get_js_code = nullptr; +} napi_module_with_js; + +typedef enum { + napi_eprio_vip = 0, + napi_eprio_immediate = 1, + napi_eprio_high = 2, + napi_eprio_low = 3, + napi_eprio_idle = 4, +} napi_event_priority; + +NAPI_EXTERN napi_status napi_create_limit_runtime(napi_env env, napi_env *result_env); +NAPI_EXTERN void napi_module_with_js_register(napi_module_with_js *mod); +NAPI_EXTERN napi_status napi_is_callable(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_create_runtime(napi_env env, napi_env *result_env); +NAPI_EXTERN napi_status napi_serialize_inner(napi_env env, napi_value object, napi_value transfer_list, + napi_value clone_list, bool defaultTransfer, bool defaultCloneSendable, void **result); +NAPI_EXTERN napi_status napi_run_actor(napi_env env, uint8_t *buffer, size_t bufferSize, const char *descriptor, + napi_value *result, char *entryPoint = nullptr); +NAPI_EXTERN napi_status napi_wrap_with_size(napi_env env, napi_value js_object, void *native_object, + napi_finalize finalize_cb, void *finalize_hint, napi_ref *result, size_t native_binding_size); +NAPI_EXTERN napi_status napi_wrap_async_finalizer(napi_env env, napi_value js_object, void *native_object, + napi_finalize finalize_cb, void *finalize_hint, napi_ref *result, size_t native_binding_size); +NAPI_EXTERN napi_status napi_create_external_with_size(napi_env env, void *data, napi_finalize finalize_cb, + void *finalize_hint, napi_value *result, size_t native_binding_size); NAPI_EXTERN napi_status napi_set_promise_rejection_callback(napi_env env, napi_ref ref, napi_ref checkRef); -NAPI_EXTERN napi_status napi_is_arguments_object(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_is_async_function(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_is_boolean_object(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_is_generator_function(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_is_date(napi_env env, napi_value value, bool* result); - -NAPI_EXTERN napi_status napi_is_map_iterator(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_is_set_iterator(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_is_generator_object(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_is_module_namespace_object(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_is_proxy(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_is_reg_exp(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_is_number_object(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_is_map(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_is_set(napi_env env, napi_value value, bool* result); - -NAPI_EXTERN napi_status napi_is_string_object(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_is_symbol_object(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_is_weak_map(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_is_weak_set(napi_env env, napi_value value, bool* result); +NAPI_EXTERN napi_status napi_is_arguments_object(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_async_function(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_boolean_object(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_generator_function(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_date(napi_env env, napi_value value, bool *result); + +NAPI_EXTERN napi_status napi_is_map_iterator(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_set_iterator(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_generator_object(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_module_namespace_object(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_proxy(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_reg_exp(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_number_object(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_map(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_set(napi_env env, napi_value value, bool *result); + +NAPI_EXTERN napi_status napi_is_string_object(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_symbol_object(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_weak_map(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_weak_set(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_big_int64_array(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_big_uint64_array(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_is_shared_array_buffer(napi_env env, napi_value value, bool *result); +NAPI_EXTERN napi_status napi_get_stack_trace(napi_env env, std::string &stack); +NAPI_EXTERN napi_status napi_get_hybrid_stack_trace(napi_env env, std::string &stack); +NAPI_EXTERN napi_status napi_get_own_property_descriptor(napi_env env, napi_value object, const char *utf8name, + napi_value *result); +NAPI_EXTERN napi_status napi_object_get_keys(napi_env env, napi_value data, napi_value *result); +NAPI_EXTERN napi_status napi_get_print_string(napi_env env, napi_value value, std::string &result); +/* + * @brief Send a task to the JS Thread + * + * @param env The native engine. + * @param cb CallBack in JS Thread + * @param priority Task priority + */ +NAPI_EXTERN napi_status napi_send_event(napi_env env, const std::function &cb, napi_event_priority priority); +/* + * @brief Send a task to the JS Thread + * + * @param env The native engine. + * @param cb CallBack in JS Thread. + * @param data Input parameter of callback. + * @param priority Task priority. + * @param handleId Handle to cancel a task. + * @param name Task name, Use the task name and handleId as the tag of task. + */ +NAPI_EXTERN napi_status napi_send_cancelable_event(napi_env env, const std::function &cb, void *data, + napi_event_priority priority, uint64_t *handleId, const char *name); +/* + * @brief Send a task to the JS Thread + * + * @param env The native engine. + * @param handleId Handle to cancel a task, But sometimes it do not work when used alone. + * @param name Task name, The name must be the same as the name of the task send. + */ +NAPI_EXTERN napi_status napi_cancel_event(napi_env env, uint64_t handleId, const char *name); +NAPI_EXTERN napi_status napi_open_fast_native_scope(napi_env env, napi_fast_native_scope *scope); +NAPI_EXTERN napi_status napi_close_fast_native_scope(napi_env env, napi_fast_native_scope scope); +NAPI_EXTERN napi_status napi_get_shared_array_buffer_info(napi_env env, napi_value arraybuffer, void **data, + size_t *byte_length); +NAPI_EXTERN napi_status napi_encode(napi_env env, napi_value src, napi_value *result); +NAPI_EXTERN napi_status napi_is_bitvector(napi_env env, napi_value value, bool *result); #endif /* FOUNDATION_ACE_NAPI_INTERFACES_KITS_NAPI_NATIVE_NODE_API_H */ diff --git a/mock/innerkits/os_account/os_account_innerkits/include/os_account_manager.h b/mock/innerkits/os_account/os_account_innerkits/include/os_account_manager.h index 473ffc4e2981341e3c3fed540fffc338f32aada4..d43d6ae8cf33f9c360766645d5c80de7020a7ac5 100644 --- a/mock/innerkits/os_account/os_account_innerkits/include/os_account_manager.h +++ b/mock/innerkits/os_account/os_account_innerkits/include/os_account_manager.h @@ -162,6 +162,7 @@ public: */ static ErrCode IsOsAccountVerified(const int id, bool &isVerified); + static ErrCode IsOsAccountDeactivating(const int id, bool &isVerified); /** * @brief Gets the number of all OS accounts created on a device. * @permission ohos.permission.MANAGE_LOCAL_ACCOUNTS @@ -589,7 +590,6 @@ public: */ static ErrCode IsOsAccountForeground(const int32_t localId, const uint64_t displayId, bool &isForeground); - /** * @brief Gets the id from default display. * @param localId - Indicates the corresponding localId of default display. diff --git a/mock/innerkits/os_account/os_account_innerkits/include/os_account_state_reply_callback.h b/mock/innerkits/os_account/os_account_innerkits/include/os_account_state_reply_callback.h new file mode 100644 index 0000000000000000000000000000000000000000..1d1135612e3f5efb19a0db8d11e7e313c16a4a50 --- /dev/null +++ b/mock/innerkits/os_account/os_account_innerkits/include/os_account_state_reply_callback.h @@ -0,0 +1,43 @@ +/* +* Copyright (c) 2024 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 OS_ACCOUNT_FRAMEWORKS_OSACCOUNT_CORE_INCLUDE_OS_ACCOUNT_STATE_REPLY_CALLBACK_H +#define OS_ACCOUNT_FRAMEWORKS_OSACCOUNT_CORE_INCLUDE_OS_ACCOUNT_STATE_REPLY_CALLBACK_H + +#include "iremote_proxy.h" +#include + +namespace OHOS { +namespace AccountSA { +class IOsAccountStateReplyCallback : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.accountfwk.IOsAccountStateReplyCallback"); + + virtual void OnComplete() = 0; +}; + +class OsAccountStateReplyCallback : public IRemoteProxy { +public: + explicit OsAccountStateReplyCallback(const sptr &object) : IRemoteProxy(object) {} + ~OsAccountStateReplyCallback() override = default; + + void OnComplete() override {} + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace AccountSA +} // namespace OHOS +#endif // OS_ACCOUNT_FRAMEWORKS_OSACCOUNT_CORE_INCLUDE_OS_ACCOUNT_STATE_REPLY_CALLBACK_H diff --git a/mock/innerkits/os_account/os_account_innerkits/include/os_account_subscribe_info.h b/mock/innerkits/os_account/os_account_innerkits/include/os_account_subscribe_info.h index c464b0e101cac2526725262ee9de6257fc3bb553..5ac7c8cc3b565de4237743d38922d606e14b6b3b 100644 --- a/mock/innerkits/os_account/os_account_innerkits/include/os_account_subscribe_info.h +++ b/mock/innerkits/os_account/os_account_innerkits/include/os_account_subscribe_info.h @@ -1,21 +1,24 @@ /* - * Copyright (c) 2021-2022 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. - */ +* Copyright (c) 2021-2024 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 OS_ACCOUNT_INTERFACES_INNERKITS_OSACCOUNT_NATIVE_INCLUDE_OS_ACCOUNT_SUBSCRIBE_INFO_H #define OS_ACCOUNT_INTERFACES_INNERKITS_OSACCOUNT_NATIVE_INCLUDE_OS_ACCOUNT_SUBSCRIBE_INFO_H +#include +#include + #include "account_error_no.h" #include "parcel.h" @@ -23,7 +26,7 @@ namespace OHOS { namespace AccountSA { typedef enum { INVALID_TYPE = -1, - ACTIVED = 0, + ACTIVATED = 0, ACTIVATING, UNLOCKED, CREATED, @@ -32,17 +35,21 @@ typedef enum { STOPPED, SWITCHING, SWITCHED, -} OS_ACCOUNT_SUBSCRIBE_TYPE; +} OS_ACCOUNT_SUBSCRIBE_TYPE, OsAccountState; + class OsAccountSubscribeInfo : public Parcelable { public: OsAccountSubscribeInfo(); - explicit OsAccountSubscribeInfo(const OS_ACCOUNT_SUBSCRIBE_TYPE &osAccountSubscribeType, const std::string &name); + OsAccountSubscribeInfo(const std::set &states, bool withHandshake = false); + OsAccountSubscribeInfo(const OS_ACCOUNT_SUBSCRIBE_TYPE &osAccountSubscribeType, const std::string &name); ~OsAccountSubscribeInfo() override; void GetOsAccountSubscribeType(OS_ACCOUNT_SUBSCRIBE_TYPE &osAccountSubscribeType) const; void SetOsAccountSubscribeType(const OS_ACCOUNT_SUBSCRIBE_TYPE &osAccountSubscribeType); void GetName(std::string &name) const; void SetName(const std::string &name); + void GetStates(std::set &states) const; + bool IsWithHandshake() const; bool Marshalling(Parcel &parcel) const override; static OsAccountSubscribeInfo *Unmarshalling(Parcel &parcel); @@ -51,10 +58,12 @@ private: bool ReadFromParcel(Parcel &parcel); private: - OS_ACCOUNT_SUBSCRIBE_TYPE osAccountSubscribeType_; + OS_ACCOUNT_SUBSCRIBE_TYPE osAccountSubscribeType_ = INVALID_TYPE; std::string name_; + std::set states_; + bool withHandshake_ = false; }; -} // namespace AccountSA -} // namespace OHOS +} // namespace AccountSA +} // namespace OHOS -#endif // OS_ACCOUNT_INTERFACES_INNERKITS_OSACCOUNT_NATIVE_INCLUDE_OS_ACCOUNT_SUBSCRIBE_INFO_H +#endif // OS_ACCOUNT_INTERFACES_INNERKITS_OSACCOUNT_NATIVE_INCLUDE_OS_ACCOUNT_SUBSCRIBE_INFO_H diff --git a/mock/innerkits/os_account/os_account_innerkits/include/os_account_subscriber.h b/mock/innerkits/os_account/os_account_innerkits/include/os_account_subscriber.h index 1f0472aec210faa298a4497490b33f7d214243e9..41e799b277666c312156308beb2e3745e14c8857 100644 --- a/mock/innerkits/os_account/os_account_innerkits/include/os_account_subscriber.h +++ b/mock/innerkits/os_account/os_account_innerkits/include/os_account_subscriber.h @@ -1,39 +1,50 @@ /* - * Copyright (c) 2021-2024 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. - */ +* Copyright (c) 2021-2024 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 OS_ACCOUNT_INTERFACES_INNERKITS_OSACCOUNT_NATIVE_INCLUDE_OS_ACCOUNT_SUBSCRIBER_H #define OS_ACCOUNT_INTERFACES_INNERKITS_OSACCOUNT_NATIVE_INCLUDE_OS_ACCOUNT_SUBSCRIBER_H #include "os_account_info.h" +#include "os_account_state_reply_callback.h" #include "os_account_subscribe_info.h" namespace OHOS { namespace AccountSA { +struct OsAccountStateData { + OsAccountState state = OsAccountState::INVALID_TYPE; + int32_t fromId = -1; + int32_t toId = -1; + sptr callback = nullptr; +}; + class OsAccountSubscriber { public: - OsAccountSubscriber(); - explicit OsAccountSubscriber(const OsAccountSubscribeInfo &subscribeInfo); - virtual ~OsAccountSubscriber(); + OsAccountSubscriber() {} + OsAccountSubscriber(const OsAccountSubscribeInfo &subscribeInfo) {} + virtual ~OsAccountSubscriber() {} + + virtual void OnStateChanged(const OsAccountStateData &data) {}; + + virtual void OnAccountsChanged(const int &id) {}; - virtual void OnAccountsChanged(const int &id) = 0; - virtual void OnAccountsSwitch(const int &newId, const int &oldId) {}; + virtual void OnAccountsSwitch(const int &newId, const int &oldId) {}; - void GetSubscribeInfo(OsAccountSubscribeInfo &subscribeInfo) const; + void GetSubscribeInfo(OsAccountSubscribeInfo &subscribeInfo) const {} -private: - OsAccountSubscribeInfo subscribeInfo_; + private: + OsAccountSubscribeInfo subscribeInfo_; }; } // namespace AccountSA } // namespace OHOS diff --git a/mock/innerkits/safwk/system_ability_fwk/include/system_ability.h b/mock/innerkits/safwk/system_ability_fwk/include/system_ability.h index 874b01390e7d0e4d6c5831414157df398d16393a..f93e3cbbdf335c73ac613b746d19250b3d459905 100644 --- a/mock/innerkits/safwk/system_ability_fwk/include/system_ability.h +++ b/mock/innerkits/safwk/system_ability_fwk/include/system_ability.h @@ -1,110 +1,236 @@ /* - * Copyright (c) 2021 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 SYSTEM_ABILITY_H_ -#define SYSTEM_ABILITY_H_ +* Copyright (c) 2021 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 SYSTEM_ABILITY_H +#define SYSTEM_ABILITY_H #include -#include +#include #include -#include + #include "iremote_object.h" +#include "refbase.h" +//#include "system_ability_ondemand_reason.h" +class CSystemAbilityInnerService; namespace OHOS { #define REGISTER_SYSTEM_ABILITY_BY_ID(abilityClassName, systemAbilityId, runOnCreate) \ - const bool abilityClassName##_##RegisterResult = \ - SystemAbility::MakeAndRegisterAbility(new abilityClassName(systemAbilityId, runOnCreate)); + const bool abilityClassName##_##RegisterResult = \ + SystemAbility::MakeAndRegisterAbility(new abilityClassName(systemAbilityId, runOnCreate)); -#define DECLEAR_SYSTEM_ABILITY(className) \ -public: \ -virtual std::string GetClassName() override { \ -return #className; \ -} +#define DECLEAR_SYSTEM_ABILITY(className) \ +public: \ + virtual std::string GetClassName() override \ + { \ + return #className; \ + } #define DECLEAR_BASE_SYSTEM_ABILITY(className) \ -public: \ -virtual std::string GetClassName() = 0; +public: \ + virtual std::string GetClassName() = 0 -#define DECLARE_SYSTEM_ABILITY(className) \ -public: \ -virtual std::string GetClassName() override { \ -return #className; \ -} +#define DECLARE_SYSTEM_ABILITY(className) \ +public: \ + virtual std::string GetClassName() override \ + { \ + return #className; \ + } #define DECLARE_BASE_SYSTEM_ABILITY(className) \ -public: \ -virtual std::string GetClassName() = 0; - - -#define DECLARE_SYSTEM_ABILITY(className) \ -public: \ -virtual std::string GetClassName() override { \ -return #className; \ -} - -#define DECLARE_BASE_SYSTEM_ABILITY(className) \ -public: \ -virtual std::string GetClassName() = 0; +public: \ + virtual std::string GetClassName() = 0 +enum class SystemAbilityState { + NOT_LOADED = 0, + ACTIVE, + IDLE, +}; +/** +* @class SystemAbility. +* SystemAbility provides a base class for each SA. +*/ class SystemAbility { DECLARE_BASE_SYSTEM_ABILITY(SystemAbility); public: - static bool MakeAndRegisterAbility(SystemAbility* systemAbility); + /** + * MakeAndRegisterAbility, Register SA into the localAbilityManager. + * + * @param systemAbility, SA required to register. + * @return Returns true on success. + */ + static bool MakeAndRegisterAbility(SystemAbility *systemAbility); + + /** + * AddSystemAbilityListener, Provide the function of SA monitoring and waiting for other SA. + * + * @param systemAbilityId, said that needs to be monitored. + * @return Returns true on success. + */ bool AddSystemAbilityListener(int32_t systemAbilityId); + + /** + * RemoveSystemAbilityListener, Remove the SA you are listening to. + * + * @param systemAbilityId, The listening said that needs to be removed. + * @return Returns true on success. + */ bool RemoveSystemAbilityListener(int32_t systemAbilityId); protected: + /** + * OnDump, Dump sa. + * + * @return Returns void. + */ virtual void OnDump(); + + /** + * OnStart, The user needs to override onstart, initialize and publish SA. + * + * @return Returns void. + */ virtual void OnStart(); + + /** + * OnStart, The user needs to override onstart, initialize and publish SA. + * + * @param startReason, The reason for start SA. + * @return Returns void. + */ +// virtual void OnStart(const SystemAbilityOnDemandReason &startReason); + + /** + * OnIdle, The user needs to override OnIdle, OnIdle is a callback function when uninstalling SA. + * + * @param idleReason, The reason for unload SA. + * @return Returns void. + */ +// virtual int32_t OnIdle(const SystemAbilityOnDemandReason &idleReason); + + /** + * OnActive, The user needs to override OnActive, OnActive is a callback function when CancelIdle. + * + * @param activeReason, The reason for active SA. + * @return Returns void. + */ +// virtual void OnActive(const SystemAbilityOnDemandReason &activeReason); + + /** + * OnStop, The user needs to override OnStop, Onstop is called when the SA is uninstalled. + * + * @return Returns void. + */ virtual void OnStop(); - virtual void OnAddSystemAbility(int32_t systemAbilityId, const std::string& deviceId); - virtual void OnRemoveSystemAbility(int32_t systemAbilityId, const std::string& deviceId); + /** + * OnStop, The user needs to override OnStop, Onstop is called when the SA is uninstalled. + * + * @param stopReason, The reason for stop SA. + * @return Returns void. + */ +// virtual void OnStop(const SystemAbilityOnDemandReason &stopReason); + + /** + * OnAddSystemAbility, OnAddSystemAbility will be called when the listening SA starts. + * + * @param systemAbilityId, The said being listened to. + * @param deviceId, deviceId is empty. + * @return void. + */ + virtual void OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId); + + /** + * OnRemoveSystemAbility, OnRemoveSystemAbility will be called when the listening SA Uninstall. + * + * @param systemAbilityId, The said being listened to. + * @param deviceId, deviceId is empty. + * @return void. + */ + virtual void OnRemoveSystemAbility(int32_t systemAbilityId, const std::string &deviceId); + + /** + * OnSvcCmd, OnSvcCmd will be called when svc cmd is send + * + * @param fd, used to dump execution information. + * @param args, command args. + * @return int32_t, error code. + */ + virtual int32_t OnSvcCmd(int32_t fd, const std::vector &args); + + /** + * GetSystemAbility, get systemability. + * + * @param systemAbilityId, The said number that needs to be obtained. + * @return nullptr indicates that sa does not exist. + */ sptr GetSystemAbility(int32_t systemAbilityId); + + /** + * Publish, Register functions for sa. + * + * @param systemAbility, SA that need to be registered. + * @return True indicates successful registration. + */ bool Publish(sptr systemAbility); - void StopAbility(int32_t systemAbilityId); + + /** + * CancelIdle, Cancel Uninstall, Calling the function from idle to active. + * + * @return True indicates Cancel succeeded. + */ + bool CancelIdle(); + + /** + * StopAbility, Remove sa from samgr. + * + * @param systemAbilityId, Said to be deleted. + * @return void. + */ + static void StopAbility(int32_t systemAbilityId); SystemAbility(bool runOnCreate = false); SystemAbility(int32_t systemAbilityId, bool runOnCreate = false); virtual ~SystemAbility(); -private: - void Start(); - void Stop(); - void SADump(); - int32_t GetSystemAbilitId() const; - void SetLibPath(const std::u16string& libPath); - const std::u16string& GetLibPath() const; - void SetDependSa(const std::vector& dependSa); - const std::vector& GetDependSa() const; - void SetRunOnCreate(bool isRunOnCreate); - bool IsRunOnCreate() const; - void SetDistributed(bool isDistributed); - bool GetDistributed() const; - void SetDumpLevel(unsigned int dumpLevel); - unsigned int GetDumpLevel() const; - void SetDependTimeout(int dependTimeout); - int GetDependTimeout() const; - bool GetRunningStatus() const; - void SetCapability(const std::u16string& capability); - const std::u16string& GetCapability() const; - void SetPermission(const std::u16string& defPerm); - - friend class LocalAbilityManager; - + /** + * GetAbilityState, Obtain status information of sa. + * + * @return status information of sa. + */ + SystemAbilityState GetAbilityState(); + + /** + * OnDeviceLevelChanged, OnDeviceLevelChanged will be called when listen strategy send. + * + * @param type, type is a certain device status type. + * @param level, level is level of a certain device status type. + * @param action, action is scheduling strategy. + * @return void. + */ + virtual void OnDeviceLevelChanged(int32_t type, int32_t level, std::string &action); + + /** + * OnExtension, OnExtension will be called when extension is send + * + * @param extension, the system ability extension name. + * @param data, extension data. + * @param reply, extension reply. + * @return int32_t, error code. + */ + virtual int32_t OnExtension(const std::string &extension, MessageParcel &data, MessageParcel &reply); private: int32_t saId_ = 0; std::u16string libPath_; @@ -118,6 +244,6 @@ private: sptr publishObj_; std::u16string permission_; }; -} +} // namespace OHOS #endif diff --git a/mock/innerkits/window_manager/libwm/include/window_manager.h b/mock/innerkits/window_manager/libwm/include/window_manager.h index 09aae692ee22de6c8f44fcf4f2f517be973d3890..540a6339aebd68a243bba4978a9831128c65d430 100644 --- a/mock/innerkits/window_manager/libwm/include/window_manager.h +++ b/mock/innerkits/window_manager/libwm/include/window_manager.h @@ -20,7 +20,7 @@ #include #include #include -#include "wm_single_instance.h" +//#include "wm_single_instance.h" #include "wm_common.h" namespace OHOS { @@ -43,8 +43,14 @@ public: windowType_(type), abilityToken_(abilityToken) {}; ~FocusChangeInfo() = default; - virtual bool Marshalling(Parcel& parcel) const override; - static FocusChangeInfo* Unmarshalling(Parcel& parcel); + virtual bool Marshalling(Parcel& parcel) const override + { + return false; + } + static FocusChangeInfo* Unmarshalling(Parcel& parcel) + { + return nullptr; + } uint32_t windowId_ = INVALID_WINDOW_ID; DisplayId displayId_ = 0; @@ -131,9 +137,11 @@ public: }; class WindowManager { -WM_DECLARE_SINGLE_INSTANCE_BASE(WindowManager); +//WM_DECLARE_SINGLE_INSTANCE_BASE(WindowManager); friend class WindowManagerAgent; public: + static WindowManager &GetInstance(); + void GetFocusWindowInfo(FocusChangeInfo& focusInfo, DisplayId displayId = 0); void RegisterFocusChangedListener(const sptr& listener); void UnregisterFocusChangedListener(const sptr& listener); void RegisterSystemBarChangedListener(const sptr& listener); @@ -152,17 +160,17 @@ public: private: WindowManager(); ~WindowManager() = default; - class Impl; - std::unique_ptr pImpl_; - - void UpdateFocusStatus(uint32_t windowId, const sptr& abilityToken, WindowType windowType, - DisplayId displayId, bool focused) const; - void UpdateFocusChangeInfo(const sptr& focusChangeInfo, bool focused) const; - void UpdateSystemBarRegionTints(DisplayId displayId, const SystemBarRegionTints& tints) const; - void NotifyAccessibilityWindowInfo(const sptr& windowInfo, WindowUpdateType type) const; - void UpdateWindowVisibilityInfo( - const std::vector>& windowVisibilityInfos) const; - void UpdateCameraFloatWindowStatus(uint32_t accessTokenId, bool isShowing) const; +// class Impl; +// std::unique_ptr pImpl_; +// +// void UpdateFocusStatus(uint32_t windowId, const sptr& abilityToken, WindowType windowType, +// DisplayId displayId, bool focused) const; +// void UpdateFocusChangeInfo(const sptr& focusChangeInfo, bool focused) const; +// void UpdateSystemBarRegionTints(DisplayId displayId, const SystemBarRegionTints& tints) const; +// void NotifyAccessibilityWindowInfo(const sptr& windowInfo, WindowUpdateType type) const; +// void UpdateWindowVisibilityInfo( +// const std::vector>& windowVisibilityInfos) const; +// void UpdateCameraFloatWindowStatus(uint32_t accessTokenId, bool isShowing) const; }; } // namespace Rosen } // namespace OHOS diff --git a/mock/sqlite/include/sqlite3.h b/mock/sqlite/include/sqlite3.h index 4e484c3db7596497c4900701a48510bad13be1c9..92bf71564f9a3730609c5438023f8b542c182a15 100644 --- a/mock/sqlite/include/sqlite3.h +++ b/mock/sqlite/include/sqlite3.h @@ -441,38 +441,38 @@ SQLITE_API int sqlite3_exec( ** ** See also: [extended result code definitions] */ -#define SQLITE_OK 0 /* ³É¹¦ | Successful result */ -/* ´íÎóÂ뿪ʼ */ -#define SQLITE_ERROR 1 /* SQL´íÎó »ò ¶ªÊ§Êý¾Ý¿â | SQL error or missing database */ -#define SQLITE_INTERNAL 2 /* SQLite ÄÚ²¿Âß¼­´íÎó | Internal logic error in SQLite */ -#define SQLITE_PERM 3 /* ¾Ü¾ø·ÃÎÊ | Access permission denied */ -#define SQLITE_ABORT 4 /* »Øµ÷º¯ÊýÇëÇóÈ¡Ïû²Ù×÷ | Callback routine requested an abort */ -#define SQLITE_BUSY 5 /* Êý¾Ý¿âÎļþ±»Ëø¶¨ | The database file is locked */ -#define SQLITE_LOCKED 6 /* Êý¾Ý¿âÖеÄÒ»¸ö±í±»Ëø¶¨ | A table in the database is locked */ -#define SQLITE_NOMEM 7 /* ij´Î malloc() º¯Êýµ÷ÓÃʧ°Ü | A malloc() failed */ -#define SQLITE_READONLY 8 /* ³¢ÊÔдÈëÒ»¸öÖ»¶ÁÊý¾Ý¿â | Attempt to write a readonly database */ -#define SQLITE_INTERRUPT 9 /* ²Ù×÷±» sqlite3_interupt() º¯ÊýÖÐ¶Ï | Operation terminated by sqlite3_interrupt() */ -#define SQLITE_IOERR 10 /* ·¢ÉúijЩ´ÅÅÌ I/O ´íÎó | Some kind of disk I/O error occurred */ -#define SQLITE_CORRUPT 11 /* Êý¾Ý¿â´ÅÅÌÓ³Ïñ²»ÕýÈ· | The database disk image is malformed */ -#define SQLITE_NOTFOUND 12 /* sqlite3_file_control() ÖгöÏÖδ֪²Ù×÷Êý | Unknown opcode in sqlite3_file_control() */ -#define SQLITE_FULL 13 /* ÒòΪÊý¾Ý¿âÂúµ¼Ö²åÈëʧ°Ü | Insertion failed because database is full */ -#define SQLITE_CANTOPEN 14 /* ÎÞ·¨´ò¿ªÊý¾Ý¿âÎļþ | Unable to open the database file */ -#define SQLITE_PROTOCOL 15 /* Êý¾Ý¿âËø¶¨Ð­Òé´íÎó | Database lock protocol error */ -#define SQLITE_EMPTY 16 /* Êý¾Ý¿âΪ¿Õ | Database is empty */ -#define SQLITE_SCHEMA 17 /* Êý¾Ý½á¹¹·¢Éú¸Ä±ä | The database schema changed */ -#define SQLITE_TOOBIG 18 /* ×Ö·û´®»ò¶þ½øÖÆÊý¾Ý³¬¹ý´óСÏÞÖÆ | String or BLOB exceeds size limit */ -#define SQLITE_CONSTRAINT 19 /* ÓÉÓÚÔ¼ÊøÎ¥Àý¶øÈ¡Ïû | Abort due to constraint violation */ -#define SQLITE_MISMATCH 20 /* Êý¾ÝÀàÐͲ»Æ¥Åä | Data type mismatch */ -#define SQLITE_MISUSE 21 /* ²»ÕýÈ·µÄ¿âʹÓà | Library used incorrectly */ -#define SQLITE_NOLFS 22 /* ʹÓÃÁ˲Ù×÷ϵͳ²»Ö§³ÖµÄ¹¦ÄÜ | Uses OS features not supported on host */ -#define SQLITE_AUTH 23 /* ÊÚȨʧ°Ü | Authorization denied */ -#define SQLITE_FORMAT 24 /* ¸½¼ÓÊý¾Ý¿â¸ñʽ´íÎó | Auxiliary database format error */ -#define SQLITE_RANGE 25 /* ´«µÝ¸øsqlite3_bind()µÄµÚ¶þ¸ö²ÎÊý³¬³ö·¶Î§ | 2nd parameter to sqlite3_bind out of range */ -#define SQLITE_NOTADB 26 /* ±»´ò¿ªµÄÎļþ²»ÊÇÒ»¸öÊý¾Ý¿âÎļþ | File opened that is not a database file */ +#define SQLITE_OK 0 /* �ɹ� | Successful result */ +/* �����뿪ʼ */ +#define SQLITE_ERROR 1 /* SQL���� �� ��ʧ���ݿ� | SQL error or missing database */ +#define SQLITE_INTERNAL 2 /* SQLite �ڲ��߼����� | Internal logic error in SQLite */ +#define SQLITE_PERM 3 /* �ܾ����� | Access permission denied */ +#define SQLITE_ABORT 4 /* �ص���������ȡ������ | Callback routine requested an abort */ +#define SQLITE_BUSY 5 /* ���ݿ��ļ������� | The database file is locked */ +#define SQLITE_LOCKED 6 /* ���ݿ��е�һ�������� | A table in the database is locked */ +#define SQLITE_NOMEM 7 /* ij�� malloc() ��������ʧ�� | A malloc() failed */ +#define SQLITE_READONLY 8 /* ����д��һ��ֻ�����ݿ� | Attempt to write a readonly database */ +#define SQLITE_INTERRUPT 9 /* ������ sqlite3_interupt() �����ж� | Operation terminated by sqlite3_interrupt() */ +#define SQLITE_IOERR 10 /* ����ijЩ���� I/O ���� | Some kind of disk I/O error occurred */ +#define SQLITE_CORRUPT 11 /* ���ݿ����ӳ����ȷ | The database disk image is malformed */ +#define SQLITE_NOTFOUND 12 /* sqlite3_file_control() �г���δ֪������ | Unknown opcode in sqlite3_file_control() */ +#define SQLITE_FULL 13 /* ��Ϊ���ݿ������²���ʧ�� | Insertion failed because database is full */ +#define SQLITE_CANTOPEN 14 /* �޷������ݿ��ļ� | Unable to open the database file */ +#define SQLITE_PROTOCOL 15 /* ���ݿ�����Э����� | Database lock protocol error */ +#define SQLITE_EMPTY 16 /* ���ݿ�Ϊ�� | Database is empty */ +#define SQLITE_SCHEMA 17 /* ���ݽṹ�����ı� | The database schema changed */ +#define SQLITE_TOOBIG 18 /* �ַ�������������ݳ�����С���� | String or BLOB exceeds size limit */ +#define SQLITE_CONSTRAINT 19 /* ����Լ��Υ����ȡ�� | Abort due to constraint violation */ +#define SQLITE_MISMATCH 20 /* �������Ͳ�ƥ�� | Data type mismatch */ +#define SQLITE_MISUSE 21 /* ����ȷ�Ŀ�ʹ�� | Library used incorrectly */ +#define SQLITE_NOLFS 22 /* ʹ���˲���ϵͳ��֧�ֵĹ��� | Uses OS features not supported on host */ +#define SQLITE_AUTH 23 /* ��Ȩʧ�� | Authorization denied */ +#define SQLITE_FORMAT 24 /* �������ݿ��ʽ���� | Auxiliary database format error */ +#define SQLITE_RANGE 25 /* ���ݸ�sqlite3_bind()�ĵڶ�������������Χ | 2nd parameter to sqlite3_bind out of range */ +#define SQLITE_NOTADB 26 /* ���ò¿ªµï¿½ï¿½Ä¼ï¿½ï¿½ï¿½ï¿½ï¿½Ò»ï¿½ï¿½ï¿½ï¿½ï¿½Ý¿ï¿½ï¿½Ä¼ï¿½ | File opened that is not a database file */ #define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ #define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ -#define SQLITE_ROW 100 /* sqlite3_step() ÒѾ­²úÉúÒ»¸öÐнá¹û | sqlite3_step() has another row ready */ -#define SQLITE_DONE 101 /* sqlite3_step() Íê³ÉÖ´ÐвÙ×÷ | sqlite3_step() has finished executing */ +#define SQLITE_ROW 100 /* sqlite3_step() �Ѿ�����һ���н�� | sqlite3_step() has another row ready */ +#define SQLITE_DONE 101 /* sqlite3_step() ���ִ�в��� | sqlite3_step() has finished executing */ /* end-of-error-codes */ /* @@ -2114,6 +2114,8 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ +#define SQLITE_CONFIG_CORRUPTION 30 /* xCorruption */ +#define SQLITE_CONFIG_ENABLE_ICU 31 /* boolean */ /* ** CAPI3REF: Database Connection Configuration Options diff --git a/mock/src/mock_account.cpp b/mock/src/mock_account.cpp index 34b258bb61098e28c1e7ec4a7707ea44c11eac79..8a1196ec9afebee378d9a8e6bb443a4d76cd77d6 100644 --- a/mock/src/mock_account.cpp +++ b/mock/src/mock_account.cpp @@ -13,9 +13,35 @@ * limitations under the License. */ #include "ohos_account_kits.h" +#include "os_account_subscribe_info.h" #include "os_account_manager.h" #include "account_info.h" namespace OHOS::AccountSA { +OsAccountSubscribeInfo::OsAccountSubscribeInfo() +{} +OsAccountSubscribeInfo::OsAccountSubscribeInfo(const std::set &states, bool withHandshake) {} +OsAccountSubscribeInfo::OsAccountSubscribeInfo(const OS_ACCOUNT_SUBSCRIBE_TYPE &osAccountSubscribeType, + const std::string &name) +{ +} +OsAccountSubscribeInfo::~OsAccountSubscribeInfo() {} +void OsAccountSubscribeInfo::GetOsAccountSubscribeType(OS_ACCOUNT_SUBSCRIBE_TYPE &osAccountSubscribeType) const {} +void OsAccountSubscribeInfo::SetOsAccountSubscribeType(const OS_ACCOUNT_SUBSCRIBE_TYPE &osAccountSubscribeType) {} +void OsAccountSubscribeInfo::GetName(std::string &name) const {} +void OsAccountSubscribeInfo::SetName(const std::string &name) {} +void OsAccountSubscribeInfo::GetStates(std::set &states) const {} +bool OsAccountSubscribeInfo::IsWithHandshake() const +{ + return false; +} +bool OsAccountSubscribeInfo::Marshalling(Parcel &parcel) const +{ + return false; +} +OsAccountSubscribeInfo *OsAccountSubscribeInfo::Unmarshalling(Parcel &parcel) +{ + return nullptr; +} class OhosAccountKitsImpl : public OHOS::AccountSA::OhosAccountKits { public: std::pair QueryOhosAccountInfo() override; @@ -70,6 +96,18 @@ ErrCode OsAccountManager::GetForegroundOsAccountLocalId(int32_t &localId) { return 0; } +ErrCode OsAccountManager::IsOsAccountDeactivating(const int id, bool &isVerified) +{ + return 0; +} +ErrCode OsAccountManager::SubscribeOsAccount(const std::shared_ptr &subscriber) +{ + return 0; +} +ErrCode OsAccountManager::UnsubscribeOsAccount(const std::shared_ptr &subscriber) +{ + return 0; +} std::pair OhosAccountKitsImpl::QueryOhosAccountInfo() { return std::pair(); diff --git a/mock/src/mock_bundle_manager.cpp b/mock/src/mock_bundle_manager.cpp index 8d47991f0b95fbb42498c7ee857b61acb2587c6a..85c19fec86c8585964d0697488b8f4918f215ba3 100644 --- a/mock/src/mock_bundle_manager.cpp +++ b/mock/src/mock_bundle_manager.cpp @@ -778,5 +778,33 @@ ModuleInfo *ModuleInfo::Unmarshalling(Parcel &parcel) { return nullptr; } +bool SignatureInfo::ReadFromParcel(Parcel &parcel) +{ + return false; +} +bool SignatureInfo::Marshalling(Parcel &parcel) const +{ + return false; +} +SignatureInfo *SignatureInfo::Unmarshalling(Parcel &parcel) +{ + return nullptr; +} +bool SimpleAppInfo::ReadFromParcel(Parcel &parcel) +{ + return false; +} +bool SimpleAppInfo::Marshalling(Parcel &parcel) const +{ + return false; +} +SimpleAppInfo *SimpleAppInfo::Unmarshalling(Parcel &parcel) +{ + return nullptr; +} +std::string SimpleAppInfo::ToString() const +{ + return std::string(); +} } // namespace AppExecFwk } // namespace OHOS \ No newline at end of file diff --git a/mock/src/mock_dfs_service.cpp b/mock/src/mock_dfs_service.cpp index fdffc98402bde7991177888f145e6ffcaa1f834b..064b0e248420dd7003c5c635788c5ab3e6315e90 100644 --- a/mock/src/mock_dfs_service.cpp +++ b/mock/src/mock_dfs_service.cpp @@ -1,34 +1,85 @@ #include "cloud_sync_asset_manager.h" #include "cloud_sync_asset_manager_impl.h" +#include "copy/file_copy_manager.h" +#include "copy/file_size_utils.h" -namespace OHOS::FileManagement::CloudSync { +namespace OHOS { +namespace FileManagement::CloudSync { -CloudSyncAssetManager& CloudSyncAssetManager::GetInstance() +CloudSyncAssetManager &CloudSyncAssetManager::GetInstance() { return CloudSyncAssetManagerImpl::GetInstance(); } -CloudSyncAssetManagerImpl& CloudSync::CloudSyncAssetManagerImpl::GetInstance() +CloudSyncAssetManagerImpl &CloudSync::CloudSyncAssetManagerImpl::GetInstance() { static CloudSyncAssetManagerImpl cloudSyncAssetManager; return cloudSyncAssetManager; } -int32_t CloudSyncAssetManagerImpl::UploadAsset(const int32_t userId, const std::string& request, std::string& result) +int32_t CloudSyncAssetManagerImpl::UploadAsset(const int32_t userId, const std::string &request, std::string &result) { return 0; } -int32_t CloudSyncAssetManagerImpl::DownloadFile(const int32_t userId, const std::string& bundleName, AssetInfo& assetInfo) +int32_t CloudSyncAssetManagerImpl::DownloadFile(const int32_t userId, const std::string &bundleName, + AssetInfo &assetInfo) { return 0; } -int32_t CloudSyncAssetManagerImpl::DeleteAsset(const int32_t userId, const std::string& uri) +int32_t CloudSyncAssetManagerImpl::DeleteAsset(const int32_t userId, const std::string &uri) { return 0; } -int32_t CloudSyncAssetManagerImpl::DownloadFile(const int32_t userId, const std::string& bundleName, const std::string& networkId, - AssetInfo& assetInfo, CloudSyncAssetManager::ResultCallback resultCallback) +int32_t CloudSyncAssetManagerImpl::DownloadFile(const int32_t userId, const std::string &bundleName, + const std::string &networkId, AssetInfo &assetInfo, CloudSyncAssetManager::ResultCallback resultCallback) { return 0; } -} // namespace OHOS::FileManagement::CloudSync \ No newline at end of file +} // namespace FileManagement::CloudSync +namespace Storage::DistributedFile { +std::shared_ptr FileCopyManager::GetInstance() +{ + static std::shared_ptr Manger = std::make_shared(); + return Manger; +} +int32_t FileCopyManager::Copy(const std::string &srcUri, const std::string &destUri, ProcessCallback &processCallback) +{ + return 0; +} +int32_t FileCopyManager::Cancel(const std::string &srcUri, const std::string &destUri) +{ + return 0; +} +int32_t FileCopyManager::Cancel() +{ + return 0; +} +void FileSizeUtils::Deleter(struct NameList *arg) +{} +int32_t FileSizeUtils::GetSize(const std::string &uri, bool isSrcUri, uint64_t &size) +{ + return 0; +} +int32_t FileSizeUtils::IsDirectory(const std::string &uri, bool isSrcUri, bool &isDirectory) +{ + return 0; +} +std::string FileSizeUtils::GetPathFromUri(const std::string &uri, bool isSrcUri) +{ + return std::string(); +} +int32_t FileSizeUtils::GetFileSize(const std::string &path, uint64_t &size) +{ + return 0; +} +int32_t FileSizeUtils::GetDirSize(const std::string &path, uint64_t &size) +{ + return 0; +} +std::unique_ptr FileSizeUtils::GetDirNameList(const std::string &path) +{ + NameList *list = new NameList; + return std::unique_ptr(list, Deleter); +} +} +} // namespace OHOS \ No newline at end of file diff --git a/mock/src/mock_ipc.cpp b/mock/src/mock_ipc.cpp index bb3aacdc0a5f63ce35163fe43f44c621dcbfc1bd..f0fbf1653056cd3bc8d00b23ebe4f09d81a1131f 100644 --- a/mock/src/mock_ipc.cpp +++ b/mock/src/mock_ipc.cpp @@ -146,6 +146,49 @@ bool IPCSkeleton::SetCallingIdentity(std::string &identity) { return true; } +bool IPCSkeleton::SetMaxWorkThreadNum(int maxThreadNum) +{ + return false; +} +void IPCSkeleton::JoinWorkThread() {} +void IPCSkeleton::StopWorkThread() {} +uint32_t IPCSkeleton::GetFirstTokenID() +{ + return 0; +} +uint64_t IPCSkeleton::GetFirstFullTokenID() +{ + return 0; +} +std::string IPCSkeleton::GetLocalDeviceID() +{ + return std::string(); +} +std::string IPCSkeleton::GetCallingDeviceID() +{ + return std::string(); +} +bool IPCSkeleton::IsLocalCalling() +{ + return false; +} +IPCSkeleton &IPCSkeleton::GetInstance() +{ + static IPCSkeleton instance; + return instance; +} +sptr IPCSkeleton::GetContextObject() +{ + return sptr(); +} +bool IPCSkeleton::SetContextObject(sptr &object) +{ + return false; +} +int IPCSkeleton::FlushCommands(IRemoteObject *object) +{ + return 0; +} MessageOption::MessageOption(int flags, int waitTime) {} void MessageOption::SetFlags(int flags) {} int MessageOption::GetFlags() const { return 0; } diff --git a/mock/src/mock_js_napi.cpp b/mock/src/mock_js_napi.cpp index 6fb33ee3a94010455799104721830ca6afbfdabb..22a13f9a49a9abab71c97af1daa467cbb878f8dc 100644 --- a/mock/src/mock_js_napi.cpp +++ b/mock/src/mock_js_napi.cpp @@ -18,7 +18,31 @@ #include "napi/native_api.h" #include "napi/native_common.h" #include "napi/native_node_api.h" +#include "node_api.h" extern "C" { +napi_status napi_create_threadsafe_function(napi_env env, napi_value func, napi_value async_resource, + napi_value async_resource_name, size_t max_queue_size, size_t initial_thread_count, void *thread_finalize_data, + napi_finalize thread_finalize_cb, void *context, napi_threadsafe_function_call_js call_js_cb, + napi_threadsafe_function *result) +{ + return napi_ok; +} +napi_status napi_call_threadsafe_function(napi_threadsafe_function func, void *data, + napi_threadsafe_function_call_mode is_blocking) +{ + return napi_ok; +} + +napi_status napi_acquire_threadsafe_function(napi_threadsafe_function func) +{ + return napi_ok; +} + +napi_status napi_release_threadsafe_function(napi_threadsafe_function func, napi_threadsafe_function_release_mode mode) +{ + return napi_ok; +} + napi_status napi_create_object_with_properties(napi_env env, napi_value *result, size_t property_count, const napi_property_descriptor *properties) { @@ -239,259 +263,259 @@ void napi_module_register(napi_module *mod) {} napi_status napi_async_init(napi_env env, napi_value async_resource, napi_value async_resource_name, napi_async_context *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_async_destroy(napi_env env, napi_async_context async_context) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_make_callback(napi_env env, napi_async_context async_context, napi_value recv, napi_value func, size_t argc, const napi_value *argv, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_buffer(napi_env env, size_t length, void **data, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_external_buffer(napi_env env, size_t length, void *data, napi_finalize finalize_cb, void *finalize_hint, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_buffer_copy(napi_env env, size_t length, const void *data, void **result_data, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_buffer(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_get_buffer_info(napi_env env, napi_value value, void **data, size_t *length) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_cancel_async_work(napi_env env, napi_async_work work) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_get_node_version(napi_env env, const napi_node_version **version) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_get_uv_event_loop(napi_env env, struct uv_loop_s **loop) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_get_null(napi_env env, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_array(napi_env env, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_uint32(napi_env env, uint32_t value, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_string_latin1(napi_env env, const char *str, size_t length, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_string_utf16(napi_env env, const char16_t *str, size_t length, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_symbol(napi_env env, napi_value description, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_function(napi_env env, const char *utf8name, size_t length, napi_callback cb, void *data, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_type_error(napi_env env, napi_value code, napi_value msg, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_range_error(napi_env env, napi_value code, napi_value msg, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_get_value_uint32(napi_env env, napi_value value, uint32_t *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_get_value_int64(napi_env env, napi_value value, int64_t *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_get_value_string_latin1(napi_env env, napi_value value, char *buf, size_t bufsize, size_t *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_get_value_string_utf16(napi_env env, napi_value value, char16_t *buf, size_t bufsize, size_t *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_coerce_to_bool(napi_env env, napi_value value, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_coerce_to_number(napi_env env, napi_value value, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_coerce_to_object(napi_env env, napi_value value, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_coerce_to_string(napi_env env, napi_value value, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_get_prototype(napi_env env, napi_value object, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_set_property(napi_env env, napi_value object, napi_value key, napi_value value) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_has_property(napi_env env, napi_value object, napi_value key, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_delete_property(napi_env env, napi_value object, napi_value key, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_has_own_property(napi_env env, napi_value object, napi_value key, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_has_named_property(napi_env env, napi_value object, const char *utf8name, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_has_element(napi_env env, napi_value object, uint32_t index, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_delete_element(napi_env env, napi_value object, uint32_t index, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_array(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_strict_equals(napi_env env, napi_value lhs, napi_value rhs, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_instanceof(napi_env env, napi_value object, napi_value constructor, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_remove_wrap(napi_env env, napi_value js_object, void **result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_external(napi_env env, void *data, napi_finalize finalize_cb, void *finalize_hint, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_get_value_external(napi_env env, napi_value value, void **result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_open_handle_scope(napi_env env, napi_handle_scope *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_close_handle_scope(napi_env env, napi_handle_scope scope) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_open_escapable_handle_scope(napi_env env, napi_escapable_handle_scope *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_close_escapable_handle_scope(napi_env env, napi_escapable_handle_scope scope) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_escape_handle(napi_env env, napi_escapable_handle_scope scope, napi_value escapee, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_throw(napi_env env, napi_value error) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_throw_type_error(napi_env env, const char *code, const char *msg) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_throw_range_error(napi_env env, const char *code, const char *msg) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_error(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_get_and_clear_last_exception(napi_env env, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_external_arraybuffer(napi_env env, void *external_data, size_t byte_length, napi_finalize finalize_cb, void *finalize_hint, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_get_arraybuffer_info(napi_env env, napi_value arraybuffer, void **data, size_t *byte_length) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_dataview(napi_env env, size_t length, napi_value arraybuffer, size_t byte_offset, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_dataview(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_get_dataview_info(napi_env env, napi_value dataview, size_t *bytelength, void **data, napi_value *arraybuffer, size_t *byte_offset) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_get_version(napi_env env, uint32_t *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_promise(napi_env env, napi_value value, bool *is_promise) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_run_script(napi_env env, napi_value script, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_adjust_external_memory(napi_env env, int64_t change_in_bytes, int64_t *adjusted_value) { - return napi_escape_called_twice; + return napi_ok; } UV_EXTERN int uv_queue_work(uv_loop_t *loop, uv_work_t *req, uv_work_cb work_cb, uv_after_work_cb after_work_cb) @@ -504,7 +528,7 @@ UV_EXTERN int uv_queue_work_with_qos(uv_loop_t *loop, uv_work_t *req, uv_work_cb return 0; } -NAPI_EXTERN napi_status napi_object_freeze(napi_env env, napi_value object) +napi_status napi_object_freeze(napi_env env, napi_value object) { return napi_ok; } @@ -512,7 +536,7 @@ int uv_cancel(uv_req_t *req) { return napi_ok; } -NAPI_EXTERN napi_status napi_get_all_property_names(napi_env env, napi_value object, napi_key_collection_mode key_mode, +napi_status napi_get_all_property_names(napi_env env, napi_value object, napi_key_collection_mode key_mode, napi_key_filter key_filter, napi_key_conversion key_conversion, napi_value *result) { return napi_ok; @@ -524,13 +548,13 @@ napi_status napi_add_finalizer(napi_env env, napi_value js_object, void *native_ return napi_ok; } -NAPI_EXTERN napi_status napi_create_bigint_words(napi_env env, int sign_bit, size_t word_count, const uint64_t *words, +napi_status napi_create_bigint_words(napi_env env, int sign_bit, size_t word_count, const uint64_t *words, napi_value *result) { return napi_ok; } -NAPI_EXTERN napi_status napi_get_value_bigint_words(napi_env env, napi_value value, int *sign_bit, size_t *word_count, +napi_status napi_get_value_bigint_words(napi_env env, napi_value value, int *sign_bit, size_t *word_count, uint64_t *words) { return napi_ok; @@ -546,327 +570,418 @@ napi_status napi_is_map(napi_env env, napi_value value, bool *result) } napi_status napi_is_callable(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_runtime(napi_env env, napi_env *result_env) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_serialize(napi_env env, napi_value object, napi_value transfer_list, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_deserialize(napi_env env, napi_value recorder, napi_value *object) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_delete_serialization_data(napi_env env, napi_value value) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_get_exception_info_for_worker(napi_env env, napi_value obj) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_run_buffer_script(napi_env env, std::vector &buffer, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_run_actor(napi_env env, std::vector &buffer, const char *descriptor, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_set_promise_rejection_callback(napi_env env, napi_ref ref, napi_ref checkRef) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_arguments_object(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_async_function(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_boolean_object(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_generator_function(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_date(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_map_iterator(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_set_iterator(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_generator_object(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_module_namespace_object(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_proxy(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_reg_exp(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_number_object(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_set(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_string_object(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_symbol_object(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_weak_map(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_weak_set(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; +} +napi_status napi_send_event(napi_env env, const std::function &cb, napi_event_priority priority) +{ + return napi_ok; +} +napi_status napi_create_limit_runtime(napi_env env, napi_env *result_env) +{ + return napi_ok; +} +void napi_module_with_js_register(napi_module_with_js *mod) {} +napi_status napi_serialize_inner(napi_env env, napi_value object, napi_value transfer_list, napi_value clone_list, + bool defaultTransfer, bool defaultCloneSendable, void **result) +{ + return napi_ok; +} +napi_status napi_run_actor(napi_env env, uint8_t *buffer, size_t bufferSize, const char *descriptor, + napi_value *result, char *entryPoint) +{ + return napi_ok; +} +napi_status napi_wrap_with_size(napi_env env, napi_value js_object, void *native_object, napi_finalize finalize_cb, + void *finalize_hint, napi_ref *result, size_t native_binding_size) +{ + return napi_ok; +} +napi_status napi_wrap_async_finalizer(napi_env env, napi_value js_object, void *native_object, + napi_finalize finalize_cb, void *finalize_hint, napi_ref *result, size_t native_binding_size) +{ + return napi_ok; +} +napi_status napi_create_external_with_size(napi_env env, void *data, napi_finalize finalize_cb, void *finalize_hint, + napi_value *result, size_t native_binding_size) +{ + return napi_ok; +} +napi_status napi_is_big_int64_array(napi_env env, napi_value value, bool *result) +{ + return napi_ok; +} +napi_status napi_is_big_uint64_array(napi_env env, napi_value value, bool *result) +{ + return napi_ok; } -napi_status napi_create_sendable_typedarray(napi_env env, - napi_typedarray_type type, - size_t length, - napi_value arraybuffer, - size_t byte_offset, - napi_value* result) +napi_status napi_is_shared_array_buffer(napi_env env, napi_value value, bool *result) +{ + return napi_ok; +} +napi_status napi_get_stack_trace(napi_env env, std::string &stack) +{ + return napi_ok; +} +napi_status napi_get_hybrid_stack_trace(napi_env env, std::string &stack) +{ + return napi_ok; +} +napi_status napi_get_own_property_descriptor(napi_env env, napi_value object, const char *utf8name, napi_value *result) +{ + return napi_ok; +} +napi_status napi_object_get_keys(napi_env env, napi_value data, napi_value *result) +{ + return napi_ok; +} +napi_status napi_get_print_string(napi_env env, napi_value value, std::string &result) +{ + return napi_ok; +} +napi_status napi_send_cancelable_event(napi_env env, const std::function &cb, void *data, + napi_event_priority priority, uint64_t *handleId, const char *name) +{ + return napi_ok; +} +napi_status napi_cancel_event(napi_env env, uint64_t handleId, const char *name) +{ + return napi_ok; +} +napi_status napi_open_fast_native_scope(napi_env env, napi_fast_native_scope *scope) +{ + return napi_ok; +} +napi_status napi_close_fast_native_scope(napi_env env, napi_fast_native_scope scope) +{ + return napi_ok; +} +napi_status napi_get_shared_array_buffer_info(napi_env env, napi_value arraybuffer, void **data, size_t *byte_length) +{ + return napi_ok; +} +napi_status napi_encode(napi_env env, napi_value src, napi_value *result) +{ + return napi_ok; +} +napi_status napi_is_bitvector(napi_env env, napi_value value, bool *result) +{ + return napi_ok; +} +napi_status napi_create_sendable_typedarray(napi_env env, napi_typedarray_type type, size_t length, + napi_value arraybuffer, size_t byte_offset, napi_value *result) { return napi_ok; } -napi_status napi_map_get_size(napi_env env, napi_value map, uint32_t* result) +napi_status napi_map_get_size(napi_env env, napi_value map, uint32_t *result) { return napi_ok; } napi_status napi_create_sendable_array_with_length(napi_env env, size_t length, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_fatal_exception(napi_env env, napi_value err) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_type_tag_object(napi_env env, napi_value value, const napi_type_tag *type_tag) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_check_object_type_tag(napi_env env, napi_value value, const napi_type_tag *type_tag, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_run_script_path(napi_env env, const char *path, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_load_module(napi_env env, const char *path, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_load_module_with_info(napi_env env, const char *path, const char *module_info, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_get_instance_data(napi_env env, void **data) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_set_instance_data(napi_env env, void *data, napi_finalize finalize_cb, void *finalize_hint) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_remove_env_cleanup_hook(napi_env env, void (*fun)(void *), void *arg) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_add_env_cleanup_hook(napi_env env, void (*fun)(void *), void *arg) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_remove_async_cleanup_hook(napi_async_cleanup_hook_handle remove_handle) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_add_async_cleanup_hook(napi_env env, napi_async_cleanup_hook hook, void *arg, napi_async_cleanup_hook_handle *remove_handle) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_close_callback_scope(napi_env env, napi_callback_scope scope) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_open_callback_scope(napi_env env, napi_value resource_object, napi_async_context context, napi_callback_scope *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status node_api_get_module_file_name(napi_env env, const char **result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_object_with_named_properties(napi_env env, napi_value *result, size_t property_count, const char **keys, const napi_value *values) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_coerce_to_native_binding_object(napi_env env, napi_value js_object, napi_native_binding_detach_callback detach_cb, napi_native_binding_attach_callback attach_cb, void *native_object, void *hint) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_run_event_loop(napi_env env, napi_event_mode mode) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_stop_event_loop(napi_env env) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_ark_runtime(napi_env *env) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_destroy_ark_runtime(napi_env *env) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_serialize(napi_env env, napi_value object, napi_value transfer_list, napi_value clone_list, void **result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_deserialize(napi_env env, void *buffer, napi_value *object) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_delete_serialization_data(napi_env env, void *buffer) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_is_concurrent_function(napi_env env, napi_value value, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_call_threadsafe_function_with_priority(napi_threadsafe_function func, void *data, napi_task_priority priority, bool isTail) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_map(napi_env env, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_map_set_property(napi_env env, napi_value map, napi_value key, napi_value value) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_map_set_named_property(napi_env env, napi_value map, const char *utf8name, napi_value value) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_map_get_property(napi_env env, napi_value map, napi_value key, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_map_get_named_property(napi_env env, napi_value map, const char *utf8name, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_map_has_property(napi_env env, napi_value map, napi_value key, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_map_has_named_property(napi_env env, napi_value map, const char *utf8name, bool *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_map_delete_property(napi_env env, napi_value map, napi_value key) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_map_clear(napi_env env, napi_value map) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_map_get_entries(napi_env env, napi_value map, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_map_get_keys(napi_env env, napi_value map, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_map_get_values(napi_env env, napi_value map, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_map_iterator_get_next(napi_env env, napi_value iterator, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_define_sendable_class(napi_env env, const char *utf8name, size_t length, napi_callback constructor, void *data, size_t property_count, const napi_property_descriptor *properties, napi_value parent, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_sendable_object_with_properties(napi_env env, size_t property_count, const napi_property_descriptor *properties, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_sendable_array(napi_env env, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_sendable_arraybuffer(napi_env env, size_t byte_length, void **data, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_create_sendable_map(napi_env env, napi_value *result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_wrap_sendable(napi_env env, napi_value js_object, void *native_object, napi_finalize finalize_cb, void *finalize_hint) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_wrap_sendable_with_size(napi_env env, napi_value js_object, void *native_object, napi_finalize finalize_cb, void *finalize_hint, size_t native_binding_size) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_unwrap_sendable(napi_env env, napi_value js_object, void **result) { - return napi_escape_called_twice; + return napi_ok; } napi_status napi_remove_wrap_sendable(napi_env env, napi_value js_object, void **result) { - return napi_escape_called_twice; + return napi_ok; } diff --git a/mock/src/mock_sys_ability.cpp b/mock/src/mock_sys_ability.cpp index 560744dd886f76872288f2aa34f889e72da40d68..2fdaeb4240c6fd4e9d641c63b910bfe28d2f07d1 100644 --- a/mock/src/mock_sys_ability.cpp +++ b/mock/src/mock_sys_ability.cpp @@ -61,4 +61,30 @@ bool SystemAbility::AddSystemAbilityListener(int32_t systemAbilityId) { return true; } +bool SystemAbility::RemoveSystemAbilityListener(int32_t systemAbilityId) +{ + return false; +} +int32_t SystemAbility::OnSvcCmd(int32_t fd, const std::vector &args) +{ + return 0; +} +sptr SystemAbility::GetSystemAbility(int32_t systemAbilityId) +{ + return sptr(); +} +bool SystemAbility::CancelIdle() +{ + return false; +} +void SystemAbility::StopAbility(int32_t systemAbilityId) {} +SystemAbilityState SystemAbility::GetAbilityState() +{ + return SystemAbilityState::IDLE; +} +void SystemAbility::OnDeviceLevelChanged(int32_t type, int32_t level, std::string &action) {} +int32_t SystemAbility::OnExtension(const std::string &extension, MessageParcel &data, MessageParcel &reply) +{ + return 0; +} } \ No newline at end of file diff --git a/mock/src/mock_window.cpp b/mock/src/mock_window.cpp new file mode 100644 index 0000000000000000000000000000000000000000..51d0543a1dc6e053600dcd0a5b974e89a9e6bfbe --- /dev/null +++ b/mock/src/mock_window.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 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 "window_manager.h" +namespace OHOS::Rosen { +WindowManager &WindowManager::GetInstance() +{ + static WindowManager manger; + return manger; +} +WindowManager::WindowManager() {} +void WindowManager::GetFocusWindowInfo(FocusChangeInfo &focusInfo, DisplayId displayId) {} +} // namespace OHOS::Rosen \ No newline at end of file diff --git a/preferences/bundle.json b/preferences/bundle.json index 17709c44a49d7437191b8cfa6aaa19b2faee8c28..f28dcd5b9953d73d16b001bd1c2240f9d76e92d4 100644 --- a/preferences/bundle.json +++ b/preferences/bundle.json @@ -3,7 +3,7 @@ "version": "3.1.0", "description": "Local Data Management", "homePage": "https://gitee.com/openharmony", - "license": "Apache V2", + "license": "Apache-2.0", "repository": "https://gitee.com/openharmony/distributeddatamgr_preferences", "domain": "ohos", "language": "", diff --git a/preferences/frameworks/js/napi/preferences/include/napi_preferences.h b/preferences/frameworks/js/napi/preferences/include/napi_preferences.h index 9e2ebe1330e2421ec6b8104e43a8d0f795305f4f..7d0d281afbd0bbe35cf403b55fb08e2cd21d0e15 100644 --- a/preferences/frameworks/js/napi/preferences/include/napi_preferences.h +++ b/preferences/frameworks/js/napi/preferences/include/napi_preferences.h @@ -82,4 +82,4 @@ private: } // namespace PreferencesJsKit } // namespace OHOS -#endif // PREFERENCES_JSKIT_NAPI_PREFERENCE_H +#endif // PREFERENCES_JSKIT_NAPI_PREFERENCE_H \ No newline at end of file diff --git a/preferences/frameworks/js/napi/preferences/src/napi_preferences_helper.cpp b/preferences/frameworks/js/napi/preferences/src/napi_preferences_helper.cpp index a76f605590253204e53bbda18983250173855195..ec3056b0b8d314cc618ac2db0217c3fd37cbb9db 100644 --- a/preferences/frameworks/js/napi/preferences/src/napi_preferences_helper.cpp +++ b/preferences/frameworks/js/napi/preferences/src/napi_preferences_helper.cpp @@ -29,6 +29,7 @@ namespace OHOS { namespace PreferencesJsKit { constexpr const char* DATA_GROUP_ID = "dataGroupId"; constexpr const char* NAME = "name"; +constexpr const char* STORAGE_TYPE = "storageType"; struct HelperAysncContext : public BaseContext { std::string path; @@ -36,6 +37,8 @@ struct HelperAysncContext : public BaseContext { std::string bundleName; std::string dataGroupId; std::shared_ptr proxy; + StorageType storageType = StorageType::XML; + bool isStorageTypeSupported = false; HelperAysncContext() { @@ -43,26 +46,59 @@ struct HelperAysncContext : public BaseContext { virtual ~HelperAysncContext(){}; }; +int ParseOptionalParameters(const napi_env env, napi_value *argv, std::shared_ptr context) +{ + napi_value temp = nullptr; + bool hasGroupId = false; + PRE_CHECK_RETURN_ERR_SET(napi_has_named_property(env, argv[1], DATA_GROUP_ID, &hasGroupId) == napi_ok, + std::make_shared("napi call failed when check dataGroupId.")); + if (hasGroupId) { + PRE_CHECK_RETURN_ERR_SET(napi_get_named_property(env, argv[1], DATA_GROUP_ID, &temp) == napi_ok, + std::make_shared("napi call failed when get dataGroupId.")); + napi_valuetype type = napi_undefined; + napi_status status = napi_typeof(env, temp, &type); + if (status == napi_ok && (type != napi_null && type != napi_undefined)) { + PRE_CHECK_RETURN_ERR_SET(JSUtils::Convert2NativeValue(env, temp, context->dataGroupId) == napi_ok, + std::make_shared("The dataGroupId must be string.")); + } + PRE_CHECK_RETURN_ERR_SET(status == napi_ok, + std::make_shared("parse group id: type of api failed")); + } + bool hasStorageType = false; + PRE_CHECK_RETURN_ERR_SET(napi_has_named_property(env, argv[1], STORAGE_TYPE, &hasStorageType) == napi_ok, + std::make_shared("napi call failed when check storageType")); + if (hasStorageType) { + temp = nullptr; + PRE_CHECK_RETURN_ERR_SET(napi_get_named_property(env, argv[1], STORAGE_TYPE, &temp) == napi_ok, + std::make_shared("napi call failed when get storageType.")); + napi_valuetype type = napi_undefined; + napi_status status = napi_typeof(env, temp, &type); + if (status == napi_ok && (type != napi_null && type != napi_undefined)) { + int32_t intVal = 0; + PRE_CHECK_RETURN_ERR_SET(napi_get_value_int32(env, temp, &intVal) == napi_ok, + std::make_shared("The storageType must be StorageType which is enum.")); + bool isTypeValid = (intVal == static_cast(StorageType::XML) || + intVal == static_cast(StorageType::CLKV)); + PRE_CHECK_RETURN_ERR_SET(isTypeValid, std::make_shared("Storage type value invalid.")); + context->storageType = (intVal == static_cast(StorageType::XML)) ? + StorageType::XML : StorageType::CLKV; + } + PRE_CHECK_RETURN_ERR_SET(status == napi_ok, + std::make_shared("parse storage type: type of api failed")); + } + return OK; +} + int ParseParameters(const napi_env env, napi_value *argv, std::shared_ptr context) { if (JSUtils::Convert2NativeValue(env, argv[1], context->name) != napi_ok) { napi_value temp = nullptr; - napi_get_named_property(env, argv[1], NAME, &temp); + PRE_CHECK_RETURN_ERR_SET(napi_get_named_property(env, argv[1], NAME, &temp) == napi_ok, + std::make_shared("napi call failed when get name.")); PRE_CHECK_RETURN_ERR_SET(temp && JSUtils::Convert2NativeValue(env, temp, context->name) == napi_ok, std::make_shared("The name must be string.")); - - bool hasGroupId = false; - napi_has_named_property(env, argv[1], DATA_GROUP_ID, &hasGroupId); - if (hasGroupId) { - temp = nullptr; - napi_get_named_property(env, argv[1], DATA_GROUP_ID, &temp); - napi_valuetype type = napi_undefined; - napi_status status = napi_typeof(env, temp, &type); - if (status == napi_ok && (type != napi_null && type != napi_undefined)) { - PRE_CHECK_RETURN_ERR_SET(JSUtils::Convert2NativeValue(env, temp, context->dataGroupId) == napi_ok, - std::make_shared("The dataGroupId must be string.")); - } - } + PRE_CHECK_RETURN_ERR_SET(ParseOptionalParameters(env, argv, context) == OK, + std::make_shared("parse optional param failed")); } JSAbility::ContextInfo contextInfo; std::shared_ptr err = JSAbility::GetContextInfo(env, argv[0], context->dataGroupId, contextInfo); @@ -82,7 +118,8 @@ napi_value GetPreferences(napi_env env, napi_callback_info info) }; auto exec = [context]() -> int { int errCode = E_OK; - Options options(context->path, context->bundleName, context->dataGroupId); + Options options(context->path, context->bundleName, context->dataGroupId, + context->storageType == StorageType::CLKV); context->proxy = PreferencesHelper::GetPreferences(options, errCode); return errCode; }; @@ -139,6 +176,62 @@ napi_value RemovePreferencesFromCache(napi_env env, napi_callback_info info) return AsyncCall::Call(env, context, "RemovePreferencesFromCache"); } +napi_value IsStorageTypeSupported(napi_env env, napi_callback_info info) +{ + auto context = std::make_shared(); + auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { + // check param number + PRE_NAPI_ASSERT_RETURN_VOID(env, argc == 1, std::make_shared("must have 1 param")); + // check param data type and value + int32_t intVal = 0; + PRE_NAPI_ASSERT_RETURN_VOID(env, napi_get_value_int32(env, argv[0], &intVal) == napi_ok, + std::make_shared("The storageType must be StorageType which is enum.")); + bool isTypeValid = (intVal == static_cast(StorageType::XML) || + intVal == static_cast(StorageType::CLKV)); + PRE_NAPI_ASSERT_RETURN_VOID(env, isTypeValid, std::make_shared("Storage type value invalid.")); + context->storageType = (intVal == static_cast(StorageType::XML)) ? + StorageType::XML : StorageType::CLKV; + }; + + auto exec = [context]() -> int { + context->isStorageTypeSupported = PreferencesHelper::IsStorageTypeSupported(context->storageType); + return OK; + }; + + auto output = [context](napi_env env, napi_value &result) { + napi_status status = napi_get_boolean(env, context->isStorageTypeSupported, &result); + PRE_NAPI_ASSERT_RETURN_VOID(env, status == napi_ok, + std::make_shared("Failed to get boolean when checking storage type")); + LOG_DEBUG("isStorageTypeSupported end."); + }; + context->SetAction(env, info, input, exec, output); + + PRE_CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK); + return AsyncCall::Call(env, context, "IsStorageTypeSupported"); +} + +static napi_status SetNamedProperty(napi_env env, napi_value& obj, const std::string& name, int32_t value) +{ + napi_value property = nullptr; + napi_status status = napi_create_int32(env, value, &property); + PRE_NAPI_ASSERT_BASE(env, status == napi_ok, std::make_shared("napi_create_int32 failed!"), status); + + status = napi_set_named_property(env, obj, name.c_str(), property); + PRE_NAPI_ASSERT_BASE(env, status == napi_ok, std::make_shared("napi_set_named_property failed!"), + status); + return status; +} + +static napi_value ExportStorageType(napi_env env) +{ + napi_value storageType = nullptr; + napi_create_object(env, &storageType); + SetNamedProperty(env, storageType, "XML", static_cast(StorageType::XML)); + SetNamedProperty(env, storageType, "CLKV", static_cast(StorageType::CLKV)); + napi_object_freeze(env, storageType); + return storageType; +} + napi_value InitPreferencesHelper(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { @@ -150,6 +243,8 @@ napi_value InitPreferencesHelper(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION_WITH_DATA("removePreferencesFromCacheSync", RemovePreferencesFromCache, SYNC), DECLARE_NAPI_PROPERTY("MAX_KEY_LENGTH", JSUtils::Convert2JSValue(env, Preferences::MAX_KEY_LENGTH)), DECLARE_NAPI_PROPERTY("MAX_VALUE_LENGTH", JSUtils::Convert2JSValue(env, Preferences::MAX_VALUE_LENGTH)), + DECLARE_NAPI_PROPERTY("StorageType", ExportStorageType(env)), + DECLARE_NAPI_FUNCTION_WITH_DATA("isStorageTypeSupported", IsStorageTypeSupported, SYNC), }; NAPI_CALL(env, napi_define_properties(env, exports, sizeof(properties) / sizeof(*properties), properties)); return exports; diff --git a/preferences/frameworks/js/napi/sendable_preferences/src/napi_preferences.cpp b/preferences/frameworks/js/napi/sendable_preferences/src/napi_preferences.cpp index 0e2e01b34e128ee7c824551be9c0c1c01e881581..2903786fdd194057f6ace7cc53c22800f746385b 100644 --- a/preferences/frameworks/js/napi/sendable_preferences/src/napi_preferences.cpp +++ b/preferences/frameworks/js/napi/sendable_preferences/src/napi_preferences.cpp @@ -64,7 +64,9 @@ PreferencesProxy::~PreferencesProxy() void PreferencesProxy::Destructor(napi_env env, void *nativeObject, void *finalize_hint) { PreferencesProxy *obj = static_cast(nativeObject); - delete obj; + if (obj != nullptr) { + delete obj; + } } void PreferencesProxy::Init(napi_env env, napi_value exports) diff --git a/preferences/frameworks/js/napi/storage/src/napi_storage.cpp b/preferences/frameworks/js/napi/storage/src/napi_storage.cpp index 4124c57ea5e595fde763f525473c0d7860ea1cc3..37f5787e59dc643689cbf9a57e164ddf61e4fe8c 100644 --- a/preferences/frameworks/js/napi/storage/src/napi_storage.cpp +++ b/preferences/frameworks/js/napi/storage/src/napi_storage.cpp @@ -57,7 +57,9 @@ StorageProxy::StorageProxy(std::shared_ptr StorageProxy::~StorageProxy() { for (auto &observer : dataObserver_) { - value_->UnRegisterObserver(observer); + if (observer != nullptr) { + value_->UnRegisterObserver(observer); + } } dataObserver_.clear(); } diff --git a/preferences/frameworks/native/include/concurrent_map.h b/preferences/frameworks/native/include/concurrent_map.h index b64100fbddca965a8445f822dceba500ad22e949..0948516f51d4802a4b10e62a384a11a794a18187 100644 --- a/preferences/frameworks/native/include/concurrent_map.h +++ b/preferences/frameworks/native/include/concurrent_map.h @@ -17,6 +17,7 @@ #define OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_CONCURRENT_MAP_H #include #include +#include #include namespace OHOS { @@ -319,8 +320,8 @@ public: if (action == nullptr) { return; } - auto tmp = Clone(); std::shared_lock lock(mutex_); + auto tmp = entries_; action(tmp); return; } diff --git a/preferences/frameworks/native/include/preferences_base.h b/preferences/frameworks/native/include/preferences_base.h index 236bfe3607a50b10ed427c9c2c5346b691ee1ece..4a8bdff150bc69b84906fa748d25e4692fe4df42 100644 --- a/preferences/frameworks/native/include/preferences_base.h +++ b/preferences/frameworks/native/include/preferences_base.h @@ -101,10 +101,22 @@ public: int CloseDb() override; + virtual int Close() + { + return E_OK; + } + + virtual bool IsClose() + { + return false; + } + std::pair GetValue(const std::string &key, const PreferencesValue &defValue) override; std::pair> GetAllData() override; + std::string GetBundleName() const override; + protected: Uri MakeUri(const std::string &key = ""); struct WeakPtrCompare { diff --git a/preferences/frameworks/native/include/preferences_impl.h b/preferences/frameworks/native/include/preferences_impl.h index 1fc3dd4a54bdd9ea11c6a03a63835b1b32115f7e..3457c9c2c716ead34291f4fef85a67ab9dbbdf9e 100644 --- a/preferences/frameworks/native/include/preferences_impl.h +++ b/preferences/frameworks/native/include/preferences_impl.h @@ -30,6 +30,7 @@ namespace OHOS { namespace NativePreferences { + class PreferencesImpl : public PreferencesBase, public std::enable_shared_from_this { public: static std::shared_ptr GetPreferences(const Options &options) @@ -56,32 +57,37 @@ public: int FlushSync() override; + int Close() override; + + bool IsClose() override; + std::pair GetValue(const std::string &key, const PreferencesValue &defValue) override; std::pair> GetAllData() override; private: explicit PreferencesImpl(const Options &options); - + void NotifyPreferencesObserver(const std::list &keysModified, const std::map &writeToDiskMap); bool StartLoadFromDisk(); + bool PreLoad(); /* thread function */ static void LoadFromDisk(std::shared_ptr pref); + bool ReloadFromDisk(); void AwaitLoadFile(); bool WriteSettingXml(const Options &options, const std::map &writeToDiskMap); static int WriteToDiskFile(std::shared_ptr pref); - static bool ReadSettingXml(std::shared_ptr pref); + bool ReadSettingXml(ConcurrentMap &conMap); std::atomic loaded_; - - /* Current memory state (always increasing) */ - int64_t currentMemoryStateGeneration_; - /* Latest memory state that was committed to disk */ - int64_t diskStateGeneration_; + bool isNeverUnlock_; + bool loadResult_; std::list modifiedKeys_; + std::atomic isActive_; + ConcurrentMap valuesCache_; std::shared_ptr> queue_; diff --git a/preferences/frameworks/native/include/preferences_xml_utils.h b/preferences/frameworks/native/include/preferences_xml_utils.h index 3988712419b463fcd9f57a9c09e63a20b40ce0bc..274366e81474438d227a0ef578b7baa77217a7d2 100644 --- a/preferences/frameworks/native/include/preferences_xml_utils.h +++ b/preferences/frameworks/native/include/preferences_xml_utils.h @@ -18,6 +18,7 @@ #include #include + namespace OHOS { namespace NativePreferences { class Element { @@ -32,9 +33,9 @@ public: class PreferencesXmlUtils { public: static bool ReadSettingXml(const std::string &fileName, const std::string &bundleName, - const std::string &dataGroupId, std::vector &settings); + std::vector &settings); static bool WriteSettingXml(const std::string &fileName, const std::string &bundleName, - const std::string &dataGroupId, const std::vector &settings); + const std::vector &settings); static void LimitXmlPermission(const std::string &fileName); private: diff --git a/preferences/frameworks/native/include/visibility.h b/preferences/frameworks/native/include/visibility.h index 26bf0fdb71b680b9a811648550942689fbf752ed..7c7726f4aae34aec74462562be9762c31fea7e43 100644 --- a/preferences/frameworks/native/include/visibility.h +++ b/preferences/frameworks/native/include/visibility.h @@ -22,8 +22,5 @@ #ifndef API_LOCAL #define API_LOCAL __attribute__((visibility("hidden"))) #endif -#ifndef UNUSED_FUNCTION -#define UNUSED_FUNCTION __attribute__((unused)) -#endif #endif // OHOS_PREFERENCES_FRAMEWORKS_COMMON_VISIBILITY_H diff --git a/preferences/frameworks/native/platform/include/preferences_anonymous.h b/preferences/frameworks/native/platform/include/preferences_anonymous.h index 3e79000dc614a49fc7445b2b55caa4d88508e03c..6161747f431bf59e0285cda8e7df41295743c291 100644 --- a/preferences/frameworks/native/platform/include/preferences_anonymous.h +++ b/preferences/frameworks/native/platform/include/preferences_anonymous.h @@ -30,13 +30,19 @@ public: if (data.size() < MIN_SIZE) { return (data.substr(0, HEAD_SIZE) + REPLACE_CHAIN); } - return (data.substr(0, HEAD_SIZE) + REPLACE_CHAIN + data.substr(data.size() - END_SIZE, END_SIZE)); + if (data.size() < MEDIAN_SIZE) { + return (data.substr(0, HEAD_SIZE) + REPLACE_CHAIN + data.substr(data.size() - END_SIZE, END_SIZE)); + } + return (data.substr(0, DATA_HEAD) + REPLACE_CHAIN + data.substr(data.size() - DATA_END, DATA_END)); } private: static constexpr size_t HEAD_SIZE = 3; static constexpr size_t END_SIZE = 3; + static constexpr size_t DATA_HEAD = 4; + static constexpr size_t DATA_END = 4; static constexpr size_t MIN_SIZE = HEAD_SIZE + END_SIZE + 3; + static constexpr size_t MEDIAN_SIZE = DATA_HEAD + DATA_END + 3; static constexpr const char *REPLACE_CHAIN = "***"; static constexpr const char *DEFAULT_ANONYMOUS = "******"; }; diff --git a/preferences/frameworks/native/platform/include/preferences_dfx_adapter.h b/preferences/frameworks/native/platform/include/preferences_dfx_adapter.h index 3dd7650ad7849bcbc53bcdaee873895bb8930ca3..dd32d101de5fcac63730e183d234aad652560411 100644 --- a/preferences/frameworks/native/platform/include/preferences_dfx_adapter.h +++ b/preferences/frameworks/native/platform/include/preferences_dfx_adapter.h @@ -18,29 +18,54 @@ #include +#include "concurrent_map.h" #include "preferences_errno.h" + namespace OHOS { namespace NativePreferences { static constexpr const char *NORMAL_DB = "XMLDB"; static constexpr const char *ENHANCE_DB = "ENHANCEDB"; static constexpr const char *EVENT_NAME_DB_CORRUPTED = "DATABASE_CORRUPTED"; +static constexpr const char *EVENT_NAME_PREFERENCES_FAULT = "PREFERENCES_FAULT"; +static constexpr const char *EVENT_NAME_ARKDATA_PREFERENCES_FAULT = "ARKDATA_PREFERENCES_FAULT"; static constexpr const char *DISTRIBUTED_DATAMGR = "DISTDATAMGR"; +enum class ReportedFaultBitMap { + RESTORE_FROM_BAK, + USE_WHEN_SCREEN_LOCKED, + OBJECT_IS_NOT_ACTIVE +}; + struct ReportParam { std::string bundleName; // bundleName std::string dbType; // NORMAL_DB or ENHANCE_DB - std::string storeName; // filename + std::string storeName; // filename uint32_t errCode = E_OK; - int32_t errnoCode = 0; // errno + int32_t errnoCode = 0; // errno // additional info, "operation: reason", such as "read failed" - std::string appendix; // additional info + std::string appendix; // additional info +}; + +struct ReportFaultParam { + std::string faultType; // faultType + std::string bundleName; // bundleName + std::string dbType; // NORMAL_DB or ENHANCE_DB + std::string storeName; // filename + int32_t errCode = E_OK; + // additional info, "operation: reason", such as "read failed" + std::string appendix; // additional info }; class PreferencesDfxManager { public: - static void ReportDbFault(const ReportParam &reportParam); + static void Report(const ReportParam &reportParam, const char *eventName); + static void ReportFault(const ReportFaultParam &reportParam); static std::string GetModuleName(); + + static void ReportAbnormalOperation(const ReportParam &reportParam, ReportedFaultBitMap faultOffset); +private: + static ConcurrentMap reportedFaults_; }; } // namespace NativePreferences } // namespace OHOS diff --git a/preferences/frameworks/native/platform/include/preferences_file_lock.h b/preferences/frameworks/native/platform/include/preferences_file_lock.h index 964898d25300c790f608c129c9f2b173640d37f1..d63cecb75cfe4a521093ef6ee19f36fba8d49bca 100644 --- a/preferences/frameworks/native/platform/include/preferences_file_lock.h +++ b/preferences/frameworks/native/platform/include/preferences_file_lock.h @@ -35,12 +35,17 @@ private: }; class PreferencesFileLock final { public: - PreferencesFileLock(const std::string &path, const std::string &dataGroupId); + PreferencesFileLock(const std::string &path); ~PreferencesFileLock(); + void ReadLock(bool &isMultiProcessing); + void WriteLock(bool &isMultiProcessing); private: + void Lock(short lockType, bool &isMultiProcessing); + int fd_{ -1 }; std::shared_ptr inProcessMutex_; + std::string filePath_; }; } // namespace NativePreferences } // namespace OHOS diff --git a/preferences/frameworks/native/platform/include/preferences_file_operation.h b/preferences/frameworks/native/platform/include/preferences_file_operation.h index 726968019aee263d8b096a0b84c09c2cbd5234df..20127b3cef487530b56ddd0df7cb527097c1b4b5 100644 --- a/preferences/frameworks/native/platform/include/preferences_file_operation.h +++ b/preferences/frameworks/native/platform/include/preferences_file_operation.h @@ -22,6 +22,7 @@ #include #include "visibility.h" +#include "preferences_anonymous.h" #ifndef _WIN32 #include @@ -59,6 +60,15 @@ namespace OHOS { namespace NativePreferences { +constexpr int32_t PRE_OFFSET_SIZE = 1; +constexpr int32_t AREA_MINI_SIZE = 4; +constexpr int32_t AREA_OFFSET_SIZE = 5; +constexpr int32_t FILE_PATH_MINI_SIZE = 6; + +#ifndef UNUSED_FUNCTION +#define UNUSED_FUNCTION __attribute__((unused)) +#endif + static UNUSED_FUNCTION void *DBDlOpen() { #ifndef _WIN32 @@ -115,11 +125,23 @@ static UNUSED_FUNCTION bool Fsync(const std::string &filePath) static UNUSED_FUNCTION std::string ExtractFileName(const std::string &path) { - auto pos = path.rfind('/'); - if (pos == std::string::npos) { - return path; + auto pre = path.find("/"); + auto end = path.rfind("/"); + if (pre == std::string::npos || end - pre < FILE_PATH_MINI_SIZE) { + return Anonymous::ToBeAnonymous(path); + } + std::string fileName = path.substr(end + 1); // preferences file name + auto filePath = path.substr(pre, end - pre); + auto area = filePath.find("/el"); + if (area == std::string::npos || area + AREA_MINI_SIZE > path.size()) { + filePath = ""; + } else if (area + AREA_OFFSET_SIZE < path.size()) { + filePath = path.substr(area, AREA_MINI_SIZE) + "/***"; + } else { + filePath = path.substr(area, AREA_MINI_SIZE); } - return path.substr(pos + 1); + fileName = Anonymous::ToBeAnonymous(fileName); + return path.substr(0, pre + PRE_OFFSET_SIZE) + "***" + filePath + "/"+ fileName; } } // namespace NativePreferences } // namespace OHOS diff --git a/preferences/frameworks/native/platform/src/preferences_db_adapter.cpp b/preferences/frameworks/native/platform/src/preferences_db_adapter.cpp index 985f4f654fc8e6535378133e4371631cec7c4c6b..e3a10163b89b51652c3d6f39e051675f38b3825f 100644 --- a/preferences/frameworks/native/platform/src/preferences_db_adapter.cpp +++ b/preferences/frameworks/native/platform/src/preferences_db_adapter.cpp @@ -217,7 +217,6 @@ int PreferencesDb::RepairDb() } int errCode = PreferenceDbAdapter::GetApiInstance().DbRepairApi(dbPath_.c_str(), CONFIG_STR); if (errCode != GRD_OK) { - std::string errMsg = "db repair failed"; LOG_ERROR("repair db failed, errCode: %{public}d", errCode); } return errCode; @@ -271,19 +270,15 @@ int PreferencesDb::Init(const std::string &dbPath, const std::string &bundleName bundleName_ = bundleName; int errCode = OpenDb(false); if (errCode == GRD_DATA_CORRUPTED) { - PreferencesDfxManager::ReportDbFault(GetReportParam("db corrupted", errCode)); - } - if (errCode == GRD_DATA_CORRUPTED || errCode == GRD_INNER_ERR) { + PreferencesDfxManager::Report(GetReportParam("db corrupted", errCode), EVENT_NAME_DB_CORRUPTED); int innerErr = TryRepairAndRebuild(errCode); if (innerErr != GRD_OK) { // log inside return TransferGrdErrno(innerErr); } - if (errCode == GRD_DATA_CORRUPTED) { - ReportParam param = GetReportParam("db repair success", GRD_OK); - param.errnoCode = 0; - PreferencesDfxManager::ReportDbFault(param); - } + ReportParam param = GetReportParam("db repair success", GRD_OK); + param.errnoCode = 0; + PreferencesDfxManager::Report(param, EVENT_NAME_DB_CORRUPTED); } else if (errCode != GRD_OK) { LOG_ERROR("db open failed, errCode: %{public}d", errCode); return TransferGrdErrno(errCode); @@ -387,19 +382,20 @@ int PreferencesDb::Get(const std::vector &key, std::vector &va GRD_KVItemT innerVal = { NULL, 0 }; int retryTimes = CREATE_COLLECTION_RETRY_TIMES; - int ret = E_OK; + int ret = GRD_OK; do { ret = PreferenceDbAdapter::GetApiInstance().DbKvGetApi(db_, TABLENAME, &innerKey, &innerVal); if (ret == GRD_UNDEFINED_TABLE) { LOG_INFO("CreateCollection called when Get, file: %{public}s", ExtractFileName(dbPath_).c_str()); (void)CreateCollection(); } else { - if (ret == E_OK) { + if (ret == GRD_OK) { break; - } else { + } + if (ret != GRD_NO_DATA) { LOG_ERROR("rd get failed:%{public}d", ret); - return TransferGrdErrno(ret); } + return TransferGrdErrno(ret); } retryTimes--; } while (retryTimes > 0); diff --git a/preferences/frameworks/native/platform/src/preferences_dfx_adapter.cpp b/preferences/frameworks/native/platform/src/preferences_dfx_adapter.cpp index be84ddf25e9c2c1989c5940c9bc6899589ee50b3..64289ac5aeb71b4d8ca698ee0d6522dde5bd3d27 100644 --- a/preferences/frameworks/native/platform/src/preferences_dfx_adapter.cpp +++ b/preferences/frameworks/native/platform/src/preferences_dfx_adapter.cpp @@ -21,6 +21,7 @@ #include #include "log_print.h" + #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) #include @@ -31,6 +32,9 @@ namespace OHOS { namespace NativePreferences { + +ConcurrentMap PreferencesDfxManager::reportedFaults_; + #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) std::string GetCurrentTime() { @@ -68,53 +72,110 @@ std::string PreferencesDfxManager::GetModuleName() return moduleName; } -void PreferencesDfxManager::ReportDbFault(const ReportParam &reportParam) +void PreferencesDfxManager::ReportAbnormalOperation(const ReportParam &reportParam, ReportedFaultBitMap faultOffset) { - std::thread thread([reportParam]() { - std::string nowTime = GetCurrentTime(); - std::string moudleName = GetModuleName(); - if (moudleName.empty()) { - moudleName = reportParam.storeName; + uint64_t offset = static_cast(faultOffset); + PreferencesDfxManager::reportedFaults_.Compute( + reportParam.storeName, [reportParam, offset](auto &, uint64_t &report) { + uint64_t mask = 0x01; + if ((report >> offset) & mask) { + return true; } - std::string bundleName = reportParam.bundleName.empty() ? moudleName : reportParam.bundleName; - HiSysEventParam params[] = { - { .name = "BUNDLE_NAME", - .t = HISYSEVENT_STRING, - .v = { .s = const_cast(bundleName.c_str()) }, - .arraySize = 0 }, - { .name = "MODULE_NAME", - .t = HISYSEVENT_STRING, - .v = { .s = const_cast(moudleName.c_str()) }, - .arraySize = 0 }, - { .name = "STORE_TYPE", - .t = HISYSEVENT_STRING, - .v = { .s = const_cast(reportParam.dbType.c_str()) }, - .arraySize = 0 }, - { .name = "STORE_NAME", - .t = HISYSEVENT_STRING, - .v = { .s = const_cast(reportParam.storeName.c_str()) }, - .arraySize = 0 }, - { .name = "SECURITY_LEVEL", .t = HISYSEVENT_UINT32, .v = { .ui32 = 0u }, .arraySize = 0 }, - { .name = "PATH_AREA", .t = HISYSEVENT_UINT32, .v = { .ui32 = 0u }, .arraySize = 0 }, - { .name = "ENCRYPT_STATUS", .t = HISYSEVENT_UINT32, .v = { .ui32 = 0u }, .arraySize = 0 }, - { .name = "INTERGITY_CHECK", .t = HISYSEVENT_UINT32, .v = { .ui32 = 0u }, .arraySize = 0 }, - { .name = "ERROR_CODE", .t = HISYSEVENT_UINT32, .v = { .ui32 = reportParam.errCode }, .arraySize = 0 }, - { .name = "ERRNO", .t = HISYSEVENT_INT32, .v = { .i32 = reportParam.errnoCode }, .arraySize = 0 }, - { .name = "APPENDIX", - .t = HISYSEVENT_STRING, - .v = { .s = const_cast(reportParam.appendix.c_str()) }, - .arraySize = 0 }, - { .name = "ERROR_TIME", - .t = HISYSEVENT_STRING, - .v = { .s = const_cast(nowTime.c_str()) }, - .arraySize = 0 }, - }; - size_t len = sizeof(params) / sizeof(params[0]); - OH_HiSysEvent_Write(DISTRIBUTED_DATAMGR, EVENT_NAME_DB_CORRUPTED, HISYSEVENT_FAULT, params, len); + PreferencesDfxManager::Report(reportParam, EVENT_NAME_PREFERENCES_FAULT); + report |= (mask << offset); + return true; }); - thread.detach(); } + +void PreferencesDfxManager::Report(const ReportParam &reportParam, const char *eventName) +{ + std::string nowTime = GetCurrentTime(); + std::string moduleName = GetModuleName(); + if (moduleName.empty()) { + moduleName = reportParam.storeName; + } + std::string bundleName = reportParam.bundleName.empty() ? moduleName : reportParam.bundleName; + HiSysEventParam params[] = { + { .name = "BUNDLE_NAME", + .t = HISYSEVENT_STRING, + .v = { .s = const_cast(bundleName.c_str()) }, + .arraySize = 0 }, + { .name = "MODULE_NAME", + .t = HISYSEVENT_STRING, + .v = { .s = const_cast(moduleName.c_str()) }, + .arraySize = 0 }, + { .name = "STORE_TYPE", + .t = HISYSEVENT_STRING, + .v = { .s = const_cast(reportParam.dbType.c_str()) }, + .arraySize = 0 }, + { .name = "STORE_NAME", + .t = HISYSEVENT_STRING, + .v = { .s = const_cast(reportParam.storeName.c_str()) }, + .arraySize = 0 }, + { .name = "SECURITY_LEVEL", .t = HISYSEVENT_UINT32, .v = { .ui32 = 0u }, .arraySize = 0 }, + { .name = "PATH_AREA", .t = HISYSEVENT_UINT32, .v = { .ui32 = 0u }, .arraySize = 0 }, + { .name = "ENCRYPT_STATUS", .t = HISYSEVENT_UINT32, .v = { .ui32 = 0u }, .arraySize = 0 }, + { .name = "INTERGITY_CHECK", .t = HISYSEVENT_UINT32, .v = { .ui32 = 0u }, .arraySize = 0 }, + { .name = "ERROR_CODE", .t = HISYSEVENT_UINT32, .v = { .ui32 = reportParam.errCode }, .arraySize = 0 }, + { .name = "ERRNO", .t = HISYSEVENT_INT32, .v = { .i32 = reportParam.errnoCode }, .arraySize = 0 }, + { .name = "APPENDIX", + .t = HISYSEVENT_STRING, + .v = { .s = const_cast(reportParam.appendix.c_str()) }, + .arraySize = 0 }, + { .name = "ERROR_TIME", + .t = HISYSEVENT_STRING, + .v = { .s = const_cast(nowTime.c_str()) }, + .arraySize = 0 }, + }; + size_t len = sizeof(params) / sizeof(params[0]); + OH_HiSysEvent_Write(DISTRIBUTED_DATAMGR, eventName, HISYSEVENT_FAULT, params, len); +} + +void PreferencesDfxManager::ReportFault(const ReportFaultParam &reportParam) +{ + std::string nowTime = GetCurrentTime(); + std::string moduleName = GetModuleName(); + if (moduleName.empty()) { + moduleName = reportParam.storeName; + } + std::string bundleName = reportParam.bundleName.empty() ? moduleName : reportParam.bundleName; + HiSysEventParam params[] = { + { .name = "FAULT_TIME", + .t = HISYSEVENT_STRING, + .v = { .s = const_cast(nowTime.c_str()) }, + .arraySize = 0 }, + { .name = "FAULT_TYPE", + .t = HISYSEVENT_STRING, + .v = { .s = const_cast(reportParam.faultType.c_str()) }, + .arraySize = 0 }, + { .name = "BUNDLE_NAME", + .t = HISYSEVENT_STRING, + .v = { .s = const_cast(bundleName.c_str()) }, + .arraySize = 0 }, + { .name = "MODULE_NAME", + .t = HISYSEVENT_STRING, + .v = { .s = const_cast(moduleName.c_str()) }, + .arraySize = 0 }, + { .name = "STORE_NAME", + .t = HISYSEVENT_STRING, + .v = { .s = const_cast(reportParam.storeName.c_str()) }, + .arraySize = 0 }, + { .name = "BUSINESE_TYPE", + .t = HISYSEVENT_STRING, + .v = { .s = const_cast(reportParam.dbType.c_str()) }, + .arraySize = 0 }, + { .name = "ERROR_CODE", .t = HISYSEVENT_INT32, .v = { .i32 = reportParam.errCode }, .arraySize = 0 }, + { .name = "APPENDIX", + .t = HISYSEVENT_STRING, + .v = { .s = const_cast(reportParam.appendix.c_str()) }, + .arraySize = 0 }, + }; + size_t len = sizeof(params) / sizeof(params[0]); + OH_HiSysEvent_Write(DISTRIBUTED_DATAMGR, EVENT_NAME_ARKDATA_PREFERENCES_FAULT, HISYSEVENT_FAULT, params, len); +} + #else + std::string GetCurrentTime() { return ""; @@ -125,9 +186,19 @@ std::string PreferencesDfxManager::GetModuleName() return ""; } -void PreferencesDfxManager::ReportDbFault(const ReportParam &reportParam) +void PreferencesDfxManager::Report(const ReportParam &reportParam, const char *eventName) +{ +} + +void PreferencesDfxManager::ReportFault(const ReportFaultParam &reportParam) { } + + +void PreferencesDfxManager::ReportAbnormalOperation(const ReportParam &reportParam, ReportedFaultBitMap faultOffset) +{ +} + #endif } // End of namespace NativePreferences } // End of namespace OHOS diff --git a/preferences/frameworks/native/platform/src/preferences_file_lock.cpp b/preferences/frameworks/native/platform/src/preferences_file_lock.cpp index dc4ae796d5cfac8573919d47e99a8f87fe81a68a..b2ebebe5b60da372566fa4aef7b7ef3002c4c5af 100644 --- a/preferences/frameworks/native/platform/src/preferences_file_lock.cpp +++ b/preferences/frameworks/native/platform/src/preferences_file_lock.cpp @@ -13,6 +13,7 @@ * limitations under the License. */ +#include "preferences_utils.h" #include "preferences_file_lock.h" #include "preferences_file_operation.h" @@ -44,21 +45,56 @@ std::shared_ptr PreferencesLockManager::Get(const std::string fileNa #if !defined(WINDOWS_PLATFORM) static const std::chrono::microseconds WAIT_CONNECT_TIMEOUT(20); -static const int ATTEMPTS = 5; -PreferencesFileLock::PreferencesFileLock(const std::string &path, const std::string &dataGroupId) - : inProcessMutex_(PreferencesLockManager::Get(path)) +static const int ATTEMPTS = 50; +PreferencesFileLock::PreferencesFileLock(const std::string &path) { + filePath_ = MakeFilePath(path, STR_LOCK); + inProcessMutex_ = PreferencesLockManager::Get(filePath_); inProcessMutex_->lock(); - if (dataGroupId.empty()) { +} + +PreferencesFileLock::~PreferencesFileLock() +{ + inProcessMutex_->unlock(); + if (Access(filePath_) != 0 && Access(MakeFilePath(filePath_, STR_BACKUP)) != 0) { return; } - fd_ = open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (fd_ > 0) { + struct flock fileLockInfo = { 0 }; + fileLockInfo.l_type = F_UNLCK; + fileLockInfo.l_whence = SEEK_SET; + fileLockInfo.l_start = 0; + fileLockInfo.l_len = 0; + if (fcntl(fd_, F_SETLK, &fileLockInfo) == -1) { + LOG_ERROR("failed to release file lock error %{public}d.", errno); + } + close(fd_); + fd_ = -1; + } +} + +void PreferencesFileLock::ReadLock(bool &isMultiProcessing) +{ + if (Access(filePath_) != 0 && Access(MakeFilePath(filePath_, STR_BACKUP)) != 0) { + return; + } + Lock(F_RDLCK, isMultiProcessing); +} + +void PreferencesFileLock::WriteLock(bool &isMultiProcessing) +{ + Lock(F_WRLCK, isMultiProcessing); +} + +void PreferencesFileLock::Lock(short lockType, bool &isMultiProcessing) +{ + fd_ = open(filePath_.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (fd_ == -1) { - LOG_ERROR("Couldn't open file %{public}s errno %{public}d.", ExtractFileName(path).c_str(), errno); + LOG_ERROR("Couldn't open file %{public}s errno %{public}d.", ExtractFileName(filePath_).c_str(), errno); return; } struct flock fileLockInfo = { 0 }; - fileLockInfo.l_type = F_WRLCK; + fileLockInfo.l_type = lockType; fileLockInfo.l_whence = SEEK_SET; fileLockInfo.l_start = 0; fileLockInfo.l_len = 0; @@ -69,31 +105,15 @@ PreferencesFileLock::PreferencesFileLock(const std::string &path, const std::str return; } LOG_DEBUG("Attempt to obtain file lock again %{public}d", errno); + isMultiProcessing = true; std::this_thread::sleep_for(WAIT_CONNECT_TIMEOUT); } - LOG_ERROR("attempt to lock file %{public}s failed. Please try again", ExtractFileName(path).c_str()); -} - -PreferencesFileLock::~PreferencesFileLock() -{ - inProcessMutex_->unlock(); - if (fd_ > 0) { - struct flock fileLockInfo = { 0 }; - fileLockInfo.l_type = F_UNLCK; - fileLockInfo.l_whence = SEEK_SET; - fileLockInfo.l_start = 0; - fileLockInfo.l_len = 0; - if (fcntl(fd_, F_SETLK, &fileLockInfo) == -1) { - LOG_ERROR("failed to release file lock error %{public}d.", errno); - } - close(fd_); - fd_ = -1; - } + LOG_ERROR("attempt to lock file %{public}s failed.", ExtractFileName(filePath_).c_str()); } #else -PreferencesFileLock::PreferencesFileLock(const std::string &path, const std::string &dataGroupId) +PreferencesFileLock::PreferencesFileLock(const std::string &path) { fd_ = -1; inProcessMutex_.reset(); @@ -103,6 +123,18 @@ PreferencesFileLock::~PreferencesFileLock() { } +void PreferencesFileLock::ReadLock(bool &isMultiProcessing) +{ +} + +void PreferencesFileLock::WriteLock(bool &isMultiProcessing) +{ +} + +void PreferencesFileLock::Lock(short lockType, bool &isMultiProcessing) +{ +} + #endif } // End of namespace NativePreferences } // End of namespace OHOS \ No newline at end of file diff --git a/preferences/frameworks/native/src/base64_helper.cpp b/preferences/frameworks/native/src/base64_helper.cpp index c4f9891a750fd825988e9427fad5a5184d1ffc30..61e3c6905ca27a53892ea6b88b2ddfce6792c4fb 100644 --- a/preferences/frameworks/native/src/base64_helper.cpp +++ b/preferences/frameworks/native/src/base64_helper.cpp @@ -19,8 +19,7 @@ namespace OHOS { namespace NativePreferences { -static const uint8_t base64Encoder[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const uint8_t base64Encoder[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char base64Decoder[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, diff --git a/preferences/frameworks/native/src/preferences_base.cpp b/preferences/frameworks/native/src/preferences_base.cpp index 4c07bc25445488f8594208dde21253fc63c028b8..cbce9136b2295837fa38333cf94a9b15d8e94c99 100644 --- a/preferences/frameworks/native/src/preferences_base.cpp +++ b/preferences/frameworks/native/src/preferences_base.cpp @@ -25,6 +25,8 @@ #include "base64_helper.h" #include "executor_pool.h" #include "log_print.h" +#include "preferences_dfx_adapter.h" +#include "preferences_file_operation.h" #include "preferences_observer_stub.h" namespace OHOS { @@ -161,6 +163,7 @@ int PreferencesBase::FlushSync() int PreferencesBase::RegisterObserver(std::shared_ptr preferencesObserver, RegisterMode mode) { + IsClose(); std::unique_lock writeLock(obseverMetux_); if (mode == RegisterMode::LOCAL_CHANGE) { std::weak_ptr weakPreferencesObserver = preferencesObserver; @@ -174,6 +177,10 @@ int PreferencesBase::RegisterObserver(std::shared_ptr prefe int errcode = dataObsMgrClient->RegisterObserver(MakeUri(), observer); if (errcode != 0) { LOG_ERROR("RegisterObserver multiProcessChange failed, errCode %{public}d", errcode); + ReportFaultParam param = { "subscribe error", options_.bundleName, NORMAL_DB, + ExtractFileName(options_.filePath), E_SUBSCRIBE_FAILED, + "subscribe failed, the reason is " + std::to_string(errcode) }; + PreferencesDfxManager::ReportFault(param); return errcode; } multiProcessObservers_.push_back(observer); @@ -185,6 +192,7 @@ int PreferencesBase::RegisterObserver(std::shared_ptr prefe int PreferencesBase::UnRegisterDataObserver(std::shared_ptr preferencesObserver, const std::vector &keys) { + IsClose(); std::unique_lock writeLock(obseverMetux_); auto it = dataObserversMap_.find(preferencesObserver); if (it == dataObserversMap_.end()) { @@ -230,9 +238,15 @@ std::pair> PreferencesBase::GetAllD return std::make_pair(E_OK, map); } +std::string PreferencesBase::GetBundleName() const +{ + return options_.bundleName; +} + int PreferencesBase::RegisterDataObserver(std::shared_ptr preferencesObserver, const std::vector &keys) { + IsClose(); std::unique_lock writeLock(obseverMetux_); auto it = dataObserversMap_.find(preferencesObserver); if (it == dataObserversMap_.end()) { @@ -247,6 +261,7 @@ int PreferencesBase::RegisterDataObserver(std::shared_ptr p int PreferencesBase::UnRegisterObserver(std::shared_ptr preferencesObserver, RegisterMode mode) { + IsClose(); std::unique_lock writeLock(obseverMetux_); if (mode == RegisterMode::LOCAL_CHANGE) { for (auto it = localObservers_.begin(); it != localObservers_.end(); ++it) { diff --git a/preferences/frameworks/native/src/preferences_enhance_impl.cpp b/preferences/frameworks/native/src/preferences_enhance_impl.cpp index 9121a5b4a2cff9a50da6b984770eadc48ac82b01..cddc7bb61a375a2a7da84717ef66381a9ae6db22 100644 --- a/preferences/frameworks/native/src/preferences_enhance_impl.cpp +++ b/preferences/frameworks/native/src/preferences_enhance_impl.cpp @@ -48,6 +48,11 @@ PreferencesEnhanceImpl::~PreferencesEnhanceImpl() int PreferencesEnhanceImpl::Init() { std::unique_lock writeLock(dbMutex_); + PreferenceDbAdapter::ApiInit(); + if (!PreferenceDbAdapter::IsEnhandceDbEnable()) { + LOG_ERROR("enhance api load failed."); + return E_ERROR; + } db_ = std::make_shared(); cachedDataVersion_ = 0; int errCode = db_->Init(options_.filePath, options_.bundleName); @@ -84,6 +89,9 @@ PreferencesValue PreferencesEnhanceImpl::Get(const std::string &key, const Prefe std::vector oriKey(key.begin(), key.end()); std::vector oriValue; int errCode = db_->Get(oriKey, oriValue); + if (errCode == E_NO_DATA) { + return defValue; + } if (errCode != E_OK) { LOG_ERROR("get key failed, errCode=%{public}d", errCode); return defValue; @@ -126,6 +134,9 @@ bool PreferencesEnhanceImpl::HasKey(const std::string &key) std::vector oriKey(key.begin(), key.end()); std::vector oriValue; int errCode = db_->Get(oriKey, oriValue); + if (errCode == E_NO_DATA) { + return false; + } if (errCode != E_OK) { LOG_ERROR("get key failed, errCode=%{public}d", errCode); return false; @@ -391,6 +402,9 @@ std::pair PreferencesEnhanceImpl::GetValue(const std::str std::vector oriKey(key.begin(), key.end()); std::vector oriValue; errCode = db_->Get(oriKey, oriValue); + if (errCode == E_NO_DATA) { + return std::make_pair(errCode, defValue); + } if (errCode != E_OK) { LOG_ERROR("get key failed, errCode=%{public}d", errCode); return std::make_pair(errCode, defValue); diff --git a/preferences/frameworks/native/src/preferences_helper.cpp b/preferences/frameworks/native/src/preferences_helper.cpp index c59c60b846a9c8fd30aead7fab12eda5b1c36bec..58949143356d4eef947999f0c629287372881ba9 100644 --- a/preferences/frameworks/native/src/preferences_helper.cpp +++ b/preferences/frameworks/native/src/preferences_helper.cpp @@ -29,10 +29,12 @@ #include "preferences_dfx_adapter.h" #include "preferences_impl.h" #include "preferences_enhance_impl.h" + namespace OHOS { namespace NativePreferences { std::map, bool>> PreferencesHelper::prefsCache_; std::mutex PreferencesHelper::prefsCacheMutex_; +std::atomic PreferencesHelper::isReportFault_(false); static constexpr const int DB_SUFFIX_NUM = 6; static constexpr const char *DB_SUFFIX[DB_SUFFIX_NUM] = { ".ctrl", ".ctrl.dwr", ".redo", ".undo", ".safe", ".map" }; @@ -115,26 +117,54 @@ std::string PreferencesHelper::GetRealPath(const std::string &path, int &errorCo return path; } -#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) -static bool IsUseEnhanceDb(const Options &options) +static bool IsInTrustList(const std::string &bundleName) { + std::vector trustList = {"uttest", "alipay", "com.jd.", "cmblife", "os.mms", "os.ouc", + "meetimeservice"}; + for (size_t i = 0; i < trustList.size(); i++) { + if (bundleName.find(trustList[i]) != std::string::npos) { + return true; + } + } + return false; +} + +int PreferencesHelper::GetPreferencesInner(const Options &options, bool &isEnhancePreferences, + std::shared_ptr &pref) +{ + if (IsInTrustList(options.bundleName)) { + if (!IsFileExist(options.filePath) && IsStorageTypeSupported(StorageType::CLKV)) { + pref = PreferencesEnhanceImpl::GetPreferences(options); + isEnhancePreferences = true; + return std::static_pointer_cast(pref)->Init(); + } + pref = PreferencesImpl::GetPreferences(options); + isEnhancePreferences = false; + return std::static_pointer_cast(pref)->Init(); + } + if (!options.isEnhance) { + // xml + if (IsFileExist(options.filePath + ".db")) { + LOG_ERROR("CLKV exists, failed to get preferences by XML."); + return E_NOT_SUPPORTED; + } + pref = PreferencesImpl::GetPreferences(options); + isEnhancePreferences = false; + return std::static_pointer_cast(pref)->Init(); + } + // clkv if (IsFileExist(options.filePath)) { - return false; + LOG_ERROR("XML exists, failed to get preferences by CLKV."); + return E_NOT_SUPPORTED; } - bool bundleCheck = (options.bundleName.find("uttest") != std::string::npos || - options.bundleName.find("alipay") != std::string::npos || - options.bundleName.find("com.jd.") != std::string::npos || - options.bundleName.find("cmblife") != std::string::npos || - options.bundleName.find("os.mms") != std::string::npos || - options.bundleName.find("os.ouc") != std::string::npos || - options.bundleName.find("meetimeservice") != std::string::npos); - if (!options.isEnhance && !bundleCheck) { - return false; + if (!IsStorageTypeSupported(StorageType::CLKV)) { + // log inside + return E_NOT_SUPPORTED; } - PreferenceDbAdapter::ApiInit(); - return PreferenceDbAdapter::IsEnhandceDbEnable(); + pref = PreferencesEnhanceImpl::GetPreferences(options); + isEnhancePreferences = true; + return std::static_pointer_cast(pref)->Init(); } -#endif std::shared_ptr PreferencesHelper::GetPreferences(const Options &options, int &errCode) { @@ -156,22 +186,19 @@ std::shared_ptr PreferencesHelper::GetPreferences(const Options &op } const_cast(options).filePath = realPath; - std::shared_ptr pref = nullptr; - bool isEnhancePreferences = false; -#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) &&!defined(IOS_PLATFORM) - if (IsUseEnhanceDb(options)) { - LOG_DEBUG("PreferencesHelper::GetPreferences using enhance db."); - pref = PreferencesEnhanceImpl::GetPreferences(options); - errCode = std::static_pointer_cast(pref)->Init(); - isEnhancePreferences = true; - } else { - pref = PreferencesImpl::GetPreferences(options); - errCode = std::static_pointer_cast(pref)->Init(); + std::string::size_type pos = realPath.find_last_of('/'); + std::string filePath = realPath.substr(0, pos); + if (Access(filePath.c_str()) != 0) { + LOG_ERROR("The path is invalid, prefName is %{public}s.", ExtractFileName(filePath).c_str()); + if (!PreferencesHelper::isReportFault_.exchange(true)) { + ReportParam param = { options.bundleName, NORMAL_DB, ExtractFileName(options.filePath), + E_INVALID_FILE_PATH, 2, "The path is invalid." }; + PreferencesDfxManager::Report(param, EVENT_NAME_PREFERENCES_FAULT); + } } -#else - pref = PreferencesImpl::GetPreferences(options); - errCode = std::static_pointer_cast(pref)->Init(); -#endif + bool isEnhancePreferences = false; + std::shared_ptr pref = nullptr; + errCode = GetPreferencesInner(options, isEnhancePreferences, pref); if (errCode != E_OK) { return nullptr; } @@ -179,6 +206,30 @@ std::shared_ptr PreferencesHelper::GetPreferences(const Options &op return pref; } +std::pair PreferencesHelper::DeletePreferencesCache(const std::string &realPath) +{ + std::string bundleName; + int errCode = E_OK; + std::map, bool>>::iterator it = prefsCache_.find(realPath); + if (it != prefsCache_.end()) { + auto pref = it->second.first; + if (pref != nullptr) { + LOG_INFO("Begin to Delete Preferences: %{public}s", ExtractFileName(realPath).c_str()); + bundleName = pref->GetBundleName(); + if (it->second.second) { + errCode = pref->CloseDb(); + } else { + errCode = std::static_pointer_cast(pref)->Close(); + } + } + if (errCode == E_OK) { + prefsCache_.erase(it); + } + } + + return { bundleName, errCode }; +} + int PreferencesHelper::DeletePreferences(const std::string &path) { int errCode = E_OK; @@ -187,27 +238,16 @@ int PreferencesHelper::DeletePreferences(const std::string &path) return errCode; } - std::string dataGroupId = ""; + std::string bundleName; { std::lock_guard lock(prefsCacheMutex_); - std::map, bool>>::iterator it = prefsCache_.find(realPath); - if (it != prefsCache_.end()) { - auto pref = it->second.first; - if (pref != nullptr) { - LOG_INFO("Begin to Delete Preferences: %{public}s", ExtractFileName(path).c_str()); - dataGroupId = pref->GetGroupId(); - errCode = pref->CloseDb(); - if (errCode != E_OK) { - LOG_ERROR("failed to close db when delete preferences."); - return errCode; - } - } - pref = nullptr; - prefsCache_.erase(it); - LOG_DEBUG("DeletePreferences: found preferences in cache, erase it."); - } else { - LOG_DEBUG("DeletePreferences: cache not found, just delete files."); + auto [ name, code ] = DeletePreferencesCache(realPath); + if (code != E_OK) { + LOG_ERROR("file %{public}s failed to close when delete preferences, errCode is: %{public}d", + ExtractFileName(realPath).c_str(), code); + return code; } + bundleName = name; } std::string filePath = realPath.c_str(); @@ -215,19 +255,24 @@ int PreferencesHelper::DeletePreferences(const std::string &path) std::string brokenPath = MakeFilePath(filePath, STR_BROKEN); std::string lockFilePath = MakeFilePath(filePath, STR_LOCK); - PreferencesFileLock fileLock(lockFilePath, dataGroupId); + bool isMultiProcessing = false; + PreferencesFileLock fileLock(filePath); + fileLock.WriteLock(isMultiProcessing); + if (isMultiProcessing) { + LOG_ERROR("The file has cross-process operations, fileName is %{public}s.", ExtractFileName(filePath).c_str()); + ReportParam param = { bundleName, NORMAL_DB, ExtractFileName(path), + E_OPERAT_IS_CROSS_PROESS, 0, "Cross-process operations exist during file deleting." }; + PreferencesDfxManager::Report(param, EVENT_NAME_PREFERENCES_FAULT); + } std::remove(filePath.c_str()); std::remove(backupPath.c_str()); std::remove(brokenPath.c_str()); + std::remove(lockFilePath.c_str()); if (RemoveEnhanceDbFileIfNeed(path) != E_OK) { return E_DELETE_FILE_FAIL; } - if (!dataGroupId.empty()) { - std::remove(lockFilePath.c_str()); - } - - if (IsFileExist(filePath) || IsFileExist(backupPath) || IsFileExist(brokenPath)) { + if (IsFileExist(filePath) || IsFileExist(backupPath) || IsFileExist(brokenPath) || IsFileExist(lockFilePath)) { return E_DELETE_FILE_FAIL; } return E_OK; @@ -248,17 +293,38 @@ int PreferencesHelper::RemovePreferencesFromCache(const std::string &path) return E_OK; } - if (it->second.second) { - auto pref = it->second.first; - errCode = std::static_pointer_cast(pref)->CloseDb(); - if (errCode != E_OK) { - LOG_ERROR("RemovePreferencesFromCache: failed to close db."); - return E_ERROR; + auto pref = it->second.first; + if (pref != nullptr) { + if (it->second.second) { + errCode = std::static_pointer_cast(pref)->CloseDb(); + if (errCode != E_OK) { + LOG_ERROR("RemovePreferencesFromCache: file %{public}s failed to close db, errCode is %{public}d.", + ExtractFileName(realPath).c_str(), errCode); + return E_ERROR; + } + } else { + std::static_pointer_cast(pref)->Close(); } } prefsCache_.erase(it); return E_OK; } + +bool PreferencesHelper::IsStorageTypeSupported(const StorageType &type) +{ + if (type == StorageType::XML) { + return true; + } + if (type == StorageType::CLKV) { +#if !defined(CROSS_PLATFORM) && defined(ARKDATA_DATABASE_CORE_ENABLE) + return true; +#else + LOG_WARN("CLKV not support this platform."); + return false; +#endif + } + return false; +} } // End of namespace NativePreferences } // End of namespace OHOS \ No newline at end of file diff --git a/preferences/frameworks/native/src/preferences_impl.cpp b/preferences/frameworks/native/src/preferences_impl.cpp index 3d5de80346b784d8f28b1f84996e3f63544a37d9..0e96f96b78ed1690da2cc44fc3464bd8ec87db2b 100644 --- a/preferences/frameworks/native/src/preferences_impl.cpp +++ b/preferences/frameworks/native/src/preferences_impl.cpp @@ -32,6 +32,7 @@ #include "preferences_xml_utils.h" #include "preferences_file_operation.h" #include "preferences_anonymous.h" +#include "preferences_dfx_adapter.h" namespace OHOS { namespace NativePreferences { @@ -40,6 +41,7 @@ using namespace std::chrono; constexpr int32_t WAIT_TIME = 2; constexpr int32_t TASK_EXEC_TIME = 100; +constexpr int32_t LOAD_XML_LOG_TIME = 1000; template std::string GetTypeName() @@ -128,9 +130,10 @@ std::string GetTypeName() PreferencesImpl::PreferencesImpl(const Options &options) : PreferencesBase(options) { loaded_.store(false); - currentMemoryStateGeneration_ = 0; - diskStateGeneration_ = 0; + isNeverUnlock_ = false; + loadResult_= false; queue_ = std::make_shared>(1); + isActive_.store(true); } PreferencesImpl::~PreferencesImpl() @@ -147,7 +150,10 @@ int PreferencesImpl::Init() bool PreferencesImpl::StartLoadFromDisk() { + std::lock_guard lock(mutex_); loaded_.store(false); + isNeverUnlock_ = false; + loadResult_ = false; ExecutorPool::Task task = [pref = shared_from_this()] { PreferencesImpl::LoadFromDisk(pref); }; return (executorPool_.Execute(std::move(task)) == ExecutorPool::INVALID_TASK_ID) ? false : true; @@ -161,18 +167,62 @@ void PreferencesImpl::LoadFromDisk(std::shared_ptr pref) } std::lock_guard lock(pref->mutex_); if (!pref->loaded_.load()) { - bool loadResult = PreferencesImpl::ReadSettingXml(pref); + std::string::size_type pos = pref->options_.filePath.find_last_of('/'); + std::string filePath = pref->options_.filePath.substr(0, pos); + if (Access(filePath) != 0) { + pref->isNeverUnlock_ = true; + } + ConcurrentMap values; + bool loadResult = pref->ReadSettingXml(values); if (!loadResult) { LOG_WARN("The settingXml %{public}s load failed.", ExtractFileName(pref->options_.filePath).c_str()); + } else { + pref->valuesCache_ = std::move(values); + pref->loadResult_ = true; + pref->isNeverUnlock_ = false; } pref->loaded_.store(true); pref->cond_.notify_all(); } } +bool PreferencesImpl::ReloadFromDisk() +{ + if (loadResult_) { + return false; + } + + ConcurrentMap values = valuesCache_; + bool loadResult = ReadSettingXml(values); + LOG_WARN("The settingXml %{public}s reload result is %{public}d", + ExtractFileName(options_.filePath).c_str(), loadResult); + if (loadResult) { + valuesCache_ = std::move(values); + isNeverUnlock_ = false; + loadResult_ = true; + return true; + } + return false; +} + +bool PreferencesImpl::PreLoad() +{ + std::lock_guard lock(mutex_); + if (!loaded_.load()) { + return true; + } + if (isNeverUnlock_ || (!isNeverUnlock_ && !loadResult_)) { + if (Access(options_.filePath) == 0) { + return ReloadFromDisk(); + } + } + return true; +} + void PreferencesImpl::AwaitLoadFile() { if (loaded_.load()) { + PreLoad(); return; } std::unique_lock lock(mutex_); @@ -192,6 +242,7 @@ PreferencesValue PreferencesImpl::Get(const std::string &key, const PreferencesV } AwaitLoadFile(); + IsClose(); auto it = valuesCache_.Find(key); if (it.first) { @@ -203,6 +254,7 @@ PreferencesValue PreferencesImpl::Get(const std::string &key, const PreferencesV std::map PreferencesImpl::GetAll() { AwaitLoadFile(); + IsClose(); return valuesCache_.Clone(); } @@ -283,27 +335,41 @@ bool Convert2PrefValue(const Element &element, std::variant &value) return GetPrefValue(element, value); } -void ReadXmlElement(const Element &element, std::map &prefMap) +void ReadXmlElement(const Element &element, ConcurrentMap &prefConMap) { PreferencesValue value(static_cast(0)); if (Convert2PrefValue(element, value.value_)) { - prefMap.insert(std::make_pair(element.key_, value)); + prefConMap.Insert(element.key_, value); + } +} + +static int64_t GetFileSize(const std::string &path) +{ + int64_t fileSize = -1; + struct stat buffer; + if (stat(path.c_str(), &buffer) == 0) { + fileSize = static_cast(buffer.st_size); } + return fileSize; } -bool PreferencesImpl::ReadSettingXml(std::shared_ptr pref) +bool PreferencesImpl::ReadSettingXml(ConcurrentMap &conMap) { std::vector settings; - if (!PreferencesXmlUtils::ReadSettingXml(pref->options_.filePath, pref->options_.bundleName, - pref->options_.dataGroupId, settings)) { + auto begin = static_cast(duration_cast(system_clock::now().time_since_epoch()).count()); + if (!PreferencesXmlUtils::ReadSettingXml(options_.filePath, options_.bundleName, settings)) { return false; } + auto end = static_cast(duration_cast(system_clock::now().time_since_epoch()).count()); + if (end - begin > LOAD_XML_LOG_TIME) { + LOG_ERROR("The settingXml %{public}s load time exceed 1s, file size:%{public}" PRId64 ".", + ExtractFileName(options_.filePath).c_str(), GetFileSize(options_.filePath)); + } - std::map values; for (const auto &element : settings) { - ReadXmlElement(element, values); + ReadXmlElement(element, conMap); } - pref->valuesCache_ = std::move(values); + return true; } @@ -383,6 +449,26 @@ void WriteXmlElement(Element &elem, const PreferencesValue &value) Convert2Element(elem, value.value_); } +int PreferencesImpl::Close() +{ + isActive_.store(false); + return E_OK; +} + +bool PreferencesImpl::IsClose() +{ + if (isActive_.load()) { + return false; + } + + LOG_WARN("file %{public}s is inactive.", ExtractFileName(options_.filePath).c_str()); + std::string operationMsg = "operation: Invalid operation on the preference instance."; + ReportParam reportParam = { options_.bundleName, NORMAL_DB, ExtractFileName(options_.filePath), + E_OBJECT_NOT_ACTIVE, 0, operationMsg}; + PreferencesDfxManager::ReportAbnormalOperation(reportParam, ReportedFaultBitMap::OBJECT_IS_NOT_ACTIVE); + return true; +} + bool PreferencesImpl::WriteSettingXml( const Options &options, const std::map &writeToDiskMap) { @@ -395,7 +481,7 @@ bool PreferencesImpl::WriteSettingXml( settings.push_back(elem); } - return PreferencesXmlUtils::WriteSettingXml(options.filePath, options.bundleName, options.dataGroupId, settings); + return PreferencesXmlUtils::WriteSettingXml(options.filePath, options.bundleName, settings); } @@ -406,6 +492,7 @@ bool PreferencesImpl::HasKey(const std::string &key) } AwaitLoadFile(); + IsClose(); return valuesCache_.Contains(key); } @@ -420,6 +507,7 @@ int PreferencesImpl::Put(const std::string &key, const PreferencesValue &value) return errCode; } AwaitLoadFile(); + IsClose(); valuesCache_.Compute(key, [this, &value](auto &key, PreferencesValue &val) { if (val == value) { @@ -439,6 +527,7 @@ int PreferencesImpl::Delete(const std::string &key) return errCode; } AwaitLoadFile(); + IsClose(); valuesCache_.EraseIf(key, [this](auto &key, PreferencesValue &val) { modifiedKeys_.push_back(key); return true; @@ -449,6 +538,7 @@ int PreferencesImpl::Delete(const std::string &key) int PreferencesImpl::Clear() { AwaitLoadFile(); + IsClose(); valuesCache_.EraseIf([this](auto &key, PreferencesValue &val) { modifiedKeys_.push_back(key); return true; @@ -476,39 +566,54 @@ int PreferencesImpl::WriteToDiskFile(std::shared_ptr pref) if (!pref->WriteSettingXml(pref->options_, writeToDiskMap)) { return E_ERROR; } + if (pref->isNeverUnlock_) { + pref->isNeverUnlock_ = false; + } + if (!pref->loadResult_) { + pref->loadResult_ = true; + } pref->NotifyPreferencesObserver(keysModified, writeToDiskMap); return E_OK; } void PreferencesImpl::Flush() { + IsClose(); auto success = queue_->PushNoWait(1); - if (success) { - std::weak_ptr> queue = queue_; - ExecutorPool::Task task = [queue, self = weak_from_this()] { - auto realQueue = queue.lock(); - auto realThis = self.lock(); - if (realQueue == nullptr || realThis == nullptr) { - return ; - } - uint64_t value = 0; - std::lock_guard lock(realThis->mutex_); - auto has = realQueue->PopNotWait(value); - if (has && value == 1) { - PreferencesImpl::WriteToDiskFile(realThis); - } - }; - executorPool_.Schedule(std::chrono::milliseconds(TASK_EXEC_TIME), std::move(task)); + if (!success) { + return; } + std::weak_ptr> queue = queue_; + ExecutorPool::Task task = [queue, self = weak_from_this()] { + auto realQueue = queue.lock(); + auto realThis = self.lock(); + if (realQueue == nullptr || realThis == nullptr) { + return; + } + uint64_t value = 0; + if (!realThis->PreLoad()) { + return; + } + std::lock_guard lock(realThis->mutex_); + auto has = realQueue->PopNotWait(value); + if (has && value == 1) { + PreferencesImpl::WriteToDiskFile(realThis); + } + }; + executorPool_.Schedule(std::chrono::milliseconds(TASK_EXEC_TIME), std::move(task)); } int PreferencesImpl::FlushSync() { + IsClose(); auto success = queue_->PushNoWait(1); if (success) { if (queue_ == nullptr) { return E_ERROR; } + if (!PreLoad()) { + return E_OK; + } uint64_t value = 0; std::lock_guard lock(mutex_); auto has = queue_->PopNotWait(value); @@ -527,6 +632,7 @@ std::pair PreferencesImpl::GetValue(const std::string &ke } AwaitLoadFile(); + IsClose(); auto iter = valuesCache_.Find(key); if (iter.first) { return std::make_pair(E_OK, iter.second); @@ -537,6 +643,7 @@ std::pair PreferencesImpl::GetValue(const std::string &ke std::pair> PreferencesImpl::GetAllData() { AwaitLoadFile(); + IsClose(); return std::make_pair(E_OK, valuesCache_.Clone()); } diff --git a/preferences/frameworks/native/src/preferences_xml_utils.cpp b/preferences/frameworks/native/src/preferences_xml_utils.cpp index 43b8657a044087c77ca35b31ed02c80dfa190cfb..5204394ed52b61d13f0bd609350180b059cdffeb 100644 --- a/preferences/frameworks/native/src/preferences_xml_utils.cpp +++ b/preferences/frameworks/native/src/preferences_xml_utils.cpp @@ -64,24 +64,24 @@ static xmlDoc *ReadFile(const std::string &fileName, int &errCode) return doc; } -static void ReportXmlFileIsBroken(const std::string &fileName, const std::string &bundleName, +static void ReportXmlFileCorrupted(const std::string &fileName, const std::string &bundleName, const std::string &operationMsg, int errCode) { - ReportParam reportParam = { bundleName, NORMAL_DB, ExtractFileName(fileName), E_ERROR, errCode, operationMsg }; - PreferencesDfxManager::ReportDbFault(reportParam); + ReportParam reportParam = { bundleName, NORMAL_DB, ExtractFileName(fileName), + E_ERROR, errCode, operationMsg }; + PreferencesDfxManager::Report(reportParam, EVENT_NAME_DB_CORRUPTED); ReportParam succreportParam = reportParam; succreportParam.errCode = E_OK; succreportParam.errnoCode = 0; succreportParam.appendix = "operation: restore success"; - PreferencesDfxManager::ReportDbFault(succreportParam); + PreferencesDfxManager::Report(succreportParam, EVENT_NAME_DB_CORRUPTED); } -static bool RenameFromBackupFile(const std::string &fileName, const std::string &bundleName, - bool &isReportCorrupt, std::string &operationMsg) +static bool RenameFromBackupFile(const std::string &fileName, const std::string &bundleName, bool &isReportCorrupt) { std::string backupFileName = MakeFilePath(fileName, STR_BACKUP); if (!IsFileExist(backupFileName)) { - operationMsg.append("backup file not exist."); + LOG_DEBUG("the backup file does not exist."); return false; } xmlResetLastError(); @@ -95,18 +95,28 @@ static bool RenameFromBackupFile(const std::string &fileName, const std::string ExtractFileName(fileName).c_str(), errCode, errMessage.c_str()); std::remove(backupFileName.c_str()); if (errCode == REQUIRED_KEY_NOT_AVAILABLE || errCode == REQUIRED_KEY_REVOKED) { + std::string operationMsg = "Read bak file when the screen is locked."; + const ReportParam reportParam = { bundleName, NORMAL_DB, ExtractFileName(fileName), + E_OBJECT_NOT_ACTIVE, errCode, operationMsg}; + PreferencesDfxManager::ReportAbnormalOperation(reportParam, ReportedFaultBitMap::USE_WHEN_SCREEN_LOCKED); return false; } - operationMsg.append("backup file corrupt."); isReportCorrupt = true; return false; } if (std::rename(backupFileName.c_str(), fileName.c_str())) { LOG_ERROR("failed to restore backup errno %{public}d.", errno); - operationMsg.append("rename file from backup file failed."); return false; } isReportCorrupt = false; + struct stat fileStats; + if (stat(fileName.c_str(), &fileStats) == -1) { + LOG_ERROR("failed to stat backup file."); + } + std::string appindex = "Restored from the backup. The file size is " + std::to_string(fileStats.st_size) + "."; + const ReportParam reportParam = { bundleName, NORMAL_DB, ExtractFileName(fileName), + E_XML_RESTORED_FROM_BACKUP_FILE, 0, appindex}; + PreferencesDfxManager::ReportAbnormalOperation(reportParam, ReportedFaultBitMap::RESTORE_FROM_BAK); LOG_INFO("restore XML file %{public}s successfully.", ExtractFileName(fileName).c_str()); return true; } @@ -131,52 +141,69 @@ static bool RenameToBrokenFile(const std::string &fileName) return RenameFile(fileName, STR_BROKEN); } -static xmlDoc *XmlReadFile(const std::string &fileName, const std::string &bundleName, const std::string &dataGroupId) +static xmlDoc *XmlReadFile(const std::string &fileName, const std::string &bundleName) { xmlDoc *doc = nullptr; bool isReport = false; - PreferencesFileLock fileLock(MakeFilePath(fileName, STR_LOCK), dataGroupId); + bool isMultiProcessing = false; + PreferencesFileLock fileLock(fileName); + fileLock.ReadLock(isMultiProcessing); int errCode = 0; - std::string operationMsg = "read file: "; + std::string errMessage; if (IsFileExist(fileName)) { + LOG_INFO("read xml file:%{public}s, muti processing status is %{public}d.", ExtractFileName(fileName).c_str(), + isMultiProcessing); doc = ReadFile(fileName, errCode); if (doc != nullptr) { return doc; } xmlErrorPtr xmlErr = xmlGetLastError(); - std::string errMessage = (xmlErr != nullptr) ? xmlErr->message : "null"; + errMessage = (xmlErr != nullptr) ? xmlErr->message : "null"; LOG_ERROR("failed to read XML format file: %{public}s, errno is %{public}d, error is %{public}s.", ExtractFileName(fileName).c_str(), errCode, errMessage.c_str()); if (errCode == REQUIRED_KEY_NOT_AVAILABLE || errCode == REQUIRED_KEY_REVOKED) { + std::string operationMsg = "Read Xml file when the screen is locked."; + const ReportParam reportParam = { bundleName, NORMAL_DB, ExtractFileName(fileName), + E_OPERAT_IS_LOCKED, errCode, operationMsg}; + PreferencesDfxManager::ReportAbnormalOperation(reportParam, ReportedFaultBitMap::USE_WHEN_SCREEN_LOCKED); return nullptr; } if (!RenameToBrokenFile(fileName)) { return doc; } - operationMsg.append("current file corrupt."); isReport = true; } - if (RenameFromBackupFile(fileName, bundleName, isReport, operationMsg)) { - doc = ReadFile(fileName, errCode); + if (RenameFromBackupFile(fileName, bundleName, isReport)) { + int bakErrCode = 0; + doc = ReadFile(fileName, bakErrCode); + xmlErrorPtr xmlErr = xmlGetLastError(); + std::string message = (xmlErr != nullptr) ? xmlErr->message : "null"; + errMessage.append(" bak: errno is " + std::to_string(bakErrCode) + ", errMessage is " + message); } - if (isReport) { - ReportXmlFileIsBroken(fileName, bundleName, operationMsg, errCode); + if (!isMultiProcessing) { + if (isReport) { + const std::string operationMsg = "operation: failed to read XML format file, errMessage:" + errMessage; + ReportXmlFileCorrupted(fileName, bundleName, operationMsg, errCode); + } + } else { + ReportParam param = { bundleName, NORMAL_DB, ExtractFileName(fileName), + E_OPERAT_IS_CROSS_PROESS, errCode, "Cross-process operations exist during file reading." }; + PreferencesDfxManager::Report(param, EVENT_NAME_PREFERENCES_FAULT); } return doc; } /* static */ bool PreferencesXmlUtils::ReadSettingXml(const std::string &fileName, const std::string &bundleName, - const std::string &dataGroupId, std::vector &settings) + std::vector &settings) { - LOG_RECORD_FILE_NAME("Read setting xml start."); if (fileName.size() == 0) { LOG_ERROR("The length of the file name is 0."); return false; } auto doc = - std::shared_ptr(XmlReadFile(fileName, bundleName, dataGroupId), [](xmlDoc *doc) { xmlFreeDoc(doc); }); + std::shared_ptr(XmlReadFile(fileName, bundleName), [](xmlDoc *doc) { xmlFreeDoc(doc); }); if (doc == nullptr) { return false; } @@ -200,9 +227,6 @@ bool PreferencesXmlUtils::ReadSettingXml(const std::string &fileName, const std: break; } } - - /* free the document */ - LOG_RECORD_FILE_NAME("Read setting xml end."); return success; } @@ -329,54 +353,65 @@ static std::pair SaveFormatFileEnc(const std::string &fileName, xmlDo return {xmlSaveFormatFileEnc(fileName.c_str(), doc, "UTF-8", 1) > 0, errno}; } -bool XmlSaveFormatFileEnc( - const std::string &fileName, const std::string &bundleName, const std::string &dataGroupId, xmlDoc *doc) +bool XmlSaveFormatFileEnc(const std::string &fileName, const std::string &bundleName, xmlDoc *doc) { - PreferencesFileLock fileLock(MakeFilePath(fileName, STR_LOCK), dataGroupId); - LOG_INFO("save xml file:%{public}s.", ExtractFileName(fileName).c_str()); + PreferencesFileLock fileLock(fileName); + bool isMultiProcessing = false; + fileLock.WriteLock(isMultiProcessing); + LOG_INFO("save xml file:%{public}s, muti processing status is %{public}d.", ExtractFileName(fileName).c_str(), + isMultiProcessing); if (IsFileExist(fileName) && !RenameToBackupFile(fileName)) { return false; } - bool isReport = false; - std::string operationMsg = "write file: "; auto [ret, errCode] = SaveFormatFileEnc(fileName, doc); if (!ret) { + bool isReport = false; xmlErrorPtr xmlErr = xmlGetLastError(); std::string errMessage = (xmlErr != nullptr) ? xmlErr->message : "null"; LOG_ERROR("failed to save XML format file: %{public}s, errno is %{public}d, error is %{public}s.", ExtractFileName(fileName).c_str(), errCode, errMessage.c_str()); if (errCode == REQUIRED_KEY_NOT_AVAILABLE || errCode == REQUIRED_KEY_REVOKED) { + std::string operationMsg = "Write Xml file when the screen is locked."; + const ReportParam reportParam = { bundleName, NORMAL_DB, ExtractFileName(fileName), + E_OPERAT_IS_LOCKED, errCode, operationMsg}; + PreferencesDfxManager::ReportAbnormalOperation(reportParam, ReportedFaultBitMap::USE_WHEN_SCREEN_LOCKED); return false; } - if (IsFileExist(fileName)) { RenameToBrokenFile(fileName); - operationMsg.append("original file exist."); isReport = true; } - RenameFromBackupFile(fileName, bundleName, isReport, operationMsg); - if (isReport) { - ReportXmlFileIsBroken(fileName, bundleName, operationMsg, errCode); + RenameFromBackupFile(fileName, bundleName, isReport); + if (!isMultiProcessing) { + if (isReport) { + const std::string operationMsg = "operation: failed to save XML format file, errMessage:" + errMessage; + ReportXmlFileCorrupted(fileName, bundleName, operationMsg, errCode); + } + } else { + ReportParam param = { bundleName, NORMAL_DB, ExtractFileName(fileName), + E_OPERAT_IS_CROSS_PROESS, errCode, "Cross-process operations exist during file writing." + }; + PreferencesDfxManager::Report(param, EVENT_NAME_PREFERENCES_FAULT); } return false; } - RemoveBackupFile(fileName); - PreferencesXmlUtils::LimitXmlPermission(fileName); // make sure the file is written to disk. if (!Fsync(fileName)) { LOG_WARN("failed to write the file to the disk."); } + + RemoveBackupFile(fileName); + PreferencesXmlUtils::LimitXmlPermission(fileName); LOG_DEBUG("successfully saved the XML format file"); return true; } /* static */ bool PreferencesXmlUtils::WriteSettingXml(const std::string &fileName, const std::string &bundleName, - const std::string &dataGroupId, const std::vector &settings) + const std::vector &settings) { - LOG_RECORD_FILE_NAME("Write setting xml start."); if (fileName.size() == 0) { LOG_ERROR("The length of the file name is 0."); return false; @@ -414,8 +449,7 @@ bool PreferencesXmlUtils::WriteSettingXml(const std::string &fileName, const std } /* 1: formatting spaces are added. */ - bool result = XmlSaveFormatFileEnc(fileName, bundleName, dataGroupId, doc.get()); - LOG_RECORD_FILE_NAME("Write setting xml end."); + bool result = XmlSaveFormatFileEnc(fileName, bundleName, doc.get()); return result; } @@ -536,5 +570,6 @@ void PreferencesXmlUtils::LimitXmlPermission(const std::string &fileName) } } } + } // End of namespace NativePreferences } // End of namespace OHOS \ No newline at end of file diff --git a/preferences/frameworks/ndk/include/convertor_error_code.h b/preferences/frameworks/ndk/include/oh_convertor.h similarity index 69% rename from preferences/frameworks/ndk/include/convertor_error_code.h rename to preferences/frameworks/ndk/include/oh_convertor.h index 18ebb0758fe24f7ec0bd263df569b8be5fb90dd5..f9bab941c33facc85e3bf638e115010a8d334123 100644 --- a/preferences/frameworks/ndk/include/convertor_error_code.h +++ b/preferences/frameworks/ndk/include/oh_convertor.h @@ -13,18 +13,21 @@ * limitations under the License. */ -#ifndef CONVERTOR_ERROR_CODE_H -#define CONVERTOR_ERROR_CODE_H +#ifndef OH_CONVERTOR_H +#define OH_CONVERTOR_H -namespace OHOS::PreferencesNdk { +#include "oh_preferences_option.h" +#include "preferences.h" -class ConvertorErrorCode final { +namespace OHOS::PreferencesNdk { +class OHConvertor final { public: static int NativeErrToNdk(int nativeErrCode); + static OHOS::NativePreferences::StorageType NdkStorageTypeToNative(const Preferences_StorageType &type); private: - ConvertorErrorCode() = default; - ~ConvertorErrorCode() = default; + OHConvertor() = default; + ~OHConvertor() = default; }; } // namespace OHOS::PreferencesNdk -#endif // CONVERTOR_ERROR_CODE_H \ No newline at end of file +#endif // OH_CONVERTOR_H \ No newline at end of file diff --git a/preferences/frameworks/ndk/include/oh_preferences_impl.h b/preferences/frameworks/ndk/include/oh_preferences_impl.h index 645e3616760200a1d2500dada404936118f0287d..6790dcd5a1bf32509dd0626dfd4d5c304a3f07b7 100644 --- a/preferences/frameworks/ndk/include/oh_preferences_impl.h +++ b/preferences/frameworks/ndk/include/oh_preferences_impl.h @@ -81,13 +81,16 @@ struct OH_PreferencesOption { std::string fileName = ""; std::string bundleName = ""; std::string dataGroupId = ""; - std::shared_mutex opMutex_; int SetFileName(const std::string &str); void SetBundleName(const std::string &str); void SetDataGroupId(const std::string &str); std::string GetFileName(); std::string GetBundleName(); std::string GetDataGroupId(); + Preferences_StorageType storageType = Preferences_StorageType::PREFERENCES_STORAGE_CLKV; + void SetStorageType(const Preferences_StorageType &type); + Preferences_StorageType GetStorageType(); + std::shared_mutex opMutex_; }; class NDKPreferencesUtils { diff --git a/preferences/frameworks/ndk/src/convertor_error_code.cpp b/preferences/frameworks/ndk/src/oh_convertor.cpp similarity index 84% rename from preferences/frameworks/ndk/src/convertor_error_code.cpp rename to preferences/frameworks/ndk/src/oh_convertor.cpp index 435bd8754e75423e101385da09c9d3ea328efac2..d700492484049635c73b13715c65e13fa79bbd47 100644 --- a/preferences/frameworks/ndk/src/convertor_error_code.cpp +++ b/preferences/frameworks/ndk/src/oh_convertor.cpp @@ -13,17 +13,11 @@ * limitations under the License. */ #include -#include "convertor_error_code.h" +#include "oh_convertor.h" #include "oh_preferences_err_code.h" #include "preferences_errno.h" namespace OHOS::PreferencesNdk { - -struct NdkErrCode { - int nativeCode; - int ndkCode; -}; - const std::map ERROR_CODE_MAP = { { OHOS::NativePreferences::E_OK, OH_Preferences_ErrCode::PREFERENCES_OK }, { OHOS::NativePreferences::E_INVALID_ARGS, OH_Preferences_ErrCode::PREFERENCES_ERROR_INVALID_PARAM }, @@ -38,7 +32,7 @@ const std::map ERROR_CODE_MAP = { { OHOS::NativePreferences::E_OBSERVER_RESERVE, OH_Preferences_ErrCode::PREFERENCES_OK } }; -int ConvertorErrorCode::NativeErrToNdk(int nativeCode) +int OHConvertor::NativeErrToNdk(int nativeCode) { auto iter = ERROR_CODE_MAP.find(nativeCode); if (iter != ERROR_CODE_MAP.end()) { @@ -46,4 +40,12 @@ int ConvertorErrorCode::NativeErrToNdk(int nativeCode) } return PREFERENCES_ERROR_STORAGE; } + +OHOS::NativePreferences::StorageType OHConvertor::NdkStorageTypeToNative(const Preferences_StorageType &type) +{ + if (type == Preferences_StorageType::PREFERENCES_STORAGE_CLKV) { + return OHOS::NativePreferences::StorageType::CLKV; + } + return OHOS::NativePreferences::StorageType::XML; +} } \ No newline at end of file diff --git a/preferences/frameworks/ndk/src/oh_preferences.cpp b/preferences/frameworks/ndk/src/oh_preferences.cpp index 180fa4abce2895852cd06e004d4a89066423569a..b713d1c53295face89f3484f7c162c216eb5e672 100644 --- a/preferences/frameworks/ndk/src/oh_preferences.cpp +++ b/preferences/frameworks/ndk/src/oh_preferences.cpp @@ -16,7 +16,7 @@ #include "oh_preferences.h" #include "application_context.h" -#include "convertor_error_code.h" +#include "oh_convertor.h" #include "log_print.h" #include "oh_preferences_err_code.h" #include "oh_preferences_impl.h" @@ -65,11 +65,8 @@ std::pair GetPreferencesDir(OH_PreferencesOption *options) OH_Preferences *OH_Preferences_Open(OH_PreferencesOption *option, int *errCode) { - int err = OH_Preferences_ErrCode::PREFERENCES_OK; - if (option == nullptr || option->fileName.empty() || - !NDKPreferencesUtils::PreferencesStructValidCheck( - option->cid, PreferencesNdkStructId::PREFERENCES_OH_OPTION_CID) || - errCode == nullptr) { + if (option == nullptr || option->fileName.empty() || !NDKPreferencesUtils::PreferencesStructValidCheck( + option->cid, PreferencesNdkStructId::PREFERENCES_OH_OPTION_CID) || errCode == nullptr) { LOG_ERROR("open preference cfg error, option is null: %{public}d, fileName is null: %{public}d, " "errCode is null: %{public}d, err:%{public}d", (option == nullptr), (option == nullptr) ? 1 : option->fileName.empty(), (errCode == nullptr), @@ -87,20 +84,22 @@ OH_Preferences *OH_Preferences_Open(OH_PreferencesOption *option, int *errCode) } std::string filePath = dirRes.second + "/" + option->GetFileName(); + Preferences_StorageType type = option->GetStorageType(); OHOS::NativePreferences::Options nativeOptions(filePath, option->GetBundleName(), - option->GetDataGroupId(), true); + option->GetDataGroupId(), type == PREFERENCES_STORAGE_CLKV); + int nativeErr = OHOS::NativePreferences::E_OK; std::shared_ptr innerPreferences= - OHOS::NativePreferences::PreferencesHelper::GetPreferences(nativeOptions, err); - err = ConvertorErrorCode::NativeErrToNdk(err); - *errCode = err; - if (innerPreferences== nullptr || err != OH_Preferences_ErrCode::PREFERENCES_OK) { + OHOS::NativePreferences::PreferencesHelper::GetPreferences(nativeOptions, nativeErr); + *errCode = OHConvertor::NativeErrToNdk(nativeErr); + if (innerPreferences == nullptr || *errCode != OH_Preferences_ErrCode::PREFERENCES_OK) { LOG_ERROR("Get native Preferences failed: %{public}s, errcode: %{public}d", - OHOS::NativePreferences::ExtractFileName(nativeOptions.filePath).c_str(), err); + OHOS::NativePreferences::ExtractFileName(nativeOptions.filePath).c_str(), *errCode); return nullptr; } OH_PreferencesImpl *preferenceImpl = new (std::nothrow) OH_PreferencesImpl(innerPreferences); if (preferenceImpl == nullptr) { + innerPreferences = nullptr; LOG_ERROR("new impl object failed"); *errCode = OH_Preferences_ErrCode::PREFERENCES_ERROR_MALLOC; return nullptr; @@ -170,7 +169,7 @@ int OH_Preferences_Close(OH_Preferences *preference) preferencesImpl->GetPreferencesStoreFilePath()); if (errCode != OHOS::NativePreferences::E_OK) { LOG_ERROR("preference close failed: %{public}d", errCode); - return ConvertorErrorCode::NativeErrToNdk(errCode); + return OHConvertor::NativeErrToNdk(errCode); } delete preferencesImpl; return OH_Preferences_ErrCode::PREFERENCES_OK; @@ -189,7 +188,7 @@ int OH_Preferences_GetInt(OH_Preferences *preference, const char *key, int *valu auto res = innerPreferences->GetValue(key, OHOS::NativePreferences::PreferencesValue()); if (res.first != OHOS::NativePreferences::E_OK) { LOG_ERROR("Get Int failed, %{public}d", res.first); - return ConvertorErrorCode::NativeErrToNdk(res.first); + return OHConvertor::NativeErrToNdk(res.first); } if (res.second.IsInt()) { @@ -201,7 +200,7 @@ int OH_Preferences_GetInt(OH_Preferences *preference, const char *key, int *valu } } - return ConvertorErrorCode::NativeErrToNdk(res.first); + return OHConvertor::NativeErrToNdk(res.first); } int OH_Preferences_GetString(OH_Preferences *preference, const char *key, char **value, @@ -219,7 +218,7 @@ int OH_Preferences_GetString(OH_Preferences *preference, const char *key, char * auto res = innerPreferences->GetValue(key, OHOS::NativePreferences::PreferencesValue()); if (res.first != OHOS::NativePreferences::E_OK) { LOG_ERROR("Get string failed, %{public}d", res.first); - return ConvertorErrorCode::NativeErrToNdk(res.first); + return OHConvertor::NativeErrToNdk(res.first); } if (res.second.IsString()) { @@ -234,19 +233,19 @@ int OH_Preferences_GetString(OH_Preferences *preference, const char *key, char * LOG_ERROR("malloc failed when get string, errno: %{public}d", errno); return OH_Preferences_ErrCode::PREFERENCES_ERROR_MALLOC; } - *value = (char *)ptr; - int sysErr = memset_s(*value, (strLen + 1), 0, (strLen + 1)); + int sysErr = memset_s(ptr, (strLen + 1), 0, (strLen + 1)); if (sysErr != EOK) { LOG_ERROR("memset failed when get string, errCode: %{public}d", sysErr); } if (strLen > 0) { - sysErr = memcpy_s(*value, strLen, str.c_str(), strLen); + sysErr = memcpy_s(ptr, strLen, str.c_str(), strLen); if (sysErr != EOK) { LOG_ERROR("memcpy failed when get string, errCode: %{public}d", sysErr); free(ptr); return OH_Preferences_ErrCode::PREFERENCES_ERROR_MALLOC; } } + *value = reinterpret_cast(ptr); *valueLen = strLen + 1; } else { LOG_ERROR("Get string failed, value's type is not string, err: %{public}d", res.first); @@ -255,15 +254,11 @@ int OH_Preferences_GetString(OH_Preferences *preference, const char *key, char * } } - return ConvertorErrorCode::NativeErrToNdk(res.first); + return OHConvertor::NativeErrToNdk(res.first); } void OH_Preferences_FreeString(char *string) { - if (string == nullptr) { - LOG_ERROR("free string failed, string is null"); - return; - } free(string); } @@ -280,7 +275,7 @@ int OH_Preferences_GetBool(OH_Preferences *preference, const char *key, bool *va auto res = innerPreferences->GetValue(key, OHOS::NativePreferences::PreferencesValue()); if (res.first != OHOS::NativePreferences::E_OK) { LOG_ERROR("Get bool failed, %{public}d", res.first); - return ConvertorErrorCode::NativeErrToNdk(res.first); + return OHConvertor::NativeErrToNdk(res.first); } if (res.second.IsBool()) { @@ -292,7 +287,7 @@ int OH_Preferences_GetBool(OH_Preferences *preference, const char *key, bool *va } } - return ConvertorErrorCode::NativeErrToNdk(res.first); + return OHConvertor::NativeErrToNdk(res.first); } int OH_Preferences_SetInt(OH_Preferences *preference, const char *key, int value) @@ -308,7 +303,7 @@ int OH_Preferences_SetInt(OH_Preferences *preference, const char *key, int value if (errCode != OHOS::NativePreferences::E_OK) { LOG_ERROR("preference put int failed, err: %{public}d", errCode); } - return ConvertorErrorCode::NativeErrToNdk(errCode); + return OHConvertor::NativeErrToNdk(errCode); } int OH_Preferences_SetBool(OH_Preferences *preference, const char *key, bool value) @@ -324,7 +319,7 @@ int OH_Preferences_SetBool(OH_Preferences *preference, const char *key, bool val if (errCode != OHOS::NativePreferences::E_OK) { LOG_ERROR("preference put bool failed, err: %{public}d", errCode); } - return ConvertorErrorCode::NativeErrToNdk(errCode); + return OHConvertor::NativeErrToNdk(errCode); } int OH_Preferences_SetString(OH_Preferences *preference, const char *key, const char *value) @@ -341,7 +336,7 @@ int OH_Preferences_SetString(OH_Preferences *preference, const char *key, const if (errCode != OHOS::NativePreferences::E_OK) { LOG_ERROR("preference put string failed, err: %{public}d", errCode); } - return ConvertorErrorCode::NativeErrToNdk(errCode); + return OHConvertor::NativeErrToNdk(errCode); } int OH_Preferences_Delete(OH_Preferences *preference, const char *key) @@ -357,7 +352,7 @@ int OH_Preferences_Delete(OH_Preferences *preference, const char *key) if (errCode != OHOS::NativePreferences::E_OK) { LOG_ERROR("preference delete value failed, err: %{public}d", errCode); } - return ConvertorErrorCode::NativeErrToNdk(errCode); + return OHConvertor::NativeErrToNdk(errCode); } int OH_Preferences_RegisterDataObserver(OH_Preferences *preference, void *context, @@ -376,7 +371,7 @@ int OH_Preferences_RegisterDataObserver(OH_Preferences *preference, void *contex keysVec.push_back(keys[i]); } - return ConvertorErrorCode::NativeErrToNdk(preferencesImpl->RegisterDataObserver(observer, context, keysVec)); + return OHConvertor::NativeErrToNdk(preferencesImpl->RegisterDataObserver(observer, context, keysVec)); } int OH_Preferences_UnregisterDataObserver(OH_Preferences *preference, void *context, @@ -393,7 +388,24 @@ int OH_Preferences_UnregisterDataObserver(OH_Preferences *preference, void *cont for (uint32_t i = 0; i < keyCount; i++) { keysVec.push_back(keys[i]); } - return ConvertorErrorCode::NativeErrToNdk(preferencesImpl->UnregisterDataObserver(observer, context, keysVec)); + return OHConvertor::NativeErrToNdk(preferencesImpl->UnregisterDataObserver(observer, context, keysVec)); +} + +int OH_Preferences_IsStorageTypeSupported(Preferences_StorageType type, bool *isSupported) +{ + if (type < Preferences_StorageType::PREFERENCES_STORAGE_XML || + type > Preferences_StorageType::PREFERENCES_STORAGE_CLKV || isSupported == nullptr) { + LOG_ERROR("param check failed, type: %{public}d, isSupported is null: %{public}d", static_cast(type), + isSupported == nullptr); + return OH_Preferences_ErrCode::PREFERENCES_ERROR_INVALID_PARAM; + } + + *isSupported = OHOS::NativePreferences::PreferencesHelper:: + IsStorageTypeSupported(OHConvertor::NdkStorageTypeToNative(type)); + if (!*isSupported) { + LOG_WARN("current type not supported on this platform"); + } + return OH_Preferences_ErrCode::PREFERENCES_OK; } int OH_PreferencesImpl::RegisterDataObserver( @@ -408,7 +420,7 @@ int OH_PreferencesImpl::RegisterDataObserver( } else { dataObservers_.emplace_back(std::make_pair(std::move(ndkObserver), context)); } - return ConvertorErrorCode::NativeErrToNdk(errCode); + return OHConvertor::NativeErrToNdk(errCode); } NDKPreferencesObserver::NDKPreferencesObserver(OH_PreferencesDataObserver observer, void *context) @@ -444,6 +456,7 @@ void NDKPreferencesObserver::OnChange(const std::mapcid = PreferencesNdkStructId::PREFERENCES_OH_VALUE_CID; valueImpl->value_ = value; @@ -471,7 +484,7 @@ int OH_PreferencesImpl::UnregisterDataObserver(OH_PreferencesDataObserver observ int errCode = preferences_->UnRegisterDataObserver(dataObservers_[i].first, keys); if (errCode != OHOS::NativePreferences::E_OK) { LOG_ERROR("un register observer failed, err: %{public}d", errCode); - return ConvertorErrorCode::NativeErrToNdk(errCode); + return OHConvertor::NativeErrToNdk(errCode); } if (keys.empty()) { dataObservers_[i] = { nullptr, nullptr }; diff --git a/preferences/frameworks/ndk/src/oh_preferences_option.cpp b/preferences/frameworks/ndk/src/oh_preferences_option.cpp index e25e68ea55b9e6fbb12cd2e4cd3257b87ac7be81..5c58edd03b91ca8470397c3be9f9dde6710f13f1 100644 --- a/preferences/frameworks/ndk/src/oh_preferences_option.cpp +++ b/preferences/frameworks/ndk/src/oh_preferences_option.cpp @@ -16,8 +16,10 @@ #include "oh_preferences_option.h" #include "log_print.h" +#include "oh_convertor.h" #include "oh_preferences_impl.h" #include "oh_preferences_err_code.h" +#include "preferences_helper.h" using namespace OHOS::PreferencesNdk; @@ -44,18 +46,33 @@ void OH_PreferencesOption::SetDataGroupId(const std::string &str) dataGroupId = str; } +void OH_PreferencesOption::SetStorageType(const Preferences_StorageType &type) +{ + std::unique_lock writeLock(opMutex_); + storageType = type; +} + +Preferences_StorageType OH_PreferencesOption::GetStorageType() +{ + std::shared_lock readLock(opMutex_); + return storageType; +} + std::string OH_PreferencesOption::GetFileName() { + std::shared_lock readLock(opMutex_); return fileName; } std::string OH_PreferencesOption::GetBundleName() { + std::shared_lock readLock(opMutex_); return bundleName; } std::string OH_PreferencesOption::GetDataGroupId() { + std::shared_lock readLock(opMutex_); return dataGroupId; } @@ -67,6 +84,10 @@ OH_PreferencesOption* OH_PreferencesOption_Create(void) return nullptr; } option->cid = PreferencesNdkStructId::PREFERENCES_OH_OPTION_CID; + if (!OHOS::NativePreferences::PreferencesHelper::IsStorageTypeSupported( + OHConvertor::NdkStorageTypeToNative(Preferences_StorageType::PREFERENCES_STORAGE_CLKV))) { + option->SetStorageType(Preferences_StorageType::PREFERENCES_STORAGE_XML); + } return option; } @@ -111,6 +132,23 @@ int OH_PreferencesOption_SetDataGroupId(OH_PreferencesOption *option, const char return OH_Preferences_ErrCode::PREFERENCES_OK; } +int OH_PreferencesOption_SetStorageType(OH_PreferencesOption *option, Preferences_StorageType type) +{ + if (option == nullptr || !NDKPreferencesUtils::PreferencesStructValidCheck( + option->cid, PreferencesNdkStructId::PREFERENCES_OH_OPTION_CID)) { + LOG_ERROR("set option's storage type failed, option is null: %{public}d", (option == nullptr)); + return OH_Preferences_ErrCode::PREFERENCES_ERROR_INVALID_PARAM; + } + if (type < Preferences_StorageType::PREFERENCES_STORAGE_XML || + type > Preferences_StorageType::PREFERENCES_STORAGE_CLKV) { + LOG_ERROR("set option's storage type failed, type invalid: %{public}d", static_cast(type)); + return OH_Preferences_ErrCode::PREFERENCES_ERROR_INVALID_PARAM; + } + + option->SetStorageType(type); + return OH_Preferences_ErrCode::PREFERENCES_OK; +} + int OH_PreferencesOption_Destroy(OH_PreferencesOption* option) { if (option == nullptr || diff --git a/preferences/frameworks/ndk/src/oh_preferences_value.cpp b/preferences/frameworks/ndk/src/oh_preferences_value.cpp index 509c9567955d4c06694695dec46f1e35ba5973ee..0dc0818fe7a00acbfb58ccb901d49b060b6ddfcf 100644 --- a/preferences/frameworks/ndk/src/oh_preferences_value.cpp +++ b/preferences/frameworks/ndk/src/oh_preferences_value.cpp @@ -136,19 +136,20 @@ int OH_PreferencesValue_GetString(const OH_PreferencesValue *object, char **valu LOG_ERROR("malloc failed when value get string, errno: %{public}d", errno); return OH_Preferences_ErrCode::PREFERENCES_ERROR_MALLOC; } - *value = (char *)ptr; - int sysErr = memset_s(*value, (strLen + 1), 0, (strLen + 1)); + + int sysErr = memset_s(ptr, (strLen + 1), 0, (strLen + 1)); if (sysErr != EOK) { - LOG_ERROR("memset failed when get string, errCode: %{public}d", sysErr); + LOG_ERROR("memset failed when value get string, errCode: %{public}d", sysErr); } if (strLen > 0) { - sysErr = memcpy_s(*value, strLen, str.c_str(), strLen); + sysErr = memcpy_s(ptr, strLen, str.c_str(), strLen); if (sysErr != EOK) { LOG_ERROR("memcpy failed when value get string, errCode: %{public}d", sysErr); free(ptr); return OH_Preferences_ErrCode::PREFERENCES_ERROR_MALLOC; } } + *value = reinterpret_cast(ptr); *valueLen = strLen + 1; return OH_Preferences_ErrCode::PREFERENCES_OK; } diff --git a/preferences/interfaces/inner_api/BUILD.gn b/preferences/interfaces/inner_api/BUILD.gn index 0196fe083d8f0ba048da91e3fb563d3076ba10a3..61d5693f9fa30826ccfb643c3c4f7d73cf7d67c5 100644 --- a/preferences/interfaces/inner_api/BUILD.gn +++ b/preferences/interfaces/inner_api/BUILD.gn @@ -70,6 +70,11 @@ if (!is_ohos) { if (is_ohos) { ohos_shared_library("native_preferences") { + defines = [] + if (!defined(global_parts_info) || + defined(global_parts_info.distributeddatamgr_arkdata_database_core)) { + defines += [ "ARKDATA_DATABASE_CORE_ENABLE" ] + } branch_protector_ret = "pac_ret" sanitize = { boundary_sanitize = true @@ -132,10 +137,16 @@ if (is_ohos) { ] if (is_mac) { buildos = "mac" - defines = [ "MAC_PLATFORM" ] + defines = [ + "MAC_PLATFORM", + "CROSS_PLATFORM", + ] } else { buildos = "windows" - defines = [ "WINDOWS_PLATFORM" ] + defines = [ + "WINDOWS_PLATFORM", + "CROSS_PLATFORM", + ] ldflags = [ "-lws2_32" ] } deps = [ @@ -156,7 +167,10 @@ if (is_ohos) { sources = base_sources sources += mock_sources - defines = [ "ANDROID_PLATFORM" ] + defines = [ + "ANDROID_PLATFORM", + "CROSS_PLATFORM", + ] configs = [ ":native_preferences_config" ] configs += [ ":mock_config" ] @@ -176,7 +190,10 @@ if (is_ohos) { all_dependent_configs = [ ":native_preferences_public_config" ] sources = base_sources sources += mock_sources - defines = [ "IOS_PLATFORM" ] + defines = [ + "IOS_PLATFORM", + "CROSS_PLATFORM", + ] configs = [ ":native_preferences_config" ] configs += [ ":mock_config" ] @@ -208,10 +225,16 @@ ohos_static_library("native_preferences_static") { ] if (is_mac) { buildos = "mac" - defines = [ "MAC_PLATFORM" ] + defines = [ + "MAC_PLATFORM", + "CROSS_PLATFORM", + ] } else { buildos = "windows" - defines = [ "WINDOWS_PLATFORM" ] + defines = [ + "WINDOWS_PLATFORM", + "CROSS_PLATFORM", + ] ldflags = [ "-lws2_32" ] } deps = [ @@ -223,6 +246,11 @@ ohos_static_library("native_preferences_static") { ] } else { if (is_ohos) { + defines = [] + if (!defined(global_parts_info) || + defined(global_parts_info.distributeddatamgr_arkdata_database_core)) { + defines += [ "ARKDATA_DATABASE_CORE_ENABLE" ] + } branch_protector_ret = "pac_ret" sanitize = { boundary_sanitize = true diff --git a/preferences/interfaces/inner_api/include/preferences.h b/preferences/interfaces/inner_api/include/preferences.h index 175750b044f2ec3152b2aa3ba3b694fcb19f29c7..b5ba2453bb46e48212bae9f7b17318329820d81d 100644 --- a/preferences/interfaces/inner_api/include/preferences.h +++ b/preferences/interfaces/inner_api/include/preferences.h @@ -29,6 +29,10 @@ namespace OHOS { namespace NativePreferences { using RegisterMode = PreferencesObserver::RegisterMode; +enum StorageType { + XML = 0, + CLKV +}; struct Options { public: Options(const std::string inputFilePath) : filePath(inputFilePath) @@ -420,6 +424,18 @@ public: { return {E_OK, {}}; } + + /** + * @brief Get Bundle Name. + * + * This function is used to Get Bundle Name. + * + * @return Returns the bundleName when it exists, otherwise returns an empty string. + */ + virtual std::string GetBundleName() const + { + return ""; + } }; } // End of namespace NativePreferences } // End of namespace OHOS diff --git a/preferences/interfaces/inner_api/include/preferences_errno.h b/preferences/interfaces/inner_api/include/preferences_errno.h index 1ea6ca2d7718a6b7362d3f2351a0af6e1d61acef..7bd87484e9bbd4ca655cede54aa1b1b38e2cd307 100644 --- a/preferences/interfaces/inner_api/include/preferences_errno.h +++ b/preferences/interfaces/inner_api/include/preferences_errno.h @@ -155,9 +155,34 @@ constexpr int E_OBSERVER_RESERVE = (E_BASE + 20); constexpr int E_ALREADY_CLOSED = (E_BASE + 21); /** -* @brief The error code is used to indicate that database has been closed. +* @brief The error code is used to indicate that the key is not exists. */ constexpr int E_NO_DATA = (E_BASE + 22); + +/** +* @brief This code is used for the XML file restored from backup file. +*/ +constexpr int E_XML_RESTORED_FROM_BACKUP_FILE = (E_BASE + 23); + +/** +* @brief This code is used for operating XML file when the screen os locked. +*/ +constexpr int E_OPERAT_IS_LOCKED = (E_BASE + 24); + +/** +* @brief This code is used for operating XML file when there is a cross process operation. +*/ +constexpr int E_OPERAT_IS_CROSS_PROESS = (E_BASE + 25); + +/** +* @brief This code is subscribe failed. +*/ +constexpr int E_SUBSCRIBE_FAILED = (E_BASE + 26); + +/** +* @brief This code is still operated after the removePreferencesFromCache or deletePreferences operation is performed. +*/ +constexpr int E_OBJECT_NOT_ACTIVE = (E_BASE + 27); } // namespace NativePreferences } // namespace OHOS #endif // PREFERENCES_ERRNO_H diff --git a/preferences/interfaces/inner_api/include/preferences_helper.h b/preferences/interfaces/inner_api/include/preferences_helper.h index 984788f575e80bdf92c5941d59e0df892f04737f..5a631db02ec863814809eaee4cd719144b3e12bb 100644 --- a/preferences/interfaces/inner_api/include/preferences_helper.h +++ b/preferences/interfaces/inner_api/include/preferences_helper.h @@ -68,12 +68,23 @@ public: */ PREF_API_EXPORT static int RemovePreferencesFromCache(const std::string &path); + /** + * @brief Detrmine a {@link StorageType} type is supported or not on current system. + * @param { StorageType } type - Indicates the type of storage that user want to check. + * @returns { boolean } a boolean value indicates this system support the type or not. + */ + PREF_API_EXPORT static bool IsStorageTypeSupported(const StorageType &type); + private: // use bool to mark whether Preferences is EnhancePreferences or not static std::map, bool>> prefsCache_; static std::mutex prefsCacheMutex_; + static std::atomic isReportFault_; static std::string GetRealPath(const std::string &path, int &errorCode); + static int GetPreferencesInner(const Options &options, bool &isEnhancePreferences, + std::shared_ptr &pref); + static std::pair DeletePreferencesCache(const std::string &realPath); }; } // End of namespace NativePreferences } // End of namespace OHOS diff --git a/preferences/interfaces/ndk/BUILD.gn b/preferences/interfaces/ndk/BUILD.gn index 02473bbd824a4385599f9fe9e6caf879bee095d0..50522b17fbb842a287293cef88b4ec707c8ed3e7 100644 --- a/preferences/interfaces/ndk/BUILD.gn +++ b/preferences/interfaces/ndk/BUILD.gn @@ -31,7 +31,7 @@ config("ndk_preferences_public_config") { if (is_ohos) { base_sources = [ - "${preferences_ndk_path}/src/convertor_error_code.cpp", + "${preferences_ndk_path}/src/oh_convertor.cpp", "${preferences_ndk_path}/src/oh_preferences.cpp", "${preferences_ndk_path}/src/oh_preferences_option.cpp", "${preferences_ndk_path}/src/oh_preferences_value.cpp", diff --git a/preferences/interfaces/ndk/include/oh_preferences.h b/preferences/interfaces/ndk/include/oh_preferences.h index c3a56fd957325706b955d94fa3568c5d8a7d1824..992d5f5b664f7d88ef5d648ab00be2bc7752c086 100644 --- a/preferences/interfaces/ndk/include/oh_preferences.h +++ b/preferences/interfaces/ndk/include/oh_preferences.h @@ -264,6 +264,20 @@ int OH_Preferences_RegisterDataObserver(OH_Preferences *preference, void *contex int OH_Preferences_UnregisterDataObserver(OH_Preferences *preference, void *context, OH_PreferencesDataObserver observer, const char *keys[], uint32_t keyCount); +/** + * @brief Check if a type is supported or not. + * + * @param type Pointer to a storage type {@Link Preferences_StorageType}. + * @param isSupported Pointer to the Boolean value obtained. + * true indicates storage type is supported. + * false indicates storage type is not supported. + * @return Returns the status code of the execution. + * {@link PREFERENCES_OK} indicates the operation is successful. + * {@link PREFERENCES_ERROR_INVALID_PARAM} indicates invalid args are passed in. + * @since 16 + */ +int OH_Preferences_IsStorageTypeSupported(Preferences_StorageType type, bool *isSupported); + #ifdef __cplusplus }; #endif diff --git a/preferences/interfaces/ndk/include/oh_preferences_err_code.h b/preferences/interfaces/ndk/include/oh_preferences_err_code.h index 8d72febd0c0011721b8d804b99c5fb4ba32b4385..95f60f6af1e559751b00714598eab66e96ffc9bd 100644 --- a/preferences/interfaces/ndk/include/oh_preferences_err_code.h +++ b/preferences/interfaces/ndk/include/oh_preferences_err_code.h @@ -73,5 +73,5 @@ typedef enum OH_Preferences_ErrCode { #ifdef __cplusplus }; #endif - +/** @} */ #endif // OH_PREFERENCES_ERR_CODE_H \ No newline at end of file diff --git a/preferences/interfaces/ndk/include/oh_preferences_option.h b/preferences/interfaces/ndk/include/oh_preferences_option.h index a8a25af9f55287456e3595803981a3c727390acf..9100f40542804fe103e789b5f72ae002e98fe4d7 100644 --- a/preferences/interfaces/ndk/include/oh_preferences_option.h +++ b/preferences/interfaces/ndk/include/oh_preferences_option.h @@ -52,6 +52,18 @@ extern "C" { */ typedef struct OH_PreferencesOption OH_PreferencesOption; +/** + * @brief Enumerates the preferences storage types. + * + * @since 16 + */ +typedef enum Preferences_StorageType { + /** XML storage*/ + PREFERENCES_STORAGE_XML = 0, + /** CLKV storage */ + PREFERENCES_STORAGE_CLKV +} Preferences_StorageType; + /** * @brief Creates an {@Link OH_PreferencesOption} instance. * @@ -101,6 +113,19 @@ int OH_PreferencesOption_SetBundleName(OH_PreferencesOption *option, const char */ int OH_PreferencesOption_SetDataGroupId(OH_PreferencesOption *option, const char *dataGroupId); +/** + * @brief Sets the storage type in an {@Link OH_PreferencesOption} instance. + * + * @param option Represents a pointer to an {@link OH_PreferencesOption} instance. + * @param type Represents preferences storage type. + * @return Returns the status code of the execution. + * {@link PREFERENCES_OK} success. + * {@link PREFERENCES_ERROR_INVALID_PARAM} indicates invalid args are passed in. + * @see OH_PreferencesOption. + * @since 16 + */ +int OH_PreferencesOption_SetStorageType(OH_PreferencesOption *option, Preferences_StorageType type); + /** * @brief Destroys an {@Link OH_PreferencesOption} instance. * @@ -115,4 +140,5 @@ int OH_PreferencesOption_Destroy(OH_PreferencesOption *option); #ifdef __cplusplus }; #endif +/** @} */ #endif // OH_PREFERENCES_OPTION_H \ No newline at end of file diff --git a/preferences/interfaces/ndk/include/oh_preferences_value.h b/preferences/interfaces/ndk/include/oh_preferences_value.h index 945e28fc62980fe1de55cd342a2f1eb33e3d2bb7..5be471f187269ef8f1dc587217e49c3998364db9 100644 --- a/preferences/interfaces/ndk/include/oh_preferences_value.h +++ b/preferences/interfaces/ndk/include/oh_preferences_value.h @@ -172,4 +172,5 @@ int OH_PreferencesValue_GetString(const OH_PreferencesValue *object, char **valu #ifdef __cplusplus }; #endif +/** @} */ #endif // OH_PREFERENCES_VALUE_H \ No newline at end of file diff --git a/preferences/test/js/unittest/preferences/src/PreferencesSyncJsunit.test.js b/preferences/test/js/unittest/preferences/src/PreferencesSyncJsunit.test.js index b472621e9c5e17d76d239daec82d078505b06733..35bcbe6bcc07b7d3bb55937731e6b36c420df427 100644 --- a/preferences/test/js/unittest/preferences/src/PreferencesSyncJsunit.test.js +++ b/preferences/test/js/unittest/preferences/src/PreferencesSyncJsunit.test.js @@ -351,4 +351,21 @@ describe('preferencesSyncTest', function () { let pre2 = await mPreferences.getSync(KEY_TEST_BIGINT, BigInt(0)); expect(bigint === pre2).assertTrue(); }) + + /** + * @tc.name put String sync and flushSync interface test + * @tc.number SUB_DDM_AppDataFWK_JSPreferences_Preferences_0163 + * @tc.desc put String sync interface test + */ + it('testPreferenceflushSync0163', 0, async function () { + mPreferences.putSync(KEY_TEST_STRING_ELEMENT, 'string'); + let per = mPreferences.getSync(KEY_TEST_STRING_ELEMENT, "defaultvalue"); + expect('string').assertEqual(per); + mPreferences.flushSync(); + data_preferences.removePreferencesFromCacheSync(context, NAME); + mPreferences = null; + mPreferences = data_preferences.getPreferencesSync(context, NAME); + let per2 = mPreferences.getSync(KEY_TEST_STRING_ELEMENT, "defaultvalue"); + expect('string').assertEqual(per2); + }) }) \ No newline at end of file diff --git a/preferences/test/js/unittest/stage_unittest/preferences/src/entry/src/main/ets/test/StagePreferencesSynctest.ets b/preferences/test/js/unittest/stage_unittest/preferences/src/entry/src/main/ets/test/StagePreferencesSynctest.ets index 9bd70c6ff8349744fc24f669c2d874faa2fcfcb1..6c2c95d24a02437f518fdf1a428790e2e3aadce1 100644 --- a/preferences/test/js/unittest/stage_unittest/preferences/src/entry/src/main/ets/test/StagePreferencesSynctest.ets +++ b/preferences/test/js/unittest/stage_unittest/preferences/src/entry/src/main/ets/test/StagePreferencesSynctest.ets @@ -15,14 +15,32 @@ import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; import data_preferences from '@ohos.data.preferences'; +import fs from '@ohos.file.fs'; const TAG = "[stagePreferencesSyncJsTest]" let mPreferences; +let context; + +function isFileExists(path: string) : boolean { + if (!path) { + console.error(TAG, 'path is undefined'); + return false; + } + try { + if (fs.accessSync(path)) { + return true; + } + } catch (err) { + console.error(TAG, 'accessSync failed: ' + JSON.stringify(err)); + } + return false; +} export default function stagePreferencesSyncJsTest() { describe('stagePreferencesSyncJsTest', () =>{ beforeAll(() => { console.log('stagePreferencesSyncJsTest TestAbility context' + globalThis.abilityContext); + context = globalThis.abilityContext; console.info('beforeAll'); }) afterAll(() => { @@ -183,5 +201,211 @@ export default function stagePreferencesSyncJsTest() { expect().assertFail(); } }) - }) + + /** + * @tc.name isStorageTypeSupported + * @tc.number SUB_DDM_AppDataFWK_JSPreferences_Preferences_StorageType_001 + * @tc.desc test StorageType + */ + it('testPreferencesStorageType001', 0, () => { + try { + // normal storage type + console.info(TAG + "enum value of xml: ${data_preferences.StorageType.XML}"); + console.info(TAG + "enum value of clkv: ${data_preferences.StorageType.CLKV}"); + expect(0).assertEqual(data_preferences.StorageType.XML); + expect(1).assertEqual(data_preferences.StorageType.CLKV); + + let isXmlSupported = data_preferences.isStorageTypeSupported(data_preferences.StorageType.XML); + console.info(TAG + "isXmlSupported: ${isXmlSupported}"); + expect(isXmlSupported).assertTrue() + + let isClkvSupported = data_preferences.isStorageTypeSupported(data_preferences.StorageType.CLKV); + console.info(TAG + "isClkvSupported: ${isClkvSupported}"); + expect(isClkvSupported).assertFalse() + + console.info("====>testPreferencesStorageType001 success: part1") + } catch (err) { + console.info("====>testPreferencesStorageType001 throw_err:" + JSON.stringify(err)) + expect().assertFail() + } + // invalid storage type + try { + let boolVar = data_preferences.isStorageTypeSupported(-1); + expect().assertFail(); + } catch (err) { + console.log("try catch err =" + err + ", code =" + err.code +", message =" + err.message); + expect("401").assertEqual(err.code.toString()); + console.info("====>testPreferencesStorageType001 success: part2") + } + try { + let boolVar = data_preferences.isStorageTypeSupported(2); + expect().assertFail(); + } catch (err) { + console.log("try catch err =" + err + ", code =" + err.code +", message =" + err.message); + expect("401").assertEqual(err.code.toString()); + console.info("====>testPreferencesStorageType001 success: part3") + } + }) + + /** + * @tc.name GetPreferencesSync + * @tc.number SUB_DDM_AppDataFWK_JSPreferences_Preferences_StorageType_002 + * @tc.desc test StorageType + */ + it('testPreferencesStorageType002', 0, async() => { + let OptionArray: data_preferences.Options[] = [ + { name: "default_storage_002_1" }, + { name: "default_storage_002_2", dataGroupId: null }, + { name: "default_storage_002_3", storageType: null }, + { name: "default_storage_002_4", storageType: 0 }, + { name: "default_storage_002_5", storageType: data_preferences.StorageType.XML } + ] + let spArray:data_preferences.Preferences[] = [] + for (let i = 0; i < OptionArray.length; i++) { + try { + spArray[i] = data_preferences.getPreferencesSync(context, OptionArray[i]); + expect(spArray[i] != null).assertTrue(); + spArray[i].putSync("key", "value"); + await spArray[i].flush(); + data_preferences.removePreferencesFromCacheSync(context, OptionArray[i]); + } catch (err) { + console.error(TAG + "try put and flush catch err =" + err + ", code =" + err.code + + ", message =" + err.message); + expect().assertFail(); + } + } + for (let i = 0; i < OptionArray.length; i++) { + if (!isFileExists(context.preferencesDir + '/' + OptionArray[i].name)) { + console.error(TAG + 'check file failed: ' + context.preferencesDir + '/' + + OptionArray[i].name); + expect().assertFail(); + } + } + }) + + /** + * @tc.name GetPreferencesSync + * @tc.number SUB_DDM_AppDataFWK_JSPreferences_Preferences_StorageType_004 + * @tc.desc test StorageType + */ + it('testPreferencesStorageType004', 0, async () => { + // not white list + // when xml exists, open again, it should be ok and be xml + // firstly create xml + let sp = await data_preferences.getPreferences(context, + {name: "storage_004_1", storageType: null}); + expect(sp != null).assertTrue(); + sp.putSync("key", "value"); + await sp.flush(); + data_preferences.removePreferencesFromCacheSync(context, + {name: "storage_004_1", storageType: null}); + expect(isFileExists(context.preferencesDir + '/' + "storage_004_1")).assertTrue(); + + // open again + try { + sp = await data_preferences.getPreferences(context, + {name: "storage_004_1", storageType: null}); + expect(sp != null).assertTrue(); + data_preferences.removePreferencesFromCacheSync(context, + {name: "storage_004_1", storageType: null}); + } catch (err) { + console.log("try catch err =" + err + ", code =" + err.code +", message =" + err.message); + expect().assertFail(); + } + }) + + /** + * @tc.name GetPreferencesSync + * @tc.number SUB_DDM_AppDataFWK_JSPreferences_Preferences_StorageType_005 + * @tc.desc test StorageType + */ + it('testPreferencesStorageType005', 0, () => { + // open with xml type but clkv exists + // it should return not supported + // firstly create clkv + let isEnhance = data_preferences.isStorageTypeSupported(data_preferences.StorageType.CLKV); + if (isEnhance) { + const Options : data_preferences.Options = { + name: "storage_005", + storageType: data_preferences.StorageType.CLKV + }; + let sp = data_preferences.getPreferencesSync(context, Options); + expect(sp != null).assertTrue(); + data_preferences.removePreferencesFromCacheSync(context, Options); + expect(isFileExists(context.preferencesDir + '/' + "storage_005.db")).assertTrue(); + const Options2 : data_preferences.Options = { + name: "storage_005", + storageType: data_preferences.StorageType.XML + }; + + // secondly, open with xml type + try { + sp = data_preferences.getPreferencesSync(context, Options2); + expect(sp == null).assertTrue(); + } catch (err) { + console.log("try catch err =" + err + ", code =" + err.code +", message =" + err.message); + console.info("====>testPreferencesStorageType005 success") + } + } + }) + /** + * @tc.name GetPreferencesSync + * @tc.number SUB_DDM_AppDataFWK_JSPreferences_Preferences_StorageType_006 + * @tc.desc test StorageType + */ + it('testPreferencesStorageType006', 0, async () => { + // open with clkv type but xml exists + // it should return not supported + // firstly create xml + const Options : data_preferences.Options = { + name: "storage_006" + } + let sp = await data_preferences.getPreferences(context, Options); + expect(sp != null).assertTrue(); + sp.putSync("key", "value"); + await sp.flush(); + data_preferences.removePreferencesFromCacheSync(context, Options); + expect(isFileExists(context.preferencesDir + '/' + Options.name)).assertTrue(); + + // open with clkv + const Options2 : data_preferences.Options = { + name: "storage_006", + storageType: data_preferences.StorageType.CLKV + } + try { + sp = data_preferences.getPreferencesSync(context, Options2); + expect(sp == null).assertTrue(); + } catch (err) { + console.log("try catch err =" + err + ", code =" + err.code +", message =" + err.message); + console.info("====>testPreferencesStorageType006 success") + } + }) + /** + * @tc.name GetPreferencesSync + * @tc.number SUB_DDM_AppDataFWK_JSPreferences_Preferences_StorageType_007 + * @tc.desc test StorageType + */ + it('testPreferencesStorageType007', 0, () => { + // open with clkv type and open again + // firstly create clkv + let isEnhance = data_preferences.isStorageTypeSupported(data_preferences.StorageType.CLKV); + if (isEnhance) { + try { + const Options : data_preferences.Options = { + name: "storage_007", + storageType: data_preferences.StorageType.CLKV + }; + let sp = data_preferences.getPreferencesSync(context, Options); + expect(sp != null).assertTrue(); + data_preferences.removePreferencesFromCacheSync(context, Options); + + sp = data_preferences.getPreferencesSync(context, Options); + expect(sp != null).assertTrue(); + data_preferences.removePreferencesFromCacheSync(context, Options); + } catch (err) { + console.log("try catch err =" + err + ", code =" + err.code +", message =" + err.message); + expect().assertFail(); + } + } + }) } diff --git a/preferences/test/native/BUILD.gn b/preferences/test/native/BUILD.gn index fbd0b67d15275795d1cce5b1c77801f2426b92d4..375a25b1655d896bf0e6a4356f0b561d122915a9 100644 --- a/preferences/test/native/BUILD.gn +++ b/preferences/test/native/BUILD.gn @@ -21,6 +21,7 @@ config("module_private_config") { include_dirs = [ "${preferences_native_path}/include/", + "${preferences_native_path}/platform/include/", "${preferences_innerapi_path}/include", "${preferences_base_path}/frameworks/common/include", ] @@ -39,6 +40,7 @@ ohos_unittest("NativePreferencesTest") { "unittest/base64_helper_test.cpp", "unittest/preferences_file_test.cpp", "unittest/preferences_helper_test.cpp", + "unittest/preferences_storage_type_test.cpp", "unittest/preferences_test.cpp", "unittest/preferences_xml_utils_test.cpp", ] diff --git a/preferences/test/native/unittest/preferences_file_test.cpp b/preferences/test/native/unittest/preferences_file_test.cpp index fb03834c89c9361f24a15c1c21254af3bf15daa9..f3a607cfa2de7de113f4e2a7ff6a7e7bdceb6579 100644 --- a/preferences/test/native/unittest/preferences_file_test.cpp +++ b/preferences/test/native/unittest/preferences_file_test.cpp @@ -21,6 +21,7 @@ #include "log_print.h" #include "preferences.h" #include "preferences_errno.h" +#include "preferences_file_operation.h" #include "preferences_helper.h" #include "preferences_xml_utils.h" @@ -82,7 +83,7 @@ HWTEST_F(PreferencesFileTest, NativePreferencesFileTest_001, TestSize.Level1) elem.tag_ = std::string("int"); elem.value_ = std::to_string(10); settings.push_back(elem); - PreferencesXmlUtils::WriteSettingXml(backupFile, "", "", settings); + PreferencesXmlUtils::WriteSettingXml(backupFile, "", settings); int errCode = E_OK; std::shared_ptr pref = PreferencesHelper::GetPreferences(file, errCode); @@ -250,4 +251,223 @@ HWTEST_F(PreferencesFileTest, NativePreferencesFileTest_004, TestSize.Level3) ret = PreferencesHelper::DeletePreferences("/data/test/test_helper"); EXPECT_EQ(ret, E_OK); } + +/** + * @tc.name: NativePreferencesFileTest_005 + * @tc.desc: normal testcase of fallback logic + * @tc.type: FUNC + */ +HWTEST_F(PreferencesFileTest, NativePreferencesFileTest_005, TestSize.Level1) +{ + std::string path = "/data/test/file_test005"; + std::string file = path + "/test"; + int ret = PreferencesHelper::DeletePreferences(file); + EXPECT_EQ(ret, E_OK); + + int errCode = E_OK; + std::shared_ptr pref = PreferencesHelper::GetPreferences(file, errCode); + EXPECT_EQ(errCode, E_OK); + ret = pref->GetInt("intKey", 0); + EXPECT_EQ(ret, 0); + ret = pref->GetInt("intKey1", 0); + EXPECT_EQ(ret, 0); + pref->PutInt("intKey", 2); + + OHOS::NativePreferences::Mkdir(path); + std::vector settings; + Element elem; + elem.key_ = "intKey"; + elem.tag_ = std::string("int"); + elem.value_ = std::to_string(10); + Element elem1; + elem1.key_ = "intKey1"; + elem1.tag_ = std::string("int"); + elem1.value_ = std::to_string(10); + settings.push_back(elem); + settings.push_back(elem1); + PreferencesXmlUtils::WriteSettingXml(file, "", settings); + + ret = pref->GetInt("intKey", 0); + EXPECT_EQ(ret, 2); + ret = pref->GetInt("intKey1", 0); + EXPECT_EQ(ret, 10); + + pref = nullptr; + ret = PreferencesHelper::DeletePreferences(file); + EXPECT_EQ(ret, E_OK); + rmdir(path.c_str()); +} + +/** + * @tc.name: NativePreferencesFileTest_006 + * @tc.desc: normal testcase of fallback logic + * @tc.type: FUNC + */ +HWTEST_F(PreferencesFileTest, NativePreferencesFileTest_006, TestSize.Level1) +{ + std::string path = "/data/test/file_test006"; + std::string file = path + "/test"; + int ret = PreferencesHelper::DeletePreferences(file); + EXPECT_EQ(ret, E_OK); + + int errCode = E_OK; + std::shared_ptr pref = PreferencesHelper::GetPreferences(file, errCode); + EXPECT_EQ(errCode, E_OK); + EXPECT_EQ(false, pref->HasKey("intKey")); + EXPECT_EQ(false, pref->HasKey("intKey1")); + pref->PutInt("intKey", 2); + + OHOS::NativePreferences::Mkdir(path); + std::vector settings; + Element elem; + elem.key_ = "intKey"; + elem.tag_ = std::string("int"); + elem.value_ = std::to_string(20); + Element elem1; + elem1.key_ = "intKey1"; + elem1.tag_ = std::string("int"); + elem1.value_ = std::to_string(20); + settings.push_back(elem); + settings.push_back(elem1); + PreferencesXmlUtils::WriteSettingXml(file, "", settings); + + pref->FlushSync(); + + std::vector settingsRes = {}; + bool res = PreferencesXmlUtils::ReadSettingXml(file, "", settingsRes); + EXPECT_EQ(res, true); + EXPECT_EQ(settingsRes.empty(), false); + EXPECT_EQ(elem.key_, settingsRes[0].key_); + EXPECT_EQ(elem.tag_, settingsRes[0].tag_); + EXPECT_EQ(std::to_string(2), settingsRes[0].value_); + + EXPECT_EQ(elem1.key_, settingsRes[1].key_); + EXPECT_EQ(elem1.tag_, settingsRes[1].tag_); + EXPECT_EQ(elem1.value_, settingsRes[1].value_); + + pref = nullptr; + ret = PreferencesHelper::DeletePreferences(file); + EXPECT_EQ(ret, E_OK); + rmdir(path.c_str()); +} + +/** + * @tc.name: NativePreferencesFileTest_007 + * @tc.desc: normal testcase of fallback logic + * @tc.type: FUNC + */ +HWTEST_F(PreferencesFileTest, NativePreferencesFileTest_007, TestSize.Level1) +{ + std::string file = "/data/test/test"; + int ret = PreferencesHelper::DeletePreferences(file); + EXPECT_EQ(ret, E_OK); + + int errCode = E_OK; + std::shared_ptr pref = PreferencesHelper::GetPreferences(file, errCode); + EXPECT_EQ(errCode, E_OK); + pref->PutInt("intKey", 7); + + std::vector settings; + Element elem; + elem.key_ = "intKey"; + elem.tag_ = std::string("int"); + elem.value_ = std::to_string(70); + Element elem1; + elem1.key_ = "intKey1"; + elem1.tag_ = std::string("int"); + elem1.value_ = std::to_string(70); + settings.push_back(elem); + settings.push_back(elem1); + PreferencesXmlUtils::WriteSettingXml(file, "", settings); + + ret = pref->GetInt("intKey", 0); + EXPECT_EQ(ret, 7); + ret = pref->GetInt("intKey1", 0); + EXPECT_EQ(ret, 70); + + pref = nullptr; + ret = PreferencesHelper::DeletePreferences(file); + EXPECT_EQ(ret, E_OK); +} + +/** + * @tc.name: NativePreferencesFileTest_008 + * @tc.desc: normal testcase of fallback logic + * @tc.type: FUNC + */ +HWTEST_F(PreferencesFileTest, NativePreferencesFileTest_008, TestSize.Level1) +{ + std::string file = "/data/test/test"; + int ret = PreferencesHelper::DeletePreferences(file); + EXPECT_EQ(ret, E_OK); + + int errCode = E_OK; + std::shared_ptr pref = PreferencesHelper::GetPreferences(file, errCode); + EXPECT_EQ(errCode, E_OK); + EXPECT_EQ(false, pref->HasKey("intKey")); + EXPECT_EQ(false, pref->HasKey("intKey1")); + pref->PutInt("intKey", 8); + + std::vector settings; + Element elem; + elem.key_ = "intKey"; + elem.tag_ = std::string("int"); + elem.value_ = std::to_string(80); + Element elem1; + elem1.key_ = "intKey1"; + elem1.tag_ = std::string("int"); + elem1.value_ = std::to_string(80); + settings.push_back(elem); + settings.push_back(elem1); + PreferencesXmlUtils::WriteSettingXml(file, "", settings); + + pref->FlushSync(); + + std::vector settingsRes = {}; + bool res = PreferencesXmlUtils::ReadSettingXml(file, "", settingsRes); + EXPECT_EQ(res, true); + EXPECT_EQ(settingsRes.empty(), false); + EXPECT_EQ(elem.key_, settingsRes[0].key_); + EXPECT_EQ(elem.tag_, settingsRes[0].tag_); + EXPECT_EQ(std::to_string(8), settingsRes[0].value_); + + EXPECT_EQ(elem1.key_, settingsRes[1].key_); + EXPECT_EQ(elem1.tag_, settingsRes[1].tag_); + EXPECT_EQ(elem1.value_, settingsRes[1].value_); + + pref = nullptr; + ret = PreferencesHelper::DeletePreferences(file); + EXPECT_EQ(ret, E_OK); +} + +/** + * @tc.name: NativePreferencesFileTest_009 + * @tc.desc: normal testcase of fallback logic + * @tc.type: FUNC + */ +HWTEST_F(PreferencesFileTest, NativePreferencesFileTest_009, TestSize.Level1) +{ + std::string file = "/data/test/test"; + int ret = PreferencesHelper::DeletePreferences(file); + EXPECT_EQ(ret, E_OK); + + int errCode = E_OK; + std::shared_ptr pref = PreferencesHelper::GetPreferences(file, errCode); + EXPECT_EQ(errCode, E_OK); + pref->PutInt("intKey", 9); + + pref->FlushSync(); + + std::vector settingsRes = {}; + bool res = PreferencesXmlUtils::ReadSettingXml(file, "", settingsRes); + EXPECT_EQ(res, true); + EXPECT_EQ(settingsRes.empty(), false); + EXPECT_EQ("intKey", settingsRes[0].key_); + EXPECT_EQ(std::string("int"), settingsRes[0].tag_); + EXPECT_EQ(std::to_string(9), settingsRes[0].value_); + + pref = nullptr; + ret = PreferencesHelper::DeletePreferences(file); + EXPECT_EQ(ret, E_OK); +} } diff --git a/preferences/test/native/unittest/preferences_helper_test.cpp b/preferences/test/native/unittest/preferences_helper_test.cpp index b930532e3cd7ace79e63dcc68025cd9c726601a3..c1ee5e1567794cbf0fca3c21927a4013f8813b75 100644 --- a/preferences/test/native/unittest/preferences_helper_test.cpp +++ b/preferences/test/native/unittest/preferences_helper_test.cpp @@ -148,4 +148,18 @@ HWTEST_F(PreferencesHelperTest, NativePreferencesHelperTest_005, TestSize.Level1 EXPECT_EQ(preferences, nullptr); preferences = nullptr; } + +/** + * @tc.name: NativePreferencesHelperTest_006 + * @tc.desc: error testcase of GetRealPath + * @tc.type: FUNC + */ +HWTEST_F(PreferencesHelperTest, NativePreferencesHelperTest_006, TestSize.Level1) +{ + Options option = Options("/data/test/preferences/test01", "", ""); + int errCode = E_OK; + std::shared_ptr preferences = PreferencesHelper::GetPreferences(option, errCode); + EXPECT_EQ(errCode, E_OK); + preferences = nullptr; +} } diff --git a/preferences/test/native/unittest/preferences_test.cpp b/preferences/test/native/unittest/preferences_test.cpp index 8ade6d4b231ac6747dad93148a4f69670152d011..2a9efb7f3547600e2bbee81ba6a9b775d2a1b924 100644 --- a/preferences/test/native/unittest/preferences_test.cpp +++ b/preferences/test/native/unittest/preferences_test.cpp @@ -174,6 +174,7 @@ HWTEST_F(PreferencesTest, NativePreferencesGroupIdTest_001, TestSize.Level1) std::shared_ptr preferences = PreferencesHelper::GetPreferences(option, errCode); EXPECT_EQ(errCode, E_OK); EXPECT_EQ(preferences->GetGroupId(), "2002001"); + EXPECT_EQ(preferences->GetBundleName(), "ohos.test.demo"); preferences = nullptr; int ret = PreferencesHelper::DeletePreferences("/data/test/test1"); @@ -1000,6 +1001,29 @@ HWTEST_F(PreferencesTest, NativePreferencesTest_032, TestSize.Level1) EXPECT_EQ(static_cast(counter.get())->notifyTimes, 1); } +/** + * @tc.name: NativePreferencesTest_033 + * @tc.desc: RegisterObserver testing + * @tc.type: FUNC + */ +HWTEST_F(PreferencesTest, NativePreferencesTest_033, TestSize.Level1) +{ + vector> counters; + for (int i = 0; i <= 50; i++) { + std::shared_ptr counter = std::make_shared(); + counters.push_back(counter); + int ret = pref->RegisterObserver(counter, RegisterMode::MULTI_PRECESS_CHANGE); + EXPECT_EQ(ret, E_OK); + } + std::shared_ptr counter = std::make_shared(); + int ret = pref->RegisterObserver(counter, RegisterMode::MULTI_PRECESS_CHANGE); + EXPECT_NE(ret, E_OK); + for (auto counter : counters) { + ret = pref->UnRegisterObserver(counter, RegisterMode::MULTI_PRECESS_CHANGE); + EXPECT_EQ(ret, E_OK); + } +} + /** * @tc.name: OperatorTest_001 * @tc.desc: normal testcase of PreferencesValue Operator diff --git a/preferences/test/native/unittest/preferences_xml_utils_test.cpp b/preferences/test/native/unittest/preferences_xml_utils_test.cpp index 987690ba816a871f90e775762d50df5799ad0b3f..9bb98f336488db234f18a08bd4cc9a86b814bda5 100644 --- a/preferences/test/native/unittest/preferences_xml_utils_test.cpp +++ b/preferences/test/native/unittest/preferences_xml_utils_test.cpp @@ -61,14 +61,14 @@ void PreferencesXmlUtilsTest::TearDown(void) HWTEST_F(PreferencesXmlUtilsTest, ReadSettingXmlTest_001, TestSize.Level1) { std::vector settings = {}; - bool ret = PreferencesXmlUtils::ReadSettingXml("", "", "", settings); + bool ret = PreferencesXmlUtils::ReadSettingXml("", "", settings); EXPECT_EQ(ret, false); std::string path = "/data/test/test_helper" + std::string(4096, 't'); - ret = PreferencesXmlUtils::ReadSettingXml(path, "", "", settings); + ret = PreferencesXmlUtils::ReadSettingXml(path, "", settings); EXPECT_EQ(ret, false); - ret = PreferencesXmlUtils::ReadSettingXml("data/test/test_helper", "", "", settings); + ret = PreferencesXmlUtils::ReadSettingXml("data/test/test_helper", "", settings); EXPECT_EQ(ret, false); } @@ -107,10 +107,10 @@ HWTEST_F(PreferencesXmlUtilsTest, ReadSettingXmlTest_003, TestSize.Level1) elem.tag_ = "int"; elem.value_ = "999"; settings.push_back(elem); - PreferencesXmlUtils::WriteSettingXml(file, "", "123456", settings); + PreferencesXmlUtils::WriteSettingXml(file, "", settings); std::vector settingsRes = {}; - bool ret = PreferencesXmlUtils::ReadSettingXml(file, "", "123456", settingsRes); + bool ret = PreferencesXmlUtils::ReadSettingXml(file, "", settingsRes); EXPECT_EQ(ret, true); EXPECT_EQ(settingsRes.empty(), false); EXPECT_EQ(elem.key_, settingsRes.front().key_); @@ -128,22 +128,22 @@ HWTEST_F(PreferencesXmlUtilsTest, ReadSettingXmlTest_003, TestSize.Level1) HWTEST_F(PreferencesXmlUtilsTest, UnnormalReadSettingXml_001, TestSize.Level1) { std::vector settings = {}; - PreferencesXmlUtils::WriteSettingXml("", "", "", settings); - bool ret = PreferencesXmlUtils::ReadSettingXml("", "", "", settings); + PreferencesXmlUtils::WriteSettingXml("", "", settings); + bool ret = PreferencesXmlUtils::ReadSettingXml("", "", settings); EXPECT_EQ(ret, false); std::string path = "/data/test/test_helper" + std::string(4096, 't'); - ret = PreferencesXmlUtils::ReadSettingXml(path, "", "", settings); + ret = PreferencesXmlUtils::ReadSettingXml(path, "", settings); EXPECT_EQ(ret, false); - ret = PreferencesXmlUtils::ReadSettingXml("data/test/test_helper", "", "", settings); + ret = PreferencesXmlUtils::ReadSettingXml("data/test/test_helper", "", settings); EXPECT_EQ(ret, false); Element elem; settings.push_back(elem); path = "data/test/test_helper"; - PreferencesXmlUtils::WriteSettingXml(path, "", "", settings); - ret = PreferencesXmlUtils::ReadSettingXml(path, "", "", settings); + PreferencesXmlUtils::WriteSettingXml(path, "", settings); + ret = PreferencesXmlUtils::ReadSettingXml(path, "", settings); EXPECT_EQ(ret, false); } @@ -163,7 +163,7 @@ HWTEST_F(PreferencesXmlUtilsTest, StringNodeElementTest_001, TestSize.Level1) elem.tag_ = std::string("string"); elem.value_ = "test"; settings.push_back(elem); - PreferencesXmlUtils::WriteSettingXml(file, "", "", settings); + PreferencesXmlUtils::WriteSettingXml(file, "", settings); int errCode = E_OK; std::shared_ptr pref = PreferencesHelper::GetPreferences(file, errCode); @@ -201,7 +201,7 @@ HWTEST_F(PreferencesXmlUtilsTest, ArrayNodeElementTest_001, TestSize.Level1) elem.children_.push_back(elemChild); settings.push_back(elem); std::vector inputStringArray = { "test_child1", "test_child2" }; - PreferencesXmlUtils::WriteSettingXml(file, "", "", settings); + PreferencesXmlUtils::WriteSettingXml(file, "", settings); int errCode = E_OK; std::shared_ptr pref = PreferencesHelper::GetPreferences(file, errCode); @@ -241,7 +241,7 @@ HWTEST_F(PreferencesXmlUtilsTest, ArrayNodeElementTest_002, TestSize.Level1) elem.children_.push_back(elemChild); settings.push_back(elem); std::vector inputDoubleArray = { 1.0, 2.0 }; - PreferencesXmlUtils::WriteSettingXml(file, "", "", settings); + PreferencesXmlUtils::WriteSettingXml(file, "", settings); int errCode = E_OK; std::shared_ptr pref = PreferencesHelper::GetPreferences(file, errCode); @@ -281,7 +281,7 @@ HWTEST_F(PreferencesXmlUtilsTest, ArrayNodeElementTest_003, TestSize.Level1) elem.children_.push_back(elemChild); settings.push_back(elem); std::vector inputBoolArray = { false, true }; - PreferencesXmlUtils::WriteSettingXml(file, "", "", settings); + PreferencesXmlUtils::WriteSettingXml(file, "", settings); int errCode = E_OK; std::shared_ptr pref = PreferencesHelper::GetPreferences(file, errCode); @@ -309,9 +309,9 @@ HWTEST_F(PreferencesXmlUtilsTest, ArrayNodeElementTest_004, TestSize.Level1) elem.key_ = "boolArrayKey"; elem.tag_ = std::string("boolArray"); elem.value_ = std::to_string(false); - + settings.push_back(elem); - PreferencesXmlUtils::WriteSettingXml(file, "", "", settings); + PreferencesXmlUtils::WriteSettingXml(file, "", settings); int errCode = E_OK; std::shared_ptr pref = PreferencesHelper::GetPreferences(file, errCode); @@ -343,7 +343,7 @@ HWTEST_F(PreferencesXmlUtilsTest, ArrayNodeElementTest_005, TestSize.Level1) elem.value_ = std::to_string(false); settings.push_back(elem); - PreferencesXmlUtils::WriteSettingXml(file, "", "", settings); + PreferencesXmlUtils::WriteSettingXml(file, "", settings); int errCode = E_OK; std::shared_ptr pref = PreferencesHelper::GetPreferences(file, errCode); @@ -373,9 +373,9 @@ HWTEST_F(PreferencesXmlUtilsTest, ArrayNodeElementTest_006, TestSize.Level1) elem.key_ = "doubleArrayKey"; elem.tag_ = std::string("doubleArray"); elem.value_ = std::to_string(1); - + settings.push_back(elem); - PreferencesXmlUtils::WriteSettingXml(file, "", "", settings); + PreferencesXmlUtils::WriteSettingXml(file, "", settings); int errCode = E_OK; std::shared_ptr pref = PreferencesHelper::GetPreferences(file, errCode); @@ -409,7 +409,7 @@ HWTEST_F(PreferencesXmlUtilsTest, RenameToBrokenFileTest_001, TestSize.Level1) elem.value_ = "2"; settings.push_back(elem); - PreferencesXmlUtils::WriteSettingXml(MakeFilePath(fileName, STR_BACKUP), "", "", settings); + PreferencesXmlUtils::WriteSettingXml(MakeFilePath(fileName, STR_BACKUP), "", settings); int errCode = E_OK; std::shared_ptr pref = PreferencesHelper::GetPreferences(fileName, errCode); @@ -438,7 +438,7 @@ HWTEST_F(PreferencesXmlUtilsTest, ReadSettingXmlTest_004, TestSize.Level1) ossBak << "corruptedBak"; std::vector settings; - bool res = PreferencesXmlUtils::ReadSettingXml(fileName, "", "", settings); + bool res = PreferencesXmlUtils::ReadSettingXml(fileName, "", settings); EXPECT_EQ(res, false); int ret = PreferencesHelper::DeletePreferences(fileName); @@ -460,10 +460,40 @@ HWTEST_F(PreferencesXmlUtilsTest, WriteSettingXmlWhenFileIsNotExistTest_001, Tes elem.value_ = ""; settings.push_back(elem); - bool result = PreferencesXmlUtils::WriteSettingXml("/data/test/preferences/test01", "", "", settings); + bool result = PreferencesXmlUtils::WriteSettingXml("/data/test/preferences/test01", "", settings); EXPECT_EQ(result, false); - result = PreferencesXmlUtils::WriteSettingXml(fileName, "", "", settings); + result = PreferencesXmlUtils::WriteSettingXml(fileName, "", settings); EXPECT_EQ(result, true); } + +/** +* @tc.name: ReadSettingXmlTest_005 +* @tc.desc: Restore testcase of PreferencesXmlUtils +* @tc.type: FUNC +*/ +HWTEST_F(PreferencesXmlUtilsTest, ReadSettingXmlTest_005, TestSize.Level1) +{ + std::string fileName = "/data/test/test01"; + std::string bakFileName = "/data/test/test01.bak"; + // construct an unreadable file + std::ofstream oss(fileName); + oss << "corrupted"; + + std::vector settings; + Element elem; + elem.key_ = "stringKey"; + elem.tag_ = "string"; + elem.value_ = ""; + + settings.push_back(elem); + bool result = PreferencesXmlUtils::WriteSettingXml(MakeFilePath(fileName, STR_BACKUP), "", settings); + EXPECT_EQ(result, true); + + bool res = PreferencesXmlUtils::ReadSettingXml(fileName, "", settings); + EXPECT_EQ(res, true); + + int ret = PreferencesHelper::DeletePreferences(fileName); + EXPECT_EQ(ret, E_OK); +} } diff --git a/preferences/test/ndk/BUILD.gn b/preferences/test/ndk/BUILD.gn index f3cecbf9eca75d9402e4f5b19220b483aaabeef0..0fe19acefcbb6fe9ebaf3793aa40db557a26788e 100644 --- a/preferences/test/ndk/BUILD.gn +++ b/preferences/test/ndk/BUILD.gn @@ -33,6 +33,11 @@ config("module_private_config") { } ohos_unittest("NDKPreferencesTest") { + defines = [] + if (!defined(global_parts_info) || + defined(global_parts_info.distributeddatamgr_arkdata_database_core)) { + defines += [ "ARKDATA_DATABASE_CORE_ENABLE" ] + } branch_protector_ret = "pac_ret" sanitize = { cfi = true @@ -59,11 +64,12 @@ ohos_unittest("NDKPreferencesTest") { "${preferences_native_path}/src/preferences_value.cpp", "${preferences_native_path}/src/preferences_value_parcel.cpp", "${preferences_native_path}/src/preferences_xml_utils.cpp", - "${preferences_ndk_path}/src/convertor_error_code.cpp", + "${preferences_ndk_path}/src/oh_convertor.cpp", "${preferences_ndk_path}/src/oh_preferences.cpp", "${preferences_ndk_path}/src/oh_preferences_option.cpp", "${preferences_ndk_path}/src/oh_preferences_value.cpp", "mock/application_context.cpp", + "unittest/preferences_ndk_storage_type_test.cpp", "unittest/preferences_ndk_test.cpp", "unittest/preferences_ndk_value_test.cpp", "unittest/preferences_test_utils.cpp", diff --git a/preferences/test/ndk/unittest/preferences_ndk_storage_type_test.cpp b/preferences/test/ndk/unittest/preferences_ndk_storage_type_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ea5c28fe775670fb293ca9b1a4b6ec3eacad15e --- /dev/null +++ b/preferences/test/ndk/unittest/preferences_ndk_storage_type_test.cpp @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2024 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log_print.h" +#include "preferences_test_utils.h" +#include "oh_preferences_impl.h" +#include "oh_preferences.h" +#include "oh_preferences_err_code.h" +#include "oh_preferences_value.h" +#include "oh_preferences_option.h" +#include "preferences_helper.h" + +using namespace testing::ext; +using namespace testing; +using namespace OHOS::PreferencesNdk; +using namespace OHOS::NativePreferences; +namespace { + +const std::string TEST_PATH = "/data/test/"; + +class PreferencesNdkStorageTypeTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void PreferencesNdkStorageTypeTest::SetUpTestCase(void) +{ + NdkTestUtils::CreateDirectoryRecursively(TEST_PATH); +} +void PreferencesNdkStorageTypeTest::TearDownTestCase(void) {} + +void PreferencesNdkStorageTypeTest::SetUp(void) +{ + NdkTestUtils::CreateDirectoryRecursively(TEST_PATH); +} + +void PreferencesNdkStorageTypeTest::TearDown(void) {} + +static bool IsFileExist(const std::string &path) +{ + struct stat buffer; + return (stat(path.c_str(), &buffer) == 0); +} + +/** + * @tc.name: NDKStorageTypeBaseTest_001 + * @tc.desc: test api OH_Preferences_IsStorageTypeSupported + * @tc.type: FUNC + * @tc.require: NA + * @tc.author: huangboxin + */ +HWTEST_F(PreferencesNdkStorageTypeTest, NDKStorageTypeBaseTest_001, TestSize.Level1) +{ + bool isSupport = false; + int errCode = OH_Preferences_IsStorageTypeSupported(Preferences_StorageType::PREFERENCES_STORAGE_XML, &isSupport); + ASSERT_EQ(errCode, PREFERENCES_OK); + ASSERT_EQ(isSupport, true); + + errCode = OH_Preferences_IsStorageTypeSupported(Preferences_StorageType::PREFERENCES_STORAGE_CLKV, &isSupport); + ASSERT_EQ(errCode, PREFERENCES_OK); + ASSERT_EQ(isSupport, false); + + errCode = OH_Preferences_IsStorageTypeSupported( + static_cast(Preferences_StorageType::PREFERENCES_STORAGE_XML - 1), &isSupport); + ASSERT_EQ(errCode, PREFERENCES_ERROR_INVALID_PARAM); + + errCode = OH_Preferences_IsStorageTypeSupported( + static_cast(Preferences_StorageType::PREFERENCES_STORAGE_CLKV + 1), &isSupport); + ASSERT_EQ(errCode, PREFERENCES_ERROR_INVALID_PARAM); +} + +/** + * @tc.name: NDKStorageTypeBaseTest_002 + * @tc.desc: test storage type when default which is not setting storage type + * @tc.type: FUNC + * @tc.require: NA + * @tc.author: huangboxin + */ +HWTEST_F(PreferencesNdkStorageTypeTest, NDKStorageTypeBaseTest_002, TestSize.Level1) +{ + // without setting storage type + // it should be xml when not in enhance by default, or clkv in enhance + OH_PreferencesOption *option = OH_PreferencesOption_Create(); + const char *fileName = "CStorageTypeTest002"; + ASSERT_EQ(OH_PreferencesOption_SetFileName(option, fileName), PREFERENCES_OK); + int errCode = PREFERENCES_OK; + OH_Preferences *pref = OH_Preferences_Open(option, &errCode); + ASSERT_EQ(errCode, PREFERENCES_OK); + (void)OH_PreferencesOption_Destroy(option); + ASSERT_EQ(OH_Preferences_SetInt(pref, "key", 2), PREFERENCES_OK); + EXPECT_EQ(OH_Preferences_Close(pref), PREFERENCES_OK); + + bool isEnhance = false; + errCode = OH_Preferences_IsStorageTypeSupported(Preferences_StorageType::PREFERENCES_STORAGE_CLKV, &isEnhance); + ASSERT_EQ(errCode, PREFERENCES_OK); + if (isEnhance) { + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName) + ".db"), true); + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName)), false); + } else { + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName) + ".db"), false); + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName)), true); + } + ASSERT_EQ(OHOS::NativePreferences::PreferencesHelper::DeletePreferences(TEST_PATH + std::string(fileName)), + OHOS::NativePreferences::E_OK); +} + +/** + * @tc.name: NDKStorageTypeXMLTest_003 + * @tc.desc: test storage type when new with xml, and open with xml when xml exists + * @tc.type: FUNC + * @tc.require: NA + * @tc.author: huangboxin + */ +HWTEST_F(PreferencesNdkStorageTypeTest, NDKStorageTypeXMLTest_003, TestSize.Level1) +{ + // new with xml storage type + // it should be xml in enhance or not + OH_PreferencesOption *option = OH_PreferencesOption_Create(); + const char *fileName = "CStorageTypeTest003"; + ASSERT_EQ(OH_PreferencesOption_SetFileName(option, fileName), PREFERENCES_OK); + bool isXmlSupported = false; + ASSERT_EQ(OH_Preferences_IsStorageTypeSupported(Preferences_StorageType::PREFERENCES_STORAGE_XML, &isXmlSupported), + PREFERENCES_OK); + ASSERT_EQ(isXmlSupported, true); + ASSERT_EQ(OH_PreferencesOption_SetStorageType(option, Preferences_StorageType::PREFERENCES_STORAGE_XML), + PREFERENCES_OK); + int errCode = PREFERENCES_OK; + OH_Preferences *pref = OH_Preferences_Open(option, &errCode); + ASSERT_EQ(errCode, PREFERENCES_OK); + ASSERT_EQ(OH_Preferences_SetInt(pref, "key", 2), PREFERENCES_OK); + ASSERT_EQ(OH_Preferences_Close(pref), PREFERENCES_OK); + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName) + ".db"), false); + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName)), true); + + // xml exists, open in xml mode + pref = OH_Preferences_Open(option, &errCode); + ASSERT_EQ(errCode, PREFERENCES_OK); + ASSERT_EQ(OH_Preferences_Close(pref), PREFERENCES_OK); + (void)OH_PreferencesOption_Destroy(option); + + ASSERT_EQ(OHOS::NativePreferences::PreferencesHelper::DeletePreferences(TEST_PATH + std::string(fileName)), + OHOS::NativePreferences::E_OK); +} + +/** + * @tc.name: NDKStorageTypeXMLTest_003 + * @tc.desc: test storage type when clkv exists and open with xml + * @tc.type: FUNC + * @tc.require: NA + * @tc.author: huangboxin + */ +HWTEST_F(PreferencesNdkStorageTypeTest, NDKStorageTypeXMLTest_004, TestSize.Level1) +{ + // clkv exists, open in xml mode, should return invalid_args + // create fake clkv firstly + OH_PreferencesOption *option = OH_PreferencesOption_Create(); + const char *fileName = "CStorageTypeTest004"; + ASSERT_EQ(OH_PreferencesOption_SetFileName(option, "CStorageTypeTest004.db"), PREFERENCES_OK); + ASSERT_EQ(OH_PreferencesOption_SetStorageType(option, Preferences_StorageType::PREFERENCES_STORAGE_XML), + PREFERENCES_OK); + int errCode = PREFERENCES_OK; + OH_Preferences *pref = OH_Preferences_Open(option, &errCode); + ASSERT_EQ(errCode, PREFERENCES_OK); + ASSERT_EQ(OH_Preferences_SetInt(pref, "key", 2), PREFERENCES_OK); + ASSERT_EQ(OH_Preferences_Close(pref), PREFERENCES_OK); + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName) + ".db"), true); + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName)), false); + + + // open in xml mode + ASSERT_EQ(OH_PreferencesOption_SetFileName(option, fileName), PREFERENCES_OK); + pref = OH_Preferences_Open(option, &errCode); + ASSERT_EQ(errCode, PREFERENCES_ERROR_NOT_SUPPORTED); + + (void)OH_PreferencesOption_Destroy(option); +} + +/** + * @tc.name: NDKStorageTypeCLKVTest_005 + * @tc.desc: test storage type when new with clkv + * @tc.type: FUNC + * @tc.require: NA + * @tc.author: huangboxin + */ +HWTEST_F(PreferencesNdkStorageTypeTest, NDKStorageTypeCLKVTest_005, TestSize.Level1) +{ + // new with clkv mode + OH_PreferencesOption *option = OH_PreferencesOption_Create(); + const char *fileName = "CStorageTypeTest005"; + ASSERT_EQ(OH_PreferencesOption_SetFileName(option, fileName), PREFERENCES_OK); + + bool isEnhance = false; + int errCode = OH_Preferences_IsStorageTypeSupported(Preferences_StorageType::PREFERENCES_STORAGE_CLKV, &isEnhance); + ASSERT_EQ(errCode, PREFERENCES_OK); + + if (isEnhance) { + ASSERT_EQ(OH_PreferencesOption_SetStorageType(option, Preferences_StorageType::PREFERENCES_STORAGE_CLKV), + PREFERENCES_OK); + OH_Preferences *pref = OH_Preferences_Open(option, &errCode); + ASSERT_EQ(errCode, PREFERENCES_OK); + ASSERT_EQ(OH_Preferences_SetInt(pref, "key", 2), PREFERENCES_OK); + ASSERT_EQ(OH_Preferences_Close(pref), PREFERENCES_OK); + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName) + ".db"), true); + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName)), false); + } else { + ASSERT_EQ(OH_PreferencesOption_SetStorageType(option, Preferences_StorageType::PREFERENCES_STORAGE_CLKV), + PREFERENCES_OK); + (void)OH_Preferences_Open(option, &errCode); + ASSERT_EQ(errCode, PREFERENCES_ERROR_NOT_SUPPORTED); + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName) + ".db"), false); + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName)), false); + } + (void)OH_PreferencesOption_Destroy(option); + ASSERT_EQ(OHOS::NativePreferences::PreferencesHelper::DeletePreferences(TEST_PATH + std::string(fileName)), + OHOS::NativePreferences::E_OK); +} + +/** + * @tc.name: NDKStorageTypeCLKVTest_006 + * @tc.desc: test storage type when xml exists but open with clkv + * @tc.type: FUNC + * @tc.require: NA + * @tc.author: huangboxin + */ +HWTEST_F(PreferencesNdkStorageTypeTest, NDKStorageTypeCLKVTest_006, TestSize.Level1) +{ + // xml exists but open with clkv + // create xml firstly + OH_PreferencesOption *option = OH_PreferencesOption_Create(); + const char *fileName = "CStorageTypeTest006"; + ASSERT_EQ(OH_PreferencesOption_SetFileName(option, fileName), PREFERENCES_OK); + ASSERT_EQ(OH_PreferencesOption_SetStorageType(option, Preferences_StorageType::PREFERENCES_STORAGE_XML), + PREFERENCES_OK); + int errCode = PREFERENCES_OK; + OH_Preferences *pref = OH_Preferences_Open(option, &errCode); + ASSERT_EQ(errCode, PREFERENCES_OK); + ASSERT_EQ(OH_Preferences_SetInt(pref, "key", 2), PREFERENCES_OK); + ASSERT_EQ(OH_Preferences_Close(pref), PREFERENCES_OK); + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName) + ".db"), false); + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName)), true); + + // open with clkv + bool isEnhance = false; + errCode = OH_Preferences_IsStorageTypeSupported(Preferences_StorageType::PREFERENCES_STORAGE_CLKV, &isEnhance); + ASSERT_EQ(errCode, PREFERENCES_OK); + if (isEnhance) { + ASSERT_EQ(OH_PreferencesOption_SetStorageType(option, Preferences_StorageType::PREFERENCES_STORAGE_CLKV), + PREFERENCES_OK); + pref = OH_Preferences_Open(option, &errCode); + ASSERT_EQ(errCode, PREFERENCES_ERROR_NOT_SUPPORTED); + } else { + ASSERT_EQ(OH_PreferencesOption_SetStorageType(option, Preferences_StorageType::PREFERENCES_STORAGE_CLKV), + PREFERENCES_OK); + pref = OH_Preferences_Open(option, &errCode); + ASSERT_EQ(errCode, PREFERENCES_ERROR_NOT_SUPPORTED); + } + + (void)OH_PreferencesOption_Destroy(option); + ASSERT_EQ(OHOS::NativePreferences::PreferencesHelper::DeletePreferences(TEST_PATH + std::string(fileName)), + OHOS::NativePreferences::E_OK); +} + +/** + * @tc.name: NDKStorageTypeCLKVTest_007 + * @tc.desc: test storage type when clkv exists but open with clkv + * @tc.type: FUNC + * @tc.require: NA + * @tc.author: huangboxin + */ +HWTEST_F(PreferencesNdkStorageTypeTest, NDKStorageTypeCLKVTest_007, TestSize.Level1) +{ + // clkv exists, open in clkv mode + bool isEnhance = false; + int errCode = OH_Preferences_IsStorageTypeSupported(Preferences_StorageType::PREFERENCES_STORAGE_CLKV, &isEnhance); + ASSERT_EQ(errCode, PREFERENCES_OK); + OH_PreferencesOption *option = OH_PreferencesOption_Create(); + if (isEnhance) { + // create clkv firstly + const char *fileName = "CStorageTypeTest007"; + ASSERT_EQ(OH_PreferencesOption_SetFileName(option, fileName), PREFERENCES_OK); + ASSERT_EQ(OH_PreferencesOption_SetStorageType(option, Preferences_StorageType::PREFERENCES_STORAGE_CLKV), + PREFERENCES_OK); + OH_Preferences *pref = OH_Preferences_Open(option, &errCode); + ASSERT_EQ(errCode, PREFERENCES_OK); + ASSERT_EQ(OH_Preferences_SetInt(pref, "key", 2), PREFERENCES_OK); + ASSERT_EQ(OH_Preferences_Close(pref), PREFERENCES_OK); + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName) + ".db"), true); + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName)), false); + + // open again + pref = OH_Preferences_Open(option, &errCode); + ASSERT_EQ(errCode, PREFERENCES_OK); + ASSERT_EQ(OH_Preferences_Close(pref), PREFERENCES_OK); + } else { + // create fake clkv firstly + const char *fileName = "CStorageTypeTest007Fake.db"; + ASSERT_EQ(OH_PreferencesOption_SetFileName(option, fileName), PREFERENCES_OK); + // xml by default when not enhance + OH_Preferences *pref = OH_Preferences_Open(option, &errCode); + ASSERT_EQ(errCode, PREFERENCES_OK); + ASSERT_EQ(OH_Preferences_SetInt(pref, "key", 2), PREFERENCES_OK); + ASSERT_EQ(OH_Preferences_Close(pref), PREFERENCES_OK); + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName) + ".db"), false); + ASSERT_EQ(IsFileExist(TEST_PATH + std::string(fileName)), true); + + // open again + ASSERT_EQ(OH_PreferencesOption_SetStorageType(option, Preferences_StorageType::PREFERENCES_STORAGE_CLKV), + PREFERENCES_OK); + pref = OH_Preferences_Open(option, &errCode); + ASSERT_EQ(errCode, PREFERENCES_ERROR_NOT_SUPPORTED); + } + (void)OH_PreferencesOption_Destroy(option); + ASSERT_EQ(OHOS::NativePreferences::PreferencesHelper::DeletePreferences(TEST_PATH + "CStorageTypeTest007"), + OHOS::NativePreferences::E_OK); + ASSERT_EQ(OHOS::NativePreferences::PreferencesHelper::DeletePreferences(TEST_PATH + "CStorageTypeTest007Fake.db"), + OHOS::NativePreferences::E_OK); +} +} // namespace diff --git a/preferences/test/ndk/unittest/preferences_ndk_test.cpp b/preferences/test/ndk/unittest/preferences_ndk_test.cpp index dc42af4e0c0b650de1dbd56ebf73bac0480bb0cf..a56b37ceb3fb80eb79ad965cc50849bc0428d358 100644 --- a/preferences/test/ndk/unittest/preferences_ndk_test.cpp +++ b/preferences/test/ndk/unittest/preferences_ndk_test.cpp @@ -729,6 +729,8 @@ void NullTestCallback(void *context, const OH_PreferencesPair *pairs, uint32_t c */ HWTEST_F(PreferencesNdkTest, NDKPreferencesNullInputTest_001, TestSize.Level1) { + OH_Preferences_FreeString(nullptr); + int errCode = PREFERENCES_OK; OH_PreferencesOption *option = OH_PreferencesOption_Create(); diff --git a/preferences/test/ndk/unittest/preferences_test_utils.cpp b/preferences/test/ndk/unittest/preferences_test_utils.cpp index 1c6bf3468a0bd5b19f4ba19b830a69a2892a9e9f..48262b1ac58e672e886b9da0c552e72f7c85bfac 100644 --- a/preferences/test/ndk/unittest/preferences_test_utils.cpp +++ b/preferences/test/ndk/unittest/preferences_test_utils.cpp @@ -15,7 +15,7 @@ #include "preferences_test_utils.h" #include "oh_preferences.h" -#include "convertor_error_code.h" +#include "oh_convertor.h" #include "log_print.h" #include "oh_preferences_err_code.h" #include "oh_preferences_impl.h" diff --git a/relational_store/bundle.json b/relational_store/bundle.json index 76fc0b31c8808ccffcfb30177ce476e6ddda4b46..654a5b8fa12c2d57bba84dc2d3e4d4fcedd8e701 100644 --- a/relational_store/bundle.json +++ b/relational_store/bundle.json @@ -3,9 +3,8 @@ "version": "3.1.0", "description": "Local Data Management", "homePage": "https://gitee.com/openharmony", - "license": "Apache V2", + "license": "Apache-2.0", "repository": "https://gitee.com/openharmony/distributeddatamgr_relational_store", - "domain": "ohos", "language": "", "publishAs": "code-segment", "private": false, @@ -13,10 +12,6 @@ "tags": [ "foundation" ], - "keywords": [ - "distributeddatamgr", - "relational_store" - ], "envs": [], "dirs": {}, "author": { @@ -67,10 +62,13 @@ "napi", "samgr", "hisysevent", - "bounds_checking_function" + "bounds_checking_function", + "icu", + "sqlite", + "file_api", + "json" ], "third_party": [ - "icu", "sqlite" ] }, @@ -89,7 +87,10 @@ "//foundation/distributeddatamgr/relational_store/frameworks/js/napi/relationalstore:relationalstore", "//foundation/distributeddatamgr/relational_store/frameworks/js/napi/cloud_extension:cloudextension", "//foundation/distributeddatamgr/relational_store/frameworks/js/napi/common:commontype_napi", - "//foundation/distributeddatamgr/relational_store/frameworks/js/napi/sendablerelationalstore:sendablerelationalstore" + "//foundation/distributeddatamgr/relational_store/frameworks/js/napi/sendablerelationalstore:sendablerelationalstore", + "//foundation/distributeddatamgr/relational_store/frameworks/native/icu:build_module", + "//foundation/distributeddatamgr/relational_store/interfaces/inner_api/gdb:framework_graphstore", + "//foundation/distributeddatamgr/relational_store/frameworks/js/napi/graphstore:graphstore" ], "inner_kits": [ { @@ -165,6 +166,18 @@ ], "header_base": "//foundation/distributeddatamgr/relational_store/interfaces/inner_api/rdb_data_ability_adapter/include" } + }, + { + "name": "//foundation/distributeddatamgr/relational_store/interfaces/inner_api/cloud_data:cloud_data_inner", + "visibility": [ "datamgr_service" ], + "header": { + "header_files": [ + "cloud_manager.h", + "cloud_service.h", + "cloud_types.h" + ], + "header_base": "//foundation/distributeddatamgr/relational_store/interfaces/inner_api/cloud_data/include" + } } ], "test": [ @@ -182,7 +195,11 @@ "//foundation/distributeddatamgr/relational_store/test/native/rdb:fuzztest", "//foundation/distributeddatamgr/relational_store/test/native/rdb_data_ability_adapter:unittest", "//foundation/distributeddatamgr/relational_store/test/native/rdb_data_share_adapter:unittest", - "//foundation/distributeddatamgr/relational_store/test/native/rdb:distributedtest" + "//foundation/distributeddatamgr/relational_store/test/native/rdb:distributedtest", + "//foundation/distributeddatamgr/relational_store/test/native/gdb:unittest", + "//foundation/distributeddatamgr/relational_store/test/native/gdb:fuzztest", + "//foundation/distributeddatamgr/relational_store/test/js/gdb:performancetest", + "//foundation/distributeddatamgr/relational_store/test/js/gdb:unittest" ] } } diff --git a/relational_store/frameworks/cj/include/relational_store_impl_rdbstore.h b/relational_store/frameworks/cj/include/relational_store_impl_rdbstore.h index 762ca4ea3d87270b0190c99b81923d14ae867747..b2edd3f34a1c95a47e3a825c9f060f98a0b04bd6 100644 --- a/relational_store/frameworks/cj/include/relational_store_impl_rdbstore.h +++ b/relational_store/frameworks/cj/include/relational_store_impl_rdbstore.h @@ -62,16 +62,16 @@ public: std::function *GetCallBack(); private: - std::function *m_callback; - std::function m_callbackRef; + std::function *m_callback = nullptr; + std::function m_callbackRef = nullptr; int32_t mode_ = DistributedRdb::REMOTE; - int64_t callbackId; - FuncType funcType; - std::function func; - std::function &devices)> carrStrFunc; + int64_t callbackId = 0; + FuncType funcType = NoParam; + std::function func = nullptr; + std::function &devices)> carrStrFunc = nullptr; std::function - changeInfoFunc; + changeInfoFunc = nullptr; }; class SyncObserverImpl : public DistributedRdb::DetailProgressObserver { diff --git a/relational_store/frameworks/cj/src/relational_store_impl_rdbstore.cpp b/relational_store/frameworks/cj/src/relational_store_impl_rdbstore.cpp index b9da00a1f00373e9aa95cd1f41c51a66ce7d76d6..a331f5cb1fcdea0eaf70825242f4c29548486db9 100644 --- a/relational_store/frameworks/cj/src/relational_store_impl_rdbstore.cpp +++ b/relational_store/frameworks/cj/src/relational_store_impl_rdbstore.cpp @@ -712,6 +712,10 @@ namespace Relational { int64_t GetRdbStore(OHOS::AbilityRuntime::Context* context, StoreConfig config, int32_t *errCode) { + if (context == nullptr) { + *errCode = -1; + return -1; + } auto abilitycontext = std::make_shared(context->shared_from_this()); AppDataMgrJsKit::JSUtils::ContextParam param; initContextParam(param, abilitycontext); @@ -740,6 +744,10 @@ namespace Relational { void DeleteRdbStore(OHOS::AbilityRuntime::Context* context, const char* name, int32_t *errCode) { + if (context == nullptr) { + *errCode = -1; + return; + } auto abilitycontext = std::make_shared(context->shared_from_this()); AppDataMgrJsKit::JSUtils::ContextParam param; initContextParam(param, abilitycontext); @@ -757,6 +765,10 @@ namespace Relational { void DeleteRdbStoreConfig(OHOS::AbilityRuntime::Context* context, StoreConfig config, int32_t *errCode) { + if (context == nullptr) { + *errCode = -1; + return; + } auto abilitycontext = std::make_shared(context->shared_from_this()); AppDataMgrJsKit::JSUtils::ContextParam param; initContextParam(param, abilitycontext); diff --git a/relational_store/frameworks/cj/src/relational_store_utils.cpp b/relational_store/frameworks/cj/src/relational_store_utils.cpp index a6e2795de0259ada5a4aeb0799655da47661c013..bf7df7f7f242d1eaf76b4c933ae012d27ef4fc68 100644 --- a/relational_store/frameworks/cj/src/relational_store_utils.cpp +++ b/relational_store/frameworks/cj/src/relational_store_utils.cpp @@ -222,7 +222,7 @@ namespace Relational { for (size_t i = 0; i < devices.size(); i++) { cArrStr.head[i] = MallocCString(devices[i]); } - cArrStr.size = devices.size(); + cArrStr.size = static_cast(devices.size()); return cArrStr; } @@ -281,7 +281,7 @@ namespace Relational { ModifyTime MapToModifyTime(std::map &map, int32_t &errCode) { ModifyTime modifyTime{0}; - modifyTime.size = map.size(); + modifyTime.size = static_cast(map.size()); modifyTime.key = static_cast(malloc(sizeof(RetPRIKeyType) * modifyTime.size)); modifyTime.value = static_cast(malloc(sizeof(uint64_t) * modifyTime.size)); if (modifyTime.key == nullptr || modifyTime.value == nullptr) { @@ -293,7 +293,7 @@ namespace Relational { int64_t index = 0; for (auto it = map.begin(); it != map.end(); ++it) { modifyTime.key[index] = VariantToRetPRIKeyType(it->first); - modifyTime.value[index] = (it->second).date; + modifyTime.value[index] = static_cast((it->second).date); index++; } return modifyTime; @@ -312,7 +312,7 @@ namespace Relational { for (size_t i = 0; i < arr.size(); i++) { types.head[i] = VariantToRetPRIKeyType(arr[i]); } - types.size = arr.size(); + types.size = static_cast(arr.size()); return types; } @@ -348,7 +348,7 @@ namespace Relational { infos.head[index] = ToRetChangeInfo(origin, it); index++; } - infos.size = changeInfo.size(); + infos.size = static_cast(changeInfo.size()); return infos; } diff --git a/relational_store/frameworks/common/include/logger.h b/relational_store/frameworks/common/include/logger.h index 821f0e6e95104cc10996eda08f59eff84879e32a..848ebc57d7396d0190c09b04600f66031e27af29 100644 --- a/relational_store/frameworks/common/include/logger.h +++ b/relational_store/frameworks/common/include/logger.h @@ -39,6 +39,20 @@ static inline OHOS::HiviewDFX::HiLogLabel LogLabel() return { LOG_CORE, 0xD001650, "SRdb" }; } } // namespace Rdb + +namespace GraphStoreJsKit { +static inline OHOS::HiviewDFX::HiLogLabel LogLabel() +{ + return { LOG_CORE, 0xD001660, "GdbJS" }; +} +} // namespace GraphStoreJsKit + +namespace DistributedDataAip { +static inline OHOS::HiviewDFX::HiLogLabel LogLabel() +{ + return { LOG_CORE, 0xD001660, "GdbNative" }; +} +} // namespace DistributedDataAip } // namespace OHOS #define LOG_DEBUG(fmt, ...) \ diff --git a/relational_store/frameworks/js/napi/cloud_data/src/entry_point.cpp b/relational_store/frameworks/js/napi/cloud_data/src/entry_point.cpp index ab267123fb7a7d18a4abba8df2114b2e6476e14e..a42d468588105f3e572f4a45b6a3bb4b234958ce 100644 --- a/relational_store/frameworks/js/napi/cloud_data/src/entry_point.cpp +++ b/relational_store/frameworks/js/napi/cloud_data/src/entry_point.cpp @@ -26,13 +26,13 @@ static napi_value Init(napi_env env, napi_value exports) { auto sharingExport = InitCloudSharing(env, exports); napi_status status = InitSharingConstProperties(env, sharingExport); - LOG_INFO("init Enumerate Constants of Sharing: %{public}d", status); + LOG_INFO("Init Enumerate Constants of Sharing: %{public}d", status); exports = JsConfig::InitConfig(env, exports); status = InitConstProperties(env, exports); - LOG_INFO("init Enumerate Constants of Config: %{public}d", status); + LOG_INFO("Init Enumerate Constants of Config: %{public}d", status); exports = InitClient(env, exports); status = InitClientProperties(env, exports); - LOG_INFO("init Enumerate Constants of Client: %{public}d", status); + LOG_INFO("Init Enumerate Constants of Client: %{public}d", status); return exports; } @@ -46,5 +46,5 @@ static __attribute__((constructor)) void RegisterModule() .nm_priv = ((void *)0), .reserved = { 0 } }; napi_module_register(&module); - LOG_INFO("module register data.cloudData"); + LOG_INFO("Module register data.cloudData"); } diff --git a/relational_store/frameworks/js/napi/cloud_data/src/js_cloud_share.cpp b/relational_store/frameworks/js/napi/cloud_data/src/js_cloud_share.cpp index 3d2f79d2f7209214da5a2c33fa18bda60c547467..bc7a7b493eef08e5514a752c861427e0dbcb2686 100644 --- a/relational_store/frameworks/js/napi/cloud_data/src/js_cloud_share.cpp +++ b/relational_store/frameworks/js/napi/cloud_data/src/js_cloud_share.cpp @@ -141,7 +141,7 @@ napi_value Share(napi_env env, napi_callback_info info) return; } int32_t result = proxy->Share(ctxt->sharingRes, ctxt->participants, ctxt->results); - LOG_DEBUG("share result %{public}d", result); + LOG_DEBUG("Share result %{public}d", result); ctxt->status = (GenerateNapiError(result, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ? napi_ok : napi_generic_failure; }; @@ -191,7 +191,7 @@ napi_value Unshare(napi_env env, napi_callback_info info) return; } int32_t result = proxy->Unshare(ctxt->sharingRes, ctxt->participants, ctxt->results); - LOG_DEBUG("unshare result %{public}d", result); + LOG_DEBUG("Unshare result %{public}d", result); ctxt->status = (GenerateNapiError(result, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ? napi_ok : napi_generic_failure; }; @@ -235,7 +235,7 @@ napi_value Exit(napi_env env, napi_callback_info info) return; } int32_t result = proxy->Exit(ctxt->sharingRes, ctxt->result); - LOG_DEBUG("exit sharing result %{public}d", result); + LOG_DEBUG("Exit sharing result %{public}d", result); ctxt->status = (GenerateNapiError(result, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ? napi_ok : napi_generic_failure; }; @@ -287,7 +287,7 @@ napi_value ChangePrivilege(napi_env env, napi_callback_info info) return; } int32_t result = proxy->ChangePrivilege(ctxt->sharingRes, ctxt->participants, ctxt->results); - LOG_DEBUG("change privilege result %{public}d", result); + LOG_DEBUG("Change privilege result %{public}d", result); ctxt->status = (GenerateNapiError(result, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ? napi_ok : napi_generic_failure; }; @@ -331,7 +331,7 @@ napi_value Query(napi_env env, napi_callback_info info) return; } int32_t result = proxy->Query(ctxt->sharingRes, ctxt->results); - LOG_DEBUG("query participants result %{public}d", result); + LOG_DEBUG("Query participants result %{public}d", result); ctxt->status = (GenerateNapiError(result, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ? napi_ok : napi_generic_failure; }; @@ -376,7 +376,7 @@ napi_value QueryByInvitation(napi_env env, napi_callback_info info) return; } int32_t result = proxy->QueryByInvitation(ctxt->invitationCode, ctxt->results); - LOG_DEBUG("query participants by invitation result %{public}d", result); + LOG_DEBUG("Query participants by invitation result %{public}d", result); ctxt->status = (GenerateNapiError(result, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ? napi_ok : napi_generic_failure; }; @@ -428,7 +428,7 @@ napi_value ConfirmInvitation(napi_env env, napi_callback_info info) return; } int32_t result = proxy->ConfirmInvitation(ctxt->invitationCode, ctxt->confirmation, ctxt->result); - LOG_DEBUG("confirm invitation result %{public}d", result); + LOG_DEBUG("Confirm invitation result %{public}d", result); ctxt->status = (GenerateNapiError(result, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ? napi_ok : napi_generic_failure; }; @@ -480,7 +480,7 @@ napi_value ChangeConfirmation(napi_env env, napi_callback_info info) return; } int32_t result = proxy->ChangeConfirmation(ctxt->sharingRes, ctxt->confirmation, ctxt->results); - LOG_DEBUG("change confirmation result %{public}d", result); + LOG_DEBUG("Change confirmation result %{public}d", result); ctxt->status = (GenerateNapiError(result, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ? napi_ok : napi_generic_failure; }; diff --git a/relational_store/frameworks/js/napi/cloud_data/src/js_config.cpp b/relational_store/frameworks/js/napi/cloud_data/src/js_config.cpp index c09939d6b5e9bc5ef8964c477c6bf87d8365bf45..b840645dd7f727e2cc069805f68209025602ab37 100644 --- a/relational_store/frameworks/js/napi/cloud_data/src/js_config.cpp +++ b/relational_store/frameworks/js/napi/cloud_data/src/js_config.cpp @@ -439,7 +439,7 @@ napi_value JsConfig::New(napi_env env, napi_callback_info info) if (tid != 0) { LOG_ERROR("(T:%{public}d) freed! data:0x%016" PRIXPTR, tid, uintptr_t(data) & LOWER_24_BITS_MASK); } - LOG_DEBUG("cloudConfig finalize."); + LOG_DEBUG("CloudConfig finalize."); auto *config = reinterpret_cast(data); ASSERT_VOID(config != nullptr, "finalize null!"); delete config; diff --git a/relational_store/frameworks/js/napi/cloud_data/src/napi_queue.cpp b/relational_store/frameworks/js/napi/cloud_data/src/napi_queue.cpp index 27d681c42cf4deee6fe2ae18d7431d22cc636188..838f0fea257b3811d043b3f29a7d1fc22c644c3f 100644 --- a/relational_store/frameworks/js/napi/cloud_data/src/napi_queue.cpp +++ b/relational_store/frameworks/js/napi/cloud_data/src/napi_queue.cpp @@ -22,15 +22,15 @@ using namespace OHOS::Rdb; ContextBase::~ContextBase() { - LOG_DEBUG("no memory leak after callback or promise[resolved/rejected]"); + LOG_DEBUG("No memory leak after callback or promise[resolved/rejected]"); if (env != nullptr) { if (callbackRef != nullptr) { auto status = napi_delete_reference(env, callbackRef); - LOG_DEBUG("status:%{public}d", status); + LOG_DEBUG("Status:%{public}d", status); } if (selfRef != nullptr) { auto status = napi_delete_reference(env, selfRef); - LOG_DEBUG("status:%{public}d", status); + LOG_DEBUG("Status:%{public}d", status); } env = nullptr; } @@ -60,9 +60,9 @@ void ContextBase::GetCbInfo(napi_env envi, napi_callback_info info, NapiCbInfoPa status = napi_create_reference(env, argv[index], 1, &callbackRef); ASSERT_STATUS(this, "ref callback failed!"); argc = index; - LOG_DEBUG("async callback, no promise."); + LOG_DEBUG("Async callback, no promise."); } else { - LOG_DEBUG("no callback, async pormose."); + LOG_DEBUG("No callback, async pormose."); } } @@ -76,7 +76,7 @@ void ContextBase::GetCbInfo(napi_env envi, napi_callback_info info, NapiCbInfoPa napi_value NapiQueue::AsyncWork(napi_env env, std::shared_ptr ctxt, const std::string &name, NapiAsyncExecute execute, NapiAsyncComplete complete) { - LOG_DEBUG("name=%{public}s", name.c_str()); + LOG_DEBUG("Name=%{public}s", name.c_str()); AsyncContext *aCtx = new (std::nothrow) AsyncContext; if (aCtx == nullptr) { return nullptr; @@ -88,7 +88,7 @@ napi_value NapiQueue::AsyncWork(napi_env env, std::shared_ptr ctxt, napi_value promise = nullptr; if (aCtx->ctx->callbackRef == nullptr) { napi_create_promise(env, &aCtx->deferred, &promise); - LOG_DEBUG("create deferred promise."); + LOG_DEBUG("Create deferred promise."); } else { napi_get_undefined(env, &promise); } @@ -156,17 +156,17 @@ void NapiQueue::GenerateOutput(AsyncContext &ctx, napi_value output) } if (ctx.deferred != nullptr) { if (ctx.ctx->status == napi_ok) { - LOG_DEBUG("deferred promise resolved."); + LOG_DEBUG("Deferred promise resolved."); napi_resolve_deferred(ctx.env, ctx.deferred, result[RESULT_DATA]); } else { - LOG_DEBUG("deferred promise rejected."); + LOG_DEBUG("Deferred promise rejected."); napi_reject_deferred(ctx.env, ctx.deferred, result[RESULT_ERROR]); } } else { napi_value callback = nullptr; napi_get_reference_value(ctx.env, ctx.ctx->callbackRef, &callback); napi_value callbackResult = nullptr; - LOG_DEBUG("call callback function."); + LOG_DEBUG("Call callback function."); napi_call_function(ctx.env, nullptr, callback, RESULT_ALL, result, &callbackResult); } } diff --git a/relational_store/frameworks/js/napi/common/include/js_ability.h b/relational_store/frameworks/js/napi/common/include/js_ability.h index 3e3ae36fe042a80ae0738f910e0cb6b12e385a14..5f14f7530582beefd9be5c40172174a6bd144b60 100644 --- a/relational_store/frameworks/js/napi/common/include/js_ability.h +++ b/relational_store/frameworks/js/napi/common/include/js_ability.h @@ -64,6 +64,8 @@ public: static std::shared_ptr GetStageModeContext(napi_env env, napi_value value); static std::shared_ptr GetCurrentAbility(napi_env env, napi_value value); static int32_t GetHapVersion(napi_env env, napi_value value); + + static constexpr int32_t INVALID_HAP_VERSION = -1; }; } // namespace AppDataMgrJsKit } // namespace OHOS diff --git a/relational_store/frameworks/js/napi/common/include/js_sendable_utils.h b/relational_store/frameworks/js/napi/common/include/js_sendable_utils.h index 1a97c209e184d7926faa3926736b8e6c4f57bebf..22b566620b9c4308beb51a67d21032b1e4763d12 100644 --- a/relational_store/frameworks/js/napi/common/include/js_sendable_utils.h +++ b/relational_store/frameworks/js/napi/common/include/js_sendable_utils.h @@ -18,6 +18,7 @@ #include +#include "js_native_api.h" #include "js_utils.h" #include "napi/native_common.h" #include "napi/native_node_api.h" diff --git a/relational_store/frameworks/js/napi/common/include/js_utils.h b/relational_store/frameworks/js/napi/common/include/js_utils.h index 920cfd17bc960e4e5a46ea34b8b7fa970960a14f..3aa38fcac14c263170c29646ab69b3b45db376f1 100644 --- a/relational_store/frameworks/js/napi/common/include/js_utils.h +++ b/relational_store/frameworks/js/napi/common/include/js_utils.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -116,6 +117,7 @@ napi_value Convert2JSValue(napi_env env, double value); napi_value Convert2JSValue(napi_env env, bool value); napi_value Convert2JSValue(napi_env env, const std::map &value); napi_value Convert2JSValue(napi_env env, const std::monostate &value); +napi_value Convert2JSValue(napi_env env, const std::nullptr_t &value); template napi_value Convert2JSValue(napi_env env, const T &value); @@ -126,6 +128,9 @@ napi_value Convert2JSValue(napi_env env, const std::vector &value); template napi_value Convert2JSValue(napi_env env, const std::map &value); +template +napi_value Convert2JSValue(napi_env env, const std::unordered_map &value); + template napi_value Convert2JSValue(napi_env env, const std::tuple &value); @@ -267,7 +272,7 @@ int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::map(key, val)); @@ -303,6 +308,25 @@ napi_value JSUtils::Convert2JSValue(napi_env env, const std::map &value) return jsValue; } +template +napi_value JSUtils::Convert2JSValue(napi_env env, const std::unordered_map &value) +{ + napi_value jsValue; + napi_status status = napi_create_object(env, &jsValue); + if (status != napi_ok) { + return nullptr; + } + + for (const auto &[key, val] : value) { + const std::string &name = ConvertMapKey(key); + status = napi_set_named_property(env, jsValue, name.c_str(), Convert2JSValue(env, val)); + if (status != napi_ok) { + return nullptr; + } + } + return jsValue; +} + template napi_value JSUtils::Convert2JSValue(napi_env env, const std::tuple &value) { diff --git a/relational_store/frameworks/js/napi/common/src/js_ability.cpp b/relational_store/frameworks/js/napi/common/src/js_ability.cpp index f39f1cba67c734608236de8e0adcf0221bca389c..05b087b0207b80731f188fd2e5656d67e17bd52a 100644 --- a/relational_store/frameworks/js/napi/common/src/js_ability.cpp +++ b/relational_store/frameworks/js/napi/common/src/js_ability.cpp @@ -172,14 +172,15 @@ int32_t JSAbility::GetHapVersion(napi_env env, napi_value value) { auto stageContext = AbilityRuntime::GetStageModeContext(env, value); if (stageContext == nullptr) { - return napi_invalid_arg; + LOG_ERROR("GetStageModeContext failed."); + return INVALID_HAP_VERSION ; } auto appInfo = stageContext->GetApplicationInfo(); if (appInfo != nullptr) { return appInfo->apiTargetVersion % API_VERSION_MOD; } LOG_WARN("GetApplicationInfo failed."); - return napi_invalid_arg; + return INVALID_HAP_VERSION ; } } // namespace AppDataMgrJsKit } // namespace OHOS \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/common/src/js_common_type_init.cpp b/relational_store/frameworks/js/napi/common/src/js_common_type_init.cpp index f0a2b26416c04a864b01a44736d7980a3932720a..bf3450a45773274408b46c13f0a25a2f5fa1bfe4 100644 --- a/relational_store/frameworks/js/napi/common/src/js_common_type_init.cpp +++ b/relational_store/frameworks/js/napi/common/src/js_common_type_init.cpp @@ -32,7 +32,10 @@ static napi_status SetNamedProperty(napi_env env, napi_value &obj, const std::st static napi_value ExportAssetStatus(napi_env env) { napi_value assetStatus = nullptr; - napi_create_object(env, &assetStatus); + napi_status status = napi_create_object(env, &assetStatus); + if (status != napi_ok) { + return nullptr; + } SetNamedProperty(env, assetStatus, "ASSET_NORMAL", AssetValue::STATUS_NORMAL); SetNamedProperty(env, assetStatus, "ASSET_INSERT", AssetValue::STATUS_INSERT); SetNamedProperty(env, assetStatus, "ASSET_UPDATE", AssetValue::STATUS_UPDATE); diff --git a/relational_store/frameworks/js/napi/common/src/js_sendable_utils.cpp b/relational_store/frameworks/js/napi/common/src/js_sendable_utils.cpp index 197372720f9e24e493827659858ab431e1b054a0..935e2882a854e442fce35b978c2ea844a36a5229 100644 --- a/relational_store/frameworks/js/napi/common/src/js_sendable_utils.cpp +++ b/relational_store/frameworks/js/napi/common/src/js_sendable_utils.cpp @@ -18,7 +18,6 @@ #include -#include "js_native_api.h" #include "js_utils.h" #include "logger.h" #include "securec.h" @@ -175,7 +174,7 @@ napi_value JSUtils::ToSendableTypedArray(napi_env env, napi_value jsValue) ASSERT(status == napi_ok, "napi_get_typedarray_info failed", nullptr); if (type != napi_uint8_array && type != napi_float32_array) { - LOG_ERROR("type is invalid %{public}d", type); + LOG_ERROR("Type is invalid %{public}d", type); return nullptr; } napi_value sendableTypedArryay = nullptr; diff --git a/relational_store/frameworks/js/napi/common/src/js_utils.cpp b/relational_store/frameworks/js/napi/common/src/js_utils.cpp index a6f761cd245d37bad7244b64657fdfd638d5caf9..188c459f6e1d38c6bfaa6363f01769fbc62914ca 100644 --- a/relational_store/frameworks/js/napi/common/src/js_utils.cpp +++ b/relational_store/frameworks/js/napi/common/src/js_utils.cpp @@ -43,6 +43,7 @@ static constexpr JSUtils::JsFeatureSpace FEATURE_NAME_SPACES[] = { { "ohos.data.dataShare", "ZGF0YS5kYXRhU2hhcmU=", false }, { "ohos.data.distributedDataObject", "ZGF0YS5kaXN0cmlidXRlZERhdGFPYmplY3Q=", false }, { "ohos.data.distributedKVStore", "ZGF0YS5kaXN0cmlidXRlZEtWU3RvcmU=", false }, + { "ohos.data.graphStore", "ZGF0YS5ncmFwaFN0b3Jl", true }, { "ohos.data.rdb", "ZGF0YS5yZGI=", true }, { "ohos.data.relationalStore", "ZGF0YS5yZWxhdGlvbmFsU3RvcmU=", true }, }; @@ -102,6 +103,11 @@ std::string JSUtils::Convert2String(napi_env env, napi_value jsStr) return value; } +napi_value JSUtils::Convert2JSValue(napi_env env, const std::nullptr_t &jsStr) +{ + return nullptr; +} + int32_t JSUtils::Convert2ValueExt(napi_env env, napi_value jsValue, uint32_t &output) { napi_valuetype type = napi_undefined; @@ -244,7 +250,7 @@ int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::string &ou } std::unique_ptr buffer = std::make_unique(buffSize + 1); if (!buffer) { - LOG_ERROR("buffer data is nullptr."); + LOG_ERROR("Buffer data is nullptr."); return napi_invalid_arg; } status = napi_get_value_string_utf8(env, jsValue, buffer.get(), buffSize + 1, &buffSize); @@ -290,7 +296,7 @@ int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::monostate value = std::monostate(); return napi_ok; } - LOG_DEBUG("jsValue is not null."); + LOG_DEBUG("JsValue is not null."); return napi_invalid_arg; } @@ -547,19 +553,20 @@ napi_value JSUtils::DefineClass(napi_env env, const std::string &spaceName, cons if (hasProp) { napi_get_named_property(env, root, propName.c_str(), &constructor); if (constructor != nullptr) { - LOG_DEBUG("got %{public}s from %{public}s", propName.c_str(), featureSpace->spaceName); + LOG_DEBUG("Got %{public}s from %{public}s", propName.c_str(), featureSpace->spaceName); return constructor; } hasProp = false; // no constructor. } auto properties = descriptor(); - NAPI_CALL(env, napi_define_class(env, className.c_str(), className.size(), ctor, nullptr, properties.size(), - properties.data(), &constructor)); + NAPI_CALL(env, napi_define_class(env, className.c_str(), className.size(), ctor, nullptr, + properties.size(), properties.data(), &constructor)); + NAPI_ASSERT(env, constructor != nullptr, "napi_define_class failed!"); if (!hasProp) { napi_set_named_property(env, root, propName.c_str(), constructor); - LOG_DEBUG("save %{public}s to %{public}s", propName.c_str(), featureSpace->spaceName); + LOG_DEBUG("Save %{public}s to %{public}s", propName.c_str(), featureSpace->spaceName); } return constructor; } @@ -589,7 +596,7 @@ napi_value JSUtils::GetClass(napi_env env, const std::string &spaceName, const s } napi_get_named_property(env, root, propName.c_str(), &constructor); if (constructor != nullptr) { - LOG_DEBUG("got %{public}s from %{public}s", propName.c_str(), featureSpace->spaceName); + LOG_DEBUG("Got %{public}s from %{public}s", propName.c_str(), featureSpace->spaceName); return constructor; } hasProp = false; // no constructor. @@ -664,7 +671,7 @@ napi_value JSUtils::ToJsTypedArray(napi_env env, napi_value sendableValue) ASSERT(status == napi_ok, "napi_get_typedarray_info failed", nullptr); if (type != napi_uint8_array && type != napi_float32_array) { - LOG_ERROR("type is invalid %{public}d", type); + LOG_ERROR("Type is invalid %{public}d", type); return nullptr; } napi_value jsTypedArray = nullptr; diff --git a/relational_store/frameworks/js/napi/common/src/js_uv_queue.cpp b/relational_store/frameworks/js/napi/common/src/js_uv_queue.cpp index d5c612af4ac720581a0651ba45df1fd72f1b2f1c..87fbd98fc2a30eb06f754c0ff81f130547343853 100644 --- a/relational_store/frameworks/js/napi/common/src/js_uv_queue.cpp +++ b/relational_store/frameworks/js/napi/common/src/js_uv_queue.cpp @@ -32,7 +32,7 @@ UvQueue::UvQueue(napi_env env) : env_(env) UvQueue::~UvQueue() { - LOG_DEBUG("no memory leak for queue-callback."); + LOG_DEBUG("No memory leak for queue-callback."); env_ = nullptr; handler_ = nullptr; } @@ -45,13 +45,13 @@ void UvQueue::AsyncCall(UvCallback callback, Args args, Result result) } uv_work_t *work = new (std::nothrow) uv_work_t; if (work == nullptr) { - LOG_ERROR("no memory for uv_work_t."); + LOG_ERROR("No memory for uv_work_t."); return; } auto entry = new (std::nothrow) UvEntry(); if (entry == nullptr) { delete work; - LOG_ERROR("no memory for UvEntry."); + LOG_ERROR("No memory for UvEntry."); return; } entry->env_ = env_; @@ -81,7 +81,7 @@ void UvQueue::AsyncCallInOrder(UvCallback callback, Args args, Result result) } auto entry = std::make_shared(); if (entry == nullptr) { - LOG_ERROR("no memory for UvEntry."); + LOG_ERROR("No memory for UvEntry."); return; } entry->env_ = env_; @@ -101,13 +101,13 @@ void UvQueue::AsyncPromise(UvPromise promise, UvQueue::Args args) } uv_work_t *work = new (std::nothrow) uv_work_t; if (work == nullptr) { - LOG_ERROR("no memory for uv_work_t."); + LOG_ERROR("No memory for uv_work_t."); return; } auto entry = new (std::nothrow) UvEntry(); if (entry == nullptr) { delete work; - LOG_ERROR("no memory for UvEntry."); + LOG_ERROR("No memory for UvEntry."); return; } entry->env_ = env_; @@ -130,13 +130,13 @@ void UvQueue::Execute(UvQueue::Task task) } uv_work_t *work = new (std::nothrow) uv_work_t; if (work == nullptr) { - LOG_ERROR("no memory for uv_work_t."); + LOG_ERROR("No memory for uv_work_t."); return; } auto entry = new (std::nothrow) Task(); if (entry == nullptr) { delete work; - LOG_ERROR("no memory for Task."); + LOG_ERROR("No memory for Task."); return; } *entry = task; @@ -230,7 +230,7 @@ UvQueue::Task UvQueue::GenCallbackTask(std::shared_ptr entry) napi_value method = entry->GetCallback(); if (method == nullptr) { entry->DelReference(); - LOG_ERROR("the callback is invalid, maybe is cleared!"); + LOG_ERROR("The callback is invalid, maybe is cleared!"); return; } napi_value argv[ARGC_MAX] = { nullptr }; @@ -240,7 +240,7 @@ UvQueue::Task UvQueue::GenCallbackTask(std::shared_ptr entry) auto status = napi_call_function(entry->env_, object, method, argc, argv, &promise); entry->DelReference(); if (status != napi_ok) { - LOG_ERROR("notify data change failed status:%{public}d.", status); + LOG_ERROR("Notify data change failed status:%{public}d.", status); return; } entry->BindPromise(promise); diff --git a/relational_store/frameworks/js/napi/graphstore/BUILD.gn b/relational_store/frameworks/js/napi/graphstore/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..19a9f63a2ed3119a670033476a73c90cffd9ee5f --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/BUILD.gn @@ -0,0 +1,64 @@ +# Copyright (c) 2024 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. + +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/relational_store/relational_store.gni") + +ohos_shared_library("graphstore") { + sanitize = { + boundary_sanitize = true + ubsan = true + cfi = true + cfi_cross_dso = true + debug = false + } + include_dirs = [ + "${relational_store_common_path}/include", + "${relational_store_frameworks_path}/native/gdb/include", + "${relational_store_frameworks_path}/common/include", + "${relational_store_frameworks_path}/js/napi/common/include", + "${relational_store_frameworks_path}/js/napi/graphstore/include", + "${relational_store_innerapi_path}/gdb/include", + "${relational_store_innerapi_path}/rdb/include", + ] + sources = [ + "${relational_store_frameworks_path}/js/napi/common/src/js_ability.cpp", + "${relational_store_frameworks_path}/js/napi/common/src/js_scope.cpp", + "${relational_store_frameworks_path}/js/napi/common/src/js_utils.cpp", + "${relational_store_frameworks_path}/js/napi/common/src/js_uv_queue.cpp", + "${relational_store_frameworks_path}/js/napi/graphstore/src/entry_point.cpp", + "${relational_store_frameworks_path}/js/napi/graphstore/src/napi_async_call.cpp", + "${relational_store_frameworks_path}/js/napi/graphstore/src/napi_gdb_const_properties.cpp", + "${relational_store_frameworks_path}/js/napi/graphstore/src/napi_gdb_error.cpp", + "${relational_store_frameworks_path}/js/napi/graphstore/src/napi_gdb_js_utils.cpp", + "${relational_store_frameworks_path}/js/napi/graphstore/src/napi_gdb_store.cpp", + "${relational_store_frameworks_path}/js/napi/graphstore/src/napi_gdb_store_helper.cpp", + "${relational_store_frameworks_path}/js/napi/graphstore/src/napi_gdb_transaction.cpp", + ] + deps = [ "${relational_store_innerapi_path}/gdb:framework_graphstore" ] + external_deps = [ + "ability_runtime:abilitykit_native", + "ability_runtime:extensionkit_native", + "ability_runtime:napi_base_context", + "c_utils:utils", + "eventhandler:libeventhandler", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "napi:ace_napi", + ] + + subsystem_name = "distributeddatamgr" + part_name = "relational_store" + relative_install_dir = "module/data" +} diff --git a/relational_store/frameworks/js/napi/graphstore/include/gdb_common.h b/relational_store/frameworks/js/napi/graphstore/include/gdb_common.h new file mode 100644 index 0000000000000000000000000000000000000000..3ba2409305c9ddadd81a3e8319c941d8263adb83 --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/include/gdb_common.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024 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_GDB_JS_NAPI_GDB_COMMON_H +#define OHOS_DISTRIBUTED_DATA_GDB_JS_NAPI_GDB_COMMON_H +#include + +namespace OHOS::GraphStoreJsKit { +enum ColumnType : uint32_t { + + /** + * GRAPH_DB_DATATYPE_LONG: means the column type of the specified column is long. + * + * @syscap + * @since 16 + */ + GRAPH_DB_DATATYPE_LONG = 0, + + /** + * GRAPH_DB_DATATYPE_DOUBLE: means the column type of the specified column is double. + * + * @syscap SystemCapability.DistributedDataManager.DataIntelligence.Core + * @since 16 + */ + GRAPH_DB_DATATYPE_DOUBLE, + + /** + * GRAPH_DB_DATATYPE_STRING: means the column type of the specified column is string. + * + * @syscap SystemCapability.DistributedDataManager.DataIntelligence.Core + * @since 16 + */ + GRAPH_DB_DATATYPE_STRING, + + /** + * GRAPH_DB_DATATYPE_JSONSTR: means the column type of the specified column is string with json format. + * + * @syscap SystemCapability.DistributedDataManager.DataIntelligence.Core + * @since 16 + */ + GRAPH_DB_DATATYPE_JSONSTR, + + GRAPH_DB_DATATYPE_NULL, +}; +} + +#endif \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/graphstore/include/js_proxy.h b/relational_store/frameworks/js/napi/graphstore/include/js_proxy.h new file mode 100644 index 0000000000000000000000000000000000000000..9bbf5b85b1c65ad4fa43af11d3c21635140fd9ef --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/include/js_proxy.h @@ -0,0 +1,62 @@ +/* +* Copyright (c) 2024 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_GDB_JS_NAPI_JS_PROXY_H +#define OHOS_DISTRIBUTED_DATA_GDB_JS_NAPI_JS_PROXY_H +#include +namespace OHOS::GraphStoreJsKit { +template +class JSCreator { +public: + // This method will be used to call different subclasses for implementation + virtual std::shared_ptr Create() = 0; + +protected: + // It is not allowed to directly use parent class objects for construction and destruction + JSCreator() = default; + ~JSCreator() = default; +}; + +template +class JSProxy { +public: + void SetInstance(std::shared_ptr instance) + { + instance_ = std::move(instance); + } + + std::shared_ptr GetInstance() const + { + return instance_; + } + +protected: + // It is not allowed to directly use parent class objects for construction and destruction + JSProxy() = default; + ~JSProxy() = default; + +private: + std::shared_ptr instance_; +}; + +template +class JSEntity : public JSCreator, public JSProxy { +protected: + // It is not allowed to directly use parent class objects for construction and destruction + JSEntity() = default; + ~JSEntity() = default; +}; +} // namespace OHOS::JSProxy +#endif // OHOS_DISTRIBUTED_DATA_GDB_JS_NAPI_JS_PROXY_H diff --git a/relational_store/frameworks/js/napi/graphstore/include/napi_async_call.h b/relational_store/frameworks/js/napi/graphstore/include/napi_async_call.h new file mode 100644 index 0000000000000000000000000000000000000000..c2fdca11822ec23639f5957ff29aa120b3b90916 --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/include/napi_async_call.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2024 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_GDB_JS_NAPI_ASYNC_CALL_H +#define OHOS_DISTRIBUTED_DATA_GDB_JS_NAPI_ASYNC_CALL_H + +#include +#include +#include +#include +#include + +#include "aip_errors.h" +#include "logger.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "napi_gdb_error.h" + +namespace OHOS::GraphStoreJsKit { +using InputAction = std::function; +using OutputAction = std::function; +using ExecuteAction = std::function; +extern bool g_async; +extern bool g_sync; +#define AIP_ASYNC &g_async +#define AIP_SYNC &g_sync + +#define ASYNC_CALL(env, ctx) AsyncCall::Call(env, ctx, __FUNCTION__) +class ContextBase { +public: + struct RecordData { + std::atomic_uint64_t times_{0}; + int64_t lastTime_ = 0; + RecordData() = default; + RecordData(const RecordData &record) + { + times_.store(record.times_); + lastTime_ = record.lastTime_; + } + RecordData& operator= (const RecordData &record) + { + times_.store(record.times_); + lastTime_ = record.lastTime_; + return *this; + } + }; + void SetAction(napi_env env, napi_callback_info info, InputAction input, ExecuteAction exec, OutputAction output); + void SetAll(napi_env env, napi_callback_info info, InputAction input, ExecuteAction exec, OutputAction output); + void SetError(std::shared_ptr error); + virtual ~ContextBase(); + + napi_env env_ = nullptr; + bool isAsync_ = true; + void *boundObj = nullptr; + std::shared_ptr error; + std::shared_ptr executed_; + const char *fun = nullptr; + + napi_ref self_ = nullptr; + napi_ref callback_ = nullptr; + napi_deferred defer_ = nullptr; + napi_async_work work_ = nullptr; + + int execCode_ = OK; + OutputAction output_ = nullptr; + ExecuteAction exec_ = nullptr; + napi_value result_ = nullptr; + std::shared_ptr keep_; +}; + +class AsyncCall final { +public: + static napi_value Call(napi_env env, std::shared_ptr context, const char *fun); + +private: + enum { ARG_ERROR, ARG_DATA, ARG_BUTT }; + using RecordData = ContextBase::RecordData; + struct Record { + public: + RecordData total_; + RecordData completed_; + uint64_t reportTimes_ = 0; + std::shared_ptr executed_ = std::make_shared(); + }; + static constexpr uint64_t EXCEPT_DELTA = 20; + static void OnExecute(napi_env env, void *data); + static void OnComplete(napi_env env, void *data); + static void OnReturn(napi_env env, napi_status status, void *data); + static void OnComplete(napi_env env, napi_status status, void *data); + static void SetBusinessError(napi_env env, std::shared_ptr error, napi_value *businessError); + static napi_value Async(napi_env env, std::shared_ptr context); + static napi_value Sync(napi_env env, std::shared_ptr context); + static thread_local Record record_; +}; +} // namespace OHOS::GraphStoreJsKit +#endif \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_const_properties.h b/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_const_properties.h new file mode 100644 index 0000000000000000000000000000000000000000..02e400e989639ba8c44b5b4aedfe1c9d0ffaa3b0 --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_const_properties.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 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_GDB_JS_NAPI_GDB_CONST_PROPERTIES_H +#define OHOS_DISTRIBUTED_DATA_GDB_JS_NAPI_GDB_CONST_PROPERTIES_H + +#include "napi/native_common.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS::GraphStoreJsKit { +napi_status InitConstProperties(napi_env env, napi_value exports); +} +#endif \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_context.h b/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_context.h new file mode 100644 index 0000000000000000000000000000000000000000..cd39f8a21d26ca3191aaf21137a7f8a3db9dab2f --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_context.h @@ -0,0 +1,80 @@ +/* +* Copyright (c) 2024 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_GDB_JS_NAPI_GDB_CONTEXT_H +#define OHOS_DISTRIBUTED_DATA_GDB_JS_NAPI_GDB_CONTEXT_H + +#include "full_result.h" +#include "gdb_store.h" +#include "gdb_store_config.h" +#include "napi_async_call.h" + +namespace OHOS { +namespace GraphStoreJsKit { +using namespace OHOS::DistributedDataAip; +struct GdbStoreContextBase : public ContextBase { + std::shared_ptr StealGdbStore() + { + auto gdb = std::move(gdbStore); + gdbStore = nullptr; + return gdb; + } + std::shared_ptr gdbStore = nullptr; +}; + +struct ContextParam { + std::string bundleName; + std::string moduleName; + std::string baseDir; + int32_t area = 2; + bool isSystemApp = false; + bool isStageMode = true; +}; + +struct GdbStoreContext : public GdbStoreContextBase { + std::string device; + std::string gql; + std::vector columns; + int64_t int64Output; + int intOutput; + ContextParam param; + StoreConfig config; + std::shared_ptr result; + std::vector keys; + std::string key; + std::string aliasName; + std::string pathName; + std::string srcName; + std::string columnName; + int32_t enumArg; + uint64_t cursor = UINT64_MAX; + int64_t txId = 0; + napi_ref asyncHolder = nullptr; + bool isQueryGql = false; + uint32_t expiredTime = 0; + + GdbStoreContext() : int64Output(0), intOutput(0), enumArg(-1) + { + } + virtual ~GdbStoreContext() + { + } +}; + +struct CreateTransactionContext : public GdbStoreContextBase { + std::shared_ptr transaction; +}; +} // namespace GraphStoreJsKit +} // namespace OHOS +#endif \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_error.h b/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_error.h new file mode 100644 index 0000000000000000000000000000000000000000..82c1fe9213ffd94a5cd4512e6040dd341a9b83c7 --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_error.h @@ -0,0 +1,179 @@ +/* +* Copyright (c) 2024 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_GDB_JS_NAPI_ERROR_H +#define OHOS_DISTRIBUTED_DATA_GDB_JS_NAPI_ERROR_H + +#include +#include +#include +#include + +#include "logger.h" + +namespace OHOS::GraphStoreJsKit { +constexpr int MAX_INPUT_COUNT = 10; +constexpr int OK = 0; +constexpr int ERR = -1; + +constexpr int E_NON_SYSTEM_APP_ERROR = 202; +constexpr int E_PARAM_ERROR = 401; +constexpr int E_INNER_ERROR = 31300000; + +struct JsErrorCode { + int32_t status; + int32_t jsCode; + std::string_view message; +}; +std::optional GetJsErrorCode(int32_t errorCode); + +#define GDB_REVT_NOTHING +#define GDB_DO_NOTHING + +#define GDB_NAPI_ASSERT_BASE(env, assertion, error, retVal) \ + do { \ + if (!(assertion)) { \ + if ((error) == nullptr) { \ + LOG_ERROR("throw error: error message is empty"); \ + napi_throw_error((env), nullptr, "error message is empty"); \ + return retVal; \ + } \ + LOG_ERROR("throw error: code = %{public}d , message = %{public}s", (error)->GetCode(), \ + (error)->GetMessage().c_str()); \ + napi_throw_error((env), std::to_string((error)->GetCode()).c_str(), (error)->GetMessage().c_str()); \ + return retVal; \ + } \ + } while (0) + +#define GDB_NAPI_ASSERT(env, assertion, error) GDB_NAPI_ASSERT_BASE(env, assertion, error, nullptr) + +#define CHECK_RETURN_CORE(assertion, theCall, revt) \ + do { \ + if (!(assertion)) { \ + theCall; \ + return revt; \ + } \ + } while (0) + +#define CHECK_RETURN_SET_E(assertion, paramError) \ + CHECK_RETURN_CORE(assertion, context->SetError(paramError), GDB_REVT_NOTHING) + +#define CHECK_RETURN_SET(assertion, paramError) CHECK_RETURN_CORE(assertion, context->SetError(paramError), ERR) + +#define CHECK_RETURN_NULL(assertion) CHECK_RETURN_CORE(assertion, GDB_REVT_NOTHING, nullptr) + +#define CHECK_RETURN_ERR(assertion) CHECK_RETURN_CORE(assertion, GDB_REVT_NOTHING, ERR) + +#define CHECK_RETURN(assertion) CHECK_RETURN_CORE(assertion, GDB_REVT_NOTHING, GDB_REVT_NOTHING) + +class Error { +public: + virtual ~Error() = default; + virtual std::string GetMessage() = 0; + virtual int GetCode() = 0; +}; + +class InnerError : public Error { +public: + explicit InnerError(int code) + { + auto errorMsg = GetJsErrorCode(code); + if (errorMsg.has_value()) { + const auto &napiError = errorMsg.value(); + code_ = napiError.jsCode; + msg_ = napiError.message; + } else { + code_ = E_INNER_ERROR; + msg_ = "Inner error. Inner code is " + std::to_string(code % E_INNER_ERROR); + } + } + + explicit InnerError(const std::string &msg) + { + code_ = E_INNER_ERROR; + msg_ = std::string("Inner error. ") + msg; + } + + std::string GetMessage() override + { + return msg_; + } + + int GetCode() override + { + return code_; + } + +private: + int code_; + std::string msg_; +}; + +class ParamError : public Error { +public: + ParamError(const std::string &needed, const std::string &mustbe) + { + msg_ = "Parameter error. The " + needed + " must be " + mustbe; + }; + + explicit ParamError(const std::string &errMsg) + { + msg_ = "Parameter error." + errMsg; + } + + std::string GetMessage() override + { + return msg_; + }; + + int GetCode() override + { + return E_PARAM_ERROR; + }; + +private: + std::string msg_; +}; + +class NonSystemError : public Error { +public: + NonSystemError() = default; + std::string GetMessage() override + { + return "Permission verification failed, application which is not a system application uses system API."; + } + int GetCode() override + { + return E_NON_SYSTEM_APP_ERROR; + } +}; + +class ParamNumError : public Error { +public: + explicit ParamNumError(std::string wantNum) : wantNum(std::move(wantNum)) {}; + std::string GetMessage() override + { + return "Parameter error. Need " + wantNum + " parameter(s)!"; + }; + int GetCode() override + { + return E_PARAM_ERROR; + }; + +private: + std::string wantNum; +}; +} // namespace OHOS::GraphStoreJsKit + +#endif // GDB_JS_NAPI_ERROR_H \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_js_utils.h b/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_js_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..db292630561bdaf94a81867fc954b9c7b208cc0b --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_js_utils.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024 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_GDB_JS_NAPI_GDB_JS_UTILS_H +#define OHOS_DISTRIBUTED_DATA_GDB_JS_NAPI_GDB_JS_UTILS_H +#include "full_result.h" +#include "gdb_store_config.h" +#include "js_utils.h" +#include "logger.h" +#include "napi_gdb_context.h" + +namespace OHOS::AppDataMgrJsKit::JSUtils { +using namespace GraphStoreJsKit; +using StoreConfig = DistributedDataAip::StoreConfig; +using Vertex = OHOS::DistributedDataAip::Vertex; +using Edge = OHOS::DistributedDataAip::Edge; +using PathSegment = OHOS::DistributedDataAip::PathSegment; +using Path = OHOS::DistributedDataAip::Path; + +#define GRAPH_ASSERT(condition, message, retVal) \ + do { \ + if (!(condition)) { \ + LOG_ERROR("test (" #condition ") failed: " message); \ + return retVal; \ + } \ + } while (0) + +#define NAPI_CALL_RETURN_ERR(theCall, retVal) \ + do { \ + if ((theCall) != napi_ok) { \ + return retVal; \ + } \ + } while (0) + +#ifndef PATH_SPLIT +#define PATH_SPLIT '/' +#endif + +static inline OHOS::HiviewDFX::HiLogLabel LogLabel() +{ + return { LOG_CORE, 0xD001660, "GdbJSUtils" }; +} + +template<> +int32_t Convert2Value(napi_env env, napi_value jsValue, ContextParam &context); + +template<> +int32_t Convert2Value(napi_env env, napi_value jsValue, StoreConfig &config); + +template<> +napi_value Convert2JSValue(napi_env env, const std::shared_ptr &result); + +template<> +napi_value Convert2JSValue(napi_env env, const std::shared_ptr &value); + +template<> +napi_value Convert2JSValue(napi_env env, const std::shared_ptr &edge); + +template<> +napi_value Convert2JSValue(napi_env env, const std::shared_ptr &pathSegment); + +template<> +napi_value Convert2JSValue(napi_env env, const std::shared_ptr &path); + +std::tuple> GetRealPath(StoreConfig &config, ContextParam ¶m); +} // namespace OHOS::AppDataMgrJsKit::JSUtils + +#endif \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_store.h b/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_store.h new file mode 100644 index 0000000000000000000000000000000000000000..24ee51a971f544c776b3139edbb97acccd6c7024 --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_store.h @@ -0,0 +1,69 @@ +/* +* Copyright (c) 2024 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_GDB_JS_NAPI_GDB_STORE_H +#define OHOS_DISTRIBUTED_DATA_GDB_JS_NAPI_GDB_STORE_H + +#include +#include +#include +#include + +#include "gdb_store.h" +#include "js_proxy.h" +#include "js_uv_queue.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" + +namespace OHOS::GraphStoreJsKit { +using namespace DistributedDataAip; +#define ASSERT_CALL(env, theCall, object) \ + do { \ + if ((theCall) != napi_ok) { \ + delete (object); \ + GET_AND_THROW_LAST_ERROR((env)); \ + return nullptr; \ + } \ + } while (0) + +using Descriptor = std::function(void)>; +class GdbStoreProxy : public GraphStoreJsKit::JSProxy { +public: + static void Init(napi_env env, napi_value exports); + static napi_value NewInstance(napi_env env, std::shared_ptr value, bool isSystemAppCalled); + GdbStoreProxy(); + ~GdbStoreProxy(); + GdbStoreProxy(std::shared_ptr gdbStore); + GdbStoreProxy &operator=(std::shared_ptr GdbStore); + bool IsSystemAppCalled(); + static constexpr int32_t MAX_GQL_LEN = 1024 * 1024; + +private: + static napi_value Initialize(napi_env env, napi_callback_info info); + static napi_value Read(napi_env env, napi_callback_info info); + static napi_value Write(napi_env env, napi_callback_info info); + static napi_value CreateTransaction(napi_env env, napi_callback_info info); + static napi_value Close(napi_env env, napi_callback_info info); + + static Descriptor GetDescriptors(); + + static napi_value New(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *nativeObject, void *finalize_hint); + + bool isSystemAppCalled_ = false; + std::shared_ptr queue_; +}; +} // namespace OHOS::GraphStoreJsKit +#endif \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_store_helper.h b/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_store_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..5190235094fc6a8e807db900135a3f9463bf84d5 --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_store_helper.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 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_GDB_JS_NAPI_DB_STORE_HELPER_H +#define OHOS_DISTRIBUTED_DATA_GDB_JS_NAPI_DB_STORE_HELPER_H + +#include +#include +#include + +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "napi_gdb_error.h" + + +namespace OHOS::GraphStoreJsKit { +napi_value InitGdbHelper(napi_env env, napi_value exports); +} // namespace OHOS::GraphStoreJsKit + + +#endif \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_transaction.h b/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_transaction.h new file mode 100644 index 0000000000000000000000000000000000000000..2d3e1759f4cb3ad9a44bb19530bf5d3665b132c7 --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/include/napi_gdb_transaction.h @@ -0,0 +1,48 @@ +/* +* Copyright (c) 2025 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_GDB_JS_NAPI_GDB_TRANSACTION_H +#define OHOS_DISTRIBUTED_DATA_GDB_JS_NAPI_GDB_TRANSACTION_H + +#include +#include +#include +#include + +#include "js_proxy.h" +#include "js_uv_queue.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "transaction.h" + +namespace OHOS::GraphStoreJsKit { +using Transaction = DistributedDataAip::Transaction; +class GdbTransactionProxy final : public GraphStoreJsKit::JSProxy { +public: + GdbTransactionProxy() = default; + ~GdbTransactionProxy(); + explicit GdbTransactionProxy(std::shared_ptr gdbTransaction); + static void Init(napi_env env, napi_value exports); + static napi_value NewInstance(napi_env env, std::shared_ptr value); + +private: + static napi_value Initialize(napi_env env, napi_callback_info info); + static napi_value Read(napi_env env, napi_callback_info info); + static napi_value Write(napi_env env, napi_callback_info info); + static napi_value Commit(napi_env env, napi_callback_info info); + static napi_value Rollback(napi_env env, napi_callback_info info); +}; +} // namespace OHOS::GraphStoreJsKit +#endif \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/graphstore/src/entry_point.cpp b/relational_store/frameworks/js/napi/graphstore/src/entry_point.cpp new file mode 100644 index 0000000000000000000000000000000000000000..18d4d98ea3f92c0d833255fd9f9e6d7250a15c0a --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/src/entry_point.cpp @@ -0,0 +1,54 @@ +/* +* Copyright (c) 2024 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 "napi/native_api.h" +#include "napi_gdb_const_properties.h" +#include "napi_gdb_store.h" +#include "napi_gdb_store_helper.h" +#include "napi_gdb_transaction.h" + +using namespace OHOS::GraphStoreJsKit; + +EXTERN_C_START +/* + * function for module exports + */ +static napi_value Init(napi_env env, napi_value exports) +{ + InitGdbHelper(env, exports); + GdbStoreProxy::Init(env, exports); + GdbTransactionProxy::Init(env, exports); + InitConstProperties(env, exports); + return exports; +} +EXTERN_C_END + +/* + * Module define + */ +static napi_module _module = { .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "data.graphStore", + .nm_priv = ((void *)0), + .reserved = { 0 } }; + +/* + * Module register function + */ +static __attribute__((constructor)) void RegisterModule(void) +{ + napi_module_register(&_module); +} \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/graphstore/src/napi_async_call.cpp b/relational_store/frameworks/js/napi/graphstore/src/napi_async_call.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b045ae83f05e4eea80ae7eb1dc3a373190d7dea --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/src/napi_async_call.cpp @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2024 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 "GdbAsyncCall" +#include "napi_async_call.h" + +#include "db_trace.h" +#include "js_native_api_types.h" +#include "logger.h" + +namespace OHOS::GraphStoreJsKit { +bool g_async = true; // do not reset the value, used in DECLARE_NAPI_FUNCTION_WITH_DATA only +bool g_sync = false; // do not reset the value, used in DECLARE_NAPI_FUNCTION_WITH_DATA only +thread_local AsyncCall::Record AsyncCall::record_; +void ContextBase::SetAction( + napi_env env, napi_callback_info info, InputAction input, ExecuteAction exec, OutputAction output) +{ + env_ = env; + size_t argc = MAX_INPUT_COUNT; + napi_value self = nullptr; + napi_value argv[MAX_INPUT_COUNT] = { nullptr }; + void *data = nullptr; + napi_status status = napi_get_cb_info(env, info, &argc, argv, &self, &data); + if (status == napi_ok && argc > 0) { + napi_valuetype valueType = napi_undefined; + status = napi_typeof(env, argv[argc - 1], &valueType); + if (status == napi_ok && valueType == napi_function) { + LOG_DEBUG("asyncCall set callback"); + if (argc == 1) { + error = std::make_shared("1"); + } else { + status = napi_create_reference(env, argv[argc - 1], 1, &callback_); + argc = argc - 1; + } + } + } + if (data) { + isAsync_ = *reinterpret_cast(data); + } + + // int -->input_(env, argc, argv, self) + if (status == napi_ok) { + input(env, argc, argv, self); + } else { + error = std::make_shared("Failed to set action."); + } + + // if input return is not ok, then napi_throw_error context error + GDB_NAPI_ASSERT_BASE(env, error == nullptr, error, NAPI_RETVAL_NOTHING); + output_ = std::move(output); + exec_ = std::move(exec); + napi_create_reference(env, self, 1, &self_); +} + +void ContextBase::SetAll( + napi_env env, napi_callback_info info, InputAction input, ExecuteAction exec, OutputAction output) +{ + env_ = env; + size_t argc = MAX_INPUT_COUNT; + napi_value self = nullptr; + napi_value argv[MAX_INPUT_COUNT] = { nullptr }; + NAPI_CALL_RETURN_VOID(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + + // int -->input_(env, argc, argv, self) + input(env, argc, argv, self); + + // if input return is not ok, then napi_throw_error context error + GDB_NAPI_ASSERT_BASE(env, error == nullptr, error, NAPI_RETVAL_NOTHING); + output_ = std::move(output); + exec_ = std::move(exec); + napi_create_reference(env, self, 1, &self_); +} + +void ContextBase::SetError(std::shared_ptr err) +{ + error = err; +} + +ContextBase::~ContextBase() +{ + if (env_ == nullptr) { + return; + } + if (work_ != nullptr) { + napi_delete_async_work(env_, work_); + work_ = nullptr; + } + if (callback_ != nullptr) { + napi_delete_reference(env_, callback_); + callback_ = nullptr; + } + napi_delete_reference(env_, self_); + env_ = nullptr; +} + +void AsyncCall::SetBusinessError(napi_env env, std::shared_ptr error, napi_value *businessError) +{ + LOG_DEBUG("SetBusinessError enter"); + // if error is not inner error + if (error != nullptr) { + napi_value code = nullptr; + napi_value msg = nullptr; + napi_create_int32(env, error->GetCode(), &code); + napi_create_string_utf8(env, error->GetMessage().c_str(), NAPI_AUTO_LENGTH, &msg); + napi_create_error(env, code, msg, businessError); + } +} + +napi_value AsyncCall::Call(napi_env env, std::shared_ptr context, const char *fun) +{ + record_.total_.times_++; + record_.total_.lastTime_ = + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) + .count(); + context->executed_ = record_.executed_; + context->fun = (fun == nullptr || fun[0] == '\0') ? "RelationalStoreAsyncCall" : fun; + return context->isAsync_ ? Async(env, context) : Sync(env, context); +} + +napi_value AsyncCall::Async(napi_env env, std::shared_ptr context) +{ + napi_value promise = nullptr; + if (context->callback_ == nullptr) { + napi_status status = napi_create_promise(env, &context->defer_, &promise); + GDB_NAPI_ASSERT_BASE(env, status == napi_ok, + std::make_shared("failed(" + std::to_string(status) + ") to create promise"), nullptr); + } else { + napi_get_undefined(env, &promise); + } + context->keep_ = context; + napi_value resource = nullptr; + napi_create_string_utf8(env, context->fun, NAPI_AUTO_LENGTH, &resource); + // create async work, execute function is OnExecute, complete function is OnComplete + napi_create_async_work(env, nullptr, resource, AsyncCall::OnExecute, AsyncCall::OnComplete, + reinterpret_cast(context.get()), &context->work_); + // add async work to execute queue + auto status = napi_queue_async_work_with_qos(env, context->work_, napi_qos_user_initiated); + if (status != napi_ok) { + napi_get_undefined(env, &promise); + } + auto report = (record_.total_.times_.load() - record_.completed_.times_.load()) / EXCEPT_DELTA; + if (report > record_.reportTimes_ && record_.executed_ != nullptr) { + LOG_WARN("Warning:Times:(C:%{public}" PRId64 ", E:%{public}" PRId64 ", F:%{public}" PRId64 ") Last time(" + "C:%{public}" PRId64 ", E:%{public}" PRId64 ", F:%{public}" PRId64 ")", + record_.total_.times_.load(), record_.executed_->times_.load(), record_.completed_.times_.load(), + record_.total_.lastTime_, record_.executed_->lastTime_, record_.completed_.lastTime_); + } + record_.reportTimes_ = report; + return promise; +} + +napi_value AsyncCall::Sync(napi_env env, std::shared_ptr context) +{ + OnExecute(env, reinterpret_cast(context.get())); + OnComplete(env, reinterpret_cast(context.get())); + if (context->execCode_ != DistributedDataAip::E_OK) { + napi_value error; + SetBusinessError(env, context->error, &error); + napi_throw(env, error); + } + return context->result_; +} + +void AsyncCall::OnExecute(napi_env env, void *data) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + ContextBase *context = reinterpret_cast(data); + if (context->executed_ != nullptr) { + context->executed_->times_++; + context->executed_->lastTime_ = + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) + .count(); + } + if (context->error == nullptr && context->exec_) { + context->execCode_ = context->exec_(); + } + context->exec_ = nullptr; +} + +void AsyncCall::OnComplete(napi_env env, void *data) +{ + ContextBase *context = reinterpret_cast(data); + if (context->execCode_ != DistributedDataAip::E_OK) { + context->SetError(std::make_shared(context->execCode_)); + } + // if async execute status is not napi_ok then un-execute out function + if ((context->error == nullptr) && context->output_) { + context->output_(env, context->result_); + } + context->output_ = nullptr; + record_.completed_.times_++; + record_.completed_.lastTime_ = + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) + .count(); +} + +void AsyncCall::OnComplete(napi_env env, napi_status status, void *data) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + OnComplete(env, data); + OnReturn(env, status, data); +} + +void AsyncCall::OnReturn(napi_env env, napi_status status, void *data) +{ + ContextBase *context = reinterpret_cast(data); + napi_value result[ARG_BUTT] = { 0 }; + // if out function status is ok then async renturn output data, else return error. + if (context->error == nullptr) { + napi_get_undefined(env, &result[ARG_ERROR]); + if (context->result_ != nullptr) { + result[ARG_DATA] = context->result_; + } else { + napi_get_undefined(env, &result[ARG_DATA]); + } + } else { + SetBusinessError(env, context->error, &result[ARG_ERROR]); + napi_get_undefined(env, &result[ARG_DATA]); + } + if (context->defer_ != nullptr) { + // promise + if (status == napi_ok && (context->error == nullptr)) { + napi_resolve_deferred(env, context->defer_, result[ARG_DATA]); + } else { + napi_reject_deferred(env, context->defer_, result[ARG_ERROR]); + } + } else { + // callback + napi_value callback = nullptr; + napi_get_reference_value(env, context->callback_, &callback); + napi_value returnValue = nullptr; + napi_call_function(env, nullptr, callback, ARG_BUTT, result, &returnValue); + } + context->keep_.reset(); +} +} // namespace OHOS::GraphStoreJsKit \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_const_properties.cpp b/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_const_properties.cpp new file mode 100644 index 0000000000000000000000000000000000000000..124243c1d1996203e06c4e44631fcd693bb08421 --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_const_properties.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024 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 "napi_gdb_const_properties.h" + +#include "gdb_common.h" +#include "gdb_store.h" +#include "js_utils.h" + +namespace OHOS::GraphStoreJsKit { +using namespace AppDataMgrJsKit; +using namespace DistributedDataAip; +#define SET_NAPI_PROPERTY(object, prop, value) \ + napi_set_named_property((env), (object), (prop), JSUtils::Convert2JSValue((env), (value))) + +static napi_value ExportSecurityLevel(napi_env env) +{ + napi_value securityLevel = nullptr; + napi_create_object(env, &securityLevel); + + SET_NAPI_PROPERTY(securityLevel, "S1", 1); + SET_NAPI_PROPERTY(securityLevel, "S2", 2); + SET_NAPI_PROPERTY(securityLevel, "S3", 3); + SET_NAPI_PROPERTY(securityLevel, "S4", 4); + + napi_object_freeze(env, securityLevel); + return securityLevel; +} + +napi_status InitConstProperties(napi_env env, napi_value exports) +{ + const napi_property_descriptor properties[] = { + DECLARE_NAPI_PROPERTY("SecurityLevel", ExportSecurityLevel(env)), + }; + + size_t count = sizeof(properties) / sizeof(properties[0]); + return napi_define_properties(env, exports, count, properties); +} +} // namespace OHOS::GraphStoreJsKit \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_error.cpp b/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_error.cpp new file mode 100644 index 0000000000000000000000000000000000000000..037b7341e0abab642b9501a9eee9d3ca49e34ae0 --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_error.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024 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 "napi_gdb_error.h" + +#include + +#include "aip_errors.h" + +namespace OHOS::GraphStoreJsKit { +using namespace DistributedDataAip; +static constexpr JsErrorCode JS_ERROR_CODE_MSGS[] = { + { E_INVALID_ARGS, 401, "Parameter error." }, + { E_GRD_DATA_CORRUPTED, 31300001, "Database corrupted." }, + { E_GRD_DB_INSTANCE_ABNORMAL, 31300002, "Already closed." }, + { E_DATABASE_BUSY, 31300003, "The database is busy." }, + { E_GRD_FAILED_MEMORY_ALLOCATE, 31300004, "The database is out of memory." }, + { E_GRD_DISK_SPACE_FULL, 31300005, "The database is full." }, + { E_GRD_DUPLICATE_PARAM, 31300006, + "A duplicate graph name, vertex or edge type, or vertex or edge property name exists." }, + { E_GRD_UNDEFINED_PARAM, 31300007, + "The graph name, vertex or edge type, or vertex or edge property is not defined." }, + { E_GRD_INVALID_NAME, 31300008, + "The graph name, vertex or edge type, or vertex or edge property name does not conform to constraints." }, + { E_GRD_SYNTAX_ERROR, 31300009, "The GQL statement syntax error." }, + { E_GRD_SEMANTIC_ERROR, 31300010, "The GQL statement semantic error." }, + { E_GRD_OVER_LIMIT, 31300012, + "The number of graph names, vertex or edge types, or vertex or edge properties exceeds the limit." }, + { E_GRD_DATA_CONFLICT, 31300013, "A conflicting constraint already exists." }, + { E_DBPATH_ACCESS_FAILED, 31300014, "Invalid database path." }, + { E_CONFIG_INVALID_CHANGE, 31300015, "Config changed." }, +}; + +std::optional GetJsErrorCode(int32_t errorCode) +{ + auto jsErrorCode = JsErrorCode{ errorCode, -1, "" }; + auto iter = std::lower_bound(JS_ERROR_CODE_MSGS, + JS_ERROR_CODE_MSGS + sizeof(JS_ERROR_CODE_MSGS) / sizeof(JS_ERROR_CODE_MSGS[0]), jsErrorCode, + [](const JsErrorCode &jsErrorCode1, const JsErrorCode &jsErrorCode2) { + return jsErrorCode1.status < jsErrorCode2.status; + }); + if (iter < JS_ERROR_CODE_MSGS + sizeof(JS_ERROR_CODE_MSGS) / sizeof(JS_ERROR_CODE_MSGS[0]) && + iter->status == errorCode) { + return *iter; + } + return std::nullopt; +} +} // namespace OHOS::GraphStoreJsKit \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_js_utils.cpp b/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_js_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3034bc9ce9e644f16f393d87c9d93ed8c22b48a8 --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_js_utils.cpp @@ -0,0 +1,189 @@ +/* +* Copyright (c) 2024 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 "GdbJSUtil" +#include "napi_gdb_js_utils.h" + +#include "gdb_utils.h" +#include "js_ability.h" +#include "securec.h" + +namespace OHOS::AppDataMgrJsKit::JSUtils { +constexpr int MAX_PATH_LENGTH = 1024; + +int32_t GetCurrentAbilityParam(napi_env env, napi_value jsValue, ContextParam ¶m) +{ + std::shared_ptr context = JSAbility::GetCurrentAbility(env, jsValue); + if (context == nullptr) { + return napi_invalid_arg; + } + param.baseDir = context->GetDatabaseDir(); + param.moduleName = context->GetModuleName(); + param.area = context->GetArea(); + param.bundleName = context->GetBundleName(); + param.isSystemApp = context->IsSystemAppCalled(); + return napi_ok; +} + +template<> +int32_t Convert2Value(napi_env env, napi_value jsValue, ContextParam ¶m) +{ + if (jsValue == nullptr) { + LOG_INFO("hasProp is false -> fa stage"); + param.isStageMode = false; + return GetCurrentAbilityParam(env, jsValue, param); + } + + int32_t status = GetNamedProperty(env, jsValue, "stageMode", param.isStageMode); + ASSERT(status == napi_ok, "get stageMode param failed", napi_invalid_arg); + if (!param.isStageMode) { + LOG_WARN("isStageMode is false -> fa stage"); + return GetCurrentAbilityParam(env, jsValue, param); + } + LOG_DEBUG("stage mode branch"); + status = GetNamedProperty(env, jsValue, "databaseDir", param.baseDir); + ASSERT(status == napi_ok, "get databaseDir failed.", napi_invalid_arg); + status = GetNamedProperty(env, jsValue, "area", param.area, true); + ASSERT(status == napi_ok, "get area failed.", napi_invalid_arg); + + napi_value hapInfo = nullptr; + GetNamedProperty(env, jsValue, "currentHapModuleInfo", hapInfo); + if (hapInfo != nullptr) { + status = GetNamedProperty(env, hapInfo, "name", param.moduleName); + ASSERT(status == napi_ok, "get currentHapModuleInfo.name failed.", napi_invalid_arg); + } + + napi_value appInfo = nullptr; + GetNamedProperty(env, jsValue, "applicationInfo", appInfo); + if (appInfo != nullptr) { + status = GetNamedProperty(env, appInfo, "name", param.bundleName); + ASSERT(status == napi_ok, "get applicationInfo.name failed.", napi_invalid_arg); + status = GetNamedProperty(env, appInfo, "systemApp", param.isSystemApp, true); + ASSERT(status == napi_ok, "get applicationInfo.systemApp failed.", napi_invalid_arg); + int32_t hapVersion = JSAbility::GetHapVersion(env, jsValue); + JSUtils::SetHapVersion(hapVersion); + } + return napi_ok; +} + +template<> +int32_t Convert2Value(napi_env env, napi_value jsValue, StoreConfig &config) +{ + std::string name; + auto status = GetNamedProperty(env, jsValue, "name", name); + ASSERT(OK == status, "get name failed.", napi_invalid_arg); + config.SetName(name); + + int32_t securityLevel; + status = GetNamedProperty(env, jsValue, "securityLevel", securityLevel); + ASSERT(OK == status, "get securityLevel failed.", napi_invalid_arg); + config.SetSecurityLevel(securityLevel); + + bool isEncrypt = false; + status = GetNamedProperty(env, jsValue, "encrypt", isEncrypt, true); + ASSERT(OK == status, "get encrypt failed.", napi_invalid_arg); + config.SetEncryptStatus(isEncrypt); + return napi_ok; +} + +template<> +napi_value Convert2JSValue(napi_env env, const std::shared_ptr &result) +{ + std::vector descriptors = { + DECLARE_JS_PROPERTY(env, "records", result->GetAllData()), + }; + + napi_value object = nullptr; + NAPI_CALL_RETURN_ERR( + napi_create_object_with_properties(env, &object, descriptors.size(), descriptors.data()), object); + return object; +} + +template<> +napi_value Convert2JSValue(napi_env env, const std::shared_ptr &vertex) +{ + std::vector descriptors = { + DECLARE_JS_PROPERTY(env, "vid", vertex->GetId()), + DECLARE_JS_PROPERTY(env, "labels", vertex->GetLabels()), + DECLARE_JS_PROPERTY(env, "properties", vertex->GetProperties()), + }; + + napi_value object = nullptr; + NAPI_CALL_RETURN_ERR( + napi_create_object_with_properties(env, &object, descriptors.size(), descriptors.data()), object); + return object; +} + +template<> +napi_value Convert2JSValue(napi_env env, const std::shared_ptr &edge) +{ + std::vector descriptors = { + DECLARE_JS_PROPERTY(env, "eid", edge->GetId()), + DECLARE_JS_PROPERTY(env, "type", edge->GetLabel()), + DECLARE_JS_PROPERTY(env, "startVid", edge->GetSourceId()), + DECLARE_JS_PROPERTY(env, "endVid", edge->GetTargetId()), + DECLARE_JS_PROPERTY(env, "properties", edge->GetProperties()), + }; + + napi_value object = nullptr; + NAPI_CALL_RETURN_ERR( + napi_create_object_with_properties(env, &object, descriptors.size(), descriptors.data()), object); + return object; +} + +template<> +napi_value Convert2JSValue(napi_env env, const std::shared_ptr &pathSegment) +{ + std::vector descriptors = { + DECLARE_JS_PROPERTY(env, "start", pathSegment->GetSourceVertex()), + DECLARE_JS_PROPERTY(env, "end", pathSegment->GetTargetVertex()), + DECLARE_JS_PROPERTY(env, "edge", pathSegment->GetEdge()), + }; + + napi_value object = nullptr; + NAPI_CALL_RETURN_ERR( + napi_create_object_with_properties(env, &object, descriptors.size(), descriptors.data()), object); + return object; +} + +template<> +napi_value Convert2JSValue(napi_env env, const std::shared_ptr &path) +{ + std::vector descriptors = { + DECLARE_JS_PROPERTY(env, "start", path->GetStart()), + DECLARE_JS_PROPERTY(env, "end", path->GetEnd()), + DECLARE_JS_PROPERTY(env, "length", path->GetPathLength()), + DECLARE_JS_PROPERTY(env, "segments", path->GetSegments()), + }; + + napi_value object = nullptr; + NAPI_CALL_RETURN_ERR( + napi_create_object_with_properties(env, &object, descriptors.size(), descriptors.data()), object); + return object; +} + +std::tuple> GetRealPath(StoreConfig &config, ContextParam ¶m) +{ + CHECK_RETURN_CORE(config.GetName().find(PATH_SPLIT) == std::string::npos, GDB_DO_NOTHING, + std::make_tuple(ERR, std::make_shared("StoreConfig.name", "a database name without path."))); + std::string databaseDir; + databaseDir.append(param.baseDir).append("/gdb"); + auto errorCode = DistributedDataAip::GdbUtils::CreateDirectory(databaseDir); + std::string realPath = databaseDir + "/" + config.GetName(); + CHECK_RETURN_CORE(errorCode == E_OK && realPath.length() <= MAX_PATH_LENGTH, GDB_DO_NOTHING, + std::make_tuple(ERR, std::make_shared("database path", "a valid path."))); + config.SetPath(databaseDir); + return std::make_tuple(E_OK, nullptr); +} +} \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_store.cpp b/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_store.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9a05f8c539ac38a09706989d41d8f1fcd70ca1c0 --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_store.cpp @@ -0,0 +1,301 @@ +/* +* Copyright (c) 2024 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 "GdbStoreProxy" +#include "napi_gdb_store.h" + +#include +#include +#include +#include + +#include "db_trace.h" +#include "js_utils.h" +#include "logger.h" +#include "napi_gdb_context.h" +#include "napi_gdb_error.h" +#include "napi_gdb_js_utils.h" +#include "napi_gdb_transaction.h" + +namespace OHOS::GraphStoreJsKit { + +GdbStoreProxy::GdbStoreProxy() +{ +} + +GdbStoreProxy::~GdbStoreProxy() +{ +} + +GdbStoreProxy::GdbStoreProxy(std::shared_ptr gdbStore) +{ + if (GetInstance() == gdbStore) { + return; + } + SetInstance(std::move(gdbStore)); +} + +GdbStoreProxy &GdbStoreProxy::operator=(std::shared_ptr gdbStore) +{ + if (GetInstance() == gdbStore) { + return *this; + } + SetInstance(std::move(gdbStore)); + return *this; +} + +bool GdbStoreProxy::IsSystemAppCalled() +{ + return isSystemAppCalled_; +} + +Descriptor GdbStoreProxy::GetDescriptors() +{ + return []() -> std::vector { + std::vector properties = { + DECLARE_NAPI_FUNCTION("read", Read), + DECLARE_NAPI_FUNCTION("write", Write), + DECLARE_NAPI_FUNCTION("createTransaction", CreateTransaction), + DECLARE_NAPI_FUNCTION("close", Close), + }; + return properties; + }; +} + +void GdbStoreProxy::Init(napi_env env, napi_value exports) +{ + auto jsCtor = OHOS::AppDataMgrJsKit::JSUtils::DefineClass( + env, "ohos.data.graphStore", "GraphStore", GetDescriptors(), Initialize); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, exports, "GraphStore", jsCtor)); +} + +void GdbStoreProxy::Destructor(napi_env env, void *nativeObject, void *finalize_hint) +{ + auto *obj = static_cast(nativeObject); + delete obj; +} + +napi_value GdbStoreProxy::New(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = { 0 }; + napi_value thisVar = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + + // get native object + auto *obj = new GdbStoreProxy(); + ASSERT_CALL(env, + napi_wrap(env, thisVar, obj, GdbStoreProxy::Destructor, + nullptr, // finalize_hint + nullptr), + obj); + return thisVar; +} + +napi_value GdbStoreProxy::Initialize(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &self, nullptr)); + auto finalize = [](napi_env env, void *data, void *hint) { + if (data != hint) { + LOG_ERROR("GdbStoreProxy memory corrupted! data:0x%016" PRIXPTR "hint:0x%016" PRIXPTR, uintptr_t(data), + uintptr_t(hint)); + return; + } + GdbStoreProxy *proxy = reinterpret_cast(data); + proxy->SetInstance(nullptr); + delete proxy; + }; + auto *proxy = new (std::nothrow) GdbStoreProxy(); + if (proxy == nullptr) { + return nullptr; + } + napi_status status = napi_wrap(env, self, proxy, finalize, proxy, nullptr); + if (status != napi_ok) { + LOG_ERROR("GdbStoreProxy napi_wrap failed! code:%{public}d!", status); + finalize(env, proxy, proxy); + return nullptr; + } + return self; +} + +napi_value GdbStoreProxy::NewInstance(napi_env env, std::shared_ptr value, bool isSystemAppCalled) +{ + if (value == nullptr) { + LOG_ERROR("dbstore is nullptr"); + return nullptr; + } + napi_value cons = OHOS::AppDataMgrJsKit::JSUtils::GetClass(env, "ohos.data.graphStore", "GraphStore"); + if (cons == nullptr) { + LOG_ERROR("Constructor of ResultSet is nullptr!"); + return nullptr; + } + + napi_value instance = nullptr; + auto status = napi_new_instance(env, cons, 0, nullptr, &instance); + if (status != napi_ok) { + LOG_ERROR("GdbStoreProxy::NewInstance napi_new_instance failed! code:%{public}d!", status); + return nullptr; + } + + GdbStoreProxy *proxy = nullptr; + status = napi_unwrap(env, instance, reinterpret_cast(&proxy)); + if (proxy == nullptr) { + LOG_ERROR("GdbStoreProxy::NewInstance native instance is nullptr! code:%{public}d!", status); + return instance; + } + proxy->queue_ = std::make_shared(env); + proxy->SetInstance(std::move(value)); + proxy->isSystemAppCalled_ = isSystemAppCalled; + return instance; +} + +GdbStoreProxy *GetNativeInstance(napi_env env, napi_value self) +{ + GdbStoreProxy *proxy = nullptr; + napi_status status = napi_unwrap(env, self, reinterpret_cast(&proxy)); + if (proxy == nullptr) { + LOG_ERROR("GdbStoreProxy native instance is nullptr! code:%{public}d!", status); + return nullptr; + } + return proxy; +} + +int ParseThis(const napi_env &env, const napi_value &self, const std::shared_ptr &context) +{ + GdbStoreProxy *obj = GetNativeInstance(env, self); + CHECK_RETURN_SET(obj != nullptr, std::make_shared("GdbStore", "not nullptr.")); + CHECK_RETURN_SET(obj->GetInstance() != nullptr, std::make_shared(E_GRD_DB_INSTANCE_ABNORMAL)); + context->boundObj = obj; + context->gdbStore = obj->GetInstance(); + return OK; +} + +int ParseGql(const napi_env env, const napi_value arg, const std::shared_ptr &context) +{ + context->gql = OHOS::AppDataMgrJsKit::JSUtils::Convert2String(env, arg); + CHECK_RETURN_SET(!context->gql.empty(), std::make_shared("gql", "not empty")); + CHECK_RETURN_SET(context->gql.size() <= GdbStoreProxy::MAX_GQL_LEN, + std::make_shared("gql", "too long")); + return OK; +} + +napi_value GdbStoreProxy::Read(napi_env env, napi_callback_info info) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + auto context = std::make_shared(); + auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { + CHECK_RETURN_SET_E(argc == 1, std::make_shared(" 1 ")); + CHECK_RETURN(OK == ParseThis(env, self, context)); + CHECK_RETURN(OK == ParseGql(env, argv[0], context)); + }; + auto exec = [context]() -> int { + CHECK_RETURN_ERR(context->gdbStore != nullptr); + auto queryResult = context->StealGdbStore()->QueryGql(context->gql); + context->result = queryResult.second; + context->intOutput = queryResult.first; + return OK; + }; + auto output = [context](napi_env env, napi_value &result) { + result = AppDataMgrJsKit::JSUtils::Convert2JSValue(env, context->result); + CHECK_RETURN_SET_E(context->intOutput == OK, std::make_shared(context->intOutput)); + }; + context->SetAction(env, info, input, exec, output); + CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK); + return ASYNC_CALL(env, context); +} + +napi_value GdbStoreProxy::Write(napi_env env, napi_callback_info info) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + auto context = std::make_shared(); + auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { + CHECK_RETURN_SET_E(argc == 1, std::make_shared(" 1 ")); + CHECK_RETURN(OK == ParseThis(env, self, context)); + CHECK_RETURN(OK == ParseGql(env, argv[0], context)); + }; + auto exec = [context]() -> int { + CHECK_RETURN_ERR(context->gdbStore != nullptr); + auto executeResult = context->StealGdbStore()->ExecuteGql(context->gql); + context->result = executeResult.second; + context->intOutput = executeResult.first; + return OK; + }; + auto output = [context](napi_env env, napi_value &result) { + result = AppDataMgrJsKit::JSUtils::Convert2JSValue(env, context->result); + CHECK_RETURN_SET_E(context->intOutput == OK, std::make_shared(context->intOutput)); + }; + context->SetAction(env, info, input, exec, output); + CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK); + return ASYNC_CALL(env, context); +} + +napi_value GdbStoreProxy::CreateTransaction(napi_env env, napi_callback_info info) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + auto context = std::make_shared(); + auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { + CHECK_RETURN_SET_E(argc == 0, std::make_shared(" 0 ")); + CHECK_RETURN(OK == ParseThis(env, self, context)); + }; + auto exec = [context]() -> int { + CHECK_RETURN_ERR(context->gdbStore != nullptr); + int32_t code = E_ERROR; + std::tie(code, context->transaction) = context->StealGdbStore()->CreateTransaction(); + if (code != E_OK) { + context->transaction = nullptr; + return code; + } + return context->transaction != nullptr ? OK : E_ERROR; + }; + auto output = [context](napi_env env, napi_value &result) { + result = GdbTransactionProxy::NewInstance(env, context->transaction); + CHECK_RETURN_SET_E(result != nullptr, std::make_shared(E_INNER_ERROR)); + }; + context->SetAction(env, info, input, exec, output); + CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK); + return ASYNC_CALL(env, context); +} + +napi_value GdbStoreProxy::Close(napi_env env, napi_callback_info info) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + auto context = std::make_shared(); + auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { + GdbStoreProxy *proxy = GetNativeInstance(env, self); + CHECK_RETURN_SET(proxy != nullptr, std::make_shared("GdbStore", "not nullptr.")); + if (proxy->GetInstance() == nullptr) { + LOG_WARN("GdbStoreProxy native instance is nullptr!"); + return OK; + } + context->boundObj = proxy; + context->gdbStore = proxy->GetInstance(); + + auto *obj = reinterpret_cast(context->boundObj); + obj->SetInstance(nullptr); + return OK; + }; + auto exec = [context]() -> int { + context->gdbStore = nullptr; + return OK; + }; + auto output = [context](napi_env env, napi_value &result) { + napi_status status = napi_get_undefined(env, &result); + CHECK_RETURN_SET_E(status == napi_ok, std::make_shared(E_ERROR)); + }; + context->SetAction(env, info, input, exec, output); + CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK); + return ASYNC_CALL(env, context); +} +} // namespace OHOS::GraphStoreJsKit \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_store_helper.cpp b/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_store_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..50f5df70d3e93283c8ff51a9d3b340a9a8bf746a --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_store_helper.cpp @@ -0,0 +1,109 @@ +/* +* Copyright (c) 2024 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 "GdbStoreHelperProxy" +#include "napi_gdb_store_helper.h" + +#include + +#include "db_trace.h" +#include "gdb_helper.h" +#include "logger.h" +#include "napi_gdb_context.h" +#include "napi_gdb_js_utils.h" +#include "napi_gdb_store.h" + +namespace OHOS::GraphStoreJsKit { +using namespace OHOS::DistributedDataAip; + +static constexpr int MAX_GDB_DB_NAME_LENGTH = 128; + +bool IsValidDbName(const std::string &name) +{ + if (name.empty() || name.size() > MAX_GDB_DB_NAME_LENGTH) { + return false; + } + const std::regex pattern("^[a-zA-Z0-9_]+$"); + return std::regex_match(name, pattern); +} + +napi_value GetStore(napi_env env, napi_callback_info info) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + auto context = std::make_shared(); + auto input = [context, info](napi_env env, size_t argc, napi_value *argv, napi_value self) { + CHECK_RETURN_SET_E(argc == 2, std::make_shared(" 2 ")); + int errCode = AppDataMgrJsKit::JSUtils::Convert2Value(env, argv[0], context->param); + CHECK_RETURN_SET_E(OK == errCode, std::make_shared("Illegal context.")); + CHECK_RETURN_SET_E(context->param.isSystemApp, std::make_shared()); + errCode = AppDataMgrJsKit::JSUtils::Convert2Value(env, argv[1], context->config); + CHECK_RETURN_SET_E(OK == errCode, std::make_shared("Illegal StoreConfig or name.")); + CHECK_RETURN_SET_E(IsValidDbName(context->config.GetName()), std::make_shared("Illegal name.")); + auto [code, err] = AppDataMgrJsKit::JSUtils::GetRealPath(context->config, context->param); + CHECK_RETURN_SET_E(OK == code, err); + context->config.SetBundleName(context->param.bundleName); + }; + auto exec = [context]() -> int { + context->gdbStore = GDBHelper::GetDBStore(context->config, context->intOutput); + return OK; + }; + auto output = [context](napi_env env, napi_value &result) { + CHECK_RETURN_SET_E(context->intOutput == OK, std::make_shared(context->intOutput)); + result = GdbStoreProxy::NewInstance(env, context->gdbStore, context->param.isSystemApp); + CHECK_RETURN_SET_E(result != nullptr, std::make_shared(E_INNER_ERROR)); + }; + context->SetAction(env, info, input, exec, output); + + CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK); + return ASYNC_CALL(env, context); +} + +napi_value DeleteStore(napi_env env, napi_callback_info info) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + auto context = std::make_shared(); + auto input = [context, info](napi_env env, size_t argc, napi_value *argv, napi_value self) { + CHECK_RETURN_SET_E(argc == 2, std::make_shared(" 2 ")); + int errCode = AppDataMgrJsKit::JSUtils::Convert2Value(env, argv[0], context->param); + CHECK_RETURN_SET_E(OK == errCode, std::make_shared("Illegal context.")); + CHECK_RETURN_SET_E(context->param.isSystemApp, std::make_shared()); + errCode = AppDataMgrJsKit::JSUtils::Convert2Value(env, argv[1], context->config); + CHECK_RETURN_SET_E(OK == errCode, std::make_shared("Illegal StoreConfig or name.")); + CHECK_RETURN_SET_E(IsValidDbName(context->config.GetName()), std::make_shared("Illegal name.")); + auto [code, err] = AppDataMgrJsKit::JSUtils::GetRealPath(context->config, context->param); + CHECK_RETURN_SET_E(OK == code, err); + }; + auto exec = [context]() -> int { + context->intOutput = GDBHelper::DeleteDBStore(context->config); + return OK; + }; + auto output = [context](napi_env env, napi_value &result) { + CHECK_RETURN_SET_E(context->intOutput == OK, std::make_shared(context->intOutput)); + }; + context->SetAction(env, info, input, exec, output); + + CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK); + return ASYNC_CALL(env, context); +} + +napi_value InitGdbHelper(napi_env env, napi_value exports) +{ + napi_property_descriptor properties[] = { + DECLARE_NAPI_FUNCTION_WITH_DATA("getStore", GetStore, AIP_ASYNC), + DECLARE_NAPI_FUNCTION_WITH_DATA("deleteStore", DeleteStore, AIP_ASYNC), + }; + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(properties) / sizeof(*properties), properties)); + return exports; +} +} // namespace OHOS::GraphStoreJsKit \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_transaction.cpp b/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_transaction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..00d55c10fac99a577f3d5e7bbf9c99a93ebeb579 --- /dev/null +++ b/relational_store/frameworks/js/napi/graphstore/src/napi_gdb_transaction.cpp @@ -0,0 +1,252 @@ +/* +* Copyright (c) 2025 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 "GdbTransactionProxy" +#include "napi_gdb_transaction.h" + +#include +#include +#include +#include + +#include "db_trace.h" +#include "js_utils.h" +#include "logger.h" +#include "napi_gdb_context.h" +#include "napi_gdb_error.h" +#include "napi_gdb_js_utils.h" + +namespace OHOS::GraphStoreJsKit { +#define ASSERT_RETURN_SET_ERROR(assertion, paramError) \ + CHECK_RETURN_CORE(assertion, SetError(paramError), ERR) + +constexpr int32_t MAX_GQL_LEN = 1024 * 1024; + +constexpr const char *SPACE_NAME = "ohos.data.graphStore"; +constexpr const char *CLASS_NAME = "Transaction"; + +struct TransactionContext : public ContextBase { + void GetInstance(napi_value self) + { + auto status = napi_unwrap(env_, self, reinterpret_cast(&boundObj)); + if (status != napi_ok || boundObj == nullptr) { + LOG_ERROR("GdbTransactionProxy native instance is nullptr! code:%{public}d!", status); + return; + } + transaction_ = reinterpret_cast(boundObj)->GetInstance(); + } + std::shared_ptr StealTransaction() + { + auto trans = std::move(transaction_); + transaction_ = nullptr; + return trans; + } + std::shared_ptr transaction_ = nullptr; +}; + +GdbTransactionProxy::~GdbTransactionProxy() +{ +} + +GdbTransactionProxy::GdbTransactionProxy(std::shared_ptr gdbTransaction) +{ + if (GetInstance() == gdbTransaction) { + return; + } + SetInstance(std::move(gdbTransaction)); +} + +napi_value GdbTransactionProxy::Initialize(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &self, nullptr)); + auto *proxy = new (std::nothrow) GdbTransactionProxy(); + if (proxy == nullptr) { + return nullptr; + } + auto finalize = [](napi_env env, void *data, void *hint) { + if (data != hint) { + LOG_ERROR("memory corrupted! data:0x%016" PRIXPTR "hint:0x%016" PRIXPTR, + uintptr_t(data), uintptr_t(hint)); + return; + } + GdbTransactionProxy *proxy = reinterpret_cast(data); + proxy->SetInstance(nullptr); + delete proxy; + }; + napi_status status = napi_wrap(env, self, proxy, finalize, proxy, nullptr); + if (status != napi_ok) { + LOG_ERROR("napi_wrap failed! code:%{public}d!", status); + finalize(env, proxy, proxy); + return nullptr; + } + return self; +} + +void GdbTransactionProxy::Init(napi_env env, napi_value exports) +{ + auto lambda = []() -> std::vector { + std::vector properties = { + DECLARE_NAPI_FUNCTION("read", Read), + DECLARE_NAPI_FUNCTION("write", Write), + DECLARE_NAPI_FUNCTION("commit", Commit), + DECLARE_NAPI_FUNCTION("rollback", Rollback), + }; + return properties; + }; + auto jsCtor = AppDataMgrJsKit::JSUtils::DefineClass(env, SPACE_NAME, CLASS_NAME, lambda, Initialize); + NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, exports, CLASS_NAME, jsCtor)); +} + +napi_value GdbTransactionProxy::NewInstance(napi_env env, std::shared_ptr value) +{ + if (value == nullptr) { + LOG_ERROR("value is nullptr"); + return nullptr; + } + napi_value cons = AppDataMgrJsKit::JSUtils::GetClass(env, SPACE_NAME, CLASS_NAME); + if (cons == nullptr) { + LOG_ERROR("Constructor of Transaction is nullptr!"); + return nullptr; + } + + napi_value instance = nullptr; + auto status = napi_new_instance(env, cons, 0, nullptr, &instance); + if (status != napi_ok) { + LOG_ERROR("create new instance failed! code:%{public}d!", status); + return nullptr; + } + + GdbTransactionProxy *proxy = nullptr; + status = napi_unwrap(env, instance, reinterpret_cast(&proxy)); + if (status != napi_ok || proxy == nullptr) { + LOG_ERROR("native instance is nullptr! code:%{public}d!", status); + return instance; + } + proxy->SetInstance(std::move(value)); + return instance; +} + +struct ReadWriteContext : public TransactionContext { + int32_t Parse(napi_env env, size_t argc, napi_value *argv, napi_value self) + { + ASSERT_RETURN_SET_ERROR(argc == 1, std::make_shared(" 1 ")); + GetInstance(self); + ASSERT_RETURN_SET_ERROR(transaction_ != nullptr, std::make_shared("transaction", "not nullptr.")); + gql = AppDataMgrJsKit::JSUtils::Convert2String(env, argv[0]); + ASSERT_RETURN_SET_ERROR(!gql.empty(), std::make_shared("gql", "not empty")); + ASSERT_RETURN_SET_ERROR(gql.size() <= MAX_GQL_LEN, + std::make_shared("gql", "too long")); + return OK; + } + std::string gql; + std::shared_ptr result; + int32_t errCode; +}; + +napi_value GdbTransactionProxy::Read(napi_env env, napi_callback_info info) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + auto context = std::make_shared(); + auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { + context->Parse(env, argc, argv, self); + }; + auto exec = [context]() -> int { + CHECK_RETURN_ERR(context->transaction_ != nullptr); + std::tie(context->errCode, context->result) = context->StealTransaction()->Query(context->gql); + return context->errCode; + }; + auto output = [context](napi_env env, napi_value &result) { + result = AppDataMgrJsKit::JSUtils::Convert2JSValue(env, context->result); + CHECK_RETURN_SET_E(context->errCode == OK, std::make_shared(context->errCode)); + }; + context->SetAction(env, info, input, exec, output); + + CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK); + return ASYNC_CALL(env, context); +} + +napi_value GdbTransactionProxy::Write(napi_env env, napi_callback_info info) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + auto context = std::make_shared(); + auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { + context->Parse(env, argc, argv, self); + }; + auto exec = [context]() -> int { + CHECK_RETURN_ERR(context->transaction_ != nullptr); + std::tie(context->errCode, context->result) = context->StealTransaction()->Execute(context->gql); + return context->errCode; + }; + auto output = [context](napi_env env, napi_value &result) { + result = AppDataMgrJsKit::JSUtils::Convert2JSValue(env, context->result); + CHECK_RETURN_SET_E(context->errCode == OK, std::make_shared(context->errCode)); + }; + context->SetAction(env, info, input, exec, output); + + CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK); + return ASYNC_CALL(env, context); +} + +struct CommitRollbackContext : public TransactionContext { + int32_t Parse(napi_env env, size_t argc, napi_value *argv, napi_value self) + { + GetInstance(self); + ASSERT_RETURN_SET_ERROR(transaction_ != nullptr, std::make_shared("transaction", "a transaction.")); + return OK; + } +}; + +napi_value GdbTransactionProxy::Commit(napi_env env, napi_callback_info info) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + auto context = std::make_shared(); + auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { + context->Parse(env, argc, argv, self); + }; + auto exec = [context]() -> int { + CHECK_RETURN_ERR(context->transaction_ != nullptr); + return context->StealTransaction()->Commit(); + }; + auto output = [context](napi_env env, napi_value &result) { + napi_status status = napi_get_undefined(env, &result); + CHECK_RETURN_SET_E(status == napi_ok, std::make_shared(E_ERROR)); + }; + context->SetAction(env, info, input, exec, output); + + CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK); + return ASYNC_CALL(env, context); +} + +napi_value GdbTransactionProxy::Rollback(napi_env env, napi_callback_info info) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + auto context = std::make_shared(); + auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { + context->Parse(env, argc, argv, self); + }; + auto exec = [context]() -> int { + CHECK_RETURN_ERR(context->transaction_ != nullptr); + return context->StealTransaction()->Rollback(); + }; + auto output = [context](napi_env env, napi_value &result) { + napi_status status = napi_get_undefined(env, &result); + CHECK_RETURN_SET_E(status == napi_ok, std::make_shared(E_ERROR)); + }; + context->SetAction(env, info, input, exec, output); + + CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK); + return ASYNC_CALL(env, context); +} +} // namespace OHOS::GraphStoreJsKit diff --git a/relational_store/frameworks/js/napi/rdb/src/napi_async_call.cpp b/relational_store/frameworks/js/napi/rdb/src/napi_async_call.cpp index 1a0a90d7e8eac19072eb4625057bafb214849c71..8d23e9294c842a59d1db12ffcdf98207cd1bff7d 100644 --- a/relational_store/frameworks/js/napi/rdb/src/napi_async_call.cpp +++ b/relational_store/frameworks/js/napi/rdb/src/napi_async_call.cpp @@ -34,7 +34,7 @@ void BaseContext::SetAction( napi_valuetype valueType = napi_undefined; napi_typeof(env, argv[argc - 1], &valueType); if (valueType == napi_function) { - LOG_DEBUG("asyncCall set callback"); + LOG_DEBUG("AsyncCall set callback"); NAPI_CALL_RETURN_VOID(env, napi_create_reference(env, argv[argc - 1], 1, &callback_)); argc = argc - 1; } diff --git a/relational_store/frameworks/js/napi/rdb/src/napi_rdb_const_properties.cpp b/relational_store/frameworks/js/napi/rdb/src/napi_rdb_const_properties.cpp index 1b27562cb4fcc16142a7aaf66a22d13c5a656b25..10762fa013db9419cf22086fabe3a30644f71c76 100644 --- a/relational_store/frameworks/js/napi/rdb/src/napi_rdb_const_properties.cpp +++ b/relational_store/frameworks/js/napi/rdb/src/napi_rdb_const_properties.cpp @@ -41,7 +41,10 @@ static napi_status SetNamedProperty(napi_env env, napi_value &obj, const std::st static napi_value ExportSyncMode(napi_env env) { napi_value syncMode = nullptr; - napi_create_object(env, &syncMode); + napi_status status = napi_create_object(env, &syncMode); + if (status != napi_ok) { + return nullptr; + } (void)SetNamedProperty(env, syncMode, "SYNC_MODE_PUSH", (int32_t)SyncMode::PUSH); (void)SetNamedProperty(env, syncMode, "SYNC_MODE_PULL", (int32_t)SyncMode::PULL); napi_object_freeze(env, syncMode); @@ -51,7 +54,10 @@ static napi_value ExportSyncMode(napi_env env) static napi_value ExportSubscribeType(napi_env env) { napi_value subscribeType = nullptr; - napi_create_object(env, &subscribeType); + napi_status status = napi_create_object(env, &subscribeType); + if (status != napi_ok) { + return nullptr; + } (void)SetNamedProperty(env, subscribeType, "SUBSCRIBE_TYPE_REMOTE", (int32_t)SubscribeMode::REMOTE); napi_object_freeze(env, subscribeType); @@ -61,7 +67,10 @@ static napi_value ExportSubscribeType(napi_env env) static napi_value ExportSecurityLevel(napi_env env) { napi_value securityLevel = nullptr; - napi_create_object(env, &securityLevel); + napi_status status = napi_create_object(env, &securityLevel); + if (status != napi_ok) { + return nullptr; + } (void)SetNamedProperty(env, securityLevel, "S1", (int32_t)NativeRdb::SecurityLevel::S1); (void)SetNamedProperty(env, securityLevel, "S2", (int32_t)NativeRdb::SecurityLevel::S2); diff --git a/relational_store/frameworks/js/napi/relationalstore/BUILD.gn b/relational_store/frameworks/js/napi/relationalstore/BUILD.gn index 53b602514696544a989aa5296ac389c84cdf758e..6578c6647d4807d9fb09113ee37ef719c5439f86 100644 --- a/relational_store/frameworks/js/napi/relationalstore/BUILD.gn +++ b/relational_store/frameworks/js/napi/relationalstore/BUILD.gn @@ -34,6 +34,7 @@ sources = [ "src/napi_rdb_js_utils.cpp", "src/napi_rdb_predicates.cpp", "src/napi_rdb_sendable_utils.cpp", + "src/napi_rdb_statistics_observer.cpp", "src/napi_rdb_store.cpp", "src/napi_rdb_store_helper.cpp", "src/napi_result_set.cpp", @@ -179,7 +180,10 @@ if (is_ohos) { "-stdlib=libc++", ] - defines = [ "ANDROID_PLATFORM" ] + defines = [ + "ANDROID_PLATFORM", + "CROSS_PLATFORM", + ] sources += [ "${relational_store_js_common_path}/mock/src/js_ability.cpp", diff --git a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_error.h b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_error.h index 4ea2ec0298741aeacd391096dfc9b9bc6db6abd3..115c0e27e22462b9850aaf0b93c2df03dc801a2c 100644 --- a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_error.h +++ b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_error.h @@ -33,6 +33,7 @@ constexpr int E_PARAM_ERROR = 401; constexpr int E_INNER_ERROR = 14800000; constexpr int E_NOT_STAGE_MODE = 14801001; constexpr int E_DATA_GROUP_ID_INVALID = 14801002; +constexpr int E_INVALID_FILE_PATH = 14800010; struct JsErrorCode { int32_t status; @@ -179,6 +180,19 @@ public: private: std::string wantNum; }; + +class PathError : public Error { +public: + PathError(){}; + std::string GetMessage() override + { + return "Invalid database path."; + }; + int GetCode() override + { + return E_INVALID_FILE_PATH; + }; +}; } // namespace RelationalStoreJsKit } // namespace OHOS diff --git a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_js_utils.h b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_js_utils.h index d9bbadfcf7cb1b12f3d3fb1409ad361121508264..8b1d01a92fa4696a29d9644f860a9e0639651b9b 100644 --- a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_js_utils.h +++ b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_js_utils.h @@ -39,6 +39,7 @@ using JSChangeInfo = OHOS::RelationalStoreJsKit::NapiRdbStoreObserver::JSChangeI using PRIKey = OHOS::DistributedRdb::RdbStoreObserver::PrimaryKey; using Error = RelationalStoreJsKit::Error; using SecurityLevel = NativeRdb::SecurityLevel; +using Tokenizer = NativeRdb::Tokenizer; using RdbStoreConfig = NativeRdb::RdbStoreConfig; using BigInt = OHOS::NativeRdb::BigInteger; using SqlExecInfo = DistributedRdb::SqlObserver::SqlExecutionInfo; @@ -57,9 +58,11 @@ struct RdbConfig { bool allowRebuild = false; bool isReadOnly = false; SecurityLevel securityLevel = SecurityLevel::LAST; + Tokenizer tokenizer = Tokenizer::NONE_TOKENIZER; std::string dataGroupId; std::string name; std::string customDir; + std::string rootDir; std::string path; std::vector pluginLibs = {}; int32_t haMode = HAMode::SINGLE; diff --git a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_statistics_observer.h b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_statistics_observer.h new file mode 100644 index 0000000000000000000000000000000000000000..4b2adf7a169c664f343fb289357ef6ea3b5af271 --- /dev/null +++ b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_statistics_observer.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 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 RDB_JSKIT_NAPI_RDB_STATISTICS_OBSERVER_H +#define RDB_JSKIT_NAPI_RDB_STATISTICS_OBSERVER_H +#include + +#include "js_uv_queue.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "rdb_types.h" + +namespace OHOS { +namespace RelationalStoreJsKit { +class NapiStatisticsObserver + : public DistributedRdb::SqlObserver, public std::enable_shared_from_this { +public: + NapiStatisticsObserver(napi_env env, napi_value callback, std::shared_ptr uvQueue); + virtual ~NapiStatisticsObserver(); + void Clear(); + bool operator==(napi_value value); + void OnStatistic(const SqlExecutionInfo &sqlExeInfo) override; + +private: + napi_env env_ = nullptr; + napi_ref callback_ = nullptr; + std::shared_ptr queue_ = nullptr; +}; + +} // namespace RelationalStoreJsKit +} // namespace OHOS +#endif //RDB_JSKIT_NAPI_RDB_STATISTICS_OBSERVER_H diff --git a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_store.h b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_store.h index 23f74e460c36709bfc84b292cf873619e87e9f88..b7ddc661c782bee8a92b48eae0fffc2f90d861e6 100644 --- a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_store.h +++ b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_store.h @@ -26,7 +26,6 @@ #include "napi/native_common.h" #include "napi/native_node_api.h" #include "napi_rdb_error.h" -#include "napi_rdb_store_observer.h" #include "rdb_helper.h" #include "rdb_store.h" #include "rdb_types.h" @@ -34,15 +33,19 @@ namespace OHOS { namespace RelationalStoreJsKit { using Descriptor = std::function(void)>; +class NapiRdbStoreObserver; +class NapiStatisticsObserver; class RdbStoreProxy : public JSProxy::JSProxy { public: static void Init(napi_env env, napi_value exports); - static napi_value NewInstance(napi_env env, std::shared_ptr value, bool isSystemAppCalled); + static napi_value NewInstance(napi_env env, std::shared_ptr value, bool isSystemAppCalled, + const std::string &bundleName); RdbStoreProxy(); ~RdbStoreProxy(); RdbStoreProxy(std::shared_ptr rdbStore); RdbStoreProxy &operator=(std::shared_ptr rdbStore); bool IsSystemAppCalled(); + std::string GetBundleName(); private: static napi_value Initialize(napi_env env, napi_callback_info info); @@ -50,6 +53,7 @@ private: static napi_value Update(napi_env env, napi_callback_info info); static napi_value Insert(napi_env env, napi_callback_info info); static napi_value BatchInsert(napi_env env, napi_callback_info info); + static napi_value BatchInsertWithConflictResolution(napi_env env, napi_callback_info info); static napi_value Query(napi_env env, napi_callback_info info); static napi_value RemoteQuery(napi_env env, napi_callback_info info); static napi_value QuerySql(napi_env env, napi_callback_info info); @@ -86,6 +90,7 @@ private: static napi_value Close(napi_env env, napi_callback_info info); static napi_value CreateTransaction(napi_env env, napi_callback_info info); static Descriptor GetDescriptors(); + static void AddDistributedFunctions(std::vector &properties); static void AddSyncFunctions(std::vector &properties); static napi_value ModifyLockStatus(napi_env env, napi_callback_info info, bool isLock); static napi_value LockRow(napi_env env, napi_callback_info info); @@ -95,6 +100,7 @@ private: static napi_value UnlockCloudContainer(napi_env env, napi_callback_info info); static void SetBusinessError(napi_env env, std::shared_ptr error, napi_value *businessError); + void UnregisterAll(); static constexpr int EVENT_HANDLE_NUM = 3; static constexpr int WAIT_TIME_DEFAULT = 2; @@ -125,21 +131,6 @@ private: std::shared_ptr queue_ = nullptr; }; - class NapiStatisticsObserver - : public DistributedRdb::SqlObserver, public std::enable_shared_from_this { - public: - NapiStatisticsObserver(napi_env env, napi_value callback, std::shared_ptr uvQueue); - virtual ~NapiStatisticsObserver(); - void Clear(); - bool operator==(napi_value value); - void OnStatistic(const SqlExecutionInfo &sqlExeInfo) override; - - private: - napi_env env_ = nullptr; - napi_ref callback_ = nullptr; - std::shared_ptr queue_ = nullptr; - }; - napi_value RegisterSyncCallback(napi_env env, size_t argc, napi_value *argv); napi_value UnregisterSyncCallback(napi_env env, size_t argc, napi_value *argv); napi_value OnStatistics(napi_env env, size_t argc, napi_value *argv); @@ -169,6 +160,7 @@ private: std::map>> localSharedObservers_; std::list> syncObservers_; std::list> statisticses_; + std::string bundleName_; }; } // namespace RelationalStoreJsKit } // namespace OHOS diff --git a/relational_store/frameworks/js/napi/relationalstore/include/napi_result_set.h b/relational_store/frameworks/js/napi/relationalstore/include/napi_result_set.h index 01bf51d8b31532a693d20da4ecff891c76ce75ab..b4f4f198e15bc2b22dab560f7fcfd254a6bd75cc 100644 --- a/relational_store/frameworks/js/napi/relationalstore/include/napi_result_set.h +++ b/relational_store/frameworks/js/napi/relationalstore/include/napi_result_set.h @@ -20,6 +20,7 @@ #include "asset_value.h" #include "js_proxy.h" +#include "napi_async_call.h" #include "napi/native_api.h" #include "napi/native_common.h" #include "napi/native_node_api.h" @@ -29,6 +30,7 @@ namespace OHOS { namespace RelationalStoreJsKit { +using namespace OHOS::NativeRdb; class ResultSetProxy final : public JSProxy::JSEntity { public: ResultSetProxy() = default; @@ -40,11 +42,7 @@ public: std::shared_ptr Create() override; private: - static ResultSetProxy *GetInnerResultSet(napi_env env, napi_callback_info info); - static ResultSetProxy *ParseInt32FieldByName( - napi_env env, napi_callback_info info, int32_t &field, const std::string fieldName); - static ResultSetProxy *ParseFieldByName( - napi_env env, napi_callback_info info, std::string &field, const std::string fieldName); + static std::pair> GetRows(ResultSet &resultSet, int32_t maxCount, int32_t position); static napi_value Initialize(napi_env env, napi_callback_info info); static napi_value GetAllColumnNames(napi_env env, napi_callback_info info); @@ -75,6 +73,7 @@ private: static napi_value GetDouble(napi_env env, napi_callback_info info); static napi_value IsColumnNull(napi_env env, napi_callback_info info); static napi_value GetRow(napi_env env, napi_callback_info info); + static napi_value GetRows(napi_env env, napi_callback_info info); static napi_value GetSendableRow(napi_env env, napi_callback_info info); static napi_value GetValue(napi_env env, napi_callback_info info); static napi_value IsClosed(napi_env env, napi_callback_info info); diff --git a/relational_store/frameworks/js/napi/relationalstore/include/napi_transaction.h b/relational_store/frameworks/js/napi/relationalstore/include/napi_transaction.h index 13226b782b9278d06e84b8207d71dd122b6b081e..f0d713a925bdcda1f19e3e8412f998a009321663 100644 --- a/relational_store/frameworks/js/napi/relationalstore/include/napi_transaction.h +++ b/relational_store/frameworks/js/napi/relationalstore/include/napi_transaction.h @@ -42,6 +42,7 @@ private: static napi_value Update(napi_env env, napi_callback_info info); static napi_value Insert(napi_env env, napi_callback_info info); static napi_value BatchInsert(napi_env env, napi_callback_info info); + static napi_value BatchInsertWithConflictResolution(napi_env env, napi_callback_info info); static napi_value Query(napi_env env, napi_callback_info info); static napi_value QuerySql(napi_env env, napi_callback_info info); static napi_value Execute(napi_env env, napi_callback_info info); diff --git a/relational_store/frameworks/js/napi/relationalstore/mock/include/napi_rdb_store.h b/relational_store/frameworks/js/napi/relationalstore/mock/include/napi_rdb_store.h index 2b178af9b9866fd202774133944c731b515cb0b8..a083f073dd874b41c0740f3b32243f0838dc2d89 100644 --- a/relational_store/frameworks/js/napi/relationalstore/mock/include/napi_rdb_store.h +++ b/relational_store/frameworks/js/napi/relationalstore/mock/include/napi_rdb_store.h @@ -34,12 +34,14 @@ using Descriptor = std::function(void)>; class RdbStoreProxy : public JSProxy::JSProxy { public: static void Init(napi_env env, napi_value exports); - static napi_value NewInstance(napi_env env, std::shared_ptr value, bool isSystemAppCalled); + static napi_value NewInstance(napi_env env, std::shared_ptr value, bool isSystemAppCalled, + const std::string &bundleName); RdbStoreProxy(); ~RdbStoreProxy(); RdbStoreProxy(std::shared_ptr rdbStore); RdbStoreProxy &operator=(std::shared_ptr rdbStore); bool IsSystemAppCalled(); + std::string GetBundleName(); private: static Descriptor GetDescriptors(); @@ -75,11 +77,12 @@ private: static napi_value Restore(napi_env env, napi_callback_info info); static napi_value Close(napi_env env, napi_callback_info info); static napi_value CreateTransaction(napi_env env, napi_callback_info info); - + void UnregisterAll(); int32_t dbType = NativeRdb::DB_SQLITE; std::mutex mutex_; bool isSystemAppCalled_ = false; std::shared_ptr queue_; + std::string bundleName_; static constexpr int WAIT_TIME_DEFAULT = 2; static constexpr int WAIT_TIME_LIMIT = 300; diff --git a/relational_store/frameworks/js/napi/relationalstore/mock/include/napi_result_set.h b/relational_store/frameworks/js/napi/relationalstore/mock/include/napi_result_set.h index 48fb8604d4c3d1e3ed44cd1ad9452386877e1835..d5369b8166c2913eb4406646fe97479533066bfd 100644 --- a/relational_store/frameworks/js/napi/relationalstore/mock/include/napi_result_set.h +++ b/relational_store/frameworks/js/napi/relationalstore/mock/include/napi_result_set.h @@ -19,6 +19,7 @@ #include #include "js_proxy.h" +#include "napi_async_call.h" #include "napi/native_api.h" #include "napi/native_common.h" #include "napi/native_node_api.h" @@ -26,6 +27,7 @@ namespace OHOS { namespace RelationalStoreJsKit { +using namespace OHOS::NativeRdb; class ResultSetProxy final : public JSProxy::JSProxy { public: ResultSetProxy() = default; @@ -37,11 +39,7 @@ public: static napi_value GetConstructor(napi_env env); private: - static ResultSetProxy *GetInnerResultSet(napi_env env, napi_callback_info info); - static ResultSetProxy *ParseInt32FieldByName( - napi_env env, napi_callback_info info, int32_t &field, const std::string fieldName); - static ResultSetProxy *ParseFieldByName( - napi_env env, napi_callback_info info, std::string &field, const std::string fieldName); + static std::pair> GetRows(ResultSet &resultSet, int32_t maxCount, int32_t position); static napi_value Initialize(napi_env env, napi_callback_info info); static napi_value GetAllColumnNames(napi_env env, napi_callback_info info); @@ -72,6 +70,7 @@ private: static napi_value GetDouble(napi_env env, napi_callback_info info); static napi_value IsColumnNull(napi_env env, napi_callback_info info); static napi_value GetRow(napi_env env, napi_callback_info info); + static napi_value GetRows(napi_env env, napi_callback_info info); static napi_value GetSendableRow(napi_env env, napi_callback_info info); static napi_value GetValue(napi_env env, napi_callback_info info); static napi_value IsClosed(napi_env env, napi_callback_info info); diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_async_call.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_async_call.cpp index f9d2d82df281508375a48083d8a7b04e8e4d2226..6e333315f2b8a9b9092333f3841c007401431c7a 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_async_call.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_async_call.cpp @@ -41,7 +41,7 @@ void ContextBase::SetAction( napi_valuetype valueType = napi_undefined; status = napi_typeof(env, argv[argc - 1], &valueType); if (status == napi_ok && valueType == napi_function) { - LOG_DEBUG("asyncCall set callback"); + LOG_DEBUG("AsyncCall set callback"); if (argc == 1) { error = std::make_shared("1"); } else { diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_const_properties.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_const_properties.cpp index f4b963fb7667d283577aca05925b6eef88a98c5e..0fd5243759f1f2df70545060008841fde63fe61d 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_const_properties.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_const_properties.cpp @@ -40,7 +40,10 @@ namespace OHOS::RelationalStoreJsKit { static napi_value ExportSyncMode(napi_env env) { napi_value syncMode = nullptr; - napi_create_object(env, &syncMode); + napi_status status = napi_create_object(env, &syncMode); + if (status != napi_ok) { + return nullptr; + } SET_NAPI_PROPERTY(syncMode, "SYNC_MODE_PUSH", int32_t(SyncMode::PUSH)); SET_NAPI_PROPERTY(syncMode, "SYNC_MODE_PULL", int32_t(SyncMode::PULL)); @@ -54,7 +57,10 @@ static napi_value ExportSyncMode(napi_env env) static napi_value ExportSubscribeType(napi_env env) { napi_value subscribeType = nullptr; - napi_create_object(env, &subscribeType); + napi_status status = napi_create_object(env, &subscribeType); + if (status != napi_ok) { + return nullptr; + } SET_NAPI_PROPERTY(subscribeType, "SUBSCRIBE_TYPE_REMOTE", int32_t(SubscribeMode::REMOTE)); SET_NAPI_PROPERTY(subscribeType, "SUBSCRIBE_TYPE_CLOUD", int32_t(SubscribeMode::CLOUD)); @@ -67,7 +73,10 @@ static napi_value ExportSubscribeType(napi_env env) static napi_value ExportSecurityLevel(napi_env env) { napi_value securityLevel = nullptr; - napi_create_object(env, &securityLevel); + napi_status status = napi_create_object(env, &securityLevel); + if (status != napi_ok) { + return nullptr; + } SET_NAPI_PROPERTY(securityLevel, "S1", int32_t(SecurityLevel::S1)); SET_NAPI_PROPERTY(securityLevel, "S2", int32_t(SecurityLevel::S2)); @@ -81,7 +90,10 @@ static napi_value ExportSecurityLevel(napi_env env) static napi_value ExportProgress(napi_env env) { napi_value progress = nullptr; - napi_create_object(env, &progress); + napi_status status = napi_create_object(env, &progress); + if (status != napi_ok) { + return nullptr; + } SET_NAPI_PROPERTY(progress, "SYNC_BEGIN", int32_t(DistributedRdb::Progress::SYNC_BEGIN)); SET_NAPI_PROPERTY(progress, "SYNC_IN_PROGRESS", int32_t(DistributedRdb::Progress::SYNC_IN_PROGRESS)); @@ -93,7 +105,10 @@ static napi_value ExportProgress(napi_env env) static napi_value ExportProgressCode(napi_env env) { napi_value progressCode = nullptr; - napi_create_object(env, &progressCode); + napi_status status = napi_create_object(env, &progressCode); + if (status != napi_ok) { + return nullptr; + } SET_NAPI_PROPERTY(progressCode, "SUCCESS", int32_t(ProgressCode::SUCCESS)); SET_NAPI_PROPERTY(progressCode, "UNKNOWN_ERROR", int32_t(ProgressCode::UNKNOWN_ERROR)); @@ -110,7 +125,10 @@ static napi_value ExportProgressCode(napi_env env) static napi_value ExportOrigin(napi_env env) { napi_value origin = nullptr; - napi_create_object(env, &origin); + napi_status status = napi_create_object(env, &origin); + if (status != napi_ok) { + return nullptr; + } SET_NAPI_PROPERTY(origin, "LOCAL", int32_t(NativeRdb::AbsPredicates::Origin::LOCAL)); SET_NAPI_PROPERTY(origin, "CLOUD", int32_t(NativeRdb::AbsPredicates::Origin::CLOUD)); @@ -122,7 +140,10 @@ static napi_value ExportOrigin(napi_env env) static napi_value ExportField(napi_env env) { napi_value field = nullptr; - napi_create_object(env, &field); + napi_status status = napi_create_object(env, &field); + if (status != napi_ok) { + return nullptr; + } SET_NAPI_PROPERTY(field, "CURSOR_FIELD", std::string(DistributedRdb::Field::CURSOR_FIELD)); SET_NAPI_PROPERTY(field, "ORIGIN_FIELD", std::string(DistributedRdb::Field::ORIGIN_FIELD)); @@ -138,7 +159,10 @@ static napi_value ExportField(napi_env env) static napi_value ExportDistributedType(napi_env env) { napi_value distributedType = nullptr; - napi_create_object(env, &distributedType); + napi_status status = napi_create_object(env, &distributedType); + if (status != napi_ok) { + return nullptr; + } SET_NAPI_PROPERTY(distributedType, "DISTRIBUTED_DEVICE", int32_t(DistributedTableType::DISTRIBUTED_DEVICE)); SET_NAPI_PROPERTY(distributedType, "DISTRIBUTED_CLOUD", int32_t(DistributedTableType::DISTRIBUTED_CLOUD)); @@ -149,7 +173,10 @@ static napi_value ExportDistributedType(napi_env env) static napi_value ExportChangeType(napi_env env) { napi_value changeType = nullptr; - napi_create_object(env, &changeType); + napi_status status = napi_create_object(env, &changeType); + if (status != napi_ok) { + return nullptr; + } SET_NAPI_PROPERTY(changeType, "DATA_CHANGE", int32_t(DistributedRdb::Origin::BASIC_DATA)); SET_NAPI_PROPERTY(changeType, "ASSET_CHANGE", int32_t(DistributedRdb::Origin::ASSET_DATA)); @@ -160,7 +187,10 @@ static napi_value ExportChangeType(napi_env env) static napi_value ExportAssetStatus(napi_env env) { napi_value assetStatus = nullptr; - napi_create_object(env, &assetStatus); + napi_status status = napi_create_object(env, &assetStatus); + if (status != napi_ok) { + return nullptr; + } SET_NAPI_PROPERTY(assetStatus, "ASSET_NORMAL", int32_t(NativeRdb::AssetValue::STATUS_NORMAL)); SET_NAPI_PROPERTY(assetStatus, "ASSET_INSERT", int32_t(NativeRdb::AssetValue::STATUS_INSERT)); @@ -175,7 +205,10 @@ static napi_value ExportAssetStatus(napi_env env) static napi_value ExportConflictResolution(napi_env env) { napi_value conflictResolution = nullptr; - napi_create_object(env, &conflictResolution); + napi_status status = napi_create_object(env, &conflictResolution); + if (status != napi_ok) { + return nullptr; + } SET_NAPI_PROPERTY(conflictResolution, "ON_CONFLICT_NONE", int32_t(ConflictResolution::ON_CONFLICT_NONE)); SET_NAPI_PROPERTY(conflictResolution, "ON_CONFLICT_ROLLBACK", int32_t(ConflictResolution::ON_CONFLICT_ROLLBACK)); @@ -191,7 +224,10 @@ static napi_value ExportConflictResolution(napi_env env) static napi_value ExportRebuiltType(napi_env env) { napi_value rebuiltType = nullptr; - napi_create_object(env, &rebuiltType); + napi_status status = napi_create_object(env, &rebuiltType); + if (status != napi_ok) { + return nullptr; + } SET_NAPI_PROPERTY(rebuiltType, "NONE", int32_t(NativeRdb::RebuiltType::NONE)); SET_NAPI_PROPERTY(rebuiltType, "REBUILT", int32_t(NativeRdb::RebuiltType::REBUILT)); @@ -204,7 +240,10 @@ static napi_value ExportRebuiltType(napi_env env) static napi_value ExportHAMode(napi_env env) { napi_value haMode = nullptr; - napi_create_object(env, &haMode); + napi_status status = napi_create_object(env, &haMode); + if (status != napi_ok) { + return nullptr; + } SET_NAPI_PROPERTY(haMode, "SINGLE", int32_t(NativeRdb::HAMode::SINGLE)); SET_NAPI_PROPERTY(haMode, "MAIN_REPLICA", int32_t(NativeRdb::HAMode::MAIN_REPLICA)); @@ -215,7 +254,10 @@ static napi_value ExportHAMode(napi_env env) static napi_value ExportEncryptionAlgo(napi_env env) { napi_value encryptionAlgo = nullptr; - napi_create_object(env, &encryptionAlgo); + napi_status status = napi_create_object(env, &encryptionAlgo); + if (status != napi_ok) { + return nullptr; + } SET_NAPI_PROPERTY(encryptionAlgo, "AES_256_GCM", int32_t(NativeRdb::EncryptAlgo::AES_256_GCM)); SET_NAPI_PROPERTY(encryptionAlgo, "AES_256_CBC", int32_t(NativeRdb::EncryptAlgo::AES_256_CBC)); @@ -226,7 +268,10 @@ static napi_value ExportEncryptionAlgo(napi_env env) static napi_value ExportHmacAlgo(napi_env env) { napi_value hmacAlgo = nullptr; - napi_create_object(env, &hmacAlgo); + napi_status status = napi_create_object(env, &hmacAlgo); + if (status != napi_ok) { + return nullptr; + } SET_NAPI_PROPERTY(hmacAlgo, "SHA1", int32_t(NativeRdb::HmacAlgo::SHA1)); SET_NAPI_PROPERTY(hmacAlgo, "SHA256", int32_t(NativeRdb::HmacAlgo::SHA256)); @@ -238,7 +283,10 @@ static napi_value ExportHmacAlgo(napi_env env) static napi_value ExportKdfAlgo(napi_env env) { napi_value kdfAlgo = nullptr; - napi_create_object(env, &kdfAlgo); + napi_status status = napi_create_object(env, &kdfAlgo); + if (status != napi_ok) { + return nullptr; + } SET_NAPI_PROPERTY(kdfAlgo, "KDF_SHA1", int32_t(NativeRdb::KdfAlgo::KDF_SHA1)); SET_NAPI_PROPERTY(kdfAlgo, "KDF_SHA256", int32_t(NativeRdb::KdfAlgo::KDF_SHA256)); @@ -250,7 +298,10 @@ static napi_value ExportKdfAlgo(napi_env env) static napi_value ExportTransactionType(napi_env env) { napi_value transactionType = nullptr; - napi_create_object(env, &transactionType); + napi_status status = napi_create_object(env, &transactionType); + if (status != napi_ok) { + return nullptr; + } SET_NAPI_PROPERTY(transactionType, "DEFERRED", int32_t(NativeRdb::Transaction::DEFERRED)); SET_NAPI_PROPERTY(transactionType, "IMMEDIATE", int32_t(NativeRdb::Transaction::IMMEDIATE)); @@ -259,6 +310,20 @@ static napi_value ExportTransactionType(napi_env env) return transactionType; } +static napi_value ExportTokenizer(napi_env env) +{ + napi_value tokenizerType = nullptr; + napi_status status = napi_create_object(env, &tokenizerType); + if (status != napi_ok) { + return nullptr; + } + + SET_NAPI_PROPERTY(tokenizerType, "ICU_TOKENIZER", int32_t(NativeRdb::Tokenizer::ICU_TOKENIZER)); + SET_NAPI_PROPERTY(tokenizerType, "CUSTOM_TOKENIZER", int32_t(NativeRdb::Tokenizer::CUSTOM_TOKENIZER)); + napi_object_freeze(env, tokenizerType); + return tokenizerType; +} + napi_status InitConstProperties(napi_env env, napi_value exports) { const napi_property_descriptor properties[] = { @@ -281,6 +346,7 @@ napi_status InitConstProperties(napi_env env, napi_value exports) DECLARE_NAPI_PROPERTY("HmacAlgo", ExportHmacAlgo(env)), DECLARE_NAPI_PROPERTY("KdfAlgo", ExportKdfAlgo(env)), DECLARE_NAPI_PROPERTY("TransactionType", ExportTransactionType(env)), + DECLARE_NAPI_PROPERTY("Tokenizer", ExportTokenizer(env)), }; size_t count = sizeof(properties) / sizeof(properties[0]); diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_error.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_error.cpp index 8218b0280df6ccf0204f75ccb5ed64a983ee2b80..c1a93da75b661823ff4bb3d96a9b46f568c7e44e 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_error.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_error.cpp @@ -51,10 +51,23 @@ static constexpr JsErrorCode JS_ERROR_CODE_MSGS[] = { { NativeRdb::E_SQLITE_MISMATCH, 14800033, "SQLite: Data type mismatch." }, { NativeRdb::E_SQLITE_MISUSE, 14800034, "SQLite: Library used incorrectly." }, { NativeRdb::E_CONFIG_INVALID_CHANGE, 14800017, "Config changed." }, - { NativeRdb::E_INVALID_SECRET_KEY, 14800020, "The key parameter is invalid." }, + { NativeRdb::E_INVALID_SECRET_KEY, 14800020, "The secret key is corrupted or lost." }, + { NativeRdb::E_SQLITE_IOERR_FULL, 14800028, "SQLite: Some kind of disk I/O error occurred." }, { NativeRdb::E_NOT_SUPPORT, 801, "Capability not support." }, }; +static constexpr bool IsIncreasing() +{ + for (size_t i = 1; i < sizeof(JS_ERROR_CODE_MSGS) / sizeof(JsErrorCode); i++) { + if (JS_ERROR_CODE_MSGS[i].status <= JS_ERROR_CODE_MSGS[i - 1].status) { + return false; + } + } + return true; +} +// JS_ERROR_CODE_MSGS must ensure increment +static_assert(IsIncreasing()); + const std::optional GetJsErrorCode(int32_t errorCode) { auto jsErrorCode = JsErrorCode{ errorCode, -1, "" }; diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_js_utils.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_js_utils.cpp index 17dfdd595c9cbed9c3651d751469fb26a76e4c8a..48498e2cd47c2cadd4b04d6893df69803c1d9275 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_js_utils.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_js_utils.cpp @@ -15,7 +15,9 @@ #define LOG_TAG "NapiRdbJsUtils" #include "napi_rdb_js_utils.h" +#include #include +#include #include #include "js_ability.h" @@ -98,6 +100,8 @@ int32_t Convert2Value(napi_env env, napi_value input, DistributedRdb::Distribute NAPI_CALL_RETURN_ERR(GetNamedProperty(env, input, "autoSync", output.autoSync), napi_invalid_arg); NAPI_CALL_RETURN_ERR(GetNamedProperty(env, input, "references", output.references, true), napi_invalid_arg); + NAPI_CALL_RETURN_ERR( + GetNamedProperty(env, input, "asyncDownloadAsset", output.asyncDownloadAsset, true), napi_invalid_arg); return napi_ok; } @@ -361,6 +365,9 @@ int32_t Convert2Value(napi_env env, napi_value jsValue, RdbConfig &rdbConfig) status = GetNamedProperty(env, jsValue, "customDir", rdbConfig.customDir, true); ASSERT(OK == status, "get customDir failed.", napi_invalid_arg); + status = GetNamedProperty(env, jsValue, "rootDir", rdbConfig.rootDir, true); + ASSERT(OK == status, "get rootDir failed.", napi_invalid_arg); + GetNamedProperty(env, jsValue, "isSearchable", rdbConfig.isSearchable, true); ASSERT(OK == status, "get isSearchable failed.", napi_invalid_arg); @@ -381,6 +388,11 @@ int32_t Convert2Value(napi_env env, napi_value jsValue, RdbConfig &rdbConfig) status = GetNamedProperty(env, jsValue, "cryptoParam", rdbConfig.cryptoParam, true); ASSERT(OK == status, "get cryptoParam failed.", napi_invalid_arg); + + int32_t tokenizer = static_cast(Tokenizer::NONE_TOKENIZER); + status = GetNamedProperty(env, jsValue, "tokenizer", tokenizer, true); + ASSERT(OK == status, "get tokenizer failed.", napi_invalid_arg); + rdbConfig.tokenizer = static_cast(tokenizer); return napi_ok; } @@ -423,7 +435,7 @@ int32_t Convert2Value(napi_env env, napi_value jsValue, ContextParam ¶m) LOG_WARN("isStageMode is false -> fa stage"); return GetCurrentAbilityParam(env, jsValue, param); } - LOG_DEBUG("stage mode branch"); + LOG_DEBUG("Stage mode branch"); status = GetNamedProperty(env, jsValue, "databaseDir", param.baseDir); ASSERT(status == napi_ok, "get databaseDir failed.", napi_invalid_arg); status = GetNamedProperty(env, jsValue, "area", param.area, true); @@ -481,6 +493,18 @@ std::tuple> GetRealPath( baseDir = groupDir; } + if (!rdbConfig.rootDir.empty()) { + // determine if the first character of rootDir is '/' + CHECK_RETURN_CORE(rdbConfig.rootDir.find_first_of(PATH_SPLIT) == 0, RDB_DO_NOTHING, + std::make_tuple(ERR, std::make_shared())); + auto [realPath, errorCode] = + RdbSqlUtils::GetCustomDatabasePath(rdbConfig.rootDir, rdbConfig.name, rdbConfig.customDir); + CHECK_RETURN_CORE(errorCode == E_OK, RDB_DO_NOTHING, + std::make_tuple(ERR, std::make_shared())); + rdbConfig.path = realPath; + return std::make_tuple(E_OK, nullptr); + } + auto [realPath, errorCode] = RdbSqlUtils::GetDefaultDatabasePath(baseDir, rdbConfig.name, rdbConfig.customDir); // realPath length is limited to 1024 bytes CHECK_RETURN_CORE(errorCode == E_OK && realPath.length() <= 1024, RDB_DO_NOTHING, @@ -504,6 +528,7 @@ RdbStoreConfig GetRdbStoreConfig(const RdbConfig &rdbConfig, const ContextParam rdbStoreConfig.SetAllowRebuild(rdbConfig.allowRebuild); rdbStoreConfig.SetReadOnly(rdbConfig.isReadOnly); rdbStoreConfig.SetIntegrityCheck(IntegrityCheck::NONE); + rdbStoreConfig.SetTokenizer(rdbConfig.tokenizer); if (!param.bundleName.empty()) { rdbStoreConfig.SetBundleName(param.bundleName); @@ -527,7 +552,7 @@ bool HasDuplicateAssets(const ValueObject &value) auto item = assets->begin(); while (item != assets->end()) { if (!names.insert(item->name).second) { - LOG_ERROR("duplicate assets! name = %{public}.6s", item->name.c_str()); + LOG_ERROR("Duplicate assets! name = %{public}.6s", item->name.c_str()); return true; } item++; diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_predicates.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_predicates.cpp index c31850bede80e69f10ddb7504649262f79ca3906..a3dd2d34fa120912676f62cb190fdca41db50e53 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_predicates.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_predicates.cpp @@ -149,9 +149,9 @@ napi_value RdbPredicatesProxy::NewInstance(napi_env env, std::shared_ptr(&proxy)); - if (status != napi_ok) { + if (status != napi_ok || proxy == nullptr) { LOG_ERROR("RdbPredicatesProxy::NewInstance native instance is nullptr! napi_status:%{public}d!", status); - return instance; + return nullptr; } proxy->GetInstance() = std::move(value); return instance; diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_statistics_observer.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_statistics_observer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e7ff21669f0e50022f79682aad2feda2c2c9bcf2 --- /dev/null +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_statistics_observer.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025 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 "napi_rdb_statistics_observer.h" + +#include "napi_rdb_js_utils.h" + +namespace OHOS::RelationalStoreJsKit { +NapiStatisticsObserver::NapiStatisticsObserver( + napi_env env, napi_value callback, std::shared_ptr queue) + : env_(env), queue_(queue) +{ + napi_create_reference(env, callback, 1, &callback_); +} + +NapiStatisticsObserver::~NapiStatisticsObserver() +{ +} + +void NapiStatisticsObserver::Clear() +{ + if (callback_ == nullptr) { + return; + } + napi_delete_reference(env_, callback_); + callback_ = nullptr; +} + +bool NapiStatisticsObserver::operator==(napi_value value) +{ + return JSUtils::Equal(env_, callback_, value); +} + +void NapiStatisticsObserver::OnStatistic(const SqlExecutionInfo &sqlExeInfo) +{ + auto queue = queue_; + if (queue == nullptr) { + return; + } + queue->AsyncCall({ [observer = shared_from_this()](napi_env env) -> napi_value { + if (observer->callback_ == nullptr) { + return nullptr; + } + napi_value callback = nullptr; + napi_get_reference_value(env, observer->callback_, &callback); + return callback; + } }, + [infos = std::move(sqlExeInfo)](napi_env env, int &argc, napi_value *argv) { + argc = 1; + argv[0] = JSUtils::Convert2JSValue(env, infos); + }); +} +} // namespace OHOS::RelationalStoreJsKit \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store.cpp index 9cabb7054320b808141af44587ceb44d3fd9fa8c..0b2f730e91684d98958189dfb5fa9086b3b27fc6 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store.cpp @@ -30,11 +30,14 @@ #include "napi_rdb_context.h" #include "napi_rdb_error.h" #include "napi_rdb_js_utils.h" +#include "napi_rdb_statistics_observer.h" +#include "napi_rdb_store_observer.h" #include "napi_rdb_trace.h" #include "napi_result_set.h" #include "napi_transaction.h" #include "rdb_errno.h" #include "rdb_sql_statistic.h" +#include "rdb_fault_hiview_reporter.h" #include "securec.h" #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) @@ -63,21 +66,24 @@ struct PredicatesProxy { std::shared_ptr predicates_; }; #endif +using Reportor = RdbFaultHiViewReporter; constexpr int32_t KEY_INDEX = 0; constexpr int32_t VALUE_INDEX = 1; -RdbStoreProxy::RdbStoreProxy() +RdbStoreProxy::RdbStoreProxy() {} + +RdbStoreProxy::~RdbStoreProxy() { + UnregisterAll(); } -RdbStoreProxy::~RdbStoreProxy() +void RdbStoreProxy::UnregisterAll() { - LOG_DEBUG("RdbStoreProxy destructor."); auto rdbStore = GetInstance(); if (rdbStore == nullptr) { return; } -#if !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) +#if !defined(CROSS_PLATFORM) for (int32_t mode = DistributedRdb::REMOTE; mode < DistributedRdb::LOCAL; mode++) { for (auto &obs : observers_[mode]) { if (obs == nullptr) { @@ -130,6 +136,11 @@ bool RdbStoreProxy::IsSystemAppCalled() return isSystemAppCalled_; } +std::string RdbStoreProxy::GetBundleName() +{ + return bundleName_; +} + bool IsNapiTypeString(napi_env env, size_t argc, napi_value *argv, size_t arg) { if (arg >= argc) { @@ -148,6 +159,8 @@ Descriptor RdbStoreProxy::GetDescriptors() DECLARE_NAPI_FUNCTION_WITH_DATA("update", Update, ASYNC), DECLARE_NAPI_FUNCTION_WITH_DATA("insert", Insert, ASYNC), DECLARE_NAPI_FUNCTION_WITH_DATA("batchInsert", BatchInsert, ASYNC), + DECLARE_NAPI_FUNCTION_WITH_DATA( + "batchInsertWithConflictResolution", BatchInsertWithConflictResolution, ASYNC), DECLARE_NAPI_FUNCTION_WITH_DATA("querySql", QuerySql, ASYNC), DECLARE_NAPI_FUNCTION_WITH_DATA("query", Query, ASYNC), DECLARE_NAPI_FUNCTION_WITH_DATA("executeSql", ExecuteSql, ASYNC), @@ -167,25 +180,10 @@ Descriptor RdbStoreProxy::GetDescriptors() DECLARE_NAPI_FUNCTION("attach", Attach), DECLARE_NAPI_FUNCTION("detach", Detach), DECLARE_NAPI_FUNCTION("createTransaction", CreateTransaction), -#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) - DECLARE_NAPI_FUNCTION("remoteQuery", RemoteQuery), - DECLARE_NAPI_FUNCTION("setDistributedTables", SetDistributedTables), - DECLARE_NAPI_FUNCTION("obtainDistributedTableName", ObtainDistributedTableName), - DECLARE_NAPI_FUNCTION("sync", Sync), - DECLARE_NAPI_FUNCTION("cloudSync", CloudSync), - DECLARE_NAPI_FUNCTION("getModifyTime", GetModifyTime), - DECLARE_NAPI_FUNCTION("cleanDirtyData", CleanDirtyData), - DECLARE_NAPI_FUNCTION("on", OnEvent), - DECLARE_NAPI_FUNCTION("off", OffEvent), - DECLARE_NAPI_FUNCTION("emit", Notify), - DECLARE_NAPI_FUNCTION("querySharingResource", QuerySharingResource), - DECLARE_NAPI_FUNCTION("lockRow", LockRow), - DECLARE_NAPI_FUNCTION("unlockRow", UnlockRow), - DECLARE_NAPI_FUNCTION("queryLockedRow", QueryLockedRow), - DECLARE_NAPI_FUNCTION("lockCloudContainer", LockCloudContainer), - DECLARE_NAPI_FUNCTION("unlockCloudContainer", UnlockCloudContainer), -#endif }; +#if !defined(CROSS_PLATFORM) + AddDistributedFunctions(properties); +#endif AddSyncFunctions(properties); return properties; }; @@ -197,6 +195,8 @@ void RdbStoreProxy::AddSyncFunctions(std::vector &prop properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("updateSync", Update, SYNC)); properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("insertSync", Insert, SYNC)); properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("batchInsertSync", BatchInsert, SYNC)); + properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("batchInsertWithConflictResolutionSync", + BatchInsertWithConflictResolution, SYNC)); properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("querySqlSync", QueryByStep, SYNC)); properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("executeSync", Execute, SYNC)); properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("querySync", QueryByStep, SYNC)); @@ -223,6 +223,7 @@ napi_value RdbStoreProxy::Initialize(napi_env env, napi_callback_info info) return; } RdbStoreProxy *proxy = reinterpret_cast(data); + proxy->UnregisterAll(); proxy->SetInstance(nullptr); delete proxy; }; @@ -240,10 +241,11 @@ napi_value RdbStoreProxy::Initialize(napi_env env, napi_callback_info info) return self; } -napi_value RdbStoreProxy::NewInstance(napi_env env, std::shared_ptr value, bool isSystemAppCalled) +napi_value RdbStoreProxy::NewInstance( + napi_env env, std::shared_ptr value, bool isSystemAppCalled, const std::string &bundleName) { if (value == nullptr) { - LOG_ERROR("value is nullptr ? %{public}d", (value == nullptr)); + LOG_ERROR("Value is nullptr ? %{public}d", (value == nullptr)); return nullptr; } napi_value cons = JSUtils::GetClass(env, "ohos.data.relationalStore", "RdbStore"); @@ -261,14 +263,15 @@ napi_value RdbStoreProxy::NewInstance(napi_env env, std::shared_ptr(&proxy)); - if (proxy == nullptr) { + if (status != napi_ok || proxy == nullptr) { LOG_ERROR("RdbStoreProxy::NewInstance native instance is nullptr! code:%{public}d!", status); - return instance; + return nullptr; } proxy->queue_ = std::make_shared(env); proxy->dbType = value->GetDbType(); proxy->SetInstance(std::move(value)); proxy->isSystemAppCalled_ = isSystemAppCalled; + proxy->bundleName_ = bundleName; return instance; } @@ -568,6 +571,10 @@ int ParseValuesBucket(const napi_env env, const napi_value arg, std::shared_ptr< if (tmpValue.empty()) { valueObject = ValueObject(); } + auto proxy = reinterpret_cast(context->boundObj); + if (tmpValue.empty() && (proxy != nullptr)) { + Reportor::ReportFault(RdbEmptyBlobEvent(proxy->GetBundleName())); + } } if (ret == napi_ok) { context->valuesBucket.Put(keyStr, valueObject); @@ -582,11 +589,11 @@ int ParseValuesBuckets(const napi_env env, const napi_value arg, std::shared_ptr { bool isArray = false; napi_is_array(env, arg, &isArray); - CHECK_RETURN_SET(isArray, std::make_shared("ValuesBucket is invalid.")); + CHECK_RETURN_SET(isArray, std::make_shared("ValuesBuckets is invalid.")); uint32_t arrLen = 0; napi_status status = napi_get_array_length(env, arg, &arrLen); - CHECK_RETURN_SET(status == napi_ok && arrLen > 0, std::make_shared("ValuesBucket is invalid.")); + CHECK_RETURN_SET(status == napi_ok && arrLen > 0, std::make_shared("ValuesBuckets is invalid.")); for (uint32_t i = 0; i < arrLen; ++i) { napi_value obj = nullptr; @@ -604,8 +611,8 @@ int ParseConflictResolution(const napi_env env, const napi_value arg, std::share { int32_t conflictResolution = 0; napi_get_value_int32(env, arg, &conflictResolution); - int min = static_cast(NativeRdb::ConflictResolution::ON_CONFLICT_NONE); - int max = static_cast(NativeRdb::ConflictResolution::ON_CONFLICT_REPLACE); + int32_t min = static_cast(NativeRdb::ConflictResolution::ON_CONFLICT_NONE); + int32_t max = static_cast(NativeRdb::ConflictResolution::ON_CONFLICT_REPLACE); bool checked = (conflictResolution >= min) && (conflictResolution <= max); CHECK_RETURN_SET(checked, std::make_shared("conflictResolution", "a ConflictResolution.")); context->conflictResolution = static_cast(conflictResolution); @@ -681,6 +688,39 @@ napi_value RdbStoreProxy::BatchInsert(napi_env env, napi_callback_info info) return ASYNC_CALL(env, context); } +napi_value RdbStoreProxy::BatchInsertWithConflictResolution(napi_env env, napi_callback_info info) +{ + auto context = std::make_shared(); + auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { + CHECK_RETURN_SET_E(argc == 3, std::make_shared("3")); + CHECK_RETURN(OK == ParserThis(env, self, context)); + CHECK_RETURN(OK == ParseTableName(env, argv[0], context)); + // 'argv[1]' represents a valuesBucket + CHECK_RETURN(OK == ParseValuesBuckets(env, argv[1], context)); + CHECK_RETURN_SET_E(!HasDuplicateAssets(context->sharedValuesBuckets), + std::make_shared("Duplicate assets are not allowed")); + // 'argv[2]' represents a ConflictResolution + CHECK_RETURN_SET_E(!JSUtils::IsNull(env, argv[2]), std::make_shared("conflict", "not null")); + // 'argv[2]' represents a ConflictResolution + CHECK_RETURN(OK == ParseConflictResolution(env, argv[2], context)); + }; + auto exec = [context]() -> int { + CHECK_RETURN_ERR(context->rdbStore != nullptr); + auto rdbStore = std::move(context->rdbStore); + auto [ret, output] = rdbStore->BatchInsertWithConflictResolution( + context->tableName, context->sharedValuesBuckets, context->conflictResolution); + context->int64Output = output; + return ret; + }; + auto output = [context](napi_env env, napi_value &result) { + napi_status status = napi_create_int64(env, context->int64Output, &result); + CHECK_RETURN_SET_E(status == napi_ok, std::make_shared(E_ERROR)); + }; + context->SetAction(env, info, input, exec, output); + CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK); + return ASYNC_CALL(env, context); +} + napi_value RdbStoreProxy::Delete(napi_env env, napi_callback_info info) { auto context = std::make_shared(); @@ -776,10 +816,11 @@ napi_value RdbStoreProxy::Query(napi_env env, napi_callback_info info) context->resultSet = context->rdbStore->Query(*(context->rdbPredicates), context->columns); #endif context->rdbStore = nullptr; - return (context->resultSet != nullptr) ? E_OK : E_ERROR; + // If the API version is greater than or equal to 16, throw E_ALREADY_CLOSED. + return (context->resultSet != nullptr) ? E_OK : (JSUtils::GetHapVersion() >= 16) ? E_ALREADY_CLOSED : E_ERROR; }; auto output = [context](napi_env env, napi_value &result) { - result = ResultSetProxy::NewInstance(env, context->resultSet); + result = ResultSetProxy::NewInstance(env, std::move(context->resultSet)); CHECK_RETURN_SET_E(result != nullptr, std::make_shared(E_ERROR)); }; context->SetAction(env, info, input, exec, output); @@ -811,7 +852,7 @@ napi_value RdbStoreProxy::RemoteQuery(napi_env env, napi_callback_info info) return errCode; }; auto output = [context](napi_env env, napi_value &result) { - result = ResultSetProxy::NewInstance(env, context->resultSet); + result = ResultSetProxy::NewInstance(env, std::move(context->resultSet)); CHECK_RETURN_SET_E(result != nullptr, std::make_shared(E_ERROR)); }; context->SetAction(env, info, input, exec, output); @@ -846,10 +887,11 @@ napi_value RdbStoreProxy::QuerySql(napi_env env, napi_callback_info info) context->resultSet = context->rdbStore->QuerySql(context->sql, context->bindArgs); #endif context->rdbStore = nullptr; - return (context->resultSet != nullptr) ? E_OK : E_ERROR; + // If the API version is greater than or equal to 16, throw E_ALREADY_CLOSED. + return (context->resultSet != nullptr) ? E_OK : (JSUtils::GetHapVersion() >= 16) ? E_ALREADY_CLOSED : E_ERROR; }; auto output = [context](napi_env env, napi_value &result) { - result = ResultSetProxy::NewInstance(env, context->resultSet); + result = ResultSetProxy::NewInstance(env, std::move(context->resultSet)); CHECK_RETURN_SET_E(result != nullptr, std::make_shared(E_ERROR)); }; context->SetAction(env, info, input, exec, output); @@ -1084,18 +1126,6 @@ napi_value RdbStoreProxy::Detach(napi_env env, napi_callback_info info) return ASYNC_CALL(env, context); } -napi_value RdbStoreProxy::IsReadOnly(napi_env env, napi_callback_info info) -{ - napi_value thisObj = nullptr; - napi_get_cb_info(env, info, nullptr, nullptr, &thisObj, nullptr); - RdbStoreProxy *rdbStoreProxy = GetNativeInstance(env, thisObj); - RDB_NAPI_ASSERT(env, rdbStoreProxy != nullptr && rdbStoreProxy->GetInstance() != nullptr, - std::make_shared("RdbStore", "valid")); - bool out = rdbStoreProxy->GetInstance()->IsReadOnly(); - LOG_DEBUG("RdbStoreProxy::IsReadOnly out is : %{public}d", out); - return JSUtils::Convert2JSValue(env, out); -} - napi_value RdbStoreProxy::GetPath(napi_env env, napi_callback_info info) { napi_value thisObj = nullptr; @@ -1156,7 +1186,7 @@ napi_value RdbStoreProxy::RollBack(napi_env env, napi_callback_info info) RDB_NAPI_ASSERT( env, rdbStoreProxy->GetInstance() != nullptr, std::make_shared(NativeRdb::E_ALREADY_CLOSED)); int errCode = rdbStoreProxy->GetInstance()->RollBack(); - NAPI_ASSERT(env, errCode == E_OK, "call RollBack failed"); + RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); LOG_DEBUG("RdbStoreProxy::RollBack end, errCode is:%{public}d", errCode); return nullptr; } @@ -1199,7 +1229,7 @@ napi_value RdbStoreProxy::Commit(napi_env env, napi_callback_info info) RDB_NAPI_ASSERT(env, OK == ParserThis(env, thisObj, context), context->error); if (argc == 0) { int errCode = context->rdbStore->Commit(); - NAPI_ASSERT(env, errCode == E_OK, "call Commit failed"); + RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); LOG_DEBUG("RdbStoreProxy::Commit end, errCode is:%{public}d.", errCode); return nullptr; } @@ -1248,10 +1278,11 @@ napi_value RdbStoreProxy::QueryByStep(napi_env env, napi_callback_info info) auto rdbStore = std::move(context->rdbStore); context->resultSet = context->isQuerySql ? rdbStore->QueryByStep(context->sql, context->bindArgs) : rdbStore->QueryByStep(*(context->rdbPredicates), context->columns); - return (context->resultSet != nullptr) ? E_OK : E_ERROR; + // If the API version is greater than or equal to 16, throw E_ALREADY_CLOSED. + return (context->resultSet != nullptr) ? E_OK : (JSUtils::GetHapVersion() >= 16) ? E_ALREADY_CLOSED : E_ERROR; }; auto output = [context](napi_env env, napi_value &result) { - result = ResultSetProxy::NewInstance(env, context->resultSet); + result = ResultSetProxy::NewInstance(env, std::move(context->resultSet)); CHECK_RETURN_SET_E(result != nullptr, std::make_shared(E_ERROR)); }; context->SetAction(env, info, input, exec, output); @@ -1308,7 +1339,6 @@ napi_value RdbStoreProxy::SetVersion(napi_env env, napi_callback_info info) napi_value RdbStoreProxy::Restore(napi_env env, napi_callback_info info) { - LOG_DEBUG("RdbStoreProxy::Restore start."); auto context = std::make_shared(); auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { CHECK_RETURN_SET_E(argc == 0 || argc == 1, std::make_shared("0 to 2")); @@ -1334,10 +1364,29 @@ napi_value RdbStoreProxy::Restore(napi_env env, napi_callback_info info) return ASYNC_CALL(env, context); } -#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) +#if !defined(CROSS_PLATFORM) +void RdbStoreProxy::AddDistributedFunctions(std::vector &properties) +{ + properties.push_back(DECLARE_NAPI_FUNCTION("remoteQuery", RemoteQuery)); + properties.push_back(DECLARE_NAPI_FUNCTION("setDistributedTables", SetDistributedTables)); + properties.push_back(DECLARE_NAPI_FUNCTION("obtainDistributedTableName", ObtainDistributedTableName)); + properties.push_back(DECLARE_NAPI_FUNCTION("sync", Sync)); + properties.push_back(DECLARE_NAPI_FUNCTION("cloudSync", CloudSync)); + properties.push_back(DECLARE_NAPI_FUNCTION("getModifyTime", GetModifyTime)); + properties.push_back(DECLARE_NAPI_FUNCTION("cleanDirtyData", CleanDirtyData)); + properties.push_back(DECLARE_NAPI_FUNCTION("on", OnEvent)); + properties.push_back(DECLARE_NAPI_FUNCTION("off", OffEvent)); + properties.push_back(DECLARE_NAPI_FUNCTION("emit", Notify)); + properties.push_back(DECLARE_NAPI_FUNCTION("querySharingResource", QuerySharingResource)); + properties.push_back(DECLARE_NAPI_FUNCTION("lockRow", LockRow)); + properties.push_back(DECLARE_NAPI_FUNCTION("unlockRow", UnlockRow)); + properties.push_back(DECLARE_NAPI_FUNCTION("queryLockedRow", QueryLockedRow)); + properties.push_back(DECLARE_NAPI_FUNCTION("lockCloudContainer", LockCloudContainer)); + properties.push_back(DECLARE_NAPI_FUNCTION("unlockCloudContainer", UnlockCloudContainer)); +} + napi_value RdbStoreProxy::SetDistributedTables(napi_env env, napi_callback_info info) { - LOG_DEBUG("RdbStoreProxy::SetDistributedTables start."); auto context = std::make_shared(); auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { CHECK_RETURN_SET_E(1 <= argc && argc <= 3, std::make_shared("1 - 4")); @@ -1347,7 +1396,6 @@ napi_value RdbStoreProxy::SetDistributedTables(napi_env env, napi_callback_info CHECK_RETURN(OK == ParseDistributedConfigArg(env, argc, argv, context)); }; auto exec = [context]() -> int { - LOG_DEBUG("RdbStoreProxy::SetDistributedTables Async."); CHECK_RETURN_ERR(context->rdbStore != nullptr); auto rdbStore = std::move(context->rdbStore); return rdbStore->SetDistributedTables( @@ -1356,7 +1404,6 @@ napi_value RdbStoreProxy::SetDistributedTables(napi_env env, napi_callback_info auto output = [context](napi_env env, napi_value &result) { napi_status status = napi_get_undefined(env, &result); CHECK_RETURN_SET_E(status == napi_ok, std::make_shared(E_ERROR)); - LOG_DEBUG("RdbStoreProxy::SetDistributedTables end."); }; context->SetAction(env, info, input, exec, output); @@ -1366,7 +1413,6 @@ napi_value RdbStoreProxy::SetDistributedTables(napi_env env, napi_callback_info napi_value RdbStoreProxy::ObtainDistributedTableName(napi_env env, napi_callback_info info) { - LOG_DEBUG("RdbStoreProxy::ObtainDistributedTableName start."); auto context = std::make_shared(); auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { CHECK_RETURN_SET_E(argc == 2, std::make_shared("2 or 3")); @@ -1484,7 +1530,6 @@ InputAction GetCloudSyncInput(std::shared_ptr context) napi_value RdbStoreProxy::CloudSync(napi_env env, napi_callback_info info) { - LOG_DEBUG("RdbStoreProxy::CloudSync start."); auto context = std::make_shared(); auto input = GetCloudSyncInput(context); auto exec = [context]() -> int { @@ -1597,7 +1642,7 @@ napi_value RdbStoreProxy::OnRemote(napi_env env, size_t argc, napi_value *argv) bool result = std::any_of(observers_[mode].begin(), observers_[mode].end(), [argv](const auto &observer) { return *observer == argv[1]; }); if (result) { - LOG_INFO("duplicate subscribe."); + LOG_INFO("Duplicate subscribe."); return nullptr; } SubscribeOption option; @@ -1613,7 +1658,7 @@ napi_value RdbStoreProxy::OnRemote(napi_env env, size_t argc, napi_value *argv) } RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); observers_[mode].push_back(observer); - LOG_INFO("subscribe success."); + LOG_INFO("Subscribe success."); return nullptr; } @@ -1625,7 +1670,7 @@ napi_value RdbStoreProxy::RegisteredObserver(napi_env env, const DistributedRdb: bool result = std::any_of(list.begin(), list.end(), [callback](const auto &observer) { return *observer == callback; }); if (result) { - LOG_INFO("duplicate subscribe event: %{public}s", option.event.c_str()); + LOG_INFO("Duplicate subscribe event: %{public}s", option.event.c_str()); return nullptr; } @@ -1634,7 +1679,7 @@ napi_value RdbStoreProxy::RegisteredObserver(napi_env env, const DistributedRdb: int errCode = GetInstance()->Subscribe(option, localObserver.get()); RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); observers[option.event].push_back(localObserver); - LOG_INFO("subscribe success event: %{public}s", option.event.c_str()); + LOG_INFO("Subscribe success event: %{public}s", option.event.c_str()); return nullptr; } @@ -1684,7 +1729,7 @@ napi_value RdbStoreProxy::OffRemote(napi_env env, size_t argc, napi_value *argv) RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); (*it)->Clear(); it = observers_[mode].erase(it); - LOG_DEBUG("observer unsubscribe success"); + LOG_DEBUG("Observer unsubscribe success"); } return nullptr; } @@ -1694,7 +1739,7 @@ napi_value RdbStoreProxy::UnRegisteredObserver(napi_env env, const DistributedRd { auto obs = observers.find(option.event); if (obs == observers.end()) { - LOG_INFO("observer not found, event: %{public}s", option.event.c_str()); + LOG_INFO("Observer not found, event: %{public}s", option.event.c_str()); return nullptr; } @@ -1716,7 +1761,7 @@ napi_value RdbStoreProxy::UnRegisteredObserver(napi_env env, const DistributedRd RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); observers.erase(option.event); } - LOG_INFO("unsubscribe success, event: %{public}s", option.event.c_str()); + LOG_INFO("Unsubscribe success, event: %{public}s", option.event.c_str()); return nullptr; } @@ -1825,7 +1870,6 @@ napi_value RdbStoreProxy::Notify(napi_env env, napi_callback_info info) napi_value RdbStoreProxy::QuerySharingResource(napi_env env, napi_callback_info info) { - LOG_DEBUG("RdbStoreProxy::QuerySharingResource start."); auto context = std::make_shared(); auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { CHECK_RETURN_SET_E(argc > 0 && argc < 4, std::make_shared("1 to 3")); @@ -1838,7 +1882,6 @@ napi_value RdbStoreProxy::QuerySharingResource(napi_env env, napi_callback_info CHECK_RETURN_SET_E(obj != nullptr && obj->IsSystemAppCalled(), std::make_shared()); }; auto exec = [context]() -> int { - LOG_DEBUG("RdbStoreProxy::QuerySharingResource Async."); CHECK_RETURN_ERR(context->rdbStore != nullptr); auto status = E_ERROR; std::tie(status, context->resultSet) = @@ -1849,7 +1892,7 @@ napi_value RdbStoreProxy::QuerySharingResource(napi_env env, napi_callback_info return (status == E_OK && context->resultSet != nullptr) ? E_OK : E_ERROR; }; auto output = [context](napi_env env, napi_value &result) { - result = ResultSetProxy::NewInstance(env, context->resultSet); + result = ResultSetProxy::NewInstance(env, std::move(context->resultSet)); CHECK_RETURN_SET_E(result != nullptr, std::make_shared(E_ERROR)); LOG_DEBUG("RdbStoreProxy::QuerySharingResource end."); }; @@ -1867,14 +1910,14 @@ napi_value RdbStoreProxy::RegisterSyncCallback(napi_env env, size_t argc, napi_v bool result = std::any_of( syncObservers_.begin(), syncObservers_.end(), [argv](const auto &observer) { return *observer == argv[0]; }); if (result) { - LOG_DEBUG("duplicate subscribe."); + LOG_DEBUG("Duplicate subscribe."); return nullptr; } auto observer = std::make_shared(env, argv[0], queue_); int errCode = GetInstance()->RegisterAutoSyncCallback(observer); RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); syncObservers_.push_back(std::move(observer)); - LOG_INFO("progress subscribe success."); + LOG_INFO("Progress subscribe success."); return nullptr; } @@ -1901,7 +1944,7 @@ napi_value RdbStoreProxy::UnregisterSyncCallback(napi_env env, size_t argc, napi RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); (*it)->Clear(); it = syncObservers_.erase(it); - LOG_DEBUG("observer unsubscribe success."); + LOG_DEBUG("Observer unsubscribe success."); } return nullptr; } @@ -1914,14 +1957,14 @@ napi_value RdbStoreProxy::OnStatistics(napi_env env, size_t argc, napi_value *ar bool result = std::any_of(statisticses_.begin(), statisticses_.end(), [argv](std::shared_ptr obs) { return obs && *obs == argv[0]; }); if (result) { - LOG_DEBUG("duplicate subscribe."); + LOG_DEBUG("Duplicate subscribe."); return nullptr; } auto observer = std::make_shared(env, argv[0], queue_); int errCode = DistributedRdb::SqlStatistic::Subscribe(observer); RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); statisticses_.push_back(std::move(observer)); - LOG_DEBUG("statistics subscribe success."); + LOG_DEBUG("Statistics subscribe success."); return nullptr; } @@ -1951,18 +1994,18 @@ napi_value RdbStoreProxy::OffStatistics(napi_env env, size_t argc, napi_value *a return nullptr; } -RdbStoreProxy::NapiStatisticsObserver::NapiStatisticsObserver( +RdbStoreProxy::SyncObserver::SyncObserver( napi_env env, napi_value callback, std::shared_ptr queue) : env_(env), queue_(queue) { napi_create_reference(env, callback, 1, &callback_); } -RdbStoreProxy::NapiStatisticsObserver::~NapiStatisticsObserver() +RdbStoreProxy::SyncObserver::~SyncObserver() { } -void RdbStoreProxy::NapiStatisticsObserver::Clear() +void RdbStoreProxy::SyncObserver::Clear() { if (callback_ == nullptr) { return; @@ -1971,18 +2014,17 @@ void RdbStoreProxy::NapiStatisticsObserver::Clear() callback_ = nullptr; } -bool RdbStoreProxy::NapiStatisticsObserver::operator==(napi_value value) +bool RdbStoreProxy::SyncObserver::operator==(napi_value value) { return JSUtils::Equal(env_, callback_, value); } -void RdbStoreProxy::NapiStatisticsObserver::OnStatistic(const SqlExecutionInfo &sqlExeInfo) +void RdbStoreProxy::SyncObserver::ProgressNotification(const Details &details) { - auto queue = queue_; - if (queue == nullptr) { + if (queue_ == nullptr) { return; } - queue->AsyncCall({ [observer = shared_from_this()](napi_env env) -> napi_value { + queue_->AsyncCall({ [observer = shared_from_this()](napi_env env) -> napi_value { if (observer->callback_ == nullptr) { return nullptr; } @@ -1990,51 +2032,14 @@ void RdbStoreProxy::NapiStatisticsObserver::OnStatistic(const SqlExecutionInfo & napi_get_reference_value(env, observer->callback_, &callback); return callback; } }, - [infos = std::move(sqlExeInfo)](napi_env env, int &argc, napi_value *argv) { + [syncDetails = std::move(details)](napi_env env, int &argc, napi_value *argv) { argc = 1; - argv[0] = JSUtils::Convert2JSValue(env, infos); + argv[0] = syncDetails.empty() ? nullptr : JSUtils::Convert2JSValue(env, syncDetails.begin()->second); }); } -RdbStoreProxy::SyncObserver::SyncObserver( - napi_env env, napi_value callback, std::shared_ptr queue) - : env_(env), queue_(queue) -{ - napi_create_reference(env, callback, 1, &callback_); -} - -RdbStoreProxy::SyncObserver::~SyncObserver() -{ -} - -void RdbStoreProxy::SyncObserver::Clear() -{ - if (callback_ == nullptr) { - return; - } - napi_delete_reference(env_, callback_); - callback_ = nullptr; -} - -bool RdbStoreProxy::SyncObserver::operator==(napi_value value) -{ - return JSUtils::Equal(env_, callback_, value); -} - -void RdbStoreProxy::SyncObserver::ProgressNotification(const Details &details) -{ - if (queue_ != nullptr) { - queue_->AsyncCall({ callback_, true }, - [details, obs = shared_from_this()](napi_env env, int &argc, napi_value *argv) -> void { - argc = 1; - argv[0] = details.empty() ? nullptr : JSUtils::Convert2JSValue(env, details.begin()->second); - }); - } -} - napi_value RdbStoreProxy::ModifyLockStatus(napi_env env, napi_callback_info info, bool isLock) { - LOG_DEBUG("start."); auto context = std::make_shared(); auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { CHECK_RETURN_SET_E(argc >= 1, std::make_shared("1")); @@ -2042,7 +2047,6 @@ napi_value RdbStoreProxy::ModifyLockStatus(napi_env env, napi_callback_info info CHECK_RETURN(OK == ParsePredicates(env, argv[0], context)); }; auto exec = [context, isLock]() -> int { - LOG_DEBUG("Async."); CHECK_RETURN_ERR(context->rdbStore != nullptr && context->rdbPredicates != nullptr); auto rdbStore = std::move(context->rdbStore); return rdbStore->ModifyLockStatus(*(context->rdbPredicates), isLock); @@ -2050,7 +2054,6 @@ napi_value RdbStoreProxy::ModifyLockStatus(napi_env env, napi_callback_info info auto output = [context](napi_env env, napi_value &result) { napi_status status = napi_get_undefined(env, &result); CHECK_RETURN_SET_E(status == napi_ok, std::make_shared(E_ERROR)); - LOG_DEBUG("end."); }; context->SetAction(env, info, input, exec, output); @@ -2085,10 +2088,11 @@ napi_value RdbStoreProxy::QueryLockedRow(napi_env env, napi_callback_info info) context->rdbPredicates->EqualTo(AbsRdbPredicates::LOCK_STATUS, AbsRdbPredicates::LOCK_CHANGED)->EndWrap(); context->resultSet = context->rdbStore->QueryByStep(*(context->rdbPredicates), context->columns); context->rdbStore = nullptr; - return (context->resultSet != nullptr) ? E_OK : E_ERROR; + // If the API version is greater than or equal to 16, throw E_ALREADY_CLOSED. + return (context->resultSet != nullptr) ? E_OK : (JSUtils::GetHapVersion() >= 16) ? E_ALREADY_CLOSED : E_ERROR; }; auto output = [context](napi_env env, napi_value &result) { - result = ResultSetProxy::NewInstance(env, context->resultSet); + result = ResultSetProxy::NewInstance(env, std::move(context->resultSet)); CHECK_RETURN_SET_E(result != nullptr, std::make_shared(E_ERROR)); }; context->SetAction(env, info, input, exec, output); @@ -2158,6 +2162,7 @@ napi_value RdbStoreProxy::Close(napi_env env, napi_callback_info info) auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { CHECK_RETURN(OK == ParserThis(env, self, context)); RdbStoreProxy *obj = reinterpret_cast(context->boundObj); + obj->UnregisterAll(); obj->SetInstance(nullptr); }; auto exec = [context]() -> int { diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store_helper.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store_helper.cpp index fc0dc23eef7ff7ccdb23e4350af45b19a6b8037f..91e09773031b4b3e412b83c08f960f2520427d77 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store_helper.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store_helper.cpp @@ -69,8 +69,13 @@ napi_value GetRdbStore(napi_env env, napi_callback_info info) CHECK_RETURN_SET_E(OK == errCode, std::make_shared("Illegal StoreConfig or name.")); CHECK_RETURN_SET_E(context->config.cryptoParam.IsValid(), std::make_shared("Illegal CryptoParam.")); + CHECK_RETURN_SET_E(context->config.tokenizer >= NONE_TOKENIZER && context->config.tokenizer < TOKENIZER_END, + std::make_shared("Illegal tokenizer.")); auto [code, err] = GetRealPath(env, argv[0], context->config, context->param); + if (!context->config.rootDir.empty()) { + context->config.isReadOnly = true; + } CHECK_RETURN_SET_E(OK == code, err); }; auto exec = [context]() -> int { @@ -78,10 +83,14 @@ napi_value GetRdbStore(napi_env env, napi_callback_info info) DefaultOpenCallback callback; context->proxy = RdbHelper::GetRdbStore(GetRdbStoreConfig(context->config, context->param), -1, callback, errCode); + // If the API version is less than 14, throw E_INVALID_ARGS. + if (errCode == E_INVALID_SECRET_KEY && JSUtils::GetHapVersion() < 14) { + errCode = E_INVALID_ARGS; + } return errCode; }; auto output = [context](napi_env env, napi_value &result) { - result = RdbStoreProxy::NewInstance(env, context->proxy, context->param.isSystemApp); + result = RdbStoreProxy::NewInstance(env, context->proxy, context->param.isSystemApp, context->param.bundleName); CHECK_RETURN_SET_E(result != nullptr, std::make_shared(E_ERROR)); }; context->SetAction(env, info, input, exec, output); @@ -95,6 +104,7 @@ napi_value DeleteRdbStore(napi_env env, napi_callback_info info) struct DeleteContext : public ContextBase { ContextParam param; RdbConfig config; + bool onlyPath = false; }; auto context = std::make_shared(); auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { @@ -103,6 +113,7 @@ napi_value DeleteRdbStore(napi_env env, napi_callback_info info) CHECK_RETURN_SET_E(OK == errCode, std::make_shared("Illegal context.")); if (IsNapiString(env, argv[1])) { + context->onlyPath = true; errCode = Convert2Value(env, argv[1], context->config.name); CHECK_RETURN_SET_E(OK == errCode, std::make_shared("Illegal path.")); } else { @@ -111,10 +122,22 @@ napi_value DeleteRdbStore(napi_env env, napi_callback_info info) } auto [code, err] = GetRealPath(env, argv[0], context->config, context->param); + if (!context->config.rootDir.empty()) { + context->config.isReadOnly = true; + } CHECK_RETURN_SET_E(OK == code, err); }; auto exec = [context]() -> int { - return RdbHelper::DeleteRdbStore(context->config.path); + // If the API version is greater than or equal to 16, close the connection. + RdbStoreConfig storeConfig = GetRdbStoreConfig(context->config, context->param); + if (context->onlyPath) { + storeConfig.SetDBType(DB_SQLITE); + int errCodeSqlite = RdbHelper::DeleteRdbStore(storeConfig, JSUtils::GetHapVersion() >= 16); + storeConfig.SetDBType(DB_VECTOR); + int errCodeVector = RdbHelper::DeleteRdbStore(storeConfig, JSUtils::GetHapVersion() >= 16); + return (errCodeSqlite == E_OK && errCodeVector == E_OK) ? E_OK : E_REMOVE_FILE; + } + return RdbHelper::DeleteRdbStore(storeConfig, JSUtils::GetHapVersion() >= 16); }; auto output = [context](napi_env env, napi_value &result) { napi_status status = napi_create_int64(env, OK, &result); @@ -126,6 +149,27 @@ napi_value DeleteRdbStore(napi_env env, napi_callback_info info) return ASYNC_CALL(env, context); } +napi_value IsVectorSupported(napi_env env, napi_callback_info info) +{ + bool result = RdbHelper::IsSupportArkDataDb(); + return JSUtils::Convert2JSValue(env, result); +} + +napi_value IsTokenizerSupported(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1]{}; + napi_value self = nullptr; + int32_t status = napi_get_cb_info(env, info, &argc, argv, &self, nullptr); + RDB_NAPI_ASSERT(env, argc == 1, std::make_shared("1")); + int32_t tokenizer = static_cast(Tokenizer::NONE_TOKENIZER); + status = Convert2ValueExt(env, argv[0], tokenizer); + RDB_NAPI_ASSERT(env, status == napi_ok && tokenizer >= NONE_TOKENIZER && tokenizer < TOKENIZER_END, + std::make_shared("tokenizer", "a TOKENIZER.")); + bool result = RdbHelper::IsSupportedTokenizer(static_cast(tokenizer)); + return JSUtils::Convert2JSValue(env, result); +} + napi_value InitRdbHelper(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { @@ -133,6 +177,8 @@ napi_value InitRdbHelper(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION_WITH_DATA("getRdbStoreSync", GetRdbStore, SYNC), DECLARE_NAPI_FUNCTION_WITH_DATA("deleteRdbStore", DeleteRdbStore, ASYNC), DECLARE_NAPI_FUNCTION_WITH_DATA("deleteRdbStoreSync", DeleteRdbStore, SYNC), + DECLARE_NAPI_FUNCTION_WITH_DATA("isVectorSupported", IsVectorSupported, SYNC), + DECLARE_NAPI_FUNCTION_WITH_DATA("isTokenizerSupported", IsTokenizerSupported, SYNC), }; NAPI_CALL(env, napi_define_properties(env, exports, sizeof(properties) / sizeof(*properties), properties)); return exports; diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store_observer.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store_observer.cpp index d47534350d9939fe72680637742b779df1ee4881..d49be888e3dac31d5f390629d56075f604c2bed3 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store_observer.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store_observer.cpp @@ -117,13 +117,13 @@ bool NapiRdbStoreObserver::operator==(napi_value value) napi_value callback = nullptr; napi_status status = napi_get_reference_value(uvQueue_->GetEnv(), callback_, &callback); if (status != napi_ok) { - LOG_ERROR("call napi_get_reference_value failed status[%{public}d].", status); + LOG_ERROR("Call napi_get_reference_value failed status[%{public}d].", status); } bool isEquals = false; status = napi_strict_equals(uvQueue_->GetEnv(), value, callback, &isEquals); if (status != napi_ok) { - LOG_ERROR("call napi_strict_equals failed status[%{public}d].", status); + LOG_ERROR("Call napi_strict_equals failed status[%{public}d].", status); } return isEquals; } diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_result_set.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_result_set.cpp index 29a5f318852b64a1e3a9968a14a0917bfd4f389c..36590ab4622702648ed90316b3a16be9877e9ced 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_result_set.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_result_set.cpp @@ -16,6 +16,7 @@ #include "napi_result_set.h" #include +#include #include "js_df_manager.h" #include "js_utils.h" @@ -24,6 +25,8 @@ #include "napi_rdb_js_utils.h" #include "napi_rdb_sendable_utils.h" #include "napi_rdb_trace.h" +#include "rdb_errno.h" +#include "result_set.h" #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) #include "rdb_result_set_bridge.h" #include "string_ex.h" @@ -39,6 +42,7 @@ using Asset = AssetValue; using Assets = std::vector; using FloatVector = std::vector; static const int E_OK = 0; +static const int INIT_POSITION = -1; napi_value ResultSetProxy::NewInstance(napi_env env, std::shared_ptr resultSet) { @@ -56,9 +60,9 @@ napi_value ResultSetProxy::NewInstance(napi_env env, std::shared_ptr(&proxy)); - if (proxy == nullptr) { + if (status != napi_ok || proxy == nullptr) { LOG_ERROR("NewInstance native instance is nullptr! code:%{public}d!", status); - return instance; + return nullptr; } proxy->SetInstance(std::move(resultSet)); return instance; @@ -69,7 +73,7 @@ std::shared_ptr ResultSetProxy::Create() { auto instance = GetInstance(); if (instance == nullptr) { - LOG_ERROR("resultSet is null."); + LOG_ERROR("ResultSet is null."); return nullptr; } SetInstance(nullptr); @@ -132,21 +136,26 @@ ResultSetProxy &ResultSetProxy::operator=(std::shared_ptr resultSet) return *this; } -ResultSetProxy *ResultSetProxy::GetInnerResultSet(napi_env env, napi_callback_info info) +static ResultSetProxy *GetResultSetProxy(napi_env env, napi_callback_info info) { napi_value self = nullptr; napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr); ResultSetProxy *proxy = nullptr; - napi_unwrap(env, self, reinterpret_cast(&proxy)); - RDB_NAPI_ASSERT(env, proxy && proxy->GetInstance(), std::make_shared("napi_unwrap failed.")); + napi_status status = napi_unwrap(env, self, reinterpret_cast(&proxy)); + RDB_NAPI_ASSERT(env, status == napi_ok && proxy != nullptr, std::make_shared("napi_unwrap failed.")); return proxy; } -ResultSetProxy *ResultSetProxy::ParseInt32FieldByName( - napi_env env, napi_callback_info info, int32_t &field, const std::string name) +static std::shared_ptr GetInnerResultSet(napi_env env, napi_callback_info info) +{ + ResultSetProxy *proxy = GetResultSetProxy(env, info); + return proxy == nullptr ? nullptr : proxy->GetInstance(); +} + +static std::shared_ptr ParseInt32FieldByName( + napi_env env, napi_callback_info info, int32_t &field, const std::string &name) { - DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); napi_value self = nullptr; size_t argc = 1; napi_value args[1] = { 0 }; @@ -157,13 +166,13 @@ ResultSetProxy *ResultSetProxy::ParseInt32FieldByName( RDB_NAPI_ASSERT(env, status == napi_ok, std::make_shared(name, "a number.")); ResultSetProxy *proxy = nullptr; - napi_unwrap(env, self, reinterpret_cast(&proxy)); - RDB_NAPI_ASSERT(env, proxy && proxy->GetInstance(), std::make_shared("resultSet", "not null")); - return proxy; + status = napi_unwrap(env, self, reinterpret_cast(&proxy)); + RDB_NAPI_ASSERT(env, status == napi_ok && proxy != nullptr, std::make_shared("napi_unwrap failed.")); + return proxy->GetInstance(); } -ResultSetProxy *ResultSetProxy::ParseFieldByName( - napi_env env, napi_callback_info info, std::string &field, const std::string name) +static std::shared_ptr ParseFieldByName( + napi_env env, napi_callback_info info, std::string &field, const std::string &name) { napi_value self = nullptr; size_t argc = 1; @@ -175,36 +184,29 @@ ResultSetProxy *ResultSetProxy::ParseFieldByName( RDB_NAPI_ASSERT(env, !field.empty(), std::make_shared(name, "a non empty string.")); ResultSetProxy *proxy = nullptr; - napi_unwrap(env, self, reinterpret_cast(&proxy)); - RDB_NAPI_ASSERT(env, proxy && proxy->GetInstance(), std::make_shared("resultSet", "not null")); - return proxy; + napi_status status = napi_unwrap(env, self, reinterpret_cast(&proxy)); + RDB_NAPI_ASSERT(env, status == napi_ok && proxy != nullptr, std::make_shared("napi_unwrap failed.")); + return proxy->GetInstance(); } napi_value ResultSetProxy::GetAllColumnNames(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - + auto resultSet = GetInnerResultSet(env, info); std::vector colNames; - int errCode = resultSetProxy->GetInstance()->GetAllColumnNames(colNames); - if (errCode != E_OK) { - LOG_ERROR("GetAllColumnNames failed code:%{public}d", errCode); + if (resultSet != nullptr) { + resultSet->GetAllColumnNames(colNames); } - return JSUtils::Convert2JSValue(env, colNames); } napi_value ResultSetProxy::GetColumnCount(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - + auto resultSet = GetInnerResultSet(env, info); int32_t count = 0; - int errCode = resultSetProxy->GetInstance()->GetColumnCount(count); - if (errCode != E_OK) { - LOG_ERROR("GetColumnCount failed code:%{public}d", errCode); + if (resultSet != nullptr) { + resultSet->GetColumnCount(count); } return JSUtils::Convert2JSValue(env, count); @@ -214,13 +216,10 @@ napi_value ResultSetProxy::GetColumnType(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int32_t columnIndex; - auto resultSetProxy = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - - ColumnType columnType; - int errCode = resultSetProxy->GetInstance()->GetColumnType(columnIndex, columnType); - if (errCode != E_OK) { - LOG_ERROR("GetColumnType failed code:%{public}d", errCode); + auto resultSet = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); + ColumnType columnType = ColumnType::TYPE_NULL; + if (resultSet != nullptr) { + resultSet->GetColumnType(columnIndex, columnType); } return JSUtils::Convert2JSValue(env, int32_t(columnType)); @@ -229,97 +228,89 @@ napi_value ResultSetProxy::GetColumnType(napi_env env, napi_callback_info info) napi_value ResultSetProxy::GetRowCount(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - - int32_t result; - int errCode = resultSetProxy->GetInstance()->GetRowCount(result); - if (errCode != E_OK) { - LOG_ERROR("GetRowCount failed code:%{public}d", errCode); + auto resultSet = GetInnerResultSet(env, info); + // If resultSet is closed, the default rowCount is -1. + int32_t rowCount = -1; + if (resultSet != nullptr) { + resultSet->GetRowCount(rowCount); } - return JSUtils::Convert2JSValue(env, result); + return JSUtils::Convert2JSValue(env, rowCount); } napi_value ResultSetProxy::GetRowIndex(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - - int32_t result; - int errCode = resultSetProxy->GetInstance()->GetRowIndex(result); - if (errCode != E_OK) { - LOG_ERROR("GetRowIndex failed code:%{public}d", errCode); + auto resultSet = GetInnerResultSet(env, info); + // If resultSet is closed, the default rowIndex is -1. + int32_t rowIndex = -1; + if (resultSet != nullptr) { + resultSet->GetRowIndex(rowIndex); } - return JSUtils::Convert2JSValue(env, result); + return JSUtils::Convert2JSValue(env, rowIndex); } napi_value ResultSetProxy::IsEnded(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - bool result = false; - resultSetProxy->GetInstance()->IsEnded(result); - - return JSUtils::Convert2JSValue(env, result); + auto resultSet = GetInnerResultSet(env, info); + bool isEnded = true; + if (resultSet != nullptr) { + resultSet->IsEnded(isEnded); + } + return JSUtils::Convert2JSValue(env, isEnded); } napi_value ResultSetProxy::IsBegin(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - - bool result = false; - int errCode = resultSetProxy->GetInstance()->IsStarted(result); - if (errCode != E_OK) { - LOG_ERROR("IsBegin failed code:%{public}d", errCode); + auto resultSet = GetInnerResultSet(env, info); + bool isStarted = false; + if (resultSet != nullptr) { + resultSet->IsStarted(isStarted); } - - return JSUtils::Convert2JSValue(env, result); + return JSUtils::Convert2JSValue(env, isStarted); } napi_value ResultSetProxy::IsAtFirstRow(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - - bool result = false; - int errCode = resultSetProxy->GetInstance()->IsAtFirstRow(result); - if (errCode != E_OK) { - LOG_ERROR("IsAtFirstRow failed code:%{public}d", errCode); + auto resultSet = GetInnerResultSet(env, info); + bool isAtFirstRow = false; + if (resultSet != nullptr) { + resultSet->IsAtFirstRow(isAtFirstRow); } - return JSUtils::Convert2JSValue(env, result); + return JSUtils::Convert2JSValue(env, isAtFirstRow); } napi_value ResultSetProxy::IsAtLastRow(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - - bool result = false; - int errCode = resultSetProxy->GetInstance()->IsAtLastRow(result); - if (errCode != E_OK) { - LOG_ERROR("IsAtLastRow failed code:%{public}d", errCode); + auto resultSet = GetInnerResultSet(env, info); + bool isAtLastRow = false; + if (resultSet != nullptr) { + resultSet->IsAtLastRow(isAtLastRow); } - return JSUtils::Convert2JSValue(env, result); + return JSUtils::Convert2JSValue(env, isAtLastRow); } napi_value ResultSetProxy::Close(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - - int errCode = resultSetProxy->GetInstance()->Close(); - RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); + ResultSetProxy *resultSetProxy = GetResultSetProxy(env, info); + if (resultSetProxy == nullptr) { + return nullptr; + } + if (resultSetProxy->GetInstance() != nullptr) { + std::shared_ptr res = resultSetProxy->GetInstance(); + resultSetProxy->SetInstance(nullptr); + if (res.use_count() != 1) { + LOG_WARN("use_count = %{public}ld", res.use_count()); + } + } napi_value result = nullptr; napi_get_null(env, &result); return result; @@ -329,10 +320,14 @@ napi_value ResultSetProxy::GoToRow(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int32_t position; - auto resultSetProxy = ParseInt32FieldByName(env, info, position, "position"); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - - int errCode = resultSetProxy->GetInstance()->GoToRow(position); + auto resultSet = ParseInt32FieldByName(env, info, position, "position"); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->GoToRow(position); + } + // If the API version is less than 13, directly return. + RDB_NAPI_ASSERT(env, JSUtils::GetHapVersion() < 13 || (errCode == E_ROW_OUT_RANGE || errCode == E_OK), + std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, (errCode == E_OK)); } @@ -340,50 +335,70 @@ napi_value ResultSetProxy::GoTo(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int32_t offset; - auto resultSetProxy = ParseInt32FieldByName(env, info, offset, "offset"); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - - int errCode = resultSetProxy->GetInstance()->GoTo(offset); + auto resultSet = ParseInt32FieldByName(env, info, offset, "offset"); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->GoTo(offset); + } + // If the API version is less than 13, directly return. + RDB_NAPI_ASSERT(env, JSUtils::GetHapVersion() < 13 || (errCode == E_ROW_OUT_RANGE || errCode == E_OK), + std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, (errCode == E_OK)); } napi_value ResultSetProxy::GoToFirstRow(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - - int errCode = resultSetProxy->GetInstance()->GoToFirstRow(); + auto resultSet = GetInnerResultSet(env, info); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->GoToFirstRow(); + } + // If the API version is less than 13, directly return. + RDB_NAPI_ASSERT(env, JSUtils::GetHapVersion() < 13 || (errCode == E_ROW_OUT_RANGE || errCode == E_OK), + std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, (errCode == E_OK)); } napi_value ResultSetProxy::GoToLastRow(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - - int errCode = resultSetProxy->GetInstance()->GoToLastRow(); + auto resultSet = GetInnerResultSet(env, info); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->GoToLastRow(); + } + // If the API version is less than 13, directly return. + RDB_NAPI_ASSERT(env, JSUtils::GetHapVersion() < 13 || (errCode == E_ROW_OUT_RANGE || errCode == E_OK), + std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, (errCode == E_OK)); } napi_value ResultSetProxy::GoToNextRow(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - - int errCode = resultSetProxy->GetInstance()->GoToNextRow(); + auto resultSet = GetInnerResultSet(env, info); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->GoToNextRow(); + } + // If the API version is less than 13, directly return. + RDB_NAPI_ASSERT(env, JSUtils::GetHapVersion() < 13 || (errCode == E_ROW_OUT_RANGE || errCode == E_OK), + std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, (errCode == E_OK)); } napi_value ResultSetProxy::GoToPreviousRow(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - - int errCode = resultSetProxy->GetInstance()->GoToPreviousRow(); + auto resultSet = GetInnerResultSet(env, info); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->GoToPreviousRow(); + } + // If the API version is less than 13, directly return. + RDB_NAPI_ASSERT(env, JSUtils::GetHapVersion() < 13 || (errCode == E_ROW_OUT_RANGE || errCode == E_OK), + std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, (errCode == E_OK)); } @@ -391,11 +406,12 @@ napi_value ResultSetProxy::GetInt(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int32_t columnIndex; - auto resultSetProxy = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - + auto resultSet = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); int32_t result; - int errCode = resultSetProxy->GetInstance()->GetInt(columnIndex, result); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->GetInt(columnIndex, result); + } RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, result); @@ -405,11 +421,12 @@ napi_value ResultSetProxy::GetLong(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int32_t columnIndex; - auto resultSetProxy = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - + auto resultSet = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); int64_t result; - int errCode = resultSetProxy->GetInstance()->GetLong(columnIndex, result); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->GetLong(columnIndex, result); + } RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, result); @@ -419,11 +436,12 @@ napi_value ResultSetProxy::GetBlob(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int32_t columnIndex; - auto resultSetProxy = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - + auto resultSet = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); std::vector result; - int errCode = resultSetProxy->GetInstance()->GetBlob(columnIndex, result); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->GetBlob(columnIndex, result); + } RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, result); @@ -433,13 +451,14 @@ napi_value ResultSetProxy::GetAsset(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int32_t columnIndex; - auto resultSetProxy = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - + auto resultSet = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); Asset result; - int errCode = resultSetProxy->GetInstance()->GetAsset(columnIndex, result); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->GetAsset(columnIndex, result); + } if (errCode == E_NULL_OBJECT) { - LOG_DEBUG("getAsset col %{public}d is null.", columnIndex); + LOG_DEBUG("GetAsset col %{public}d is null.", columnIndex); return JSUtils::Convert2JSValue(env, std::monostate()); } RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); @@ -451,13 +470,14 @@ napi_value ResultSetProxy::GetAssets(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int32_t columnIndex; - auto resultSetProxy = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - + auto resultSet = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); Assets result; - int errCode = resultSetProxy->GetInstance()->GetAssets(columnIndex, result); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->GetAssets(columnIndex, result); + } if (errCode == E_NULL_OBJECT) { - LOG_DEBUG("getAssets col %{public}d is null.", columnIndex); + LOG_DEBUG("GetAssets col %{public}d is null.", columnIndex); return JSUtils::Convert2JSValue(env, std::monostate()); } RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); @@ -469,11 +489,12 @@ napi_value ResultSetProxy::GetFloat32Array(napi_env env, napi_callback_info info { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int32_t columnIndex; - auto resultSetProxy = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - + auto resultSet = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); FloatVector result = {}; - int errCode = resultSetProxy->GetInstance()->GetFloat32Array(columnIndex, result); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->GetFloat32Array(columnIndex, result); + } if (errCode == E_NULL_OBJECT) { LOG_DEBUG("GetFloat32Array col %{public}d is null.", columnIndex); return JSUtils::Convert2JSValue(env, std::monostate()); @@ -486,11 +507,12 @@ napi_value ResultSetProxy::GetString(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int32_t columnIndex; - auto resultSetProxy = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - + auto resultSet = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); std::string result; - int errCode = resultSetProxy->GetInstance()->GetString(columnIndex, result); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->GetString(columnIndex, result); + } RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, result); @@ -500,11 +522,12 @@ napi_value ResultSetProxy::GetDouble(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int32_t columnIndex; - auto resultSetProxy = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - + auto resultSet = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); double result = 0.0; - int errCode = resultSetProxy->GetInstance()->GetDouble(columnIndex, result); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->GetDouble(columnIndex, result); + } RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, result); @@ -514,11 +537,15 @@ napi_value ResultSetProxy::GetColumnIndex(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); std::string input; - auto resultSetProxy = ParseFieldByName(env, info, input, "columnName"); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - + auto resultSet = ParseFieldByName(env, info, input, "columnName"); int32_t result = -1; - resultSetProxy->GetInstance()->GetColumnIndex(input, result); + int errCode = E_OK; + if (resultSet != nullptr) { + errCode = resultSet->GetColumnIndex(input, result); + } + // If the API version is less than 13, directly return. + RDB_NAPI_ASSERT(env, JSUtils::GetHapVersion() < 13 || (errCode == E_INVALID_ARGS || errCode == E_OK), + std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, result); } @@ -526,15 +553,14 @@ napi_value ResultSetProxy::GetColumnName(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int32_t columnIndex; - auto resultSetProxy = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - + auto resultSet = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); std::string result; - int errCode = resultSetProxy->GetInstance()->GetColumnName(columnIndex, result); - if (errCode != E_OK) { - LOG_ERROR("IsAtLastRow failed code:%{public}d", errCode); + int errCode = E_OK; + if (resultSet != nullptr) { + errCode = resultSet->GetColumnName(columnIndex, result); } - + // If the API version is less than 13, directly return. + RDB_NAPI_ASSERT(env, JSUtils::GetHapVersion() < 13 || errCode == E_OK, std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, result); } @@ -542,11 +568,12 @@ napi_value ResultSetProxy::IsColumnNull(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int32_t columnIndex; - auto resultSetProxy = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - + auto resultSet = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); bool result = false; - int errCode = resultSetProxy->GetInstance()->IsColumnNull(columnIndex, result); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->IsColumnNull(columnIndex, result); + } RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, result); @@ -555,23 +582,107 @@ napi_value ResultSetProxy::IsColumnNull(napi_env env, napi_callback_info info) napi_value ResultSetProxy::GetRow(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - + auto resultSet = GetInnerResultSet(env, info); RowEntity rowEntity; - int errCode = resultSetProxy->GetInstance()->GetRow(rowEntity); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->GetRow(rowEntity); + } RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); + return JSUtils::Convert2JSValue(env, rowEntity); } +std::pair> ResultSetProxy::GetRows(ResultSet &resultSet, int32_t maxCount, int32_t position) +{ + int rowPos = 0; + resultSet.GetRowIndex(rowPos); + int errCode = E_OK; + if (position != INIT_POSITION && position != rowPos) { + errCode = resultSet.GoToRow(position); + } else if (rowPos == INIT_POSITION) { + errCode = resultSet.GoToFirstRow(); + if (errCode == E_ROW_OUT_RANGE) { + return { E_OK, std::vector() }; + } + } + + if (errCode != E_OK) { + LOG_ERROR("Failed code:%{public}d. [%{public}d, %{public}d]", errCode, maxCount, position); + return { errCode, std::vector() }; + } + + std::vector rowEntities; + for (int32_t i = 0; i < maxCount; ++i) { + RowEntity rowEntity; + int errCode = resultSet.GetRow(rowEntity); + if (errCode == E_ROW_OUT_RANGE) { + break; + } + if (errCode != E_OK) { + return { errCode, std::vector() }; + } + rowEntities.push_back(rowEntity); + errCode = resultSet.GoToNextRow(); + if (errCode == E_ROW_OUT_RANGE) { + break; + } + if (errCode != E_OK) { + return { errCode, std::vector() }; + } + } + return { E_OK, rowEntities }; +} + +napi_value ResultSetProxy::GetRows(napi_env env, napi_callback_info info) +{ + struct RowsContextBase : public ContextBase { + public: + int32_t maxCount = 0; + int32_t position = INIT_POSITION; + std::weak_ptr resultSet; + std::vector rowEntities; + }; + std::shared_ptr context = std::make_shared(); + auto resultSet = GetInnerResultSet(env, info); + RDB_NAPI_ASSERT(env, resultSet != nullptr, std::make_shared(E_ALREADY_CLOSED)); + context->resultSet = resultSet; + auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { + CHECK_RETURN_SET_E(argc > 0, std::make_shared("1 or 2")); + auto errCode = JSUtils::Convert2ValueExt(env, argv[0], context->maxCount); + CHECK_RETURN_SET_E(OK == errCode && context->maxCount > 0, std::make_shared("Invalid maxCount")); + if (argc == 2) { + errCode = JSUtils::Convert2ValueExt(env, argv[1], context->position); + CHECK_RETURN_SET_E( + OK == errCode && context->position >= 0, std::make_shared("Invalid position")); + } + }; + auto exec = [context]() -> int { + auto result = context->resultSet.lock(); + if (result == nullptr) { + return E_ALREADY_CLOSED; + } + int errCode = E_OK; + std::tie(errCode, context->rowEntities) = GetRows(*result, context->maxCount, context->position); + return errCode; + }; + auto output = [context](napi_env env, napi_value &result) { + result = JSUtils::Convert2JSValue(env, context->rowEntities); + }; + context->SetAction(env, info, input, exec, output); + CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK); + return ASYNC_CALL(env, context); +} + napi_value ResultSetProxy::GetSendableRow(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - + auto resultSet = GetInnerResultSet(env, info); RowEntity rowEntity; - int errCode = resultSetProxy->GetInstance()->GetRow(rowEntity); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->GetRow(rowEntity); + } RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); return JSUtils::Convert2Sendable(env, rowEntity); } @@ -580,11 +691,12 @@ napi_value ResultSetProxy::GetValue(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int32_t columnIndex; - auto resultSetProxy = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - + auto resultSet = ParseInt32FieldByName(env, info, columnIndex, "columnIndex"); ValueObject object; - int errCode = resultSetProxy->GetInstance()->Get(columnIndex, object); + int errCode = E_ALREADY_CLOSED; + if (resultSet != nullptr) { + errCode = resultSet->Get(columnIndex, object); + } RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, object); } @@ -592,11 +704,7 @@ napi_value ResultSetProxy::GetValue(napi_env env, napi_callback_info info) napi_value ResultSetProxy::IsClosed(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); - CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->GetInstance()); - bool result = resultSetProxy->GetInstance()->IsClosed(); - - return JSUtils::Convert2JSValue(env, result); + return JSUtils::Convert2JSValue(env, GetInnerResultSet(env, info) == nullptr); } void ResultSetProxy::Init(napi_env env, napi_value exports) @@ -624,6 +732,7 @@ void ResultSetProxy::Init(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("isColumnNull", IsColumnNull), DECLARE_NAPI_FUNCTION("getValue", GetValue), DECLARE_NAPI_FUNCTION("getRow", GetRow), + DECLARE_NAPI_FUNCTION("getRows", GetRows), DECLARE_NAPI_FUNCTION("getSendableRow", GetSendableRow), DECLARE_NAPI_GETTER("columnNames", GetAllColumnNames), diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_transaction.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_transaction.cpp index 53188809ca13fe2197ec1468ca6a53fa79a9e01e..cdf204703aab7484c857982ac858057ef5b8810a 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_transaction.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_transaction.cpp @@ -52,6 +52,7 @@ struct TransactionContext : public ContextBase { int32_t ParseSendableValuesBucket(napi_env env, napi_value arg, ValuesBucket &valuesBucket); int32_t ParseValuesBucket(napi_env env, napi_value arg, ValuesBucket &valuesBucket); int32_t ParseValuesBuckets(napi_env env, napi_value arg, std::vector &valuesBuckets); + int32_t ParseValuesBuckets(napi_env env, napi_value arg, ValuesBuckets &valuesBuckets); int32_t ParseConflictResolution(napi_env env, napi_value arg, NativeRdb::ConflictResolution &conflictResolution); std::shared_ptr transaction_ = nullptr; static constexpr int32_t KEY_INDEX = 0; @@ -162,13 +163,35 @@ int32_t TransactionContext::ParseValuesBuckets(napi_env env, napi_value arg, std return OK; } +int32_t TransactionContext::ParseValuesBuckets(napi_env env, napi_value arg, ValuesBuckets &valuesBuckets) +{ + bool isArray = false; + auto status = napi_is_array(env, arg, &isArray); + ASSERT_RETURN_SET_ERROR(status == napi_ok && isArray, std::make_shared("ValuesBucket is invalid.")); + + uint32_t arrLen = 0; + status = napi_get_array_length(env, arg, &arrLen); + ASSERT_RETURN_SET_ERROR(status == napi_ok && arrLen > 0, std::make_shared("ValuesBucket is invalid.")); + + for (uint32_t i = 0; i < arrLen; ++i) { + napi_value obj = nullptr; + status = napi_get_element(env, arg, i, &obj); + ASSERT_RETURN_SET_ERROR(status == napi_ok, std::make_shared("napi_get_element failed.")); + ValuesBucket valuesBucket; + ASSERT_RETURN_SET_ERROR( + ParseValuesBucket(env, obj, valuesBucket) == OK, std::make_shared("ValuesBucket is invalid.")); + valuesBuckets.Put(std::move(valuesBucket)); + } + return OK; +} + int32_t TransactionContext::ParseConflictResolution( const napi_env env, const napi_value arg, NativeRdb::ConflictResolution &conflictResolution) { int32_t input = 0; auto status = napi_get_value_int32(env, arg, &input); - int min = static_cast(NativeRdb::ConflictResolution::ON_CONFLICT_NONE); - int max = static_cast(NativeRdb::ConflictResolution::ON_CONFLICT_REPLACE); + int32_t min = static_cast(NativeRdb::ConflictResolution::ON_CONFLICT_NONE); + int32_t max = static_cast(NativeRdb::ConflictResolution::ON_CONFLICT_REPLACE); bool checked = status == napi_ok && (input >= min) && (input <= max); ASSERT_RETURN_SET_ERROR(checked, std::make_shared("conflictResolution", "a ConflictResolution.")); conflictResolution = static_cast(input); @@ -191,9 +214,9 @@ napi_value TransactionProxy::NewInstance(napi_env env, std::shared_ptr(&proxy)); - if (proxy == nullptr) { + if (status != napi_ok || proxy == nullptr) { LOG_ERROR("NewInstance native instance is nullptr! code:%{public}d!", status); - return instance; + return nullptr; } proxy->SetInstance(std::move(transaction)); return instance; @@ -209,6 +232,8 @@ void TransactionProxy::Init(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION_WITH_DATA("update", Update, ASYNC), DECLARE_NAPI_FUNCTION_WITH_DATA("insert", Insert, ASYNC), DECLARE_NAPI_FUNCTION_WITH_DATA("batchInsert", BatchInsert, ASYNC), + DECLARE_NAPI_FUNCTION_WITH_DATA( + "batchInsertWithConflictResolution", BatchInsertWithConflictResolution, ASYNC), DECLARE_NAPI_FUNCTION_WITH_DATA("query", Query, ASYNC), DECLARE_NAPI_FUNCTION_WITH_DATA("querySql", QuerySql, ASYNC), DECLARE_NAPI_FUNCTION_WITH_DATA("execute", Execute, ASYNC), @@ -228,6 +253,8 @@ void TransactionProxy::AddSyncFunctions(std::vector &p properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("updateSync", Update, SYNC)); properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("insertSync", Insert, SYNC)); properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("batchInsertSync", BatchInsert, SYNC)); + properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("batchInsertWithConflictResolutionSync", + BatchInsertWithConflictResolution, SYNC)); properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("querySync", Query, SYNC)); properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("querySqlSync", QuerySql, SYNC)); properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("executeSync", Execute, SYNC)); @@ -251,7 +278,7 @@ napi_value TransactionProxy::Initialize(napi_env env, napi_callback_info info) NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); auto *proxy = new (std::nothrow) TransactionProxy(); if (proxy == nullptr) { - LOG_ERROR("no memory, new TransactionProxy failed!"); + LOG_ERROR("No memory, new TransactionProxy failed!"); return nullptr; } auto finalize = [](napi_env env, void *data, void *hint) { @@ -260,7 +287,7 @@ napi_value TransactionProxy::Initialize(napi_env env, napi_callback_info info) LOG_ERROR("(T:%{public}d) freed! data:0x%016" PRIXPTR, tid, uintptr_t(data) & LOWER_24_BITS_MASK); } if (data != hint) { - LOG_ERROR("memory corrupted! data:0x%016" PRIXPTR "hint:0x%016" PRIXPTR, uintptr_t(data), uintptr_t(hint)); + LOG_ERROR("Memory corrupted! data:0x%016" PRIXPTR "hint:0x%016" PRIXPTR, uintptr_t(data), uintptr_t(hint)); return; } TransactionProxy *proxy = reinterpret_cast(data); @@ -494,6 +521,8 @@ struct BatchInsertContext : public TransactionContext { ASSERT_RETURN_SET_ERROR( JSUtils::Convert2Value(env, argv[0], tableName) == OK, std::make_shared("table", "a string.")); CHECK_RETURN_ERR(ParseValuesBuckets(env, argv[1], valuesBuckets) == OK); + ASSERT_RETURN_SET_ERROR(!JSUtils::HasDuplicateAssets(valuesBuckets), + std::make_shared("Duplicate assets are not allowed")); return OK; } std::string tableName; @@ -529,6 +558,59 @@ napi_value TransactionProxy::BatchInsert(napi_env env, napi_callback_info info) return ASYNC_CALL(env, context); } +struct BatchInsertWithConflictResolutionContext : public TransactionContext { + int32_t Parse(napi_env env, size_t argc, napi_value *argv, napi_value self) + { + ASSERT_RETURN_SET_ERROR(argc == 3, std::make_shared("3")); + GetInstance(self); + ASSERT_RETURN_SET_ERROR(transaction_ != nullptr, std::make_shared("transaction", "a transaction.")); + ASSERT_RETURN_SET_ERROR( + JSUtils::Convert2Value(env, argv[0], tableName) == OK, std::make_shared("table", "a string.")); + CHECK_RETURN_ERR(ParseValuesBuckets(env, argv[1], valuesBuckets) == OK); + ASSERT_RETURN_SET_ERROR(!JSUtils::HasDuplicateAssets(valuesBuckets), + std::make_shared("Duplicate assets are not allowed")); + // 'argv[2]' represents a ConflictResolution + ASSERT_RETURN_SET_ERROR(!JSUtils::IsNull(env, argv[2]), std::make_shared("conflict", "not null")); + // 'argv[2]' represents a ConflictResolution + CHECK_RETURN_ERR(ParseConflictResolution(env, argv[2], conflictResolution) == OK); + return OK; + } + std::string tableName; + ValuesBuckets valuesBuckets; + ConflictResolution conflictResolution; + + int64_t insertRows = -1; +}; + +/* + * [JS API Prototype] + * [Promise] + * batchInsertWithConflictResolution(table: string, values: Array, conflict: ConflictResolution): + * Promise; + */ +napi_value TransactionProxy::BatchInsertWithConflictResolution(napi_env env, napi_callback_info info) +{ + auto context = std::make_shared(); + auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) { + context->Parse(env, argc, argv, self); + }; + auto exec = [context]() -> int { + CHECK_RETURN_ERR(context->transaction_ != nullptr); + auto [code, insertRows] = context->StealTransaction()->BatchInsertWithConflictResolution( + context->tableName, context->valuesBuckets, context->conflictResolution); + context->insertRows = insertRows; + return code; + }; + auto output = [context](napi_env env, napi_value &result) { + napi_status status = napi_create_int64(env, context->insertRows, &result); + CHECK_RETURN_SET_E(status == napi_ok, std::make_shared(E_ERROR)); + }; + context->SetAction(env, info, input, exec, output); + + CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK); + return ASYNC_CALL(env, context); +} + struct QueryContext : public TransactionContext { int32_t Parse(napi_env env, size_t argc, napi_value *argv, napi_value self) { diff --git a/relational_store/frameworks/native/appdatafwk/src/shared_block.cpp b/relational_store/frameworks/native/appdatafwk/src/shared_block.cpp index 83a2e3b3c756412c774a0e583fbc95eb53880975..18cdfc1841f1b80c43bcae0eb0a3901f5c533446 100644 --- a/relational_store/frameworks/native/appdatafwk/src/shared_block.cpp +++ b/relational_store/frameworks/native/appdatafwk/src/shared_block.cpp @@ -84,7 +84,7 @@ int SharedBlock::Create(const std::string &name, size_t size, SharedBlock *&outS sptr ashmem = Ashmem::CreateAshmem(ashmemName.c_str(), size); if (ashmem == nullptr) { - LOG_ERROR("failed to create ashmem errno %{public}d", errno); + LOG_ERROR("Failed to create ashmem errno %{public}d", errno); return SHARED_BLOCK_ASHMEM_ERROR; } @@ -235,7 +235,7 @@ uint32_t *SharedBlock::AllocRowOffset() { uint32_t groupPos = mHeader->rowNums / ROW_NUM_IN_A_GROUP; if (UNLIKELY(groupPos >= GROUP_NUM)) { - LOG_ERROR("rows is full. row number %{public}u, groupPos %{public}u", mHeader->rowNums, groupPos); + LOG_ERROR("Rows is full. row number %{public}u, groupPos %{public}u", mHeader->rowNums, groupPos); return nullptr; } if (mHeader->groupOffset[groupPos] == 0) { diff --git a/relational_store/frameworks/native/cloud_data/src/cloud_manager.cpp b/relational_store/frameworks/native/cloud_data/src/cloud_manager.cpp index 832f4903097cdda68bb70590934f939eb0ef58e1..36ec5bc4c4dc6fb14bc0d221aa057da1ed8e8ad9 100644 --- a/relational_store/frameworks/native/cloud_data/src/cloud_manager.cpp +++ b/relational_store/frameworks/native/cloud_data/src/cloud_manager.cpp @@ -62,24 +62,24 @@ std::pair> CloudManager::GetCloudService( auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); if (saMgr == nullptr) { - LOG_ERROR("get system ability manager failed."); + LOG_ERROR("Get system ability manager failed."); return std::make_pair(CloudService::Status::SERVER_UNAVAILABLE, nullptr); } auto dataMgrObject = saMgr->CheckSystemAbility(DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID); if (dataMgrObject == nullptr) { - LOG_ERROR("get distributed data manager failed."); + LOG_ERROR("Get distributed data manager failed."); return std::make_pair(CloudService::Status::SERVER_UNAVAILABLE, nullptr); } sptr dataMgr = new (std::nothrow) DataMgrService(dataMgrObject); if (dataMgr == nullptr) { - LOG_ERROR("new CloudDataServiceProxy failed."); + LOG_ERROR("New CloudDataServiceProxy failed."); return std::make_pair(CloudService::Status::SERVER_UNAVAILABLE, nullptr); } auto cloudObject = dataMgr->GetFeatureInterface(CloudService::SERVICE_NAME); if (cloudObject == nullptr) { - LOG_ERROR("get cloud service failed."); + LOG_ERROR("Get cloud service failed."); return std::make_pair(CloudService::Status::FEATURE_UNAVAILABLE, nullptr); } @@ -109,12 +109,12 @@ sptr DataMgrService::GetFeatureInterface(const std::string &name) LOG_INFO("%s", name.c_str()); MessageParcel data; if (!data.WriteInterfaceToken(DataMgrService::GetDescriptor())) { - LOG_ERROR("write descriptor failed."); + LOG_ERROR("Write descriptor failed."); return nullptr; } if (!ITypesUtil::Marshal(data, name)) { - LOG_ERROR("write descriptor failed."); + LOG_ERROR("Write descriptor failed."); return nullptr; } @@ -129,7 +129,7 @@ sptr DataMgrService::GetFeatureInterface(const std::string &name) sptr remoteObject; if (!ITypesUtil::Unmarshal(reply, remoteObject)) { - LOG_ERROR("remote object is nullptr."); + LOG_ERROR("Remote object is nullptr."); return nullptr; } return remoteObject; diff --git a/relational_store/frameworks/native/cloud_data/src/cloud_service_proxy.cpp b/relational_store/frameworks/native/cloud_data/src/cloud_service_proxy.cpp index b68ad90ee72aec0eb6eed6bc162655e2a7c236cc..51d4c2e6e72c124e8cf5a377fd76d86650f1892a 100644 --- a/relational_store/frameworks/native/cloud_data/src/cloud_service_proxy.cpp +++ b/relational_store/frameworks/native/cloud_data/src/cloud_service_proxy.cpp @@ -57,7 +57,7 @@ int32_t CloudServiceProxy::EnableCloud(const std::string &id, const std::map(status); } @@ -67,7 +67,7 @@ int32_t CloudServiceProxy::DisableCloud(const std::string &id) MessageParcel reply; int32_t status = IPC_SEND(TRANS_DISABLE_CLOUD, reply, id); if (status != SUCCESS) { - LOG_ERROR("status:0x%{public}x id:%{public}.6s", status, id.c_str()); + LOG_ERROR("Status:0x%{public}x id:%{public}.6s", status, id.c_str()); } return static_cast(status); } @@ -77,7 +77,7 @@ int32_t CloudServiceProxy::ChangeAppSwitch(const std::string &id, const std::str MessageParcel reply; int32_t status = IPC_SEND(TRANS_CHANGE_APP_SWITCH, reply, id, bundleName, appSwitch); if (status != SUCCESS) { - LOG_ERROR("status:0x%{public}x id:%{public}.6s bundleName:%{public}s switch:%{public}d", status, id.c_str(), + LOG_ERROR("Status:0x%{public}x id:%{public}.6s bundleName:%{public}s switch:%{public}d", status, id.c_str(), bundleName.c_str(), appSwitch); } return static_cast(status); @@ -88,7 +88,7 @@ int32_t CloudServiceProxy::Clean(const std::string &id, const std::map(status); } @@ -98,7 +98,7 @@ int32_t CloudServiceProxy::NotifyDataChange(const std::string &id, const std::st MessageParcel reply; int32_t status = IPC_SEND(TRANS_NOTIFY_DATA_CHANGE, reply, id, bundleName); if (status != SUCCESS) { - LOG_ERROR("status:0x%{public}x id:%{public}.6s bundleName:%{public}s", status, id.c_str(), bundleName.c_str()); + LOG_ERROR("Status:0x%{public}x id:%{public}.6s bundleName:%{public}s", status, id.c_str(), bundleName.c_str()); } return static_cast(status); } @@ -108,7 +108,7 @@ int32_t CloudServiceProxy::SetGlobalCloudStrategy(Strategy strategy, const std:: MessageParcel reply; int32_t status = IPC_SEND(TRANS_SET_GLOBAL_CLOUD_STRATEGY, reply, strategy, values); if (status != SUCCESS) { - LOG_ERROR("status:0x%{public}x strategy:%{public}d values size:%{public}zu", status, + LOG_ERROR("Status:0x%{public}x strategy:%{public}d values size:%{public}zu", status, static_cast(strategy), values.size()); } return static_cast(status); @@ -121,7 +121,7 @@ std::pair> CloudServiceProxy::Allo MessageParcel reply; int32_t status = IPC_SEND(TRANS_ALLOC_RESOURCE_AND_SHARE, reply, storeId, predicates, columns, participants); if (status != SUCCESS) { - LOG_ERROR("status:0x%{public}x storeName:%{public}.6s", status, storeId.c_str()); + LOG_ERROR("Status:0x%{public}x storeName:%{public}.6s", status, storeId.c_str()); } std::vector valueBuckets; ITypesUtil::Unmarshal(reply, valueBuckets); @@ -133,7 +133,7 @@ int32_t CloudServiceProxy::NotifyDataChange(const std::string &eventId, const st MessageParcel reply; int32_t status = IPC_SEND(TRANS_NOTIFY_DATA_CHANGE_EXT, reply, eventId, extraData, userId); if (status != SUCCESS) { - LOG_ERROR("status:0x%{public}x eventId:%{public}.6s extraData:%{public}.6s", status, eventId.c_str(), + LOG_ERROR("Status:0x%{public}x eventId:%{public}.6s extraData:%{public}.6s", status, eventId.c_str(), extraData.c_str()); } return static_cast(status); @@ -146,7 +146,7 @@ std::pair> CloudServiceProxy::Que int32_t status = IPC_SEND(TRANS_QUERY_STATISTICS, reply, id, bundleName, storeId); if (status != SUCCESS) { LOG_ERROR( - "status:0x%{public}x bundleName:%{public}.6s storeId:%{public}.6s", status, id.c_str(), storeId.c_str()); + "Status:0x%{public}x bundleName:%{public}.6s storeId:%{public}.6s", status, id.c_str(), storeId.c_str()); } std::map infos; ITypesUtil::Unmarshal(reply, infos); @@ -158,7 +158,7 @@ int32_t CloudServiceProxy::Share(const std::string &sharingRes, const Participan MessageParcel reply; int32_t status = IPC_SEND(TRANS_SHARE, reply, sharingRes, participants); if (status != SUCCESS) { - LOG_ERROR("status:0x%{public}x sharingRes:%{public}.6s participants:%{public}zu", status, sharingRes.c_str(), + LOG_ERROR("Status:0x%{public}x sharingRes:%{public}.6s participants:%{public}zu", status, sharingRes.c_str(), participants.size()); } ITypesUtil::Unmarshal(reply, results); @@ -170,7 +170,7 @@ int32_t CloudServiceProxy::Unshare(const std::string &sharingRes, const Particip MessageParcel reply; int32_t status = IPC_SEND(TRANS_UNSHARE, reply, sharingRes, participants); if (status != SUCCESS) { - LOG_ERROR("status:0x%{public}x sharingRes:%{public}.6s participants:%{public}zu", status, sharingRes.c_str(), + LOG_ERROR("Status:0x%{public}x sharingRes:%{public}.6s participants:%{public}zu", status, sharingRes.c_str(), participants.size()); } ITypesUtil::Unmarshal(reply, results); @@ -182,7 +182,7 @@ int32_t CloudServiceProxy::Exit(const std::string &sharingRes, std::pair(status); @@ -194,7 +194,7 @@ int32_t CloudServiceProxy::ChangePrivilege( MessageParcel reply; int32_t status = IPC_SEND(TRANS_CHANGE_PRIVILEGE, reply, sharingRes, participants); if (status != SUCCESS) { - LOG_ERROR("status:0x%{public}x sharingRes:%{public}.6s participants:%{public}zu", status, sharingRes.c_str(), + LOG_ERROR("Status:0x%{public}x sharingRes:%{public}.6s participants:%{public}zu", status, sharingRes.c_str(), participants.size()); } ITypesUtil::Unmarshal(reply, results); @@ -206,7 +206,7 @@ int32_t CloudServiceProxy::Query(const std::string &sharingRes, QueryResults &re MessageParcel reply; int32_t status = IPC_SEND(TRANS_QUERY, reply, sharingRes); if (status != SUCCESS) { - LOG_ERROR("status:0x%{public}x sharingRes:%{public}.6s", status, sharingRes.c_str()); + LOG_ERROR("Status:0x%{public}x sharingRes:%{public}.6s", status, sharingRes.c_str()); } ITypesUtil::Unmarshal(reply, results); return static_cast(status); @@ -217,7 +217,7 @@ int32_t CloudServiceProxy::QueryByInvitation(const std::string &invitation, Quer MessageParcel reply; int32_t status = IPC_SEND(TRANS_QUERY_BY_INVITATION, reply, invitation); if (status != SUCCESS) { - LOG_ERROR("status:0x%{public}x invitation:%{public}.6s", status, invitation.c_str()); + LOG_ERROR("Status:0x%{public}x invitation:%{public}.6s", status, invitation.c_str()); } ITypesUtil::Unmarshal(reply, results); return static_cast(status); @@ -229,7 +229,7 @@ int32_t CloudServiceProxy::ConfirmInvitation( MessageParcel reply; int32_t status = IPC_SEND(TRANS_CONFIRM_INVITATION, reply, invitation, confirmation); if (status != SUCCESS) { - LOG_ERROR("status:0x%{public}x invitation:%{public}.6s", status, invitation.c_str()); + LOG_ERROR("Status:0x%{public}x invitation:%{public}.6s", status, invitation.c_str()); } ITypesUtil::Unmarshal(reply, result); return static_cast(status); @@ -241,7 +241,7 @@ int32_t CloudServiceProxy::ChangeConfirmation( MessageParcel reply; int32_t status = IPC_SEND(TRANS_CHANGE_CONFIRMATION, reply, sharingRes, confirmation); if (status != SUCCESS) { - LOG_ERROR("status:0x%{public}x sharingRes:%{public}.6s", status, sharingRes.c_str()); + LOG_ERROR("Status:0x%{public}x sharingRes:%{public}.6s", status, sharingRes.c_str()); } ITypesUtil::Unmarshal(reply, result); return static_cast(status); @@ -252,7 +252,7 @@ int32_t CloudServiceProxy::SetCloudStrategy(Strategy strategy, const std::vector MessageParcel reply; int32_t status = IPC_SEND(TRANS_SET_CLOUD_STRATEGY, reply, strategy, values); if (status != SUCCESS) { - LOG_ERROR("status:0x%{public}x strategy:%{public}d values size:%{public}zu", status, + LOG_ERROR("Status:0x%{public}x strategy:%{public}d values size:%{public}zu", status, static_cast(strategy), values.size()); } return static_cast(status); @@ -264,7 +264,7 @@ std::pair CloudServiceProxy::QueryLastSyncInfo( MessageParcel reply; int32_t status = IPC_SEND(TRANS_QUERY_LAST_SYNC_INFO, reply, id, bundleName, storeId); if (status != SUCCESS) { - LOG_ERROR("status:0x%{public}x id:%{public}.6s bundleName:%{public}s storeId:%{public}.3s", status, id.c_str(), + LOG_ERROR("Status:0x%{public}x id:%{public}.6s bundleName:%{public}s storeId:%{public}.3s", status, id.c_str(), bundleName.c_str(), storeId.c_str()); } QueryLastResults results; diff --git a/relational_store/frameworks/native/dataability/src/ishared_result_set_stub.cpp b/relational_store/frameworks/native/dataability/src/ishared_result_set_stub.cpp index 23a5c5d488a46819084b9d2fde4ba39d25001dfd..4cc03f8d312d432b20091d34067aec447234a66e 100644 --- a/relational_store/frameworks/native/dataability/src/ishared_result_set_stub.cpp +++ b/relational_store/frameworks/native/dataability/src/ishared_result_set_stub.cpp @@ -32,11 +32,11 @@ sptr ISharedResultSetStub::CreateStub( { sptr stub = new (std::nothrow) ISharedResultSetStub(result); if (stub == nullptr) { - LOG_ERROR("stub is nullptr."); + LOG_ERROR("Stub is nullptr."); return nullptr; } if (result == nullptr) { - LOG_ERROR("result is nullptr."); + LOG_ERROR("Result is nullptr."); return nullptr; } parcel.WriteRemoteObject(stub->AsObject()); diff --git a/relational_store/frameworks/native/dfx/include/rdb_fault_hiview_reporter.h b/relational_store/frameworks/native/dfx/include/rdb_fault_hiview_reporter.h index 47a12e8c54d515fd41dd586180026d4c7017cf89..fabf3609d6bc99a3e3c34cbd53e63ebd97e6b383 100644 --- a/relational_store/frameworks/native/dfx/include/rdb_fault_hiview_reporter.h +++ b/relational_store/frameworks/native/dfx/include/rdb_fault_hiview_reporter.h @@ -45,25 +45,95 @@ struct RdbCorruptedEvent { std::map debugInfos; }; -class RdbFaultHiViewReporter { +struct RdbFaultCounter { + uint8_t full{ 0 }; + uint8_t corrupt{ 0 }; + uint8_t perm{ 0 }; + uint8_t busy{ 0 }; + uint8_t noMem{ 0 }; + uint8_t ioErr{ 0 }; + uint8_t cantOpen{ 0 }; + uint8_t constraint{ 0 }; + uint8_t notDb{ 0 }; + uint8_t rootKeyFault{ 0 }; + uint8_t rootKeyNotLoad{ 0 }; + uint8_t workKeyFault{ 0 }; + uint8_t workkeyEencrypt{ 0 }; + uint8_t workKeyDcrypt{ 0 }; + uint8_t setEncrypt{ 0 }; + uint8_t setNewEncrypt{ 0 }; + uint8_t setServiceEncrypt{ 0 }; + uint8_t checkPoint{ 0 }; +}; + +// Fault Type Define +static constexpr const char *FT_OPEN = "OPEN_DB"; +static constexpr const char *FT_CURD = "CURD_DB"; +static constexpr const char *FT_EX_FILE = "EX_FILE"; +static constexpr const char *FT_EX_HUKS = "EX_HUKS"; +static constexpr const char *FT_CP = "CHECK_POINT"; + +class API_EXPORT RdbFaultEvent { +public: + RdbFaultEvent(const std::string &faultType, int32_t errorCode, const std::string &bundleName, + const std::string &custLog); + + std::string GetBundleName() const { return bundleName_; }; + std::string GetFaultType() const { return faultType_; } + int32_t GetErrCode() const { return errorCode_; } + std::string GetLogInfo() const { return custLog_; }; + virtual void Report() const; + +protected: + void SetBundleName(const std::string &name) { bundleName_ = name; }; + +private: + std::string bundleName_; + std::string faultType_; + std::string custLog_; + int32_t errorCode_; +}; + +class RdbFaultDbFileEvent : public RdbFaultEvent { +public: + RdbFaultDbFileEvent(const std::string &faultType, int32_t errorCode, const RdbStoreConfig &config, + const std::string &custLog = "", bool printDbInfo = false); + + virtual void Report() const override; + +private: + std::string BuildLogInfo() const; + std::string BuildConfigLog() const; + + const RdbStoreConfig &config_; + bool printDbInfo_; +}; + +class API_EXPORT RdbEmptyBlobEvent : public RdbFaultEvent { +public: + RdbEmptyBlobEvent(const std::string &bundleName); + virtual void Report() const override; +}; + +class API_EXPORT RdbFaultHiViewReporter { public: static RdbCorruptedEvent Create(const RdbStoreConfig &config, int32_t errCode, const std::string &appendix = ""); static bool RegCollector(Connection::Collector collector); - static void Report(const RdbCorruptedEvent &eventInfo); - static void ReportFault(const RdbCorruptedEvent &eventInfo); + static void ReportCorrupted(const RdbCorruptedEvent &eventInfo); + static void ReportCorruptedOnce(const RdbCorruptedEvent &eventInfo); + static void ReportFault(const RdbFaultEvent &faultEvent); static void ReportRestore(const RdbCorruptedEvent &eventInfo, bool repair = true); - static std::string Format(const std::map &debugs, const std::string &header); - static std::string FormatBrief(const std::map &debugs, const std::string &header); static bool IsReportCorruptedFault(const std::string &dbPath); + static std::string GetBundleName(const std::string &bundleName, const std::string &storeName); private: - static void Update(RdbCorruptedEvent &eventInfo, const std::map &infos); - static std::string GetFileStatInfo(const DebugInfo &debugInfo); + static void Update(std::map &localInfos, const std::map &infos); static void CreateCorruptedFlag(const std::string &dbPath); static void DeleteCorruptedFlag(const std::string &dbPath); - static std::string GetTimeWithMilliseconds(time_t sec, int64_t nsec); - static std::string GetBundleName(const RdbCorruptedEvent &eventInfo); + static bool IsReportFault(const std::string &bundleName, int32_t errCode); + static uint8_t *GetFaultCounter(RdbFaultCounter &counter, int32_t errCode); static Connection::Collector collector_; + static RdbFaultCounter faultCounter_; }; } // namespace OHOS::NativeRdb -#endif //DISTRIBUTEDDATAMGR_RDB_FAULT_HIVIEW_REPORTER_H +#endif // DISTRIBUTEDDATAMGR_RDB_FAULT_HIVIEW_REPORTER_H diff --git a/relational_store/frameworks/native/dfx/src/rdb_fault_hiview_reporter.cpp b/relational_store/frameworks/native/dfx/src/rdb_fault_hiview_reporter.cpp index ffa2caa9bdace40d8d1252fca0ffce7541cd4f52..7146b422bab5681dd6b17a3ec5b4fc99a6502b8e 100644 --- a/relational_store/frameworks/native/dfx/src/rdb_fault_hiview_reporter.cpp +++ b/relational_store/frameworks/native/dfx/src/rdb_fault_hiview_reporter.cpp @@ -20,11 +20,12 @@ #include #include -#include +#include #include #include #include #include +#include #include "accesstoken_kit.h" #include "connection.h" @@ -34,28 +35,28 @@ #include "rdb_errno.h" #include "sqlite_global_config.h" #include "sqlite_utils.h" +#include "rdb_time_utils.h" namespace OHOS::NativeRdb { using namespace OHOS::Rdb; using namespace Security::AccessToken; -static constexpr const char *EVENT_NAME = "DATABASE_CORRUPTED"; +static constexpr const char *CORRUPTED_EVENT = "DATABASE_CORRUPTED"; +static constexpr const char *FAULT_EVENT = "DISTRIBUTED_DATA_RDB_FAULT"; static constexpr const char *DISTRIBUTED_DATAMGR = "DISTDATAMGR"; static constexpr const char *DB_CORRUPTED_POSTFIX = ".corruptedflg"; -static constexpr int MAX_TIME_BUF_LEN = 32; -static constexpr int MILLISECONDS_LEN = 3; -static constexpr int NANO_TO_MILLI = 1000000; -static constexpr int MILLI_PRE_SEC = 1000; +static constexpr int MAX_FAULT_TIMES = 1; Connection::Collector RdbFaultHiViewReporter::collector_ = nullptr; +RdbFaultCounter RdbFaultHiViewReporter::faultCounter_ = { 0 }; -void RdbFaultHiViewReporter::ReportFault(const RdbCorruptedEvent &eventInfo) +void RdbFaultHiViewReporter::ReportCorruptedOnce(const RdbCorruptedEvent &eventInfo) { if (IsReportCorruptedFault(eventInfo.path)) { RdbCorruptedEvent eventInfoAppend = eventInfo; - eventInfoAppend.appendix += Format(eventInfoAppend.debugInfos, ""); - LOG_WARN("corrupted %{public}s errCode:0x%{public}x [%{public}s]", + eventInfoAppend.appendix += SqliteUtils::FormatDebugInfo(eventInfoAppend.debugInfos, ""); + LOG_WARN("Corrupted %{public}s errCode:0x%{public}x [%{public}s]", SqliteUtils::Anonymous(eventInfoAppend.storeName).c_str(), eventInfoAppend.errorCode, eventInfoAppend.appendix.c_str()); - Report(eventInfoAppend); + ReportCorrupted(eventInfoAppend); CreateCorruptedFlag(eventInfo.path); } } @@ -66,23 +67,22 @@ void RdbFaultHiViewReporter::ReportRestore(const RdbCorruptedEvent &eventInfo, b return; } RdbCorruptedEvent eventInfoAppend = eventInfo; - eventInfoAppend.appendix += Format(eventInfoAppend.debugInfos, ""); - LOG_INFO("restored %{public}s errCode:0x%{public}x [%{public}s]", + eventInfoAppend.appendix += SqliteUtils::FormatDebugInfo(eventInfoAppend.debugInfos, ""); + LOG_INFO("Restored %{public}s errCode:0x%{public}x [%{public}s]", SqliteUtils::Anonymous(eventInfo.storeName).c_str(), eventInfo.errorCode, eventInfoAppend.appendix.c_str()); - Report(eventInfoAppend); + ReportCorrupted(eventInfoAppend); DeleteCorruptedFlag(eventInfo.path); } -void RdbFaultHiViewReporter::Report(const RdbCorruptedEvent &eventInfo) +void RdbFaultHiViewReporter::ReportCorrupted(const RdbCorruptedEvent &eventInfo) { - std::string bundleName = GetBundleName(eventInfo); + std::string bundleName = GetBundleName(eventInfo.bundleName, eventInfo.storeName); std::string moduleName = eventInfo.moduleName; std::string storeType = eventInfo.storeType; std::string storeName = eventInfo.storeName; uint32_t checkType = eventInfo.integrityCheck; std::string appendInfo = eventInfo.appendix; - std::string occurTime = GetTimeWithMilliseconds(eventInfo.errorOccurTime, 0); - char *errorOccurTime = occurTime.data(); + std::string occurTime = RdbTimeUtils::GetCurSysTimeWithMs(); HiSysEventParam params[] = { { .name = "BUNDLE_NAME", .t = HISYSEVENT_STRING, .v = { .s = bundleName.data() }, .arraySize = 0 }, { .name = "MODULE_NAME", .t = HISYSEVENT_STRING, .v = { .s = moduleName.data() }, .arraySize = 0 }, @@ -95,24 +95,10 @@ void RdbFaultHiViewReporter::Report(const RdbCorruptedEvent &eventInfo) { .name = "ERROR_CODE", .t = HISYSEVENT_UINT32, .v = { .ui32 = eventInfo.errorCode }, .arraySize = 0 }, { .name = "ERRNO", .t = HISYSEVENT_INT32, .v = { .i32 = eventInfo.systemErrorNo }, .arraySize = 0 }, { .name = "APPENDIX", .t = HISYSEVENT_STRING, .v = { .s = appendInfo.data() }, .arraySize = 0 }, - { .name = "ERROR_TIME", .t = HISYSEVENT_STRING, .v = { .s = errorOccurTime }, .arraySize = 0 }, + { .name = "ERROR_TIME", .t = HISYSEVENT_STRING, .v = { .s = occurTime.data() }, .arraySize = 0 }, }; - OH_HiSysEvent_Write(DISTRIBUTED_DATAMGR, EVENT_NAME, HISYSEVENT_FAULT, params, sizeof(params) / sizeof(params[0])); -} - -std::string RdbFaultHiViewReporter::GetFileStatInfo(const DebugInfo &debugInfo) -{ - std::stringstream oss; - const uint32_t permission = 0777; - oss << " dev:0x" << std::hex << debugInfo.dev_ << " ino:0x" << std::hex << debugInfo.inode_; - if (debugInfo.inode_ != debugInfo.oldInode_ && debugInfo.oldInode_ != 0) { - oss << "<>0x" << std::hex << debugInfo.oldInode_; - } - oss << " mode:0" << std::oct << (debugInfo.mode_ & permission) << " size:" << std::dec << debugInfo.size_ - << " atim:" << GetTimeWithMilliseconds(debugInfo.atime_.sec_, debugInfo.atime_.nsec_) - << " mtim:" << GetTimeWithMilliseconds(debugInfo.mtime_.sec_, debugInfo.mtime_.nsec_) - << " ctim:" << GetTimeWithMilliseconds(debugInfo.ctime_.sec_, debugInfo.ctime_.nsec_); - return oss.str(); + auto size = sizeof(params) / sizeof(params[0]); + OH_HiSysEvent_Write(DISTRIBUTED_DATAMGR, CORRUPTED_EVENT, HISYSEVENT_FAULT, params, size); } bool RdbFaultHiViewReporter::IsReportCorruptedFault(const std::string &dbPath) @@ -136,7 +122,7 @@ void RdbFaultHiViewReporter::CreateCorruptedFlag(const std::string &dbPath) std::string flagFilename = dbPath + DB_CORRUPTED_POSTFIX; int fd = creat(flagFilename.c_str(), S_IRWXU | S_IRWXG); if (fd == -1) { - LOG_WARN("creat corrupted flg fail, flgname=%{public}s, errno=%{public}d", + LOG_WARN("Creat corrupted flg fail, flgname=%{public}s, errno=%{public}d", SqliteUtils::Anonymous(flagFilename).c_str(), errno); return; } @@ -151,22 +137,11 @@ void RdbFaultHiViewReporter::DeleteCorruptedFlag(const std::string &dbPath) std::string flagFilename = dbPath + DB_CORRUPTED_POSTFIX; int result = remove(flagFilename.c_str()); if (result != 0) { - LOG_WARN("remove corrupted flg fail, flgname=%{public}s, errno=%{public}d", + LOG_WARN("Remove corrupted flg fail, flgname=%{public}s, errno=%{public}d", SqliteUtils::Anonymous(flagFilename).c_str(), errno); } } -std::string RdbFaultHiViewReporter::GetTimeWithMilliseconds(time_t sec, int64_t nsec) -{ - std::stringstream oss; - char buffer[MAX_TIME_BUF_LEN] = { 0 }; - std::tm local_time; - localtime_r(&sec, &local_time); - std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &local_time); - oss << buffer << '.' << std::setfill('0') << std::setw(MILLISECONDS_LEN) << (nsec / NANO_TO_MILLI) % MILLI_PRE_SEC; - return oss.str(); -} - RdbCorruptedEvent RdbFaultHiViewReporter::Create( const RdbStoreConfig &config, int32_t errCode, const std::string &appendix) { @@ -174,7 +149,7 @@ RdbCorruptedEvent RdbFaultHiViewReporter::Create( eventInfo.bundleName = config.GetBundleName(); eventInfo.moduleName = config.GetModuleName(); eventInfo.storeType = config.GetDBType() == DB_SQLITE ? "RDB" : "VECTOR DB"; - eventInfo.storeName = config.GetName(); + eventInfo.storeName = SqliteUtils::Anonymous(config.GetName()); eventInfo.securityLevel = static_cast(config.GetSecurityLevel()); eventInfo.pathArea = static_cast(config.GetArea()); eventInfo.encryptStatus = static_cast(config.IsEncrypt()); @@ -185,8 +160,8 @@ RdbCorruptedEvent RdbFaultHiViewReporter::Create( eventInfo.errorOccurTime = time(nullptr); eventInfo.debugInfos = Connection::Collect(config); SqliteGlobalConfig::GetDbPath(config, eventInfo.path); - if (collector_ != nullptr) { - Update(eventInfo, collector_(config)); + if (collector_ != nullptr && !IsReportCorruptedFault(eventInfo.path)) { + Update(eventInfo.debugInfos, collector_(config)); } return eventInfo; } @@ -200,9 +175,10 @@ bool RdbFaultHiViewReporter::RegCollector(Connection::Collector collector) return true; } -void RdbFaultHiViewReporter::Update(RdbCorruptedEvent &eventInfo, const std::map &infos) +void RdbFaultHiViewReporter::Update(std::map &localInfos, + const std::map &infos) { - auto &local = eventInfo.debugInfos; + auto &local = localInfos; auto lIt = local.begin(); auto rIt = infos.begin(); for (; lIt != local.end() && rIt != infos.end();) { @@ -222,10 +198,10 @@ void RdbFaultHiViewReporter::Update(RdbCorruptedEvent &eventInfo, const std::map } } -std::string RdbFaultHiViewReporter::GetBundleName(const RdbCorruptedEvent &eventInfo) +std::string RdbFaultHiViewReporter::GetBundleName(const std::string &bundleName, const std::string &storeName) { - if (!eventInfo.bundleName.empty()) { - return eventInfo.bundleName; + if (!bundleName.empty()) { + return bundleName; } auto tokenId = IPCSkeleton::GetCallingTokenID(); auto tokenType = AccessTokenKit::GetTokenTypeFlag(tokenId); @@ -235,32 +211,193 @@ std::string RdbFaultHiViewReporter::GetBundleName(const RdbCorruptedEvent &event return tokenInfo.processName; } } - return SqliteUtils::Anonymous(eventInfo.storeName); + return SqliteUtils::Anonymous(storeName); +} + +uint8_t *RdbFaultHiViewReporter::GetFaultCounter(RdbFaultCounter &counter, int32_t errCode) +{ + switch (errCode) { + case E_SQLITE_FULL: + return &counter.full; + case E_SQLITE_CORRUPT: + return &counter.corrupt; + case E_SQLITE_PERM: + return &counter.perm; + case E_SQLITE_BUSY: + return &counter.busy; + case E_SQLITE_NOMEM: + return &counter.noMem; + case E_SQLITE_IOERR: + return &counter.ioErr; + case E_SQLITE_CANTOPEN: + return &counter.cantOpen; + case E_SQLITE_CONSTRAINT: + return &counter.constraint; + case E_SQLITE_NOT_DB: + return &counter.notDb; + case E_ROOT_KEY_FAULT: + return &counter.rootKeyFault; + case E_ROOT_KEY_NOT_LOAD: + return &counter.rootKeyNotLoad; + case E_WORK_KEY_FAIL: + return &counter.workKeyFault; + case E_WORK_KEY_ENCRYPT_FAIL: + return &counter.workkeyEencrypt; + case E_WORK_KEY_DECRYPT_FAIL: + return &counter.workKeyDcrypt; + case E_SET_ENCRYPT_FAIL: + return &counter.setEncrypt; + case E_SET_NEW_ENCRYPT_FAIL: + return &counter.setNewEncrypt; + case E_SET_SERVICE_ENCRYPT_FAIL: + return &counter.setServiceEncrypt; + case E_CHECK_POINT_FAIL: + return &counter.checkPoint; + default: + return nullptr; + }; } -std::string RdbFaultHiViewReporter::Format(const std::map &debugs, const std::string &header) +bool RdbFaultHiViewReporter::IsReportFault(const std::string &bundleName, int32_t errCode) { - if (debugs.empty()) { - return ""; + if (bundleName.empty()) { + return false; + } + uint8_t *counter = GetFaultCounter(faultCounter_, errCode); + if (counter == nullptr) { + return false; } - std::string appendix = header; - for (auto &[name, debugInfo] : debugs) { - appendix += "\n" + name + " :" + GetFileStatInfo(debugInfo); + if (*counter < UCHAR_MAX) { + (*counter)++; } - return appendix; + return *counter <= MAX_FAULT_TIMES; } -std::string RdbFaultHiViewReporter::FormatBrief( - const std::map &debugs, const std::string &header) +void RdbFaultHiViewReporter::ReportFault(const RdbFaultEvent &faultEvent) { - if (debugs.empty()) { - return ""; + if (!IsReportFault(faultEvent.GetBundleName(), faultEvent.GetErrCode())) { + return; } + faultEvent.Report(); +} + +RdbFaultEvent::RdbFaultEvent(const std::string &faultType, int32_t errorCode, const std::string &bundleName, + const std::string &custLog) +{ + faultType_ = faultType; + errorCode_ = errorCode; + bundleName_ = bundleName; + custLog_ = custLog; +} + +void RdbFaultEvent::Report() const +{ + std::string occurTime = RdbTimeUtils::GetCurSysTimeWithMs(); + std::string bundleName = GetBundleName(); + std::string faultType = GetFaultType(); + std::string appendInfo = GetLogInfo(); + HiSysEventParam params[] = { + { .name = "FAULT_TIME", .t = HISYSEVENT_STRING, .v = { .s = occurTime.data() }, .arraySize = 0 }, + { .name = "FAULT_TYPE", .t = HISYSEVENT_STRING, .v = { .s = faultType.data() }, .arraySize = 0 }, + { .name = "BUNDLE_NAME", .t = HISYSEVENT_STRING, .v = { .s = bundleName.data() }, .arraySize = 0 }, + { .name = "ERROR_CODE", .t = HISYSEVENT_INT32, .v = { .ui32 = static_cast(errorCode_) }, .arraySize = 0 }, + { .name = "APPENDIX", .t = HISYSEVENT_STRING, .v = { .s = appendInfo.data() }, .arraySize = 0 }, + }; + auto size = sizeof(params) / sizeof(params[0]); + OH_HiSysEvent_Write(DISTRIBUTED_DATAMGR, FAULT_EVENT, HISYSEVENT_FAULT, params, size); +} + +RdbFaultDbFileEvent::RdbFaultDbFileEvent(const std::string &faultType, int32_t errorCode, const RdbStoreConfig &config, + const std::string &custLog, bool printDbInfo) + : RdbFaultEvent(faultType, errorCode, "", custLog), config_(config), printDbInfo_(printDbInfo) +{ + SetBundleName(RdbFaultHiViewReporter::GetBundleName(config_.GetBundleName(), config_.GetName())); +} + +RdbEmptyBlobEvent::RdbEmptyBlobEvent(const std::string &bundleName) + : RdbFaultEvent(FT_CURD, E_SQLITE_FULL, "", "The input blob is empty") +{ + SetBundleName(bundleName); +} + +void RdbEmptyBlobEvent::Report() const +{ + std::string occurTime = RdbTimeUtils::GetCurSysTimeWithMs(); + std::string bundleName = GetBundleName(); + std::string faultType = GetFaultType(); + std::string appendInfo = GetLogInfo(); + HiSysEventParam params[] = { + { .name = "FAULT_TIME", .t = HISYSEVENT_STRING, .v = { .s = occurTime.data() }, .arraySize = 0 }, + { .name = "FAULT_TYPE", .t = HISYSEVENT_STRING, .v = { .s = faultType.data() }, .arraySize = 0 }, + { .name = "BUNDLE_NAME", .t = HISYSEVENT_STRING, .v = { .s = bundleName.data() }, .arraySize = 0 }, + { .name = "ERROR_CODE", .t = HISYSEVENT_INT32, .v = { .ui32 = E_SQLITE_FULL }, .arraySize = 0 }, + { .name = "APPENDIX", .t = HISYSEVENT_STRING, .v = { .s = appendInfo.data() }, .arraySize = 0 }, + }; + auto size = sizeof(params) / sizeof(params[0]); + OH_HiSysEvent_Write(DISTRIBUTED_DATAMGR, FAULT_EVENT, HISYSEVENT_FAULT, params, size); +} + +void RdbFaultDbFileEvent::Report() const +{ + std::string occurTime = RdbTimeUtils::GetCurSysTimeWithMs(); + std::string bundleName = GetBundleName(); + std::string faultType = GetFaultType(); + std::string moduleName = config_.GetModuleName(); + std::string storeName = config_.GetName(); + std::string businessType = config_.GetDBType() == DB_SQLITE ? "SQLITE" : "VECTOR"; + std::string appendInfo = BuildLogInfo(); + + HiSysEventParam params[] = { + { .name = "FAULT_TIME", .t = HISYSEVENT_STRING, .v = { .s = occurTime.data() }, .arraySize = 0 }, + { .name = "FAULT_TYPE", .t = HISYSEVENT_STRING, .v = { .s = faultType.data() }, .arraySize = 0 }, + { .name = "BUNDLE_NAME", .t = HISYSEVENT_STRING, .v = { .s = bundleName.data() }, .arraySize = 0 }, + { .name = "MODULE_NAME", .t = HISYSEVENT_STRING, .v = { .s = moduleName.data() }, .arraySize = 0 }, + { .name = "STORE_NAME", .t = HISYSEVENT_STRING, .v = { .s = storeName.data() }, .arraySize = 0 }, + { .name = "BUSINESS_TYPE", .t = HISYSEVENT_STRING, .v = { .s = businessType.data() }, .arraySize = 0 }, + { .name = "ERROR_CODE", .t = HISYSEVENT_INT32, .v = { .ui32 = static_cast(GetErrCode())}, .arraySize = 0 }, + { .name = "APPENDIX", .t = HISYSEVENT_STRING, .v = { .s = appendInfo.data() }, .arraySize = 0 }, + }; + auto size = sizeof(params) / sizeof(params[0]); + OH_HiSysEvent_Write(DISTRIBUTED_DATAMGR, FAULT_EVENT, HISYSEVENT_FAULT, params, size); +} + +std::string RdbFaultDbFileEvent::BuildConfigLog() const +{ + std::string errNoStr = std::to_string(static_cast(errno)); + std::string dbPath; + SqliteGlobalConfig::GetDbPath(config_, dbPath); + dbPath = SqliteUtils::Anonymous(dbPath); + std::vector> logInfo; + logInfo.emplace_back("S_L", std::to_string(static_cast(config_.GetSecurityLevel()))); + logInfo.emplace_back("P_A", std::to_string(static_cast(config_.GetArea()))); + logInfo.emplace_back("E_S", std::to_string(static_cast(config_.IsEncrypt()))); + logInfo.emplace_back("I_C", std::to_string(static_cast(config_.GetIntegrityCheck()))); + logInfo.emplace_back("ENO", errNoStr); + logInfo.emplace_back("PATH", dbPath); std::stringstream oss; - oss << header << ":"; - for (auto &[name, debugInfo] : debugs) { - oss << "<" << name << ",0x" << std::hex << debugInfo.inode_ << "," << std::dec << debugInfo.size_ << ">"; + for (size_t i = 0; i < logInfo.size(); i++) { + oss << logInfo[i].first << ":" << logInfo[i].second; + if (i != logInfo.size() - 1) { + oss << "," << std::endl; + } } return oss.str(); } + +std::string RdbFaultDbFileEvent::BuildLogInfo() const +{ + std::string appendInfo = GetLogInfo(); + std::string dbFileInfo = SqliteUtils::FormatDebugInfo( + RdbFaultHiViewReporter::Create(config_, GetErrCode()).debugInfos, ""); + + if (GetErrCode() == E_SQLITE_NOT_DB) { + std::string dbPath; + SqliteGlobalConfig::GetDbPath(config_, dbPath); + appendInfo += SqliteUtils::ReadFileHeader(dbPath); + } + if (printDbInfo_) { + appendInfo += ("\n" + BuildConfigLog() + "\n" + dbFileInfo); + } + return appendInfo; +} } // namespace OHOS::NativeRdb \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/adapter/include/grd_adapter.h b/relational_store/frameworks/native/gdb/adapter/include/grd_adapter.h new file mode 100644 index 0000000000000000000000000000000000000000..e6f8950bf82922ac40f705b95780437a54a7737b --- /dev/null +++ b/relational_store/frameworks/native/gdb/adapter/include/grd_adapter.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024 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_OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRD_ADAPTER_H +#define OHOS_DISTRIBUTED_DATA_OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRD_ADAPTER_H + +#include +#include +#include +#include + +#include "full_result.h" +#include "statement.h" +#include "grd_type_export.h" + +namespace OHOS::DistributedDataAip { + +class GrdAdapter { +public: + static int TransErrno(int err); + static ColumnType TransColType(int grdColType); + static int Open(const char *dbPath, const char *configStr, uint32_t flags, GRD_DB **db); + static int Repair(const char *dbPath, const char *configStr); + static int Close(GRD_DB *db, uint32_t flags); + + /* graph */ + static int32_t Prepare(GRD_DB *db, const char *str, uint32_t strLen, GRD_StmtT **stmt, const char **unusedStr); + static int32_t Reset(GRD_StmtT *stmt); + static int32_t Finalize(GRD_StmtT *stmt); + + static int32_t Step(GRD_StmtT *stmt); + static uint32_t ColumnCount(GRD_StmtT *stmt); + static GRD_DbDataTypeE ColumnType(GRD_StmtT *stmt, uint32_t idx); + static uint32_t ColumnBytes(GRD_StmtT *stmt, uint32_t idx); + static char *ColumnName(GRD_StmtT *stmt, uint32_t idx); + static GRD_DbValueT ColumnValue(GRD_StmtT *stmt, uint32_t idx); + static int64_t ColumnInt64(GRD_StmtT *stmt, uint32_t idx); + static int32_t ColumnInt(GRD_StmtT *stmt, uint32_t idx); + static double ColumnDouble(GRD_StmtT *stmt, uint32_t idx); + static const char *ColumnText(GRD_StmtT *stmt, uint32_t idx); + + static int Backup(GRD_DB *db, const char *backupDbFile, const std::vector &encryptedKey); + static int Restore(const char *dbFile, const char *backupDbFile, const std::vector &encryptedKey); + static int Rekey(const char *dbFile, const char *configStr, const std::vector &encryptedKey); + +private: + static std::map GRD_ERRNO_MAP; +}; + +} // namespace OHOS::DistributedDataAip +#endif \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/adapter/include/grd_adapter_manager.h b/relational_store/frameworks/native/gdb/adapter/include/grd_adapter_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..2f6eac3f37a0ab43502afa783c7c02dee8c96a4c --- /dev/null +++ b/relational_store/frameworks/native/gdb/adapter/include/grd_adapter_manager.h @@ -0,0 +1,77 @@ +/* +* Copyright (c) 2024 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_OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRD_ADAPTER_MANAGER_H +#define OHOS_DISTRIBUTED_DATA_OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRD_ADAPTER_MANAGER_H + +#include "grd_type_export.h" + +namespace OHOS::DistributedDataAip { + +typedef int32_t (*Open)(const char *dbPath, const char *configStr, uint32_t flags, GRD_DB **db); +typedef int32_t (*Close)(GRD_DB *db, uint32_t flags); +typedef int32_t (*Repair)(const char *dbPath, const char *configStr); + +typedef int32_t (*Prepare)(GRD_DB *db, const char *str, uint32_t strLen, GRD_StmtT **stmt, const char **unusedStr); +typedef int32_t (*Reset)(GRD_StmtT *stmt); +typedef int32_t (*Finalize)(GRD_StmtT *stmt); + +typedef int32_t (*Step)(GRD_StmtT *stmt); +typedef uint32_t (*ColumnCount)(GRD_StmtT *stmt); +typedef GRD_DbDataTypeE (*GetColumnType)(GRD_StmtT *stmt, uint32_t idx); +typedef uint32_t (*ColumnBytes)(GRD_StmtT *stmt, uint32_t idx); +typedef char *(*ColumnName)(GRD_StmtT *stmt, uint32_t idx); +typedef GRD_DbValueT (*ColumnValue)(GRD_StmtT *stmt, uint32_t idx); +typedef int64_t (*ColumnInt64)(GRD_StmtT *stmt, uint32_t idx); +typedef int32_t (*ColumnInt)(GRD_StmtT *stmt, uint32_t idx); +typedef double (*ColumnDouble)(GRD_StmtT *stmt, uint32_t idx); +typedef const char *(*ColumnText)(GRD_StmtT *stmt, uint32_t idx); + +typedef int32_t (*Backup)(GRD_DB *db, const char *backupDbFile, GRD_CipherInfoT *cipherInfo); +typedef int32_t (*Restore)(const char *dbFile, const char *backupDbFile, GRD_CipherInfoT *cipherInfo); +typedef int32_t (*Rekey)(const char *dbFile, const char *configStr, GRD_CipherInfoT *cipherInfo); + +struct GrdAdapterHolder { + Open Open = nullptr; + Close Close = nullptr; + Repair Repair = nullptr; + + Prepare Prepare = nullptr; + Reset Reset = nullptr; + Finalize Finalize = nullptr; + Step Step = nullptr; + ColumnCount ColumnCount = nullptr; + GetColumnType GetColumnType = nullptr; + ColumnBytes ColumnBytes = nullptr; + ColumnName ColumnName = nullptr; + ColumnValue ColumnValue = nullptr; + ColumnInt64 ColumnInt64 = nullptr; + ColumnInt ColumnInt = nullptr; + ColumnDouble ColumnDouble = nullptr; + ColumnText ColumnText = nullptr; + + Backup Backup = nullptr; + Restore Restore = nullptr; + Rekey Rekey = nullptr; +}; + +bool IsSupportArkDataDb(); +GrdAdapterHolder GetAdapterHolder(); + +static void *g_library = nullptr; + +} // namespace OHOS::DistributedDataAip + +#endif // OHOS_DISTRIBUTED_DATA_OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRD_ADAPTER_MANAGER_H diff --git a/relational_store/frameworks/native/gdb/adapter/include/grd_error.h b/relational_store/frameworks/native/gdb/adapter/include/grd_error.h new file mode 100644 index 0000000000000000000000000000000000000000..cb2d8e1641612c71ae18bc030bc5e2720cd8e9ff --- /dev/null +++ b/relational_store/frameworks/native/gdb/adapter/include/grd_error.h @@ -0,0 +1,164 @@ +/* +* Copyright (c) 2024 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_OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRD_ERROR_H +#define OHOS_DISTRIBUTED_DATA_OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRD_ERROR_H + +#include "grd_type_export.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Error category +#define GRD_OK 0 + +// Error category +#define GRD_NOT_SUPPORT (-1000) +#define GRD_OVER_LIMIT (-2000) +#define GRD_INVALID_ARGS (-3000) +#define GRD_SYSTEM_ERR (-4000) +#define GRD_FAILED_FILE_OPERATION (-5000) +#define GRD_INVALID_FILE_FORMAT (-6000) +#define GRD_INSUFFICIENT_SPACE (-7000) +#define GRD_INNER_ERR (-8000) +#define GRD_RESOURCE_BUSY (-9000) + +#define GRD_NO_DATA (-11000) +#define GRD_FAILED_MEMORY_ALLOCATE (-13000) +#define GRD_FAILED_MEMORY_RELEASE (-14000) +#define GRD_DATA_CONFLICT (-16000) +#define GRD_DATATYPE_MISMATCH (-17000) +#define GRD_NOT_AVAILABLE (-19000) +#define GRD_ACTIVE_TRANSACTION (-20000) +#define GRD_UNIQUE_VIOLATION (-21000) +#define GRD_DUPLICATE_TABLE (-22000) +#define GRD_UNDEFINED_TABLE (-23000) +#define GRD_INVALID_BIND_VALUE (-36000) +#define GRD_INVALID_FORMAT (-37000) +#define GRD_REBUILD_DATABASE (-38000) +#define GRD_TIME_OUT (-39000) +#define GRD_DB_INSTANCE_ABNORMAL (-40000) +#define GRD_DISK_SPACE_FULL (-41000) +#define GRD_CRC_CHECK_DISABLED (-42000) +#define GRD_PERMISSION_DENIED (-43000) +#define GRD_SYNC_PREREQUISITES_ABNORMAL (-44000) +#define GRD_DATA_CORRUPTED (-45000) +#define GRD_DB_BUSY (-46000) +#define GRD_CALC_MODE_SET_PERMISSION_DENIED (-47000) + +#define GRD_CIPHER_ERROR (-48000) +#define GRD_PASSWORD_NEED_REKEY (-48001) +#define GRD_PASSWORD_UNMATCHED (-48002) + +#define GRD_SCHEMA_CHANGED (-49000) +// not support +#define GRD_JSON_OPERATION_NOT_SUPPORT (-5001001) +#define GRD_MODEL_NOT_SUPPORT (-5001002) +#define GRD_FEATURE_NOT_SUPPORTED (-5001003) + +// Exceed limit +#define GRD_JSON_LEN_LIMIT (-5002001) +#define GRD_SUBSCRIPTION_EXCEEDED_LIMIT (-5002002) +#define GRD_SYNC_EXCEED_TASK_QUEUE_LIMIT (-5002003) +#define GRD_SHARED_OBJ_ENABLE_UNDO_EXCEED_LIMIT (-5002004) +#define GRD_TABLE_LIMIT_EXCEEDED (-5002005) + +// Invalid parameter +#define GRD_FIELD_TYPE_NOT_MATCH (-5003001) +#define GRD_LARGE_JSON_NEST (-5003002) +#define GRD_INVALID_JSON_TYPE (-5003003) +#define GRD_INVALID_CONFIG_VALUE (-5003004) +#define GRD_INVALID_OPERATOR (-5003005) +#define GRD_INVALID_PROJECTION_FIELD (-5003006) +#define GRD_INVALID_PROJECTION_VALUE (-5003007) +#define GRD_COLLECTION_NOT_EXIST (-5003008) +#define GRD_DB_NOT_EXIST (-5003009) +#define GRD_INVALID_VALUE (-5003010) +#define GRD_SHARED_OBJ_NOT_EXIST (-5003020) +#define GRD_SUBSCRIBE_NOT_EXIST (-5003021) +#define GRD_SHARED_OBJ_UNDO_MANAGER_NOT_EXIST (-5003022) +#define GRD_SHARED_OBJ_INVALID_UNDO (-5003023) +#define GRD_SHARED_OBJ_INVALID_REDO (-5003024) +#define GRD_NAME_TOO_LONG (-5003025) +#define GRD_INVALID_TABLE_DEFINITION (-5003026) +#define GRD_WRONG_STMT_OBJECT (-5003027) +#define GRD_SEMANTIC_ERROR (-5003028) +#define GRD_SYNTAX_ERROR (-5003029) + +// System err +#define GRD_JSON_LIB_HANDLE_FAILED (-5004001) +#define GRD_DIRECTORY_OPERATE_FAILED (-5004002) +#define GRD_FILE_OPERATE_FAILED (-5004003) +#define GRD_LOAD_THIRD_PARTY_LIBRARY_FAILED (-5004004) +#define GRD_THIRD_PARTY_FUNCTION_EXECUTE_FAILED (-5004005) +#define GRD_INSUFFICIENT_RESOURCES (-5004006) + +// resource busy +#define GRD_RESULTSET_BUSY (-5009001) + +// no data +#define GRD_RECORD_NOT_FOUND (-5011001) +#define GRD_FIELD_NOT_FOUND (-5011002) +#define GRD_ARRAY_INDEX_NOT_FOUND (-5011003) + +// data conflicted +#define GRD_KEY_CONFLICT (-5016001) +#define GRD_FIELD_TYPE_CONFLICT (-5016002) +#define GRD_SHARED_OBJ_CONFLICT (-5016003) +#define GRD_SUBSCRIBE_CONFLICT (-5016004) +#define GRD_EQUIP_ID_CONFLICT (-5016005) +#define GRD_SHARED_OBJ_ENABLE_UNDO_CONFLICT (-5016006) + +// data exception +#define GRD_DATA_EXCEPTION (-5017001) +#define GRD_FIELD_OVERFLOW (-5017002) +#define GRD_DIVISION_BY_ZERO (-5017003) + +// Cursor or ResultSet not available +#define GRD_RESULT_SET_NOT_AVAILABLE (-5019001) +#define GRD_SHARED_OBJ_UNDO_NOT_AVAILABLE (-5019002) +#define GRD_SHARED_OBJ_REDO_NOT_AVAILABLE (-5019003) + +// Transaction +#define GRD_TRANSACTION_ROLLBACK (-5020001) +#define GRD_NO_ACTIVE_TRANSACTION (-5020002) + +// violation +#define GRD_PRIMARY_KEY_VIOLATION (-5021001) +#define GRD_RESTRICT_VIOLATION (-5021002) +#define GRD_CONSTRAINT_CHECK_VIOLATION (-5021003) + +// duplicate +#define GRD_DUPLICATE_COLUMN (-5022001) +#define GRD_DUPLICATE_OBJECT (-5022002) + +// undefined +#define GRD_UNDEFINE_COLUMN (-5023001) +#define GRD_UNDEFINED_OBJECT (-5023002) + +// Invalid format +#define GRD_INVALID_JSON_FORMAT (-5037001) +#define GRD_INVALID_KEY_FORMAT (-5037002) +#define GRD_INVALID_COLLECTION_NAME (-5037003) +#define GRD_INVALID_EQUIP_ID (-5037004) + +// time out +#define GRD_REQUEST_TIME_OUT (-5039001) + +#ifdef __cplusplus +} +#endif // __cplusplus +#endif // OHOS_DISTRIBUTED_DATA_OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRD_ERROR_H \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/adapter/src/grd_adapter.cpp b/relational_store/frameworks/native/gdb/adapter/src/grd_adapter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d63f891a3720871f9e9d03f66b2f3e631f91855 --- /dev/null +++ b/relational_store/frameworks/native/gdb/adapter/src/grd_adapter.cpp @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2024 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 "GrdAdapter" + +#include "grd_adapter.h" + +#include +#include + +#include "aip_errors.h" +#include "gdb_utils.h" +#include "grd_adapter_manager.h" +#include "grd_error.h" +#include "logger.h" + +namespace OHOS::DistributedDataAip { + +static GrdAdapterHolder g_adapterHolder; + +std::map GrdAdapter::GRD_ERRNO_MAP = { + { GRD_OK, E_OK }, + { GRD_REBUILD_DATABASE, E_OK }, + { GRD_NO_DATA, E_GRD_NO_DATA }, + { GRD_DATA_CORRUPTED, E_GRD_DATA_CORRUPTED }, + { GRD_INVALID_FILE_FORMAT, E_GRD_INVALID_FILE_FORMAT }, + { GRD_PRIMARY_KEY_VIOLATION, E_GRD_DATA_CONFLICT }, + { GRD_RESTRICT_VIOLATION, E_GRD_DATA_CONFLICT }, + { GRD_CONSTRAINT_CHECK_VIOLATION, E_GRD_DATA_CONFLICT }, + { GRD_NOT_SUPPORT, E_GRD_NOT_SUPPORT }, + { GRD_OVER_LIMIT, E_GRD_OVER_LIMIT }, + { GRD_INVALID_ARGS, E_GRD_INVALID_ARGS }, + { GRD_FAILED_FILE_OPERATION, E_GRD_FAILED_FILE_OPERATION }, + { GRD_INSUFFICIENT_SPACE, E_GRD_DISK_SPACE_FULL }, + { GRD_RESOURCE_BUSY, E_DATABASE_BUSY }, + { GRD_DB_BUSY, E_DATABASE_BUSY }, + { GRD_FAILED_MEMORY_ALLOCATE, E_GRD_FAILED_MEMORY_ALLOCATE }, + { GRD_CRC_CHECK_DISABLED, E_GRD_CRC_CHECK_DISABLED }, + { GRD_DISK_SPACE_FULL, E_GRD_DISK_SPACE_FULL }, + + { GRD_PERMISSION_DENIED, E_GRD_PERMISSION_DENIED }, + { GRD_PASSWORD_UNMATCHED, E_GRD_PASSWORD_UNMATCHED }, + { GRD_PASSWORD_NEED_REKEY, E_GRD_PASSWORD_NEED_REKEY }, + + { GRD_NAME_TOO_LONG, E_GRD_INVALID_NAME }, + { GRD_INVALID_TABLE_DEFINITION, E_GRD_SEMANTIC_ERROR }, + { GRD_SEMANTIC_ERROR, E_GRD_SEMANTIC_ERROR }, + { GRD_SYNTAX_ERROR, E_GRD_SYNTAX_ERROR }, + { GRD_WRONG_STMT_OBJECT, E_GRD_WRONG_STMT_OBJECT }, + { GRD_DATA_CONFLICT, E_GRD_DATA_CONFLICT }, + + { GRD_INNER_ERR, E_GRD_INNER_ERR }, + { GRD_FAILED_MEMORY_RELEASE, E_GRD_FAILED_MEMORY_RELEASE }, + { GRD_NOT_AVAILABLE, E_GRD_NOT_AVAILABLE }, + { GRD_INVALID_FORMAT, E_GRD_SEMANTIC_ERROR }, + { GRD_TIME_OUT, E_DATABASE_BUSY }, + { GRD_DB_INSTANCE_ABNORMAL, E_GRD_DB_INSTANCE_ABNORMAL }, + { GRD_CIPHER_ERROR, E_GRD_CIPHER_ERROR }, + { GRD_DUPLICATE_TABLE, E_GRD_DUPLICATE_PARAM }, + { GRD_DUPLICATE_OBJECT, E_GRD_DUPLICATE_PARAM }, + { GRD_DUPLICATE_COLUMN, E_GRD_DUPLICATE_PARAM }, + { GRD_UNDEFINE_COLUMN, E_GRD_UNDEFINED_PARAM }, + { GRD_UNDEFINED_OBJECT, E_GRD_UNDEFINED_PARAM }, + { GRD_UNDEFINED_TABLE, E_GRD_UNDEFINED_PARAM }, + { GRD_INVALID_CONFIG_VALUE, E_CONFIG_INVALID_CHANGE }, + { GRD_REQUEST_TIME_OUT, E_DATABASE_BUSY }, + { GRD_DATATYPE_MISMATCH, E_GRD_SEMANTIC_ERROR }, + { GRD_UNIQUE_VIOLATION, E_GRD_DATA_CONFLICT }, + { GRD_INVALID_BIND_VALUE, E_GRD_INVALID_BIND_VALUE }, + { GRD_JSON_OPERATION_NOT_SUPPORT, E_GRD_SEMANTIC_ERROR }, + { GRD_MODEL_NOT_SUPPORT, E_GRD_SEMANTIC_ERROR }, + { GRD_FEATURE_NOT_SUPPORTED, E_GRD_SEMANTIC_ERROR }, + { GRD_JSON_LEN_LIMIT, E_GRD_DATA_CONFLICT }, + { GRD_SUBSCRIPTION_EXCEEDED_LIMIT, E_GRD_INNER_ERR }, + { GRD_SYNC_EXCEED_TASK_QUEUE_LIMIT, E_DATABASE_BUSY }, + { GRD_SHARED_OBJ_ENABLE_UNDO_EXCEED_LIMIT, E_GRD_INNER_ERR }, + { GRD_TABLE_LIMIT_EXCEEDED, E_GRD_OVER_LIMIT }, + { GRD_FIELD_TYPE_NOT_MATCH, E_GRD_SEMANTIC_ERROR }, + { GRD_LARGE_JSON_NEST, E_GRD_SEMANTIC_ERROR }, + { GRD_INVALID_JSON_TYPE, E_GRD_SEMANTIC_ERROR }, + { GRD_INVALID_OPERATOR, E_GRD_SEMANTIC_ERROR }, + { GRD_INVALID_PROJECTION_FIELD, E_GRD_SEMANTIC_ERROR }, + { GRD_INVALID_PROJECTION_VALUE, E_GRD_SEMANTIC_ERROR }, + { GRD_DB_NOT_EXIST, E_GRD_DB_NOT_EXIST }, + { GRD_INVALID_VALUE, E_GRD_INVALID_ARGS }, + { GRD_SHARED_OBJ_NOT_EXIST, E_GRD_DATA_NOT_FOUND }, + { GRD_SUBSCRIBE_NOT_EXIST, E_GRD_DATA_NOT_FOUND }, + { GRD_COLLECTION_NOT_EXIST, E_GRD_DATA_NOT_FOUND }, + { GRD_RESULTSET_BUSY, E_DATABASE_BUSY }, + { GRD_RECORD_NOT_FOUND, E_GRD_DATA_NOT_FOUND }, + { GRD_FIELD_NOT_FOUND, E_GRD_DATA_NOT_FOUND }, + { GRD_ARRAY_INDEX_NOT_FOUND, E_GRD_DATA_NOT_FOUND }, + { GRD_RESULT_SET_NOT_AVAILABLE, E_GRD_DATA_NOT_FOUND }, + { GRD_SHARED_OBJ_UNDO_NOT_AVAILABLE, E_GRD_DATA_NOT_FOUND }, + { GRD_SHARED_OBJ_REDO_NOT_AVAILABLE, E_GRD_DATA_NOT_FOUND }, + { GRD_INVALID_JSON_FORMAT, E_GRD_DATA_CONFLICT }, + { GRD_INVALID_KEY_FORMAT, E_GRD_INVALID_NAME }, + { GRD_INVALID_COLLECTION_NAME, E_GRD_INVALID_NAME }, + { GRD_INVALID_EQUIP_ID, E_GRD_SEMANTIC_ERROR }, + { GRD_KEY_CONFLICT, E_GRD_DATA_CONFLICT }, + { GRD_FIELD_TYPE_CONFLICT, E_GRD_DATA_CONFLICT }, + { GRD_SHARED_OBJ_CONFLICT, E_GRD_DATA_CONFLICT }, + { GRD_SUBSCRIBE_CONFLICT, E_GRD_DATA_CONFLICT }, + { GRD_EQUIP_ID_CONFLICT, E_GRD_DATA_CONFLICT }, + { GRD_SHARED_OBJ_ENABLE_UNDO_CONFLICT, E_GRD_DATA_CONFLICT }, + { GRD_SCHEMA_CHANGED, E_CONFIG_INVALID_CHANGE }, + { GRD_DATA_EXCEPTION, E_GRD_DATA_EXCEPTION }, + { GRD_FIELD_OVERFLOW, E_GRD_SEMANTIC_ERROR }, + { GRD_DIVISION_BY_ZERO, E_GRD_SYNTAX_ERROR }, + { GRD_TRANSACTION_ROLLBACK, E_GRD_TRANSACTION_ROLLBACK }, + { GRD_NO_ACTIVE_TRANSACTION, E_GRD_NO_ACTIVE_TRANSACTION }, + { GRD_ACTIVE_TRANSACTION, E_GRD_ACTIVE_TRANSACTION }, +}; + +int GrdAdapter::TransErrno(int err) +{ + if (err > 0) { + return err; + } + auto result = GRD_ERRNO_MAP.find(err); + if (result != GRD_ERRNO_MAP.end()) { + return result->second; + } + return E_GRD_INNER_ERR; +} + +ColumnType GrdAdapter::TransColType(int grdColType) +{ + switch (grdColType) { + case GRD_DB_DATATYPE_INTEGER: + return ColumnType::TYPE_INTEGER; + case GRD_DB_DATATYPE_FLOAT: + return ColumnType::TYPE_FLOAT; + case GRD_DB_DATATYPE_TEXT: + return ColumnType::TYPE_TEXT; + case GRD_DB_DATATYPE_BLOB: + return ColumnType::TYPE_BLOB; + case GRD_DB_DATATYPE_FLOATVECTOR: + return ColumnType::TYPE_FLOATVECTOR; + case GRD_DB_DATATYPE_JSONSTR: + return ColumnType::TYPE_JSONSTR; + case GRD_DB_DATATYPE_NULL: + return ColumnType::TYPE_NULL; + default: + LOG_ERROR("trans failed. GRD_DbDataTypeE=%{public}d.", grdColType); + return ColumnType::TYPE_NULL; + } +} + +int GrdAdapter::Open(const char *dbPath, const char *configStr, uint32_t flags, GRD_DB **db) +{ + if (g_adapterHolder.Open == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.Open == nullptr) { + return E_NOT_SUPPORT; + } + auto ret = g_adapterHolder.Open(dbPath, configStr, flags, db); + LOG_DEBUG("Open ret=%{public}d, *db=%{public}p", ret, *db); + return TransErrno(ret); +} + +int GrdAdapter::Close(GRD_DB *db, uint32_t flags) +{ + LOG_DEBUG("Close *db=%{public}p", db); + if (g_adapterHolder.Close == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.Close == nullptr) { + return E_NOT_SUPPORT; + } + auto ret = g_adapterHolder.Close(db, flags); + LOG_DEBUG("Close ret=%{public}d", ret); + return TransErrno(ret); +} + +int GrdAdapter::Repair(const char *dbPath, const char *configStr) +{ + if (g_adapterHolder.Repair == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.Repair == nullptr) { + return E_NOT_SUPPORT; + } + return E_NOT_SUPPORT; +} + +int GrdAdapter::Backup(GRD_DB *db, const char *backupDbFile, const std::vector &encryptedKey) +{ + if (g_adapterHolder.Backup == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.Backup == nullptr) { + return E_NOT_SUPPORT; + } + return E_NOT_SUPPORT; +} + +int GrdAdapter::Restore(const char *dbFile, const char *backupDbFile, const std::vector &encryptedKey) +{ + if (g_adapterHolder.Restore == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.Restore == nullptr) { + return E_NOT_SUPPORT; + } + return E_NOT_SUPPORT; +} + +int GrdAdapter::Rekey(const char *dbFile, const char *configStr, const std::vector &encryptedKey) +{ + if (g_adapterHolder.Rekey == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.Rekey == nullptr) { + return E_NOT_SUPPORT; + } + if (encryptedKey.empty()) { + return E_GRD_INVALID_ARGS; + } + int32_t ret = E_OK; + GRD_CipherInfoT info = { 0 }; + const size_t keySize = encryptedKey.size() * 2 + 1; // 2 hex number can represent a uint8_t, 1 is for '\0' + std::vector key(keySize); + info.hexPassword = GdbUtils::GetEncryptKey(encryptedKey, key.data(), keySize); + ret = g_adapterHolder.Rekey(dbFile, configStr, &info); + key.assign(keySize, 0); + return TransErrno(ret); +} + +int32_t GrdAdapter::Prepare(GRD_DB *db, const char *str, uint32_t strLen, GRD_StmtT **stmt, const char **unusedStr) +{ + LOG_DEBUG("Prepare *db=%{public}p", db); + if (g_adapterHolder.Prepare == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.Prepare == nullptr) { + return E_NOT_SUPPORT; + } + int32_t ret = g_adapterHolder.Prepare(db, str, strLen, stmt, unusedStr); + LOG_DEBUG("Prepare ret=%{public}d, stmt=%{public}p", ret, *stmt); + return TransErrno(ret); +} + +int32_t GrdAdapter::Reset(GRD_StmtT *stmt) +{ + if (g_adapterHolder.Reset == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.Reset == nullptr) { + return E_NOT_SUPPORT; + } + return TransErrno(g_adapterHolder.Reset(stmt)); +} + +int32_t GrdAdapter::Finalize(GRD_StmtT *stmt) +{ + LOG_DEBUG("Finalize *stmt=%{public}p", stmt); + if (g_adapterHolder.Finalize == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.Finalize == nullptr) { + return E_NOT_SUPPORT; + } + int32_t ret = g_adapterHolder.Finalize(stmt); + LOG_DEBUG("Finalize ret=%{public}d", ret); + return TransErrno(ret); +} + +int32_t GrdAdapter::Step(GRD_StmtT *stmt) +{ + LOG_DEBUG("Step *stmt=%{public}p", stmt); + if (g_adapterHolder.Step == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.Step == nullptr) { + return E_NOT_SUPPORT; + } + int32_t ret = g_adapterHolder.Step(stmt); + LOG_DEBUG("Step ret=%{public}d", ret); + return TransErrno(ret); +} + +uint32_t GrdAdapter::ColumnCount(GRD_StmtT *stmt) +{ + if (g_adapterHolder.ColumnCount == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.ColumnCount == nullptr) { + return E_NOT_SUPPORT; + } + return g_adapterHolder.ColumnCount(stmt); +} + +GRD_DbDataTypeE GrdAdapter::ColumnType(GRD_StmtT *stmt, uint32_t idx) +{ + if (g_adapterHolder.GetColumnType == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.GetColumnType == nullptr) { + return GRD_DB_DATATYPE_NULL; + } + return g_adapterHolder.GetColumnType(stmt, idx); +} + +uint32_t GrdAdapter::ColumnBytes(GRD_StmtT *stmt, uint32_t idx) +{ + if (g_adapterHolder.ColumnBytes == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.ColumnBytes == nullptr) { + return E_NOT_SUPPORT; + } + return g_adapterHolder.ColumnBytes(stmt, idx); +} + +char *GrdAdapter::ColumnName(GRD_StmtT *stmt, uint32_t idx) +{ + if (g_adapterHolder.ColumnName == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.ColumnName == nullptr) { + return nullptr; + } + return g_adapterHolder.ColumnName(stmt, idx); +} + +GRD_DbValueT GrdAdapter::ColumnValue(GRD_StmtT *stmt, uint32_t idx) +{ + if (g_adapterHolder.ColumnValue == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.ColumnValue == nullptr) { + return {}; + } + return g_adapterHolder.ColumnValue(stmt, idx); +} + +int64_t GrdAdapter::ColumnInt64(GRD_StmtT *stmt, uint32_t idx) +{ + if (g_adapterHolder.ColumnInt64 == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.ColumnInt64 == nullptr) { + return 0; + } + return g_adapterHolder.ColumnInt64(stmt, idx); +} + +int32_t GrdAdapter::ColumnInt(GRD_StmtT *stmt, uint32_t idx) +{ + if (g_adapterHolder.ColumnInt == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.ColumnInt == nullptr) { + return 0; + } + return g_adapterHolder.ColumnInt(stmt, idx); +} + +double GrdAdapter::ColumnDouble(GRD_StmtT *stmt, uint32_t idx) +{ + if (g_adapterHolder.ColumnDouble == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.ColumnDouble == nullptr) { + return 0; + } + return g_adapterHolder.ColumnDouble(stmt, idx); +} + +const char *GrdAdapter::ColumnText(GRD_StmtT *stmt, uint32_t idx) +{ + if (g_adapterHolder.ColumnText == nullptr) { + g_adapterHolder = GetAdapterHolder(); + } + if (g_adapterHolder.ColumnText == nullptr) { + return nullptr; + } + return g_adapterHolder.ColumnText(stmt, idx); +} + +} // namespace OHOS::DistributedDataAip diff --git a/relational_store/frameworks/native/gdb/adapter/src/grd_adapter_manager.cpp b/relational_store/frameworks/native/gdb/adapter/src/grd_adapter_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a2859a2a1b9cb20109ba07a6f4831da680530f1d --- /dev/null +++ b/relational_store/frameworks/native/gdb/adapter/src/grd_adapter_manager.cpp @@ -0,0 +1,69 @@ +/* +* Copyright (c) 2024 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 "GrdAdapter" +#include + +#include "grd_adapter_manager.h" +#include "logger.h" + +namespace OHOS::DistributedDataAip { +void GrdAdapterHolderInit(GrdAdapterHolder &adapterHolder) +{ + adapterHolder.Open = (Open)dlsym(g_library, "GRD_DBOpen"); + adapterHolder.Close = (Close)dlsym(g_library, "GRD_DBClose"); + adapterHolder.Repair = (Repair)dlsym(g_library, "GRD_DBRepair"); + adapterHolder.Backup = (Backup)dlsym(g_library, "GRD_DBBackup"); + adapterHolder.Restore = (Restore)dlsym(g_library, "GRD_DBRestore"); + adapterHolder.Rekey = (Rekey)dlsym(g_library, "GRD_DBRekey"); + + adapterHolder.Prepare = (Prepare)dlsym(g_library, "GRD_GqlPrepare"); + adapterHolder.Reset = (Reset)dlsym(g_library, "GRD_GqlReset"); + adapterHolder.Finalize = (Finalize)dlsym(g_library, "GRD_GqlFinalize"); + adapterHolder.Step = (Step)dlsym(g_library, "GRD_GqlStep"); + adapterHolder.ColumnCount = (ColumnCount)dlsym(g_library, "GRD_GqlColumnCount"); + adapterHolder.GetColumnType = (GetColumnType)dlsym(g_library, "GRD_GqlColumnType"); + adapterHolder.ColumnBytes = (ColumnBytes)dlsym(g_library, "GRD_GqlColumnBytes"); + adapterHolder.ColumnName = (ColumnName)dlsym(g_library, "GRD_GqlColumnName"); + adapterHolder.ColumnValue = (ColumnValue)dlsym(g_library, "GRD_GqlColumnValue"); + adapterHolder.ColumnInt64 = (ColumnInt64)dlsym(g_library, "GRD_GqlColumnInt64"); + adapterHolder.ColumnInt = (ColumnInt)dlsym(g_library, "GRD_GqlColumnInt"); + adapterHolder.ColumnDouble = (ColumnDouble)dlsym(g_library, "GRD_GqlColumnDouble"); + adapterHolder.ColumnText = (ColumnText)dlsym(g_library, "GRD_GqlColumnText"); +} + +bool IsSupportArkDataDb() +{ +#ifdef ARKDATA_DB_CORE_IS_EXISTS + return true; +#else + return false; +#endif +} + +GrdAdapterHolder GetAdapterHolder() +{ + GrdAdapterHolder adapterHolder; + if (g_library == nullptr) { + g_library = dlopen("libarkdata_db_core.z.so", RTLD_LAZY); + } + if (g_library == nullptr) { + LOG_WARN("use default db kernel"); + return adapterHolder; + } + GrdAdapterHolderInit(adapterHolder); + return adapterHolder; +} + +} // namespace OHOS::DistributedDataAip diff --git a/relational_store/frameworks/native/gdb/include/aip_errors.h b/relational_store/frameworks/native/gdb/include/aip_errors.h new file mode 100644 index 0000000000000000000000000000000000000000..030b52710b59920dbf5c04ce566b6cab03d27e43 --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/aip_errors.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024 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_NATIVE_GDB_AIP_ERRORS_H +#define OHOS_DISTRIBUTED_DATA_NATIVE_GDB_AIP_ERRORS_H + +#include "errors.h" + +namespace OHOS { +namespace DistributedDataAip { +enum { + AIP_MODULE_SERVICE_ID = 0x08, +}; + +constexpr ErrCode DISTRIBUTEDDATAMGR_GDB_ERR_OFFSET = ErrCodeOffset(SUBSYS_DISTRIBUTEDDATAMNG, AIP_MODULE_SERVICE_ID); + +/** +* @brief The error code in the correct case. +*/ +constexpr int E_OK = 0; + +/** +* @brief The base code of the exception error code. +*/ +constexpr int E_BASE = DISTRIBUTEDDATAMGR_GDB_ERR_OFFSET; + +/** +* @brief The error code for common exceptions. +*/ +constexpr int E_ERROR = E_BASE; + +constexpr int E_INVALID_ARGS = (E_BASE + 0x1); +constexpr int E_NOT_SUPPORT = (E_BASE + 0x2); + +/* GRD error */ + +constexpr int E_GRD_NO_DATA = (E_BASE + 0x3); +constexpr int E_GRD_DATA_CORRUPTED = (E_BASE + 0x4); +constexpr int E_GRD_DB_INSTANCE_ABNORMAL = (E_BASE + 0x5); +constexpr int E_DATABASE_BUSY = (E_BASE + 0x6); +constexpr int E_GRD_FAILED_MEMORY_ALLOCATE = (E_BASE + 0x7); +constexpr int E_GRD_DISK_SPACE_FULL = (E_BASE + 0x8); +constexpr int E_GRD_DUPLICATE_PARAM = (E_BASE + 0x9); +constexpr int E_GRD_UNDEFINED_PARAM = (E_BASE + 0xa); +constexpr int E_GRD_INVALID_NAME = (E_BASE + 0xb); +constexpr int E_GRD_SYNTAX_ERROR = (E_BASE + 0xc); +constexpr int E_GRD_SEMANTIC_ERROR = (E_BASE + 0xd); +constexpr int E_GRD_OVER_LIMIT = (E_BASE + 0xe); + +constexpr int E_GRD_INVALID_ARGS = (E_BASE + 0xf); +constexpr int E_GRD_FAILED_FILE_OPERATION = (E_BASE + 0x10); +constexpr int E_GRD_CRC_CHECK_DISABLED = (E_BASE + 0x11); +constexpr int E_GRD_PERMISSION_DENIED = (E_BASE + 0x12); +constexpr int E_GRD_PASSWORD_UNMATCHED = (E_BASE + 0x13); +constexpr int E_GRD_PASSWORD_NEED_REKEY = (E_BASE + 0x14); +constexpr int E_GRD_WRONG_STMT_OBJECT = (E_BASE + 0x15); +constexpr int E_GRD_DATA_CONFLICT = (E_BASE + 0x16); +constexpr int E_GRD_INNER_ERR = (E_BASE + 0x17); +constexpr int E_GRD_FAILED_MEMORY_RELEASE = (E_BASE + 0x18); +constexpr int E_GRD_NOT_AVAILABLE = (E_BASE + 0x19); +constexpr int E_GRD_CIPHER_ERROR = (E_BASE + 0x1a); +constexpr int E_ARGS_READ_CON_OVERLOAD = (E_BASE + 0x1b); +constexpr int E_GRD_INVALID_FILE_FORMAT = (E_BASE + 0x1c); +constexpr int E_GRD_INVALID_BIND_VALUE = (E_BASE + 0x1d); +constexpr int E_GRD_DB_NOT_EXIST = (E_BASE + 0x1e); +constexpr int E_GRD_DATA_NOT_FOUND = (E_BASE + 0x1f); +constexpr int E_GRD_DATA_EXCEPTION = (E_BASE + 0x20); +constexpr int E_GRD_TRANSACTION_ROLLBACK = (E_BASE + 0x21); +constexpr int E_GRD_NO_ACTIVE_TRANSACTION = (E_BASE + 0x22); +constexpr int E_GRD_ACTIVE_TRANSACTION = (E_BASE + 0x23); + +constexpr int E_ACQUIRE_CONN_FAILED = (E_BASE + 0x24); +constexpr int E_PREPARE_CHECK_FAILED = (E_BASE + 0x25); +constexpr int E_STEP_CHECK_FAILED = (E_BASE + 0x26); +constexpr int E_GETTED_COLNAME_EMPTY = (E_BASE + 0x27); +constexpr int E_PARSE_JSON_FAILED = (E_BASE + 0x28); +constexpr int E_INNER_ERROR = (E_BASE + 0x29); +constexpr int E_NO_DATA = (E_BASE + 0x2a); +constexpr int E_DBPATH_ACCESS_FAILED = (E_BASE + 0x2b); +constexpr int E_INIT_CONN_POOL_FAILED = (E_BASE + 0x2c); +constexpr int E_CONFIG_INVALID_CHANGE = (E_BASE + 0x2d); +constexpr int E_GRD_INVAILD_NAME_ERR = (E_BASE + 0x2e); +constexpr int E_CREATE_FOLDER_FAIT = (E_BASE + 0x3f); +constexpr int E_STATEMENT_EMPTY = (E_BASE + 0x30); +constexpr int E_STORE_HAS_CLOSED = (E_BASE + 0x31); +constexpr int E_GRD_NOT_SUPPORT = (E_BASE + 0x32); +} // namespace DistributedDataAip +} // namespace OHOS + +#endif // OHOS_DISTRIBUTED_DATA_NATIVE_GDB_AIP_ERRORS_H \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/include/connection.h b/relational_store/frameworks/native/gdb/include/connection.h new file mode 100644 index 0000000000000000000000000000000000000000..52f5eaf16c9d34cb7762d98ce364290b56b7f2f2 --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/connection.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 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_NATIVE_GDB_CONNECTION_H +#define OHOS_DISTRIBUTED_DATA_NATIVE_GDB_CONNECTION_H + +#include "gdb_store_config.h" +#include "statement.h" + +namespace OHOS::DistributedDataAip { +class StoreConfig; +class Statement; +class Connection { +public: + using SConn = std::shared_ptr; + using Stmt = std::shared_ptr; + using Creator = std::pair (*)(const StoreConfig &config, bool isWriter); + static std::pair Create(const StoreConfig &config, bool isWriter); + static int32_t RegisterCreator(DBType dbType, Creator creator); + + int32_t SetId(int32_t id); + int32_t GetId() const; + virtual ~Connection() = default; + virtual std::pair CreateStatement(const std::string &gql, std::shared_ptr conn) = 0; + virtual DBType GetDBType() const = 0; + virtual bool IsWriter() const = 0; + +private: + int32_t id_ = 0; +}; +} // namespace OHOS::DistributedDataAip +#endif // OHOS_DISTRIBUTED_DATA_NATIVE_GDB_CONNECTION_H \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/include/connection_pool.h b/relational_store/frameworks/native/gdb/include/connection_pool.h new file mode 100644 index 0000000000000000000000000000000000000000..2da03e16384daf0ed9cb0170d8235505c6d98f90 --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/connection_pool.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2024 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_NATIVE_GDB_CONNECTION_POOL_H +#define OHOS_DISTRIBUTED_DATA_NATIVE_GDB_CONNECTION_POOL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "connection.h" +#include "gdb_store_config.h" + +namespace OHOS::DistributedDataAip { +class ConnectionPool : public std::enable_shared_from_this { +public: + using SharedConn = std::shared_ptr; + static constexpr std::chrono::milliseconds INVALID_TIME = std::chrono::milliseconds(0); + static std::shared_ptr Create(const StoreConfig &config, int &errCode); + ~ConnectionPool(); + std::pair> CreateTransConn(); + SharedConn Acquire(bool isReadOnly, std::chrono::milliseconds ms = INVALID_TIME); + // this interface is only provided for resultSet + SharedConn AcquireRef(bool isReadOnly, std::chrono::milliseconds ms = INVALID_TIME); + int32_t Dump(bool isWriter, const char *header); + int RestartReaders(); + void CloseAllConnections(); + + explicit ConnectionPool(const StoreConfig &storeConfig); + +private: + struct ConnNode { + bool using_ = false; + int32_t tid_ = 0; + int32_t id_ = 0; + std::chrono::steady_clock::time_point time_ = std::chrono::steady_clock::now(); + std::shared_ptr connect_; + + explicit ConnNode(std::shared_ptr conn); + std::shared_ptr GetConnect(); + int64_t GetUsingTime() const; + bool IsWriter() const; + int32_t Unused(int32_t count, bool timeout); + }; + + struct Container { + using Creator = std::function>()>; + static constexpr int32_t MAX_RIGHT = 0x4FFFFFFF; + static constexpr int32_t MIN_TRANS_ID = 10000; + bool disable_ = true; + int max_ = 0; + int total_ = 0; + int count_ = 0; + int trans_ = 0; + int32_t left_ = 0; + int32_t right_ = 0; + std::chrono::seconds timeout_; + std::list> nodes_; + std::list> details_; + std::mutex mutex_; + std::condition_variable cond_; + Creator creator_ = nullptr; + std::pair> Initialize( + Creator creator, int32_t max, int32_t timeout, bool disable, bool acquire = false); + std::shared_ptr Acquire(std::chrono::milliseconds milliS); + std::pair> Create(); + + void Disable(); + void Enable(); + int32_t Release(std::shared_ptr node); + int32_t Drop(std::shared_ptr node); + int32_t Clear(); + bool IsFull(); + int32_t Dump(const char *header, int32_t count); + + private: + int32_t ExtendNode(); + int32_t RelDetails(std::shared_ptr node); + }; + + std::pair> Init(bool isAttach = false, bool needWriter = false); + int32_t GetMaxReaders(const StoreConfig &config); + std::shared_ptr Convert2AutoConn(std::shared_ptr node, bool isTrans = false); + void ReleaseNode(std::shared_ptr node, bool reuse = true); + + static constexpr uint32_t CHECK_POINT_INTERVAL = 5; // 5 min + static constexpr uint32_t ITER_V1 = 5000; + static constexpr uint32_t ITERS_COUNT = 2; + static constexpr uint32_t MAX_TRANS = 4; + const StoreConfig &config_; + Container writers_; + Container readers_; + int32_t maxReader_ = 0; + + std::condition_variable transCondition_; + std::atomic isInTransaction_ = false; + std::atomic transCount_ = 0; + std::atomic failedTime_; +}; + +} // namespace OHOS::DistributedDataAip +#endif diff --git a/relational_store/frameworks/native/gdb/include/db_store_impl.h b/relational_store/frameworks/native/gdb/include/db_store_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..f754a07d315398dd4edcdd2d4ede41da8b79ef93 --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/db_store_impl.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024 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_NATIVE_GDB_DB_STORE_IMPL_H +#define OHOS_DISTRIBUTED_DATA_NATIVE_GDB_DB_STORE_IMPL_H + +#include +#include + +#include "connection.h" +#include "connection_pool.h" +#include "gdb_store.h" +#include "gdb_store_config.h" +#include "transaction.h" + +namespace OHOS::DistributedDataAip { +class DBStoreImpl final : public DBStore { +public: + explicit DBStoreImpl(StoreConfig config); + ~DBStoreImpl(); + std::pair> QueryGql(const std::string &gql) override; + std::pair> ExecuteGql(const std::string &gql) override; + std::pair> CreateTransaction() override; + int32_t Close() override; + int32_t InitConn(); + +private: + std::shared_ptr GetConnectionPool(); + void SetConnectionPool(std::shared_ptr connectionPool); + + std::mutex mutex_; + std::mutex transMutex_; + StoreConfig config_; + std::shared_ptr connectionPool_ = nullptr; + std::list> transactions_; +}; +} // namespace OHOS::DistributedDataAip +#endif diff --git a/datamgr_service/services/distributeddataservice/service/matrix/include/auto_sync_matrix.h b/relational_store/frameworks/native/gdb/include/db_store_manager.h similarity index 30% rename from datamgr_service/services/distributeddataservice/service/matrix/include/auto_sync_matrix.h rename to relational_store/frameworks/native/gdb/include/db_store_manager.h index d875a2358e68bf7a77ac97e065d23af54cccce71..e5cef31d84fb8f89595055bca6499df419271481 100644 --- a/datamgr_service/services/distributeddataservice/service/matrix/include/auto_sync_matrix.h +++ b/relational_store/frameworks/native/gdb/include/db_store_manager.h @@ -12,56 +12,43 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -#ifndef OHOS_DISTRIBUTED_DATA_SERVICE_MATRIX_AUTO_SYNC_MATRIX_H -#define OHOS_DISTRIBUTED_DATA_SERVICE_MATRIX_AUTO_SYNC_MATRIX_H - -#include +#ifndef OHOS_DISTRIBUTED_DATA_NATIVE_GDB_DB_STORE_MANAGER_H +#define OHOS_DISTRIBUTED_DATA_NATIVE_GDB_DB_STORE_MANAGER_H #include #include -#include "metadata/store_meta_data.h" +#include "db_store_impl.h" -namespace OHOS::DistributedData { -class API_EXPORT AutoSyncMatrix { +namespace OHOS::DistributedDataAip { +class StoreManager { public: - static AutoSyncMatrix &GetInstance(); - void Initialize(); - void Online(const std::string &device); - void Offline(const std::string &device); - void OnChanged(const StoreMetaData &metaData); - void OnExchanged(const std::string &device, const StoreMetaData &metaData); - std::vector GetChangedStore(const std::string &device); + static StoreManager &GetInstance(); + ~StoreManager(); + std::shared_ptr GetDBStore(const StoreConfig &config, int &errCode); + void Clear(); + bool Delete(const std::string &path); private: - static constexpr uint32_t MAX_SIZE = 128; - struct Mask { - std::bitset data; - void Delete(size_t pos); - void Set(size_t pos); - void Reset(size_t pos); - void Init(size_t size); - }; - enum DataType { - STATICS = 0, - DYNAMICAL, - }; - - AutoSyncMatrix(); - ~AutoSyncMatrix(); - AutoSyncMatrix(const AutoSyncMatrix &) = delete; - AutoSyncMatrix(AutoSyncMatrix &&) noexcept = delete; - AutoSyncMatrix &operator=(const AutoSyncMatrix &) = delete; - AutoSyncMatrix &operator=(AutoSyncMatrix &&) noexcept = delete; - bool IsAutoSync(const StoreMetaData &meta); - void AddStore(const StoreMetaData &meta); - void DelStore(const StoreMetaData &meta); - void UpdateStore(const StoreMetaData &meta); - + StoreManager(); + bool DeleteFile(const std::string &path); + int SetSecurityLabel(const StoreConfig &config); + std::string GetSecurityLevelValue(SecurityLevel securityLevel); + std::string GetFileSecurityLevel(const std::string &filePath); + bool IsValidName(const std::string& name); + bool IsValidSecurityLevel(const int32_t securityLevel); std::mutex mutex_; - std::map onlines_; - std::map offlines_; - std::vector metas_; + std::string bundleName_; + std::map> storeCache_; + static constexpr const char *GRD_POST_FIXES[] = { + "", + ".redo", + ".undo", + ".ctrl", + ".ctrl.dwr", + ".safe", + ".map", + ".corruptedflg", + }; }; -} // namespace OHOS::DistributedData -#endif // OHOS_DISTRIBUTED_DATA_SERVICE_MATRIX_AUTO_SYNC_MATRIX_H \ No newline at end of file +} // namespace OHOS::DistributedDataAip +#endif \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/include/db_trace.h b/relational_store/frameworks/native/gdb/include/db_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..b8aea61efd393da3bbefc9e8a5532c73cee30324 --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/db_trace.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 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 NATIVE_GDB_TRACE_H +#define NATIVE_GDB_TRACE_H + +#define DO_NOTHING + +#ifdef DB_TRACE_ON +#include "hitrace.h" + +#ifndef DISTRIBUTED_DATA_HITRACE +#define DISTRIBUTED_DATA_HITRACE(trace) OHOS::DistributedDataAip::HiTrace hitrace(trace) +#endif + +#else +#define DISTRIBUTED_DATA_HITRACE(trace) DO_NOTHING +#endif + +#endif \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/include/edge.h b/relational_store/frameworks/native/gdb/include/edge.h new file mode 100644 index 0000000000000000000000000000000000000000..d504063da51fc098f95ad190a8a9fad073c0960c --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/edge.h @@ -0,0 +1,52 @@ +/* +* Copyright (c) 2024 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_NATIVE_GDB_GRAPH_EDGE_H +#define OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRAPH_EDGE_H + +#include +#include +#include +#include +#include +#include + +#include "nlohmann/json.hpp" +#include "vertex.h" + +namespace OHOS::DistributedDataAip { +class Edge : public Vertex { +public: + Edge(); + Edge(std::string id, std::string label, std::string sourceId, std::string targetId); + Edge(const std::shared_ptr &element, std::string sourceId, std::string targetId); + static std::shared_ptr Parse(const nlohmann::json &json, int32_t &errCode); + std::string GetSourceId() const; + void SetSourceId(std::string sourceId); + + std::string GetTargetId() const; + void SetTargetId(std::string targetId); + + static constexpr const char *SOURCEID = "start"; + static constexpr const char *TARGETID = "end"; + +private: + std::string sourceId_; + std::string targetId_; + static std::string GetIdFromJson(const std::string &key, const nlohmann::json &json, int32_t &errCode); +}; + +} +#endif //OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRAPH_EDGE_H diff --git a/relational_store/frameworks/native/gdb/include/full_result.h b/relational_store/frameworks/native/gdb/include/full_result.h new file mode 100644 index 0000000000000000000000000000000000000000..648ebaf9f2793588c8ebdf08b5461779c5240dc7 --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/full_result.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 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_NATIVE_GDB_GRAPH_FULLRESULT_H +#define OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRAPH_FULLRESULT_H + +#include +#include +#include +#include +#include +#include + +#include "edge.h" +#include "gdb_store_config.h" +#include "nlohmann/json.hpp" +#include "path.h" +#include "result.h" +#include "vertex.h" + +namespace OHOS::DistributedDataAip { +class Statement; +class FullResult final : public Result { +public: + FullResult() = default; + std::vector> GetAllData() const override; + int32_t InitData(std::shared_ptr stmt); + +private: + std::pair> GetRow(std::shared_ptr stmt); + std::vector> data_; +}; +} // namespace OHOS::DistributedDataAip +#endif //OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRAPH_FULLRESULT_H diff --git a/relational_store/frameworks/native/gdb/include/gdb_utils.h b/relational_store/frameworks/native/gdb/include/gdb_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..b339570b853798d808c429f6b928eb1b1125dec9 --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/gdb_utils.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 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_NATIVE_GDB_GDB_UTILS_H +#define OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GDB_UTILS_H +#include + +namespace OHOS::DistributedDataAip { +class GdbUtils { +public: + static bool IsTransactionGql(const std::string &gql); + static int CreateDirectory(const std::string &databaseDir); + static std::string Anonymous(const std::string &srcFile); + static void ClearAndZeroString(std::string &str); + static std::string GetConfigStr(const std::vector &keys, bool isEncrypt); + static const char *GetEncryptKey(const std::vector &encryptedKey, char outBuff[], size_t outBufSize); +private: + static constexpr int DIR_RWXRWS__X = 0771; + static constexpr const char *GRD_OPEN_CONFIG_STR = + "\"pageSize\":4, \"crcCheckEnable\":0"; + static std::string GetAnonymousName(const std::string& fileName); + static std::string AnonyDigits(const std::string& fileName); +}; +} + +#endif \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/include/graph_connection.h b/relational_store/frameworks/native/gdb/include/graph_connection.h new file mode 100644 index 0000000000000000000000000000000000000000..58542becbb58457756946b13c936d8ad8fd849c0 --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/graph_connection.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024 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_NATIVE_GDB_GRAPH_CONNECTION_H +#define OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRAPH_CONNECTION_H + +#include +#include +#include + +#include "connection.h" +#include "gdb_store_config.h" +#include "grd_adapter.h" + +namespace OHOS::DistributedDataAip { +class GraphConnection : public Connection { +public: + static std::pair> Create(const StoreConfig &config, bool isWriter); + GraphConnection(const StoreConfig &config, bool isWriter); + ~GraphConnection() override; + std::pair CreateStatement(const std::string &gql, std::shared_ptr conn) override; + DBType GetDBType() const override; + bool IsWriter() const override; + +private: + static constexpr uint32_t NO_ITER = 0; + static constexpr uint32_t ITER_V1 = 5000; + static constexpr uint32_t ITERS[] = { NO_ITER, ITER_V1 }; + static constexpr uint32_t ITERS_COUNT = sizeof(ITERS) / sizeof(ITERS[0]); + + static const int32_t regCreator_; + + int InnerOpen(const StoreConfig &config); + int32_t ResetKey(const StoreConfig &config); + GRD_DB *dbHandle_ = nullptr; + const StoreConfig config_; + bool isWriter_ = false; +}; + +} // namespace OHOS::DistributedDataAip + +#endif // OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRAPH_CONNECTION_H diff --git a/relational_store/frameworks/native/gdb/include/graph_statement.h b/relational_store/frameworks/native/gdb/include/graph_statement.h new file mode 100644 index 0000000000000000000000000000000000000000..5f4d3c2385066b7e186624a908a5d4dc6ef0f994 --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/graph_statement.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024 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_NATIVE_GDB_GRAPH_STATEMENT_H +#define OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRAPH_STATEMENT_H + +#ifndef JSON_NOEXCEPTION +#define JSON_NOEXCEPTION +#endif +#include "connection.h" +#include "grd_adapter.h" +#include "nlohmann/json.hpp" +#include "statement.h" + +namespace OHOS::DistributedDataAip { +class GraphStatement final : public Statement { +public: + GraphStatement(GRD_DB *db, const std::string &gql, std::shared_ptr conn, int32_t &errCode); + ~GraphStatement(); + + int32_t Prepare() override; + int32_t Step() override; + int32_t Finalize() override; + + uint32_t GetColumnCount() const override; + std::pair GetColumnName(int32_t index) const override; + std::pair GetColumnType(int32_t index) const override; + std::pair GetColumnValue(int32_t index) const override; + + bool IsReady() const override; + +private: + std::shared_ptr conn_; + std::string gql_; + GRD_Stmt *stmtHandle_ = nullptr; + GRD_DB *dbHandle_ = nullptr; + static GraphValue ParseJsonStr(const std::string &jsonStr, int32_t &errCode) ; +}; +} // namespace OHOS::DistributedDataAip +#endif //OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRAPH_STATEMENT_H diff --git a/relational_store/frameworks/native/gdb/include/hitrace.h b/relational_store/frameworks/native/gdb/include/hitrace.h new file mode 100644 index 0000000000000000000000000000000000000000..a1bdebd64ba738f6f16d5ed184c407e62e152f1f --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/hitrace.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025 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 DISTRIBUTEDDATAMGR_NATIVEGDB_HITRACE_H +#define DISTRIBUTEDDATAMGR_NATIVEGDB_HITRACE_H + +#include + +#include "hitrace_meter.h" + +namespace OHOS { +namespace DistributedDataAip { +class HiTrace final { +public: + inline HiTrace(const std::string &value) + { + StartTrace(HITRACE_TAG_DISTRIBUTEDDATA, value); + } + + inline ~HiTrace() + { + FinishTrace(HITRACE_TAG_DISTRIBUTEDDATA); + } +}; +} // namespace DistributedDataAip +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/include/path.h b/relational_store/frameworks/native/gdb/include/path.h new file mode 100644 index 0000000000000000000000000000000000000000..0f5a67a23b0872ce109a28f292f78a77dc2fde5c --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/path.h @@ -0,0 +1,61 @@ +/* +* Copyright (c) 2024 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_NATIVE_GDB_GRAPH_PATH_H +#define OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRAPH_PATH_H +#include +#include +#include +#include +#include +#include + +#include "edge.h" +#include "nlohmann/json.hpp" +#include "path_segment.h" +#include "vertex.h" + +namespace OHOS::DistributedDataAip { +class Path { +public: + Path(); + Path(std::shared_ptr start, std::shared_ptr end); + Path(std::shared_ptr start, std::shared_ptr end, uint32_t pathLen, + std::vector> segments); + + static std::shared_ptr Parse(const nlohmann::json &json, int32_t &errCode); + + uint32_t GetPathLength() const; + void SetPathLength(uint32_t pathLen); + std::shared_ptr GetStart() const; + void SetStart(std::shared_ptr start); + std::shared_ptr GetEnd() const; + void SetEnd(std::shared_ptr end); + const std::vector> &GetSegments() const; + + static constexpr const char *PATHLEN = "length"; + static constexpr const char *START = "start"; + static constexpr const char *END = "end"; + static constexpr const char *SEGMENTS = "segments"; + +private: + uint32_t pathLen_; + std::shared_ptr start_; + std::shared_ptr end_; + std::vector> segments_; +}; + +} // namespace OHOS::DistributedDataAip +#endif //OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRAPH_PATH_H diff --git a/relational_store/frameworks/native/gdb/include/path_segment.h b/relational_store/frameworks/native/gdb/include/path_segment.h new file mode 100644 index 0000000000000000000000000000000000000000..b927b605140af3f77207d0c54f7bf6737c4e120c --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/path_segment.h @@ -0,0 +1,55 @@ +/* +* Copyright (c) 2024 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_NATIVE_GDB_GRAPH_PATH_SEGMENT_H +#define OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRAPH_PATH_SEGMENT_H +#include +#include +#include +#include +#include +#include + +#include "edge.h" +#include "vertex.h" + +namespace OHOS::DistributedDataAip { +class PathSegment { +public: + PathSegment(); + PathSegment(std::shared_ptr sourceVertex, std::shared_ptr targetVertex, + std::shared_ptr edge); + static std::shared_ptr Parse(const nlohmann::json &json, int32_t &errCode); + + std::shared_ptr GetSourceVertex() const; + void SetSourceVertex(std::shared_ptr vertex); + + std::shared_ptr GetEdge() const; + void SetEdge(std::shared_ptr edge); + + std::shared_ptr GetTargetVertex() const; + void SetTargetVertex(std::shared_ptr vertex); + + static constexpr const char *SOURCE_VERTEX = "start"; + static constexpr const char *TARGET_VERTEX = "end"; + static constexpr const char *EDGE = "relationship"; + +private: + std::shared_ptr sourceVertex_; + std::shared_ptr edge_; + std::shared_ptr targetVertex_; +}; +} // namespace OHOS::DistributedDataAip +#endif //OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRAPH_PATH_SEGMENT_H diff --git a/relational_store/frameworks/native/gdb/include/rdb_fault_hiview_reporter.h b/relational_store/frameworks/native/gdb/include/rdb_fault_hiview_reporter.h new file mode 100644 index 0000000000000000000000000000000000000000..c67b3c2773b5e45f0bba1b8d6679c57f202f2773 --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/rdb_fault_hiview_reporter.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025 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 DISTRIBUTEDDATAMGR_GDB_FAULT_HIVIEW_REPORTER_H +#define DISTRIBUTEDDATAMGR_GDB_FAULT_HIVIEW_REPORTER_H + +#include +#include "rdb_store_config.h" + +namespace OHOS::NativeRdb { +// Fault Type Define +static constexpr const char *FT_OPEN = "OPEN_DB"; +static constexpr const char *FT_CURD = "CURD_DB"; +static constexpr const char *FT_EX_FILE = "EX_FILE"; +static constexpr const char *FT_EX_HUKS = "EX_HUKS"; +static constexpr const char *FT_CP = "CHECK_POINT"; + +class RdbFaultEvent { +public: + RdbFaultEvent(const std::string &faultType, int32_t errorCode, const std::string &bundleName, + const std::string &custLog) {}; +}; + +class RdbFaultDbFileEvent : public RdbFaultEvent { +public: + RdbFaultDbFileEvent(const std::string &faultType, int32_t errorCode, const RdbStoreConfig &config, + const std::string &custLog = "", bool printDbInfo = false) + : RdbFaultEvent(faultType, errorCode, "", custLog), config_(config) {} +private: + RdbStoreConfig config_; +}; + +class RdbFaultHiViewReporter { +public: + static void ReportFault(const RdbFaultEvent &faultEvent) {}; +}; +} // namespace OHOS::NativeRdb +#endif // DISTRIBUTEDDATAMGR_GDB_FAULT_HIVIEW_REPORTER_H \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/include/statement.h b/relational_store/frameworks/native/gdb/include/statement.h new file mode 100644 index 0000000000000000000000000000000000000000..89d29ae4b3160a7af6077f87339b4af10b1f38bf --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/statement.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 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_NATIVE_GDB_STATEMENT_H +#define OHOS_DISTRIBUTED_DATA_NATIVE_GDB_STATEMENT_H +#include +#include +#include +#include +#include + +#include "full_result.h" + +namespace OHOS::DistributedDataAip { +/** + * @brief Indicates the column type. + * + * Value returned by getColumnType(int) + */ +enum class ColumnType : int { + TYPE_INTEGER = 0, + TYPE_FLOAT, + TYPE_TEXT, + TYPE_BLOB, + TYPE_FLOATVECTOR, + TYPE_JSONSTR, + TYPE_NULL, +}; +class Statement { +public: + virtual int32_t Prepare() = 0; + virtual int32_t Step() = 0; + virtual int32_t Finalize() = 0; + + virtual uint32_t GetColumnCount() const = 0; + virtual std::pair GetColumnName(int32_t index) const = 0; + virtual std::pair GetColumnType(int32_t index) const = 0; + virtual std::pair GetColumnValue(int32_t index) const = 0; + + virtual bool IsReady() const = 0; +}; +} // namespace OHOS::DistributedDataAip +#endif //ARKDATA_INTELLIGENCE_PLATFORM_STATEMENT_H \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/include/trans_db.h b/relational_store/frameworks/native/gdb/include/trans_db.h new file mode 100644 index 0000000000000000000000000000000000000000..2694aa129e739af590aaddb1b12ebbdc23ea93fd --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/trans_db.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 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 ARKDATA_INTELLIGENCE_PLATFORM_TRANS_DB_H +#define ARKDATA_INTELLIGENCE_PLATFORM_TRANS_DB_H +#include + +#include "connection.h" +#include "gdb_store.h" +#include "graph_statement.h" +namespace OHOS::DistributedDataAip { +class TransDB : public DBStore { +public: + TransDB(std::shared_ptr connection); + std::pair> QueryGql(const std::string &gql) override; + std::pair> ExecuteGql(const std::string &gql) override; + + std::pair> CreateTransaction() override; + int32_t Close() override; + +private: + std::pair> GetStatement(const std::string &gql) const; + + std::weak_ptr conn_; +}; +} // namespace OHOS::DistributedDataAip +#endif // ARKDATA_INTELLIGENCE_PLATFORM_TRANS_DB_H \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/include/transaction_impl.h b/relational_store/frameworks/native/gdb/include/transaction_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..b191f09b94bc0172bd960b3b5d239a9142b8e2cf --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/transaction_impl.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025 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 ARKDATA_INTELLIGENCE_PLATFORM_TRANSACTION_IMPL_H +#define ARKDATA_INTELLIGENCE_PLATFORM_TRANSACTION_IMPL_H + +#include +#include +#include + +#include "connection.h" +#include "gdb_store_config.h" +#include "result.h" +#include "transaction.h" + +namespace OHOS::DistributedDataAip { +class DBStore; +class TransactionImpl : public Transaction { +public: + TransactionImpl(std::shared_ptr connection); + ~TransactionImpl() override; + + int32_t Commit() override; + int32_t Rollback() override; + int32_t Close() override; + + std::pair> Query(const std::string &gql) override; + std::pair> Execute(const std::string &gql) override; + + static std::pair> Create(std::shared_ptr conn); + +private: + int32_t Start(); + int32_t CloseInner(); + std::shared_ptr GetStore(); + + std::recursive_mutex mutex_; + std::shared_ptr store_; + std::shared_ptr connection_; + + static const int32_t regCreator_; +}; +} // namespace OHOS::DistributedDataAip +#endif diff --git a/relational_store/frameworks/native/gdb/include/vertex.h b/relational_store/frameworks/native/gdb/include/vertex.h new file mode 100644 index 0000000000000000000000000000000000000000..9e997240a71869db69afbb4b4ebabdba01c81cb7 --- /dev/null +++ b/relational_store/frameworks/native/gdb/include/vertex.h @@ -0,0 +1,57 @@ +/* +* Copyright (c) 2024 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_NATIVE_GDB_GRAPH_VERTEX_H +#define OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRAPH_VERTEX_H +#include +#include +#include +#include +#include +#include + +#include "nlohmann/json.hpp" + +namespace OHOS::DistributedDataAip { +using PropType = std::variant; +class Vertex { +public: + Vertex(); + Vertex(std::string id, std::string label); + Vertex(std::string id, std::string label, const std::unordered_map &properties); + static std::shared_ptr Parse(const nlohmann::json &json, int32_t &errCode); + + std::string GetId() const; + void SetId(std::string id); + + const std::string &GetLabel() const; + const std::vector &GetLabels() const; + void SetLabel(const std::string &label); + + const std::unordered_map &GetProperties() const; + void SetProperty(const std::string &key, PropType value); + + static constexpr const char *ID = "identity"; + static constexpr const char *LABEL = "label"; + static constexpr const char *PROPERTIES = "properties"; + +protected: + std::string id_; + std::string label_; + std::vector labels_; + std::unordered_map properties_; +}; +} // namespace OHOS::DistributedDataAip +#endif //OHOS_DISTRIBUTED_DATA_NATIVE_GDB_GRAPH_VERTEX_H diff --git a/relational_store/frameworks/native/gdb/src/connection.cpp b/relational_store/frameworks/native/gdb/src/connection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c9ab193747f5c0fe720fd5cada89aec37cfd028 --- /dev/null +++ b/relational_store/frameworks/native/gdb/src/connection.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024 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 "connection.h" + +#include "aip_errors.h" + +namespace OHOS::DistributedDataAip { +static Connection::Creator g_creators[static_cast(DBType::DB_BUTT)] = { nullptr, nullptr }; + +std::pair> Connection::Create(const StoreConfig &config, const bool isWriter) +{ + auto dbType = config.GetDbType(); + if (dbType < DBType::DB_GRAPH || dbType >= DBType::DB_BUTT) { + return { E_NOT_SUPPORT, nullptr }; + } + + auto creator = g_creators[static_cast(dbType)]; + if (creator == nullptr) { + return { E_NOT_SUPPORT, nullptr }; + } + + return creator(config, isWriter); +} + +int32_t Connection::RegisterCreator(DBType dbType, Creator creator) +{ + if (dbType < DBType::DB_GRAPH || dbType >= DBType::DB_BUTT) { + return E_NOT_SUPPORT; + } + + if (g_creators[static_cast(dbType)] != nullptr) { + return E_OK; + } + + g_creators[static_cast(dbType)] = creator; + return E_OK; +} + +int Connection::SetId(int id) +{ + id_ = id; + return id_; +} + +int Connection::GetId() const +{ + return id_; +} + +} // namespace OHOS::DistributedDataAip diff --git a/relational_store/frameworks/native/gdb/src/connection_pool.cpp b/relational_store/frameworks/native/gdb/src/connection_pool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6b36459a990c27f51501c154fbed5b84051d19c6 --- /dev/null +++ b/relational_store/frameworks/native/gdb/src/connection_pool.cpp @@ -0,0 +1,475 @@ +/* + * Copyright (c) 2024 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 "GdbConnPool" +#include "connection_pool.h" + +#include +#include + +#include "aip_errors.h" +#include "gdb_utils.h" +#include "logger.h" +#include "rdb_store_config.h" + +namespace OHOS::DistributedDataAip { +using namespace std::chrono; + +std::shared_ptr ConnectionPool::Create(const StoreConfig &config, int &errCode) +{ + std::shared_ptr pool = std::make_shared(config); + if (pool == nullptr) { + LOG_ERROR("ConnectionPool::Create new failed, pool is nullptr."); + errCode = E_INIT_CONN_POOL_FAILED; + return nullptr; + } + std::shared_ptr conn; + for (uint32_t retry = 0; retry < ITERS_COUNT; ++retry) { + std::tie(errCode, conn) = pool->Init(); + if (errCode != E_GRD_DATA_CORRUPTED) { + break; + } + config.SetIter(ITER_V1); + } + return errCode == E_OK ? pool : nullptr; +} + +ConnectionPool::ConnectionPool(const StoreConfig &storeConfig) : config_(storeConfig), writers_(), readers_() +{ +} + +std::pair> ConnectionPool::Init(bool isAttach, bool needWriter) +{ + std::pair> result; + auto &[errCode, conn] = result; + config_.GenerateEncryptedKey(); + // write connect count is 1 + std::shared_ptr node; + std::tie(errCode, node) = writers_.Initialize( + [this, isAttach]() { return Connection::Create(config_, true); }, 1, config_.GetWriteTime(), true, needWriter); + conn = Convert2AutoConn(node); + if (errCode != E_OK) { + return result; + } + + maxReader_ = GetMaxReaders(config_); + LOG_DEBUG("ConnectionPool::Init maxReader=%{public}d", maxReader_); + // max read connect count is 64 + if (maxReader_ > 64) { + LOG_ERROR("maxReader is too big. maxReader=%{public}d", maxReader_); + return { E_ARGS_READ_CON_OVERLOAD, nullptr }; + } + auto [ret, nodeRead] = readers_.Initialize([this, isAttach]() { return Connection::Create(config_, false); }, + maxReader_, config_.GetReadTime(), maxReader_ == 0); + errCode = ret; + return result; +} + +ConnectionPool::~ConnectionPool() +{ + LOG_DEBUG("enter"); + CloseAllConnections(); +} + +int32_t ConnectionPool::GetMaxReaders(const StoreConfig &config) +{ + return config.GetReadConSize(); +} + +std::shared_ptr ConnectionPool::Convert2AutoConn(std::shared_ptr node, bool isTrans) +{ + if (node == nullptr) { + return nullptr; + } + + auto conn = node->GetConnect(); + if (conn == nullptr) { + return nullptr; + } + if (isTrans) { + transCount_++; + } + + return std::shared_ptr(conn.get(), [pool = weak_from_this(), node, isTrans](auto *) mutable { + auto realPool = pool.lock(); + if (realPool == nullptr) { + return; + } + realPool->ReleaseNode(node, !isTrans); + if (isTrans) { + realPool->transCount_--; + } + node = nullptr; + }); +} + +void ConnectionPool::CloseAllConnections() +{ + writers_.Clear(); + readers_.Clear(); +} + +std::pair> ConnectionPool::CreateTransConn() +{ + if (transCount_ >= MAX_TRANS) { + writers_.Dump("NO TRANS", transCount_ + isInTransaction_); + return { E_DATABASE_BUSY, nullptr }; + } + auto [errCode, node] = writers_.Create(); + return { errCode, Convert2AutoConn(node, true) }; +} + +std::shared_ptr ConnectionPool::Acquire(bool isReadOnly, std::chrono::milliseconds ms) +{ + Container *container = (isReadOnly && maxReader_ != 0) ? &readers_ : &writers_; + auto node = container->Acquire(ms); + if (node == nullptr) { + const char *header = (isReadOnly && maxReader_ != 0) ? "readers_" : "writers_"; + container->Dump(header, transCount_ + isInTransaction_); + return nullptr; + } + return Convert2AutoConn(node); +} + +std::shared_ptr ConnectionPool::AcquireRef(bool isReadOnly, std::chrono::milliseconds ms) +{ + if (maxReader_ != 0) { + return Acquire(isReadOnly, ms); + } + auto node = writers_.Acquire(ms); + if (node == nullptr) { + writers_.Dump("writers_", transCount_ + isInTransaction_); + return nullptr; + } + auto conn = node->connect_; + writers_.Release(node); + return {conn.get(), [pool = weak_from_this(), conn](Connection *) { + auto realPool = pool.lock(); + if (realPool == nullptr) { + return; + } + realPool->writers_.cond_.notify_all(); + }}; +} + +void ConnectionPool::ReleaseNode(std::shared_ptr node, bool reuse) +{ + if (node == nullptr) { + return; + } + auto now = steady_clock::now(); + auto timeout = now > (failedTime_.load() + minutes(CHECK_POINT_INTERVAL)) || now < failedTime_.load() || + failedTime_.load() == steady_clock::time_point(); + auto transCount = transCount_ + isInTransaction_; + auto remainCount = reuse ? transCount : transCount - 1; + auto errCode = node->Unused(remainCount, timeout); + if (errCode == E_DATABASE_BUSY) { + writers_.Dump("WAL writers_", transCount); + readers_.Dump("WAL readers_", transCount); + } + LOG_DEBUG( + "ConnectionPool::ReleaseNode reuse=%{public}d,timeout=%{public}d,remainCount=%{public}d,isWriter=%{public}d", + reuse, timeout, remainCount, node->IsWriter()); + + if (node->IsWriter() && errCode != E_NOT_SUPPORT) { + failedTime_ = errCode != E_OK ? now : steady_clock::time_point(); + } + + auto &container = node->IsWriter() ? writers_ : readers_; + if (reuse) { + container.Release(node); + } else { + container.Drop(node); + } +} + +int ConnectionPool::RestartReaders() +{ + readers_.Clear(); + auto [errCode, node] = readers_.Initialize( + [this]() { return Connection::Create(config_, false); }, maxReader_, config_.GetReadTime(), maxReader_ == 0); + return errCode; +} + +int32_t ConnectionPool::Dump(bool isWriter, const char *header) +{ + Container *container = (isWriter || maxReader_ == 0) ? &writers_ : &readers_; + container->Dump(header, transCount_ + isInTransaction_); + return E_OK; +} + +ConnectionPool::ConnNode::ConnNode(std::shared_ptr conn) : connect_(std::move(conn)) +{ +} + +std::shared_ptr ConnectionPool::ConnNode::GetConnect() +{ + tid_ = gettid(); + time_ = steady_clock::now(); + return connect_; +} + +int64_t ConnectionPool::ConnNode::GetUsingTime() const +{ + auto time = steady_clock::now() - time_; + return duration_cast(time).count(); +} + +int32_t ConnectionPool::ConnNode::Unused(int32_t count, bool timeout) +{ + time_ = steady_clock::now(); + if (connect_ == nullptr) { + return E_OK; + } + time_ = steady_clock::now(); + if (!connect_->IsWriter()) { + tid_ = 0; + } + return E_OK; +} + +bool ConnectionPool::ConnNode::IsWriter() const +{ + if (connect_ != nullptr) { + return connect_->IsWriter(); + } + return false; +} + +std::pair> ConnectionPool::Container::Initialize( + Creator creator, int32_t max, int32_t timeout, bool disable, bool acquire) +{ + std::shared_ptr connNode = nullptr; + { + std::unique_lock lock(mutex_); + disable_ = disable; + max_ = max; + creator_ = std::move(creator); + timeout_ = std::chrono::seconds(timeout); + for (int i = 0; i < max; ++i) { + auto errCode = ExtendNode(); + if (errCode != E_OK) { + nodes_.clear(); + details_.clear(); + return { errCode, nullptr }; + } + } + + if (acquire && count_ > 0) { + connNode = nodes_.back(); + nodes_.pop_back(); + count_--; + } + } + cond_.notify_all(); + return { E_OK, connNode }; +} + +std::shared_ptr ConnectionPool::Container::Acquire(std::chrono::milliseconds milliS) +{ + auto interval = (milliS == INVALID_TIME) ? timeout_ : milliS; + std::unique_lock lock(mutex_); + LOG_DEBUG("count %{public}d max %{public}d total %{public}d left %{public}d right%{public}d", count_, max_, total_, + left_, right_); + if (max_ == 0) { + return nullptr; + } + auto waiter = [this]() -> bool { + if (count_ > 0) { + return true; + } + + if (disable_) { + return false; + } + return ExtendNode() == E_OK; + }; + if (cond_.wait_for(lock, interval, waiter)) { + if (nodes_.empty()) { + LOG_ERROR("nodes is empty.count %{public}d max %{public}d total %{public}d left %{public}d right%{public}d", + count_, max_, total_, left_, right_); + count_ = 0; + return nullptr; + } + auto node = nodes_.back(); + nodes_.pop_back(); + count_--; + return node; + } + return nullptr; +} + +std::pair> ConnectionPool::Container::Create() +{ + std::unique_lock lock(mutex_); + if (creator_ == nullptr) { + return { E_NOT_SUPPORT, nullptr }; + } + + auto [errCode, conn] = creator_(); + if (conn == nullptr) { + return { errCode, nullptr }; + } + + auto node = std::make_shared(conn); + if (node == nullptr) { + return { E_ERROR, nullptr }; + } + node->id_ = MIN_TRANS_ID + trans_; + conn->SetId(node->id_); + details_.push_back(node); + trans_++; + return { E_OK, node }; +} + +int32_t ConnectionPool::Container::ExtendNode() +{ + if (creator_ == nullptr) { + return E_ERROR; + } + auto [errCode, conn] = creator_(); + if (conn == nullptr) { + return errCode; + } + auto node = std::make_shared(conn); + node->id_ = right_++; + conn->SetId(node->id_); + nodes_.push_back(node); + details_.push_back(node); + count_++; + total_++; + return E_OK; +} + +void ConnectionPool::Container::Disable() +{ + disable_ = true; + cond_.notify_one(); +} + +void ConnectionPool::Container::Enable() +{ + disable_ = false; + cond_.notify_one(); +} + +int32_t ConnectionPool::Container::Release(std::shared_ptr node) +{ + { + std::unique_lock lock(mutex_); + if (node->id_ < left_ || node->id_ >= right_) { + return E_OK; + } + if (count_ == max_) { + total_ = total_ > count_ ? total_ - 1 : count_; + RelDetails(node); + } else { + nodes_.push_front(node); + count_++; + } + } + cond_.notify_one(); + return E_OK; +} + +int32_t ConnectionPool::Container::Drop(std::shared_ptr node) +{ + { + std::unique_lock lock(mutex_); + RelDetails(node); + } + cond_.notify_one(); + return E_OK; +} + +int32_t ConnectionPool::Container::RelDetails(std::shared_ptr node) +{ + for (auto it = details_.begin(); it != details_.end();) { + auto detailNode = it->lock(); + if (detailNode == nullptr || detailNode->id_ == node->id_) { + it = details_.erase(it); + } else { + it++; + } + } + return E_OK; +} + +int32_t ConnectionPool::Container::Clear() +{ + std::list> nodes; + std::list> details; + { + std::unique_lock lock(mutex_); + nodes = std::move(nodes_); + details = std::move(details_); + disable_ = true; + total_ = 0; + count_ = 0; + if (right_ > MAX_RIGHT) { + right_ = 0; + } + left_ = right_; + creator_ = nullptr; + } + nodes.clear(); + details.clear(); + LOG_DEBUG( + "Container::Clear success count=%{public}d, max=%{public}d, total=%{public}d, left=%{public}d, " + "right=%{public}d", count_, max_, total_, left_, right_); + return 0; +} + +bool ConnectionPool::Container::IsFull() +{ + std::unique_lock lock(mutex_); + return total_ == count_; +} + +int32_t ConnectionPool::Container::Dump(const char *header, int32_t count) +{ + std::string info; + std::vector> details; + std::string title = "B_M_T_C[" + std::to_string(count) + "," + std::to_string(max_) + "," + + std::to_string(total_) + "," + std::to_string(count_) + "]"; + { + std::unique_lock lock(mutex_); + details.reserve(details_.size()); + for (auto &detail : details_) { + auto node = detail.lock(); + if (node == nullptr) { + continue; + } + details.push_back(node); + } + } + + for (auto &node : details) { + info.append("<") + .append(std::to_string(node->id_)) + .append(",") + .append(std::to_string(node->tid_)) + .append(",") + .append(std::to_string(node->GetUsingTime())) + .append(">"); + // 256 represent that limit to info length + if (info.size() > 256) { + LOG_WARN("%{public}s %{public}s:%{public}s", header, title.c_str(), info.c_str()); + info.clear(); + } + } + LOG_WARN("%{public}s %{public}s:%{public}s", header, title.c_str(), info.c_str()); + return 0; +} +} // namespace OHOS::DistributedDataAip \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/src/db_helper.cpp b/relational_store/frameworks/native/gdb/src/db_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..38369dacf8a4228a37881f1df84e0d20209eadf9 --- /dev/null +++ b/relational_store/frameworks/native/gdb/src/db_helper.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 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 "aip_errors.h" +#include "db_store_manager.h" +#include "db_trace.h" +#include "gdb_helper.h" + +namespace OHOS::DistributedDataAip { + +std::shared_ptr GDBHelper::GetDBStore(const StoreConfig &config, int &errCode) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + return StoreManager::GetInstance().GetDBStore(config, errCode); +} + +int GDBHelper::DeleteDBStore(const StoreConfig &config) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + return StoreManager::GetInstance().Delete(config.GetFullPath()) ? E_OK : E_ERROR; +} +} // namespace OHOS::DistributedDataAip \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/src/db_store_impl.cpp b/relational_store/frameworks/native/gdb/src/db_store_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6817e29a00dd167fa4f83d44aa4a9c064060cdfb --- /dev/null +++ b/relational_store/frameworks/native/gdb/src/db_store_impl.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2024 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 "GdbStore" +#include "db_store_impl.h" + +#include + +#include "aip_errors.h" +#include "connection.h" +#include "db_trace.h" +#include "logger.h" +#include "gdb_utils.h" +#include "transaction.h" +#include "transaction_impl.h" + +namespace OHOS::DistributedDataAip { + +constexpr int32_t MAX_GQL_LEN = 1024 * 1024; + +DBStoreImpl::DBStoreImpl(StoreConfig config) : config_(std::move(config)) +{ +} + +DBStoreImpl::~DBStoreImpl() +{ + LOG_DEBUG("DBStoreImpl enter"); + Close(); +} + +std::shared_ptr DBStoreImpl::GetConnectionPool() +{ + std::lock_guard lock(mutex_); + return connectionPool_; +} + +void DBStoreImpl::SetConnectionPool(std::shared_ptr connectionPool) +{ + std::lock_guard lock(mutex_); + connectionPool_ = connectionPool; +} + +int32_t DBStoreImpl::InitConn() +{ + if (GetConnectionPool() != nullptr) { + LOG_INFO("connectionPool_ is not nullptr"); + return E_OK; + } + int errCode; + auto connectionPool = ConnectionPool::Create(config_, errCode); + if (errCode != E_OK || connectionPool == nullptr) { + LOG_ERROR("Create conn failed, ret=%{public}d", errCode); + return errCode; + } + SetConnectionPool(connectionPool); + return E_OK; +} + +std::pair> DBStoreImpl::QueryGql(const std::string &gql) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + if (gql.empty() || gql.length() > MAX_GQL_LEN) { + LOG_ERROR("Gql is empty or length is too long."); + return { E_INVALID_ARGS, nullptr }; + } + if (GdbUtils::IsTransactionGql(gql)) { + LOG_ERROR("Transaction related statements are not supported."); + return { E_INVALID_ARGS, nullptr }; + } + auto connectionPool = GetConnectionPool(); + if (connectionPool == nullptr) { + LOG_ERROR("The connpool is nullptr."); + return { E_STORE_HAS_CLOSED, std::make_shared() }; + } + auto conn = connectionPool->AcquireRef(true); + if (conn == nullptr) { + LOG_ERROR("Get conn failed"); + return { E_ACQUIRE_CONN_FAILED, std::make_shared() }; + } + auto [ret, stmt] = conn->CreateStatement(gql, conn); + if (ret != E_OK || stmt == nullptr) { + LOG_ERROR("Create stmt failed, ret=%{public}d", ret); + return { ret, std::make_shared() }; + } + + auto result = std::make_shared(); + ret = result->InitData(stmt); + if (ret != E_OK) { + LOG_ERROR("Get FullResult failed, ret=%{public}d", ret); + return { ret, std::make_shared() }; + } + + return { E_OK, result }; +} + +std::pair> DBStoreImpl::ExecuteGql(const std::string &gql) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + if (gql.empty() || gql.length() > MAX_GQL_LEN) { + LOG_ERROR("Gql is empty or length is too long."); + return { E_INVALID_ARGS, std::make_shared() }; + } + if (GdbUtils::IsTransactionGql(gql)) { + LOG_ERROR("Transaction related statements are not supported."); + return { E_INVALID_ARGS, std::make_shared() }; + } + auto connectionPool = GetConnectionPool(); + if (connectionPool == nullptr) { + LOG_ERROR("The connpool is nullptr."); + return { E_STORE_HAS_CLOSED, std::make_shared() }; + } + auto conn = connectionPool->AcquireRef(false); + if (conn == nullptr) { + LOG_ERROR("Get conn failed"); + return { E_ACQUIRE_CONN_FAILED, std::make_shared() }; + } + auto [ret, stmt] = conn->CreateStatement(gql, conn); + if (ret != E_OK || stmt == nullptr) { + LOG_ERROR("Create stmt failed, ret=%{public}d", ret); + return { ret, std::make_shared() }; + } + ret = stmt->Step(); + if (ret != E_OK) { + LOG_ERROR("Step stmt failed, ret=%{public}d", ret); + } + return { ret, std::make_shared() }; +} + +std::pair> DBStoreImpl::CreateTransaction() +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + auto connectionPool = GetConnectionPool(); + if (connectionPool == nullptr) { + LOG_ERROR("The connpool is nullptr."); + return { E_STORE_HAS_CLOSED, nullptr }; + } + auto [ret, conn] = connectionPool->CreateTransConn(); + if (ret != E_OK || conn == nullptr) { + LOG_ERROR("Get conn failed"); + return { ret, nullptr }; + } + std::shared_ptr trans; + std::tie(ret, trans) = TransactionImpl::Create(conn); + if (ret != E_OK || trans == nullptr) { + LOG_ERROR("Create trans failed, ret=%{public}d", ret); + return { ret, nullptr }; + } + + std::lock_guard lock(transMutex_); + for (auto it = transactions_.begin(); it != transactions_.end();) { + if (it->expired()) { + it = transactions_.erase(it); + } else { + it++; + } + } + transactions_.push_back(trans); + return { ret, trans }; +} + +int32_t DBStoreImpl::Close() +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + SetConnectionPool(nullptr); + + std::lock_guard lock(transMutex_); + for (auto &trans : transactions_) { + auto realTrans = trans.lock(); + if (realTrans) { + (void)realTrans->Close(); + } + } + transactions_ = {}; + return E_OK; +} +} // namespace OHOS::DistributedDataAip \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/src/db_store_manager.cpp b/relational_store/frameworks/native/gdb/src/db_store_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65c1ca1dbed185c90e8b049f0e97e951259e09f2 --- /dev/null +++ b/relational_store/frameworks/native/gdb/src/db_store_manager.cpp @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2024 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 "GdbStoreManager" +#include "db_store_manager.h" + +#include + +#include + +#include "aip_errors.h" +#include "db_store_impl.h" +#include "gdb_utils.h" +#include "logger.h" +#include "security_label.h" + +namespace OHOS::DistributedDataAip { +StoreManager &StoreManager::GetInstance() +{ + static StoreManager manager; + return manager; +} + +StoreManager::StoreManager() = default; + +StoreManager::~StoreManager() +{ + Clear(); +} + +bool StoreManager::IsValidName(const std::string &name) +{ + const std::regex pattern("^[a-zA-Z0-9_]+$"); + return std::regex_match(name, pattern); +} + +bool StoreManager::IsValidSecurityLevel(const int32_t securityLevel) +{ + return securityLevel >= SecurityLevel::S1 && securityLevel <= SecurityLevel::S4; +} + +std::shared_ptr StoreManager::GetDBStore(const StoreConfig &config, int &errCode) +{ + if (!IsValidName(config.GetName())) { + LOG_ERROR("GetDBStore failed. Invalid name"); + errCode = E_GRD_INVAILD_NAME_ERR; + return nullptr; + } + if (!IsValidSecurityLevel(config.GetSecurityLevel())) { + LOG_ERROR("GetDBStore failed. Invalid securityLevel: %{public}d", config.GetSecurityLevel()); + errCode = E_INVALID_ARGS; + return nullptr; + } + std::lock_guard lock(mutex_); + auto path = config.GetFullPath(); + if (storeCache_.find(path) != storeCache_.end()) { + std::shared_ptr dbStore = storeCache_[path].lock(); + if (dbStore != nullptr) { + LOG_ERROR("GetDBStore reuse success."); + return dbStore; + } + storeCache_.erase(path); + } + // open and store DBStore + std::shared_ptr dbStore = std::make_shared(config); + errCode = dbStore->InitConn(); + if (errCode != E_OK) { + LOG_ERROR("GetDBStore InitConn failed, name=%{public}s, errCode=%{public}d", + GdbUtils::Anonymous(config.GetName()).c_str(), errCode); + return nullptr; + } + errCode = SetSecurityLabel(config); + if (errCode != E_OK) { + LOG_ERROR("GetDBStore SetSecurityLabel failed, errCode=%{public}d", errCode); + return nullptr; + } + storeCache_[path] = dbStore; + return dbStore; +} + +void StoreManager::Clear() +{ + std::lock_guard lock(mutex_); + auto iter = storeCache_.begin(); + while (iter != storeCache_.end()) { + if (auto store = iter->second.lock()) { + store->Close(); + } + iter = storeCache_.erase(iter); + } + storeCache_.clear(); +} + +bool StoreManager::Delete(const std::string &path) +{ + LOG_DEBUG("Delete file, path=%{public}s", GdbUtils::Anonymous(path).c_str()); + { + std::lock_guard lock(mutex_); + auto item = storeCache_.find(path); + if (item != storeCache_.end()) { + if (auto store = item->second.lock()) { + store->Close(); + } + storeCache_.erase(path); // clean invalid store ptr + } + } + + bool deleteResult = true; + for (auto &suffix : GRD_POST_FIXES) { + deleteResult = DeleteFile(path + suffix) && deleteResult; + } + return deleteResult; +} + +bool StoreManager::DeleteFile(const std::string &path) +{ + if (access(path.c_str(), 0) != 0) { + LOG_WARN("access return, path=%{public}s", GdbUtils::Anonymous(path).c_str()); + return true; + } + auto ret = remove(path.c_str()); + if (ret != 0) { + LOG_ERROR("remove file failed errno %{public}d ret %{public}d %{public}s", errno, ret, + GdbUtils::Anonymous(path).c_str()); + return false; + } + return true; +} + +int StoreManager::SetSecurityLabel(const StoreConfig &config) +{ + if (config.GetSecurityLevel() >= SecurityLevel::S1 && config.GetSecurityLevel() <= SecurityLevel::S4) { + auto toSetLevel = GetSecurityLevelValue(static_cast(config.GetSecurityLevel())); + auto errCode = + FileManagement::ModuleSecurityLabel::SecurityLabel::SetSecurityLabel(config.GetFullPath(), toSetLevel) + ? E_OK + : E_CONFIG_INVALID_CHANGE; + if (errCode != E_OK) { + auto currentLevel = GetFileSecurityLevel(config.GetFullPath()); + LOG_ERROR( + "Set security level:%{public}s -> %{public}s, result=%{public}d, errno=%{public}d, name=%{public}s.", + currentLevel.c_str(), toSetLevel.c_str(), errCode, errno, + GdbUtils::Anonymous(config.GetName()).c_str()); + } + return errCode; + } + return E_OK; +} + +std::string StoreManager::GetSecurityLevelValue(SecurityLevel securityLevel) +{ + switch (securityLevel) { + case SecurityLevel::S1: + return "s1"; + case SecurityLevel::S2: + return "s2"; + case SecurityLevel::S3: + return "s3"; + case SecurityLevel::S4: + return "s4"; + default: + return ""; + } +} + +std::string StoreManager::GetFileSecurityLevel(const std::string &filePath) +{ + return FileManagement::ModuleSecurityLabel::SecurityLabel::GetSecurityLabel(filePath); +} + +} // namespace OHOS::DistributedDataAip \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/src/edge.cpp b/relational_store/frameworks/native/gdb/src/edge.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b36e883bca175e7cdbe33e85335b476003a3bf4 --- /dev/null +++ b/relational_store/frameworks/native/gdb/src/edge.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2024 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 "GdbEdge" +#include + +#include "aip_errors.h" +#include "full_result.h" +#include "logger.h" + +namespace OHOS::DistributedDataAip { +Edge::Edge() : Vertex(), sourceId_("0"), targetId_("0") +{ +} + +Edge::Edge(std::string id, std::string label, std::string sourceId, std::string targetId) + : Vertex(std::move(id), std::move(label)), sourceId_(std::move(sourceId)), targetId_(std::move(targetId)) +{ +} + +Edge::Edge(const std::shared_ptr &element, std::string sourceId, std::string targetId) + : sourceId_(std::move(sourceId)), targetId_(std::move(targetId)) +{ + if (element != nullptr) { + id_ = element->GetId(); + label_ = element->GetLabel(); + properties_ = element->GetProperties(); + } +} + +std::string Edge::GetSourceId() const +{ + return sourceId_; +} + +void Edge::SetSourceId(std::string sourceId) +{ + sourceId_ = std::move(sourceId); +} + +std::string Edge::GetTargetId() const +{ + return targetId_; +} + +void Edge::SetTargetId(std::string targetId) +{ + targetId_ = std::move(targetId); +} + +std::string Edge::GetIdFromJson(const std::string &key, const nlohmann::json &json, int32_t &errCode) +{ + if (key.empty() || (!json.at(key).is_string() && !json.at(key).is_number())) { + LOG_ERROR("edge start or end id is not number or string. jsonStr=%{public}s", json.dump().c_str()); + errCode = E_PARSE_JSON_FAILED; + return ""; + } + errCode = E_OK; + if (json.at(key).is_number()) { + auto sourceId = json.at(key).get(); + return std::to_string(sourceId); + } + if (json.at(key).is_string()) { + return json.at(key).get(); + } + errCode = E_PARSE_JSON_FAILED; + return ""; +} + +std::shared_ptr Edge::Parse(const nlohmann::json &json, int32_t &errCode) +{ + if (!json.contains(Edge::SOURCEID) || !json.contains(Edge::TARGETID)) { + LOG_ERROR("edge format error. jsonStr=%{public}s", json.dump().c_str()); + errCode = E_PARSE_JSON_FAILED; + return nullptr; + } + errCode = E_OK; + std::shared_ptr element = Vertex::Parse(json, errCode); + if (errCode != E_OK || element == nullptr) { + LOG_ERROR("parse edge element failed. jsonStr=%{public}s", json.dump().c_str()); + return nullptr; + } + auto sourceId = Edge::GetIdFromJson(Edge::SOURCEID, json, errCode); + if (errCode != E_OK) { + return nullptr; + } + auto targetId = Edge::GetIdFromJson(Edge::TARGETID, json, errCode); + if (errCode != E_OK) { + return nullptr; + } + return std::make_shared(element, sourceId, targetId); +} +} // namespace OHOS::DistributedDataAip diff --git a/relational_store/frameworks/native/gdb/src/full_result.cpp b/relational_store/frameworks/native/gdb/src/full_result.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bde9228a258c7bdb285cda8ebc5be4c1b91e38c6 --- /dev/null +++ b/relational_store/frameworks/native/gdb/src/full_result.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 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 "GdbDataSet" +#include "full_result.h" + +#include "aip_errors.h" +#include "statement.h" +#include "logger.h" + +namespace OHOS::DistributedDataAip { +int32_t FullResult::InitData(std::shared_ptr stmt) +{ + if (stmt == nullptr) { + return E_STATEMENT_EMPTY; + } + data_ = std::vector>(); + int32_t errCode = stmt->Step(); + while (errCode == E_OK) { + auto [ret, oneResult] = GetRow(stmt); + if (ret != E_OK) { + return ret; + } + data_.emplace_back(oneResult); + errCode = stmt->Step(); + } + return (errCode == E_GRD_NO_DATA) ? E_OK : errCode; +} + +std::vector> FullResult::GetAllData() const +{ + return data_; +} +std::pair> FullResult::GetRow(std::shared_ptr stmt) +{ + std::unordered_map res; + if (stmt == nullptr) { + return { E_STATEMENT_EMPTY, res }; + } + auto columnCount = stmt->GetColumnCount(); + if (columnCount == 0) { + LOG_ERROR("GetKeys failed ret=%{public}d.", E_NO_DATA); + return { E_NO_DATA, res }; + } + + for (int i = 0; i < columnCount; i++) { + auto [ret, key] = stmt->GetColumnName(i); + if (ret != E_OK) { + LOG_ERROR("GetKeys failed ret=%{public}d.", ret); + return { ret, res }; + } + auto [err, value] = stmt->GetColumnValue(i); + if (err != E_OK) { + LOG_ERROR("GetValue failed, key=%{public}s, ret=%{public}d.", key.c_str(), err); + return { err, res }; + } + res.emplace(key, value); + } + return { E_OK, res }; +} + +} // namespace OHOS::DistributedDataAip \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/src/gdb_utils.cpp b/relational_store/frameworks/native/gdb/src/gdb_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b23b250ebc65866683658fb16858419362f2cc41 --- /dev/null +++ b/relational_store/frameworks/native/gdb/src/gdb_utils.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2024 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 "RdbGqlUtils" +#include "gdb_utils.h" + +#include +#include +#include +#include + +#include "aip_errors.h" + +namespace OHOS::DistributedDataAip { +constexpr int32_t CONTINUOUS_DIGITS_MINI_SIZE = 5; +constexpr int32_t FILE_PATH_MINI_SIZE = 6; +constexpr int32_t AREA_MINI_SIZE = 4; +constexpr int32_t AREA_OFFSET_SIZE = 5; +constexpr int32_t PRE_OFFSET_SIZE = 1; +constexpr int32_t PREFIX_POS = 0; +constexpr int32_t PREFIX_LEN = 3; + +bool GdbUtils::IsTransactionGql(const std::string &gql) +{ + auto prefix = gql.substr(PREFIX_POS, PREFIX_LEN); + if (prefix == "STA" || prefix == "COM" || prefix == "ROL") { + return true; + } + return false; +} + +int GdbUtils::CreateDirectory(const std::string &databaseDir) +{ + std::string tempDirectory = databaseDir; + std::vector directories; + + size_t pos = tempDirectory.find('/'); + while (pos != std::string::npos) { + std::string directory = tempDirectory.substr(0, pos); + directories.push_back(directory); + tempDirectory = tempDirectory.substr(pos + 1); + pos = tempDirectory.find('/'); + } + directories.push_back(tempDirectory); + + std::string databaseDirectory; + for (const std::string &directory : directories) { + databaseDirectory += "/" + directory; + if (access(databaseDirectory.c_str(), F_OK) != 0) { + if (mkdir(databaseDirectory.c_str(), DIR_RWXRWS__X)) { + return E_CREATE_FOLDER_FAIT; + } + } + } + return E_OK; +} + +std::string GdbUtils::Anonymous(const std::string &srcFile) +{ + auto pre = srcFile.find("/"); + auto end = srcFile.rfind("/"); + if (pre == std::string::npos || end - pre < FILE_PATH_MINI_SIZE) { + return GetAnonymousName(srcFile); + } + auto path = srcFile.substr(pre, end - pre); + auto area = path.find("/el"); + if (area == std::string::npos || area + AREA_MINI_SIZE > path.size()) { + path = ""; + } else if (area + AREA_OFFSET_SIZE < path.size()) { + path = path.substr(area, AREA_MINI_SIZE) + "/***"; + } else { + path = path.substr(area, AREA_MINI_SIZE); + } + std::string fileName = srcFile.substr(end); // rdb file name + fileName = GetAnonymousName(fileName); + return srcFile.substr(0, pre + PRE_OFFSET_SIZE) + "***" + path + fileName; +} + +std::string GdbUtils::GetAnonymousName(const std::string &fileName) +{ + std::vector alnum; + std::vector noAlnum; + std::string alnumStr; + std::string noAlnumStr; + for (const auto &letter : fileName) { + if (isxdigit(letter)) { + if (!noAlnumStr.empty()) { + noAlnum.push_back(noAlnumStr); + noAlnumStr.clear(); + alnum.push_back(""); + } + alnumStr += letter; + } else { + if (!alnumStr.empty()) { + alnum.push_back(alnumStr); + alnumStr.clear(); + noAlnum.push_back(""); + } + noAlnumStr += letter; + } + } + if (!alnumStr.empty()) { + alnum.push_back(alnumStr); + noAlnum.push_back(""); + } + if (!noAlnumStr.empty()) { + noAlnum.push_back(alnumStr); + alnum.push_back(""); + } + std::string res = ""; + for (size_t i = 0; i < alnum.size(); ++i) { + res += (AnonyDigits(alnum[i]) + noAlnum[i]); + } + return res; +} + +std::string GdbUtils::AnonyDigits(const std::string &fileName) +{ + std::string::size_type digitsNum = fileName.size(); + if (digitsNum < CONTINUOUS_DIGITS_MINI_SIZE) { + return fileName; + } + constexpr std::string::size_type longDigits = 7; + std::string::size_type endDigitsNum = 4; + std::string::size_type shortEndDigitsNum = 3; + std::string name = fileName; + std::string last = ""; + if (digitsNum >= CONTINUOUS_DIGITS_MINI_SIZE && digitsNum < longDigits) { + last = name.substr(name.size() - shortEndDigitsNum); + } else { + last = name.substr(name.size() - endDigitsNum); + } + + return "***" + last; +} + +void GdbUtils::ClearAndZeroString(std::string &str) +{ + str.clear(); + std::fill(str.begin(), str.end(), char(0)); +} + +std::string GdbUtils::GetConfigStr(const std::vector &keys, bool isEncrypt) +{ + std::string config = "{"; + if (isEncrypt) { + const size_t keyBuffSize = keys.size() * 2 + 1; // 2 hex number can represent a uint8_t, 1 is for '\0' + std::vector keyBuff(keyBuffSize); + config += "\"isEncrypted\":1,"; + config += "\"hexPassword\":\""; + config += GetEncryptKey(keys, keyBuff.data(), keyBuffSize); + config += "\","; + keyBuff.assign(keyBuffSize, 0); + } + config += GRD_OPEN_CONFIG_STR; + config += "}"; + return config; +} + +const char *GdbUtils::GetEncryptKey(const std::vector &encryptedKey, char outBuff[], size_t outBufSize) +{ + char *buffer = nullptr; + auto keySize = encryptedKey.size(); + for (size_t i = 0; i < keySize; i++) { + buffer = (char *)(outBuff + i * 2); // each uint8_t will convert to 2 hex char + // each uint8_t will convert to 2 hex char + errno_t err = snprintf_s(buffer, outBufSize - i * 2, outBufSize - i * 2, "%02x", encryptedKey[i]); + if (err < 0) { + return nullptr; + } + } + return outBuff; +} +} // namespace OHOS::DistributedDataAip diff --git a/relational_store/frameworks/native/gdb/src/graph_connection.cpp b/relational_store/frameworks/native/gdb/src/graph_connection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e21813563ae8020faa4d44f00cc17f685b544542 --- /dev/null +++ b/relational_store/frameworks/native/gdb/src/graph_connection.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2024 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 "GdbConn" +#include "graph_connection.h" + +#include + +#include +#include + +#include "aip_errors.h" +#include "gdb_utils.h" +#include "graph_statement.h" +#include "logger.h" +#include "rdb_security_manager.h" +#include "securec.h" + +namespace OHOS::DistributedDataAip { +__attribute__((used)) +const int32_t GraphConnection::regCreator_ = Connection::RegisterCreator(DBType::DB_GRAPH, GraphConnection::Create); + +std::pair> GraphConnection::Create(const StoreConfig &config, bool isWriter) +{ + LOG_DEBUG("GraphConnection::Create start, name=%{public}s, isWriter=%{public}d", + GdbUtils::Anonymous(config.GetName()).c_str(), isWriter); + std::pair> result = { E_INNER_ERROR, nullptr }; + auto &[errCode, conn] = result; + for (size_t i = 0; i < ITERS_COUNT; i++) { + std::shared_ptr connection = std::make_shared(config, isWriter); + if (connection == nullptr) { + LOG_ERROR("Open new failed, connection is nullptr. name=%{public}s", + GdbUtils::Anonymous(config.GetName()).c_str()); + return result; + } + errCode = connection->InnerOpen(config); + if (errCode == E_OK) { + conn = connection; + break; + } + } + return result; +} + +GraphConnection::GraphConnection(const StoreConfig &config, bool isWriter) : config_(config), isWriter_(isWriter) +{ +} + +GraphConnection::~GraphConnection() +{ + LOG_DEBUG("enter"); + if (dbHandle_ != nullptr) { + int errCode = GrdAdapter::Close(dbHandle_, 0); + if (errCode != E_OK) { + LOG_ERROR("could not close database, err=%{public}d", errCode); + } + dbHandle_ = nullptr; + } +} + +int GraphConnection::InnerOpen(const StoreConfig &config) +{ + std::string dbPath = config.GetFullPath(); + std::vector newKey = config.GetNewEncryptKey(); + if (!newKey.empty()) { + // NewKey exists, oldKey has expired, ResetKey is required + newKey.assign(newKey.size(), 0); + auto errCode = ResetKey(config); + if (errCode != E_OK) { + LOG_ERROR("Can not reset key %{public}d.", errCode); + return errCode; + } + } + std::vector key = config.GetEncryptKey(); + std::string configJson = GdbUtils::GetConfigStr(key, config.IsEncrypt()); + LOG_DEBUG( + "GraphConnection::InnerOpen: dbPath=%{public}s, configJson=%{public}s", + GdbUtils::Anonymous(dbPath).c_str(), configJson.c_str()); + int32_t errCode = GrdAdapter::Open(dbPath.c_str(), configJson.c_str(), GRD_DB_OPEN_CREATE, &dbHandle_); + if (errCode == E_GRD_PASSWORD_NEED_REKEY) { + // Upgrading from non encrypted to encrypted, requires Rekey first and then Open + errCode = GrdAdapter::Rekey(dbPath.c_str(), GdbUtils::GetConfigStr({}, false).c_str(), key); + if (errCode != E_OK) { + key.assign(key.size(), 0); + GdbUtils::ClearAndZeroString(configJson); + LOG_ERROR("Can not rekey graph db %{public}d.", errCode); + return errCode; + } + errCode = GrdAdapter::Open(dbPath.c_str(), configJson.c_str(), GRD_DB_OPEN_CREATE, &dbHandle_); + } + key.assign(key.size(), 0); + GdbUtils::ClearAndZeroString(configJson); + if (errCode != E_OK) { + LOG_ERROR("Can not open graph db, name=%{public}s, errCode=%{public}d.", + GdbUtils::Anonymous(config.GetName()).c_str(), errCode); + return errCode; + } + return errCode; +} + +std::pair GraphConnection::CreateStatement( + const std::string &gql, std::shared_ptr connection) +{ + int32_t ret; + auto stmt = std::make_shared(dbHandle_, gql, connection, ret); + if (ret != E_OK) { + return { ret, nullptr }; + } + return { ret, stmt }; +} + +DBType GraphConnection::GetDBType() const +{ + return DBType::DB_GRAPH; +} + +bool GraphConnection::IsWriter() const +{ + return isWriter_; +} + +int32_t GraphConnection::ResetKey(const StoreConfig &config) +{ + if (!IsWriter()) { + return E_OK; + } + std::string dbPath = config.GetFullPath(); + std::vector key = config.GetEncryptKey(); + std::vector newKey = config.GetNewEncryptKey(); + std::string configStr = GdbUtils::GetConfigStr(key, config.IsEncrypt()); + auto errCode = GrdAdapter::Rekey(dbPath.c_str(), configStr.c_str(), newKey); + GdbUtils::ClearAndZeroString(configStr); + key.assign(key.size(), 0); + newKey.assign(newKey.size(), 0); + if (errCode != E_OK) { + LOG_ERROR("Rekey failed, err = %{public}d, errno = %{public}d", errCode, errno); + NativeRdb::RdbSecurityManager::GetInstance().DelKeyFile( + config.GetFullPath(), NativeRdb::RdbSecurityManager::KeyFileType::PUB_KEY_FILE_NEW_KEY); + return errCode; + } + config.ChangeEncryptKey(); + return E_OK; +} +} // namespace OHOS::DistributedDataAip diff --git a/relational_store/frameworks/native/gdb/src/graph_statement.cpp b/relational_store/frameworks/native/gdb/src/graph_statement.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d96d0c4808ef0663976700563827e60d4fe868f --- /dev/null +++ b/relational_store/frameworks/native/gdb/src/graph_statement.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2024 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 "GdbStmt" +#include "graph_statement.h" + +#include + +#include "aip_errors.h" +#include "connection.h" +#include "full_result.h" +#include "grd_error.h" +#include "logger.h" + +namespace OHOS::DistributedDataAip { +GraphStatement::GraphStatement(GRD_DB *db, const std::string &gql, std::shared_ptr conn, int32_t &errCode) + : conn_(conn), gql_(gql), dbHandle_(db) +{ + errCode = E_OK; + if (db == nullptr || gql.empty()) { + errCode = E_PREPARE_CHECK_FAILED; + return; + } + + int32_t ret = GrdAdapter::Prepare(dbHandle_, gql_.c_str(), gql_.size(), &stmtHandle_, nullptr); + if (ret != GRD_OK) { + LOG_ERROR("GRD_GqlPrepare failed. ret=%{public}d", ret); + if (stmtHandle_ != nullptr) { + GrdAdapter::Finalize(stmtHandle_); + } + errCode = GrdAdapter::TransErrno(ret); + } +} + +GraphStatement::~GraphStatement() +{ + Finalize(); +} + +int32_t GraphStatement::Prepare() +{ + if (dbHandle_ == nullptr || gql_.empty()) { + return E_PREPARE_CHECK_FAILED; + } + + int32_t ret = GrdAdapter::Prepare(dbHandle_, gql_.c_str(), gql_.size(), &stmtHandle_, nullptr); + if (ret != GRD_OK) { + LOG_ERROR("GRD_GqlPrepare failed. ret=%{public}d", ret); + } + return GrdAdapter::TransErrno(ret); +} + +int32_t GraphStatement::Step() +{ + if (stmtHandle_ == nullptr) { + return E_STEP_CHECK_FAILED; + } + int32_t ret = GrdAdapter::Step(stmtHandle_); + if (ret != GRD_OK) { + LOG_ERROR("GRD_GqlStep failed. ret=%{public}d", ret); + } + return GrdAdapter::TransErrno(ret); +} + +int32_t GraphStatement::Finalize() +{ + if (stmtHandle_ == nullptr) { + return E_OK; + } + int32_t ret = GrdAdapter::Finalize(stmtHandle_); + if (ret != GRD_OK) { + LOG_ERROR("GRD_GqlFinalize failed. ret=%{public}d", ret); + return GrdAdapter::TransErrno(ret); + } + stmtHandle_ = nullptr; + gql_ = ""; + return E_OK; +} + +uint32_t GraphStatement::GetColumnCount() const +{ + if (stmtHandle_ == nullptr) { + return E_STATEMENT_EMPTY; + } + return GrdAdapter::ColumnCount(stmtHandle_); +} + +std::pair GraphStatement::GetColumnName(int32_t index) const +{ + if (stmtHandle_ == nullptr) { + return { E_STATEMENT_EMPTY, "" }; + } + const char *name = GrdAdapter::ColumnName(stmtHandle_, index); + if (name == nullptr) { + LOG_ERROR("column_name is null. index=%{public}d", index); + return { E_GETTED_COLNAME_EMPTY, "" }; + } + return { E_OK, name }; +} + +std::pair GraphStatement::GetColumnType(int32_t index) const +{ + if (stmtHandle_ == nullptr) { + return { E_STATEMENT_EMPTY, ColumnType::TYPE_NULL }; + } + GRD_DbDataTypeE type = GrdAdapter::ColumnType(stmtHandle_, index); + return { E_OK, GrdAdapter::TransColType(type) }; +} + +GraphValue GraphStatement::ParseJsonStr(const std::string &jsonStr, int32_t &errCode) +{ + if (jsonStr.empty()) { + LOG_WARN("parse json string. jsonStr is empty"); + errCode = E_OK; + return nullptr; + } + nlohmann::json json = nlohmann::json::parse(jsonStr, nullptr, false); + if (json.is_discarded()) { + LOG_ERROR("parse json string failed. jsonStr=%{public}s", jsonStr.c_str()); + errCode = E_PARSE_JSON_FAILED; + return nullptr; + } + + errCode = E_OK; + if (json.is_null()) { + LOG_WARN("parse json string. jsonStr is empty"); + return nullptr; + } + if (!json.is_object()) { + LOG_ERROR("json format error. jsonStr=%{public}s", jsonStr.c_str()); + errCode = E_PARSE_JSON_FAILED; + return nullptr; + } + + if (json.contains(Path::SEGMENTS)) { + return Path::Parse(json, errCode); + } + if (json.contains(Edge::SOURCEID) && json.contains(Edge::TARGETID)) { + return Edge::Parse(json, errCode); + } + return Vertex::Parse(json, errCode); +} + +std::pair GraphStatement::GetColumnValue(int32_t index) const +{ + if (stmtHandle_ == nullptr) { + return { E_STATEMENT_EMPTY, nullptr }; + } + ColumnType type = GetColumnType(index).second; + GraphValue value; + + auto ret = 0; + switch (type) { + case ColumnType::TYPE_INTEGER: + value = GrdAdapter::ColumnInt(stmtHandle_, index); + break; + case ColumnType::TYPE_FLOAT: + value = GrdAdapter::ColumnDouble(stmtHandle_, index); + break; + case ColumnType::TYPE_JSONSTR: { + auto text = ""; + text = GrdAdapter::ColumnText(stmtHandle_, index); + value = ParseJsonStr(text, ret); + if (ret != E_OK) { + LOG_ERROR("ParseJsonStr failed. index=%{public}d, ret=%{public}d", index, ret); + return { ret, nullptr }; + } + break; + } + case ColumnType::TYPE_TEXT: + value = GrdAdapter::ColumnText(stmtHandle_, index); + break; + case ColumnType::TYPE_BLOB: + LOG_ERROR("not support blob type. index=%{public}d", index); + return { E_NOT_SUPPORT, nullptr }; + case ColumnType::TYPE_FLOATVECTOR: + LOG_ERROR("not support float vector type. index=%{public}d", index); + return { E_NOT_SUPPORT, nullptr }; + case ColumnType::TYPE_NULL: + default: + value = nullptr; + } + return { E_OK, value }; +} + +bool GraphStatement::IsReady() const +{ + return !gql_.empty() && stmtHandle_ != nullptr && dbHandle_ != nullptr; +} +} // namespace OHOS::DistributedDataAip diff --git a/relational_store/frameworks/native/gdb/src/path.cpp b/relational_store/frameworks/native/gdb/src/path.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ac9d388b1605cccc3c378a52287708c9c7cc634b --- /dev/null +++ b/relational_store/frameworks/native/gdb/src/path.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2024 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 "GdbPath" +#include "path.h" + +#include "aip_errors.h" +#include "path_segment.h" +#include "grd_error.h" +#include "logger.h" + +namespace OHOS::DistributedDataAip { +Path::Path(std::shared_ptr start, std::shared_ptr end) : start_(start), end_(end) +{ + pathLen_ = 0; +} + +Path::Path(std::shared_ptr start, std::shared_ptr end, uint32_t pathLen, + std::vector> segments) + : pathLen_(pathLen), start_(start), end_(end), segments_(std::move(segments)) +{ +} + +Path::Path() : pathLen_(0), start_(nullptr), end_(nullptr), segments_() +{ +} + +uint32_t Path::GetPathLength() const +{ + return pathLen_; +} + +void Path::SetPathLength(uint32_t pathLen) +{ + this->pathLen_ = pathLen; +} + +std::shared_ptr Path::GetStart() const +{ + return start_; +} + +void Path::SetStart(std::shared_ptr start) +{ + this->start_ = start; +} + +std::shared_ptr Path::GetEnd() const +{ + return end_; +} + +void Path::SetEnd(std::shared_ptr end) +{ + this->end_ = end; +} + +const std::vector> &Path::GetSegments() const +{ + return segments_; +} + +std::shared_ptr Path::Parse(const nlohmann::json &json, int32_t &errCode) +{ + if (!json.contains(Path::PATHLEN) || !json.contains(Path::START) || !json.at(Path::START).is_object() || + !json.contains(Path::END) || !json.at(Path::END).is_object() || !json.contains(Path::SEGMENTS) || + !json.at(Path::SEGMENTS).is_array() || !json.at(Path::PATHLEN).is_number_unsigned()) { + LOG_ERROR("path format error. jsonStr=%{public}s", json.dump().c_str()); + errCode = E_PARSE_JSON_FAILED; + return nullptr; + } + errCode = E_OK; + + auto pathLen = json.at(Path::PATHLEN).get(); + auto start = Vertex::Parse(json.at(Path::START), errCode); + if (errCode != E_OK) { + return nullptr; + } + + auto end = Vertex::Parse(json.at(Path::END), errCode); + if (errCode != E_OK) { + return nullptr; + } + auto pathSegments = std::vector>(); + for (const auto &item : json.at(Path::SEGMENTS)) { + if (!item.is_object()) { + LOG_ERROR("pathItem format error. jsonStr=%{public}s", json.dump().c_str()); + return nullptr; + } + auto pathSegment = PathSegment::Parse(item, errCode); + if (errCode != E_OK) { + return nullptr; + } + pathSegments.push_back(pathSegment); + } + errCode = E_OK; + return std::make_shared(start, end, pathLen, pathSegments); + ; +} +} // namespace OHOS::DistributedDataAip diff --git a/relational_store/frameworks/native/gdb/src/path_segment.cpp b/relational_store/frameworks/native/gdb/src/path_segment.cpp new file mode 100644 index 0000000000000000000000000000000000000000..df9f7b74d719e74c0ac3560d3fe69c96bb375be1 --- /dev/null +++ b/relational_store/frameworks/native/gdb/src/path_segment.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024 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 "GdbPath" +#include "path_segment.h" + +#include "aip_errors.h" +#include "grd_error.h" +#include "logger.h" + +namespace OHOS::DistributedDataAip { +PathSegment::PathSegment() : sourceVertex_(nullptr), edge_(nullptr), targetVertex_(nullptr) +{ +} + +PathSegment::PathSegment( + std::shared_ptr sourceVertex, std::shared_ptr targetVertex, std::shared_ptr edge) + : sourceVertex_(sourceVertex), edge_(edge), targetVertex_(targetVertex) +{ +} + +std::shared_ptr PathSegment::GetSourceVertex() const +{ + return sourceVertex_; +} + +void PathSegment::SetSourceVertex(std::shared_ptr vertex) +{ + sourceVertex_ = vertex; +} + +std::shared_ptr PathSegment::GetEdge() const +{ + return edge_; +} + +void PathSegment::SetEdge(std::shared_ptr edge) +{ + this->edge_ = edge; +} + +std::shared_ptr PathSegment::GetTargetVertex() const +{ + return targetVertex_; +} + +void PathSegment::SetTargetVertex(std::shared_ptr vertex) +{ + targetVertex_ = vertex; +} + +std::shared_ptr PathSegment::Parse(const nlohmann::json &json, int32_t &errCode) +{ + if (!json.contains(PathSegment::SOURCE_VERTEX) || !json.at(PathSegment::SOURCE_VERTEX).is_object() || + !json.contains(PathSegment::EDGE) || !json.at(PathSegment::EDGE).is_object() || + !json.contains(PathSegment::TARGET_VERTEX) || !json.at(PathSegment::TARGET_VERTEX).is_object()) { + LOG_ERROR("pathSegment format error. jsonStr=%{public}s", json.dump().c_str()); + errCode = E_PARSE_JSON_FAILED; + return nullptr; + } + errCode = E_OK; + std::shared_ptr segment = std::make_shared(); + auto sourceVertex = Vertex::Parse(json.at(PathSegment::SOURCE_VERTEX), errCode); + if (errCode != E_OK) { + return nullptr; + } + segment->SetSourceVertex(sourceVertex); + + auto edge = Edge::Parse(json.at(PathSegment::EDGE), errCode); + if (errCode != E_OK) { + return nullptr; + } + segment->SetEdge(edge); + + auto targetVertex = Vertex::Parse(json.at(PathSegment::TARGET_VERTEX), errCode); + if (errCode != E_OK) { + return nullptr; + } + segment->SetTargetVertex(targetVertex); + + return segment; +} +} // namespace OHOS::DistributedDataAip diff --git a/relational_store/frameworks/native/gdb/src/store_config.cpp b/relational_store/frameworks/native/gdb/src/store_config.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d54f2e8e16b4d5c03e1b4348ec566b1518dce90 --- /dev/null +++ b/relational_store/frameworks/native/gdb/src/store_config.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2024 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 "GdbStoreConfig" +#include + +#include "aip_errors.h" +#include "gdb_store_config.h" +#include "gdb_utils.h" +#include "logger.h" +#include "rdb_security_manager.h" + +namespace OHOS::DistributedDataAip { +StoreConfig::StoreConfig( + std::string name, std::string path, DBType dbType, bool status, const std::vector &encryptKey) + : name_(std::move(name)), path_(std::move(path)), dbType_(dbType), isEncrypt_(status), encryptKey_(encryptKey) +{ +} + +StoreConfig::~StoreConfig() +{ + ClearEncryptKey(); +} + +void StoreConfig::SetName(std::string name) +{ + name_ = std::move(name); +} + +void StoreConfig::SetPath(std::string path) +{ + path_ = std::move(path); +} + +void StoreConfig::SetDbType(DBType dbType) +{ + dbType_ = dbType; +} + +void StoreConfig::SetEncryptStatus(const bool status) +{ + isEncrypt_ = status; +} + +bool StoreConfig::IsEncrypt() const +{ + return isEncrypt_; +} + +std::string StoreConfig::GetJson() const +{ + return "{\"pageSize\":" + std::to_string(pageSize_) + + ", \"defaultIsolationLevel\":" + std::to_string(defaultIsolationLevel_) + "}"; +} + +std::string StoreConfig::GetFullPath() const +{ + return path_ + "/" + name_ + ".db"; +} + +std::string StoreConfig::GetPath() const +{ + return path_; +} + +std::string StoreConfig::GetName() const +{ + return name_; +} + +DBType StoreConfig::GetDbType() const +{ + return dbType_; +} + +int32_t StoreConfig::GetIter() const +{ + return iter_; +} + +void StoreConfig::SetIter(int32_t iter) const +{ + iter_ = iter; +} + +int StoreConfig::GetWriteTime() const +{ + return writeTimeout_; +} + +void StoreConfig::SetWriteTime(int timeout) +{ + writeTimeout_ = std::max(MIN_TIMEOUT, std::min(MAX_TIMEOUT, timeout)); +} + +int StoreConfig::GetReadTime() const +{ + return readTimeout_; +} + +void StoreConfig::SetReadTime(int timeout) +{ + readTimeout_ = std::max(MIN_TIMEOUT, std::min(MAX_TIMEOUT, timeout)); +} + +int StoreConfig::GetReadConSize() const +{ + return readConSize_; +} + +void StoreConfig::SetReadConSize(int readConSize) +{ + readConSize_ = readConSize; +} + +void StoreConfig::SetSecurityLevel(int32_t securityLevel) +{ + securityLevel_ = securityLevel; +} + +int32_t StoreConfig::GetSecurityLevel() const +{ + return securityLevel_; +} + +int StoreConfig::SetBundleName(const std::string &bundleName) +{ + if (bundleName.empty()) { + return E_ERROR; + } + bundleName_ = bundleName; + return E_OK; +} + +std::string StoreConfig::GetBundleName() const +{ + return bundleName_; +} + +std::vector StoreConfig::GetEncryptKey() const +{ + return encryptKey_; +} + +std::vector StoreConfig::GetNewEncryptKey() const +{ + return newEncryptKey_; +} + +void StoreConfig::GenerateEncryptedKey() const +{ + if (!IsEncrypt()) { + return; + } + auto rdbConfig = std::make_shared(GetFullPath()); + if (rdbConfig == nullptr) { + LOG_ERROR("rdbConfig is nullptr. path:%{public}s", GdbUtils::Anonymous(GetFullPath()).c_str()); + return; + } + rdbConfig->SetBundleName(bundleName_); + rdbConfig->SetEncryptStatus(true); + auto errCode = rdbConfig->Initialize(); + if (errCode != E_OK) { + LOG_ERROR("rdbConfig init encrypt failed. errCode:%{public}d, path:%{public}s", + errCode, GdbUtils::Anonymous(GetFullPath()).c_str()); + return; + } + encryptKey_.assign(encryptKey_.size(), 0); + encryptKey_ = rdbConfig->GetEncryptKey(); + newEncryptKey_.assign(newEncryptKey_.size(), 0); + newEncryptKey_ = rdbConfig->GetNewEncryptKey(); +} + +void StoreConfig::ClearEncryptKey() +{ + encryptKey_.assign(encryptKey_.size(), 0); + newEncryptKey_.assign(newEncryptKey_.size(), 0); +} + +void StoreConfig::ChangeEncryptKey() const +{ + NativeRdb::RdbSecurityManager::GetInstance().ChangeKeyFile(GetFullPath()); + if (newEncryptKey_.empty()) { + return; + } + encryptKey_.assign(encryptKey_.size(), 0); + encryptKey_ = newEncryptKey_; + newEncryptKey_.assign(newEncryptKey_.size(), 0); + newEncryptKey_.resize(0); +} +} // namespace OHOS::DistributedDataAip \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/src/trans_db.cpp b/relational_store/frameworks/native/gdb/src/trans_db.cpp new file mode 100644 index 0000000000000000000000000000000000000000..57d9fd93dc8161e1b51a94d53b05f9ad4e9d4ac1 --- /dev/null +++ b/relational_store/frameworks/native/gdb/src/trans_db.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2025 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 "TransDB" +#include "trans_db.h" + +#include "aip_errors.h" +#include "db_trace.h" +#include "gdb_utils.h" +#include "logger.h" + +namespace OHOS::DistributedDataAip { + +constexpr int32_t MAX_GQL_LEN = 1024 * 1024; + +TransDB::TransDB(std::shared_ptr connection) : conn_(connection) +{ +} + +std::pair> TransDB::QueryGql(const std::string &gql) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + if (gql.empty() || gql.length() > MAX_GQL_LEN) { + LOG_ERROR("Gql is empty or length is too long."); + return { E_INVALID_ARGS, std::make_shared() }; + } + if (GdbUtils::IsTransactionGql(gql)) { + LOG_ERROR("Transaction related statements are not supported."); + return { E_INVALID_ARGS, std::make_shared() }; + } + + auto [errCode, statement] = GetStatement(gql); + if (errCode != E_OK || statement == nullptr) { + return { errCode, std::make_shared() }; + } + + auto result = std::make_shared(); + errCode = result->InitData(statement); + if (errCode != E_OK) { + LOG_ERROR("Get FullResult failed, errCode=%{public}d", errCode); + return { errCode, std::make_shared() }; + } + + return { errCode, result }; +} + +std::pair> TransDB::ExecuteGql(const std::string &gql) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + if (gql.empty() || gql.length() > MAX_GQL_LEN) { + LOG_ERROR("Gql is empty or length is too long."); + return { E_INVALID_ARGS, std::make_shared() }; + } + if (GdbUtils::IsTransactionGql(gql)) { + LOG_ERROR("Transaction related statements are not supported."); + return { E_INVALID_ARGS, std::make_shared() }; + } + + auto [errCode, statement] = GetStatement(gql); + if (errCode != E_OK || statement == nullptr) { + return { errCode, std::make_shared() }; + } + + errCode = statement->Step(); + if (errCode != E_OK) { + LOG_ERROR("Step statement failed, errCode=%{public}d", errCode); + } + return { errCode, std::make_shared() }; +} + +std::pair> TransDB::GetStatement(const std::string &gql) const +{ + auto connection = conn_.lock(); + if (connection == nullptr) { + return { E_GRD_DB_INSTANCE_ABNORMAL, nullptr }; + } + return connection->CreateStatement(gql, connection); +} + +std::pair> TransDB::CreateTransaction() +{ + return { E_NOT_SUPPORT, nullptr }; +} + +int32_t TransDB::Close() +{ + return E_NOT_SUPPORT; +} +} // namespace OHOS::DistributedDataAip \ No newline at end of file diff --git a/relational_store/frameworks/native/gdb/src/transaction.cpp b/relational_store/frameworks/native/gdb/src/transaction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..775cfa4716176a46a7b1d7700c71921edc99e425 --- /dev/null +++ b/relational_store/frameworks/native/gdb/src/transaction.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 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 "transaction.h" + +#include "aip_errors.h" + +namespace OHOS::DistributedDataAip { +std::pair> Transaction::Create(std::shared_ptr conn) +{ + if (creator_ != nullptr) { + return creator_(std::move(conn)); + } + return { E_ERROR, nullptr }; +} + +int32_t Transaction::RegisterCreator(Creator creator) +{ + creator_ = std::move(creator); + return E_OK; +} +} // namespace OHOS::DistributedDataAip diff --git a/relational_store/frameworks/native/gdb/src/transaction_impl.cpp b/relational_store/frameworks/native/gdb/src/transaction_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..954f3171fdfd767d596ac6374f40b3cdd5d9e958 --- /dev/null +++ b/relational_store/frameworks/native/gdb/src/transaction_impl.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2025 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 "GdbTrans" +#include "transaction_impl.h" + +#include + +#include "aip_errors.h" +#include "db_trace.h" +#include "logger.h" +#include "trans_db.h" + +namespace OHOS::DistributedDataAip { + +constexpr const char *START_GQL = "START TRANSACTION;"; +constexpr const char *COMMIT_GQL = "COMMIT;"; +constexpr const char *ROLLBACK_GQL = "ROLLBACK;"; + +__attribute__((used)) +const int32_t TransactionImpl::regCreator_ = Transaction::RegisterCreator(TransactionImpl::Create); + +TransactionImpl::TransactionImpl(std::shared_ptr connection) + : connection_(std::move(connection)) +{ +} + +TransactionImpl::~TransactionImpl() +{ + CloseInner(); +} + +std::pair> TransactionImpl::Create(std::shared_ptr conn) +{ + if (conn == nullptr) { + LOG_ERROR("conn is nullptr"); + return { E_ERROR, nullptr }; + } + auto trans = std::make_shared(std::move(conn)); + if (trans == nullptr) { + LOG_ERROR("trans is nullptr"); + return { E_ERROR, nullptr }; + } + auto errorCode = trans->Start(); + if (errorCode != E_OK) { + LOG_ERROR("transaction start failed, errorCode=%{public}d", errorCode); + return { errorCode, nullptr }; + } + return { E_OK, trans }; +} + +int32_t TransactionImpl::Start() +{ + std::lock_guard lock(mutex_); + store_ = std::make_shared(connection_); + if (store_ == nullptr) { + LOG_ERROR("create trans db failed"); + return E_ERROR; + } + + if (connection_ == nullptr) { + LOG_ERROR("connection already closed"); + return E_GRD_DB_INSTANCE_ABNORMAL; + } + + auto [errorCode, statement] = connection_->CreateStatement(START_GQL, connection_); + if (errorCode != E_OK || statement == nullptr) { + LOG_ERROR("create statement failed, errorCode=%{public}d", errorCode); + CloseInner(); + return errorCode; + } + errorCode = statement->Step(); + if (errorCode != E_OK) { + LOG_ERROR("statement execute failed, errorCode=%{public}d", errorCode); + CloseInner(); + return errorCode; + } + return E_OK; +} + +int32_t TransactionImpl::Commit() +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + std::lock_guard lock(mutex_); + if (connection_ == nullptr) { + LOG_ERROR("connection already closed"); + return E_GRD_DB_INSTANCE_ABNORMAL; + } + + auto [errorCode, statement] = connection_->CreateStatement(COMMIT_GQL, connection_); + if (errorCode != E_OK || statement == nullptr) { + LOG_ERROR("create statement failed, errorCode=%{public}d", errorCode); + CloseInner(); + return errorCode; + } + + errorCode = statement->Step(); + CloseInner(); + if (errorCode != E_OK) { + LOG_ERROR("statement execute failed, errorCode=%{public}d", errorCode); + return errorCode; + } + return E_OK; +} + +int32_t TransactionImpl::Rollback() +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + std::lock_guard lock(mutex_); + if (connection_ == nullptr) { + LOG_ERROR("connection already closed"); + return E_GRD_DB_INSTANCE_ABNORMAL; + } + + auto [errorCode, statement] = connection_->CreateStatement(ROLLBACK_GQL, connection_); + if (errorCode != E_OK || statement == nullptr) { + LOG_ERROR("create statement failed, errorCode=%{public}d", errorCode); + CloseInner(); + return errorCode; + } + + errorCode = statement->Step(); + CloseInner(); + if (errorCode != E_OK) { + LOG_ERROR("statement execute failed, errorCode=%{public}d", errorCode); + return errorCode; + } + return E_OK; +} + +int32_t TransactionImpl::CloseInner() +{ + std::lock_guard lock(mutex_); + store_ = nullptr; + connection_ = nullptr; + return E_OK; +} + +int32_t TransactionImpl::Close() +{ + return Rollback(); +} + +std::shared_ptr TransactionImpl::GetStore() +{ + std::lock_guard lock(mutex_); + return store_; +} + +std::pair> TransactionImpl::Query(const std::string &gql) +{ + auto store = GetStore(); + if (store == nullptr) { + LOG_ERROR("transaction already close"); + return { E_GRD_DB_INSTANCE_ABNORMAL, std::make_shared() }; + } + return store->QueryGql(gql); +} + +std::pair> TransactionImpl::Execute(const std::string &gql) +{ + auto store = GetStore(); + if (store == nullptr) { + LOG_ERROR("transaction already close"); + return { E_GRD_DB_INSTANCE_ABNORMAL, std::make_shared() }; + } + return store->ExecuteGql(gql); +} +} // namespace OHOS::DistributedDataAip diff --git a/relational_store/frameworks/native/gdb/src/vertex.cpp b/relational_store/frameworks/native/gdb/src/vertex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bfb51f834c9f09efa89070144fcbf87fe75c1ba5 --- /dev/null +++ b/relational_store/frameworks/native/gdb/src/vertex.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2024 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 "GdbElement" +#include + +#include "aip_errors.h" +#include "full_result.h" +#include "logger.h" + +namespace OHOS::DistributedDataAip { +Vertex::Vertex() : id_("0"), properties_() +{ +} + +Vertex::Vertex(std::string id, std::string label) : id_(std::move(id)), label_(std::move(label)) +{ + labels_.emplace_back(label_); +} + +Vertex::Vertex(std::string id, std::string label, + const std::unordered_map &properties) + : id_(std::move(id)), label_(std::move(label)), properties_(properties) +{ + labels_.emplace_back(label_); +} + +std::string Vertex::GetId() const +{ + return id_; +} + +void Vertex::SetId(std::string id) +{ + id_ = std::move(id); +} + +const std::string &Vertex::GetLabel() const +{ + return label_; +} + +const std::vector &Vertex::GetLabels() const +{ + return labels_; +} + +void Vertex::SetLabel(const std::string &label) +{ + label_ = label; + labels_.emplace_back(label); +} + +const std::unordered_map &Vertex::GetProperties() const +{ + return properties_; +} + +void Vertex::SetProperty(const std::string &key, PropType value) +{ + properties_[key] = std::move(value); +} + +std::shared_ptr Vertex::Parse(const nlohmann::json &json, int32_t &errCode) +{ + std::shared_ptr element = std::make_shared(); + if (!json.contains(Vertex::LABEL) || !json.contains(Vertex::ID) || + !json.contains(Vertex::PROPERTIES) || !json.at(Vertex::PROPERTIES).is_object()) { + LOG_ERROR("element format error."); + errCode = E_PARSE_JSON_FAILED; + return nullptr; + } + + if (json.at(Vertex::ID).is_number()) { + auto id = json.at(Vertex::ID).get(); + element->SetId(std::to_string(id)); + } else if (json.at(Vertex::ID).is_string()) { + auto id = json.at(Vertex::ID).get(); + element->SetId(id); + } else { + LOG_ERROR("element id is not number or string."); + errCode = E_PARSE_JSON_FAILED; + return nullptr; + } + if (!json.at(Vertex::LABEL).is_string()) { + LOG_ERROR("element label is not string."); + errCode = E_PARSE_JSON_FAILED; + return nullptr; + } + element->SetLabel(json.at(Vertex::LABEL).get()); + for (const auto &[key, value] : json.at(Vertex::PROPERTIES).items()) { + if (value.is_string()) { + element->SetProperty(key, value.get()); + } else if (value.is_number_integer()) { + element->SetProperty(key, value.get()); + } else if (value.is_number_float()) { + element->SetProperty(key, value.get()); + } else if (value.is_boolean()) { + element->SetProperty(key, value.get()); + } else if (value.is_null()) { + element->SetProperty(key, nullptr); + } else { + LOG_ERROR("element property value type is not supported."); + errCode = E_PARSE_JSON_FAILED; + return nullptr; + } + } + errCode = E_OK; + return element; +} +} // namespace OHOS::DistributedDataAip diff --git a/relational_store/frameworks/native/icu/BUILD.gn b/relational_store/frameworks/native/icu/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..ee35d546789045b14704959c79e47862d2d18ea1 --- /dev/null +++ b/relational_store/frameworks/native/icu/BUILD.gn @@ -0,0 +1,58 @@ +# Copyright (c) 2024 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. +import("//build/ohos.gni") +import("//build/ohos/ace/ace.gni") +import("//foundation/distributeddatamgr/relational_store/relational_store.gni") + +group("build_module") { + deps = [] + if (relational_store_rdb_support_icu) { + deps += [ ":relational_store_icu" ] + } +} + +ohos_shared_library("relational_store_icu") { + branch_protector_ret = "pac_ret" + sanitize = { + boundary_sanitize = true + ubsan = true + cfi = true + cfi_cross_dso = true + debug = false + } + + ldflags = [ "-Wl,--exclude-libs,ALL" ] + cflags_cc = [ "-fvisibility=hidden" ] + + include_dirs = [ + "${relational_store_common_path}/include", + "${relational_store_native_path}/icu/include", + "${relational_store_innerapi_path}/rdb/include", + ] + + sources = [ "${relational_store_native_path}/icu/src/icu_collect.cpp" ] + + external_deps = [ + "hilog:libhilog", + "icu:shared_icui18n", + "icu:shared_icuuc", + "sqlite:sqlite", + ] + if (is_android) { + external_deps += [ "${plugins_path}/libs/icu:icu_android" ] + } else if (is_ios) { + external_deps += [ "${plugins_path}/libs/icu:icu_ios" ] + } + subsystem_name = "distributeddatamgr" + part_name = "relational_store" +} diff --git a/relational_store/frameworks/native/icu/include/icu_collect.h b/relational_store/frameworks/native/icu/include/icu_collect.h new file mode 100644 index 0000000000000000000000000000000000000000..b8f0976745f92d3fe16d24a59547096907fb4e12 --- /dev/null +++ b/relational_store/frameworks/native/icu/include/icu_collect.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 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_NATIVE_RDB_ICU_COLLECT_H +#define OHOS_NATIVE_RDB_ICU_COLLECT_H +#include + +#include "sqlite3sym.h" + +namespace OHOS::NativeRdb { + +class ICUCollect { +public: + static int32_t Local(sqlite3 *dbHandle, const std::string &str); + +private: + static int Collate8Compare(void *p, int n1, const void *v1, int n2, const void *v2); + static void LocalizedCollatorDestroy(void *collator); +}; + +} // namespace OHOS::NativeRdb + +#endif // OHOS_NATIVE_RDB_ICU_COLLECT_H \ No newline at end of file diff --git a/relational_store/frameworks/native/icu/src/icu_collect.cpp b/relational_store/frameworks/native/icu/src/icu_collect.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1153ec082c5b92fcff9490f4fbd0d1678a55f182 --- /dev/null +++ b/relational_store/frameworks/native/icu/src/icu_collect.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024 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 "ICUCollect" +#include "icu_collect.h" + +#include +#include + +#include "logger.h" +#include "rdb_errno.h" +#include "rdb_visibility.h" +#include "sqlite3.h" + +API_EXPORT int32_t ConfigICULocal(sqlite3 *, const std::string &str) asm("ConfigICULocal"); +int32_t ConfigICULocal(sqlite3 *handle, const std::string &str) +{ + return OHOS::NativeRdb::ICUCollect::Local(handle, str); +} + +namespace OHOS::NativeRdb { +using namespace OHOS::Rdb; + +int ICUCollect::Collate8Compare(void *p, int n1, const void *v1, int n2, const void *v2) +{ + UCollator *coll = reinterpret_cast(p); + UCharIterator i1; + UCharIterator i2; + UErrorCode status = U_ZERO_ERROR; + + uiter_setUTF8(&i1, (const char *)v1, n1); + uiter_setUTF8(&i2, (const char *)v2, n2); + + UCollationResult result = ucol_strcollIter(coll, &i1, &i2, &status); + + if (U_FAILURE(status)) { + LOG_ERROR("Ucol strcoll error."); + } + + if (result == UCOL_LESS) { + return -1; + } else if (result == UCOL_GREATER) { + return 1; + } + return 0; +} + +void ICUCollect::LocalizedCollatorDestroy(void *collator) +{ + ucol_close(reinterpret_cast(collator)); +} + +int32_t ICUCollect::Local(sqlite3 *dbHandle, const std::string &str) +{ + LOG_ERROR("bai:local success"); + UErrorCode status = U_ZERO_ERROR; + UCollator *collator = ucol_open(str.c_str(), &status); + if (U_FAILURE(status)) { + LOG_ERROR("Can not open collator."); + return E_ERROR; + } + ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_PRIMARY, &status); + if (U_FAILURE(status)) { + LOG_ERROR("Set attribute of collator failed."); + return E_ERROR; + } + int err = sqlite3_create_collation_v2(dbHandle, "LOCALES", SQLITE_UTF8, collator, ICUCollect::Collate8Compare, + (void (*)(void *))ICUCollect::LocalizedCollatorDestroy); + if (err != SQLITE_OK) { + LOG_ERROR("SCreate collator in sqlite3 failed."); + return err; + } + return E_OK; +} + +} // namespace OHOS::NativeRdb diff --git a/relational_store/frameworks/native/rdb/include/connection.h b/relational_store/frameworks/native/rdb/include/connection.h index 2da6c5b94a2e186d5dd8109bb0d3a10561131da9..2ae66395c69c07e87a852462c089b1048399b5a0 100644 --- a/relational_store/frameworks/native/rdb/include/connection.h +++ b/relational_store/frameworks/native/rdb/include/connection.h @@ -33,7 +33,7 @@ public: using Info = DistributedRdb::RdbDebugInfo; using SConn = std::shared_ptr; using Stmt = std::shared_ptr; - using Notifier = std::function &tables)>; + using Notifier = std::function; using Creator = std::pair (*)(const RdbStoreConfig &config, bool isWriter); using Repairer = int32_t (*)(const RdbStoreConfig &config); using Deleter = int32_t (*)(const RdbStoreConfig &config); @@ -57,6 +57,7 @@ public: virtual std::pair CreateStatement(const std::string &sql, SConn conn) = 0; virtual int32_t GetDBType() const = 0; virtual bool IsWriter() const = 0; + virtual bool IsInTrans() const = 0; virtual int32_t ReSetKey(const RdbStoreConfig &config) = 0; virtual int32_t TryCheckPoint(bool timeout) = 0; virtual int32_t LimitWalSize() = 0; diff --git a/relational_store/frameworks/native/rdb/include/delay_notify.h b/relational_store/frameworks/native/rdb/include/delay_notify.h index 52d9aa7f95ad2d362f834cbc29da66b52f66917f..3ac0f7368ebb346ef803d651a10c54d6b77233e1 100644 --- a/relational_store/frameworks/native/rdb/include/delay_notify.h +++ b/relational_store/frameworks/native/rdb/include/delay_notify.h @@ -20,11 +20,14 @@ #include #include #include +#include #include -#include "executor_pool.h" #include "rdb_types.h" -namespace OHOS::NativeRdb { + +namespace OHOS { +class ExecutorPool; +namespace NativeRdb { class DelayNotify { public: using Task = std::function; @@ -46,7 +49,7 @@ private: bool isFull_ = false; Time lastTimePoint_; std::atomic_int32_t pauseCount_; - ExecutorPool::TaskId delaySyncTaskId_ = ExecutorPool::INVALID_TASK_ID; + uint64_t delaySyncTaskId_ = 0; Task task_; std::shared_ptr pool_; std::mutex mutex_; @@ -68,5 +71,6 @@ private: static constexpr uint32_t AUTO_SYNC_MAX_INTERVAL = 3000; std::shared_ptr delayNotifier_; }; -} // namespace OHOS::NativeRdb +} // namespace NativeRdb +} // namespace OHOS #endif // NATIVE_RDB_DELAY_NOTIFY_H \ No newline at end of file diff --git a/relational_store/frameworks/native/rdb/include/grd_api_manager.h b/relational_store/frameworks/native/rdb/include/grd_api_manager.h index ed7b9d0558f3393445e689644ce050c8fff9b8b3..51a01de1fafe4ec2b391fa8b5a47648de82652c0 100644 --- a/relational_store/frameworks/native/rdb/include/grd_api_manager.h +++ b/relational_store/frameworks/native/rdb/include/grd_api_manager.h @@ -58,6 +58,7 @@ typedef int32_t (*DBRestore)(const char *dbFile, const char *backupDbFile, GRD_C typedef int32_t (*DBReKey)(const char *dbFile, const char *configStr, GRD_CipherInfoT *cipherInfo); typedef GRD_DbValueT (*DBGetConfig)(GRD_DB *db, GRD_ConfigTypeE type); typedef int32_t (*DBSetConfig)(GRD_DB *db, GRD_ConfigTypeE type, GRD_DbValueT value); +typedef int32_t (*DBSqlRegistryThreadPool)(GRD_DB *db, GRD_ThreadPool *threadPool); struct GRD_APIInfo { DBOpen DBOpenApi = nullptr; @@ -90,6 +91,7 @@ struct GRD_APIInfo { DBReKey DBReKeyApi = nullptr; DBGetConfig DBGetConfigApi = nullptr; DBSetConfig DBSetConfigApi = nullptr; + DBSqlRegistryThreadPool DBSqlRegistryThreadPool = nullptr; }; API_EXPORT bool IsUsingArkData(); diff --git a/relational_store/frameworks/native/rdb/include/grd_type_export.h b/relational_store/frameworks/native/rdb/include/grd_type_export.h index 9d3632ae5a60d1630975520fd4672fa61fe64d1c..dedcdf5275a9f48efdb940eee9cf52da20a95011 100644 --- a/relational_store/frameworks/native/rdb/include/grd_type_export.h +++ b/relational_store/frameworks/native/rdb/include/grd_type_export.h @@ -28,6 +28,12 @@ extern "C" { typedef struct GRD_DB GRD_DB; typedef struct GRD_SqlStmt GRD_SqlStmt; +typedef struct GRD_Stmt GRD_StmtT; + +typedef void (*GRD_ScheduleFunc)(void *func, void *param); +typedef struct GRD_ThreadPool { + GRD_ScheduleFunc schedule; +} GRD_ThreadPoolT; /** * @brief Open database config @@ -39,6 +45,7 @@ typedef struct GRD_SqlStmt GRD_SqlStmt; // check data in database when open database, if data is corrupted, rebuild the database. #define GRD_DB_OPEN_CHECK 0x04 #define GRD_DB_OPEN_SHARED_READ_ONLY 0x08 +#define GRD_DB_OPEN_IGNORE_DATA_CORRPUPTION 0X10 // open database for ignore the meta data corruption /** * @brief Close database config @@ -53,6 +60,7 @@ typedef enum { GRD_DB_DATATYPE_TEXT, GRD_DB_DATATYPE_BLOB, GRD_DB_DATATYPE_FLOATVECTOR, + GRD_DB_DATATYPE_JSONSTR, GRD_DB_DATATYPE_NULL, } GRD_DbDataTypeE; diff --git a/relational_store/frameworks/native/rdb/include/rd_connection.h b/relational_store/frameworks/native/rdb/include/rd_connection.h index cc245395e1fca79526eb2dc8d1e4d420a5692be4..55ce84e9b903a038213508f4fad602f79dbe881c 100644 --- a/relational_store/frameworks/native/rdb/include/rd_connection.h +++ b/relational_store/frameworks/native/rdb/include/rd_connection.h @@ -41,6 +41,7 @@ public: std::pair CreateStatement(const std::string &sql, SConn conn) override; int32_t GetDBType() const override; bool IsWriter() const override; + bool IsInTrans() const override; int32_t ReSetKey(const RdbStoreConfig &config) override; int32_t TryCheckPoint(bool timeout) override; int32_t LimitWalSize() override; @@ -61,6 +62,9 @@ public: ExchangeStrategy GenerateExchangeStrategy(const SlaveStatus &status) override; private: + static void CheckConfig(std::shared_ptr conn, const RdbStoreConfig &config); + static void ExecuteSet(std::shared_ptr conn, const std::string ¶mName, int num); + static constexpr int MAX_VARIABLE_NUM = 500; static constexpr const char *GRD_OPEN_CONFIG_STR = "\"pageSize\":8, \"crcCheckEnable\":0, \"redoFlushByTrx\":1, \"bufferPoolSize\":10240," @@ -69,6 +73,7 @@ private: static constexpr uint32_t ITER_V1 = 5000; static constexpr uint32_t ITERS[] = { NO_ITER, ITER_V1 }; static constexpr uint32_t ITERS_COUNT = sizeof(ITERS) / sizeof(ITERS[0]); + static constexpr int NCANDIDATES_DEFAULT_NUM = 128; static const int32_t regCreator_; static const int32_t regRepairer_; static const int32_t regDeleter_; diff --git a/relational_store/frameworks/native/rdb/include/rd_statement.h b/relational_store/frameworks/native/rdb/include/rd_statement.h index 795f6a8255ac2c0443e1b5ccdae4203d433ecfd4..fcba0f5b59dc96062d296e7b5a850b60a713d27b 100644 --- a/relational_store/frameworks/native/rdb/include/rd_statement.h +++ b/relational_store/frameworks/native/rdb/include/rd_statement.h @@ -59,6 +59,7 @@ private: int32_t Bind(const std::vector> &args); int InnerBindBlobTypeArgs(const ValueObject &bindArg, uint32_t index) const; int IsValid(int index) const; + int PreGetColCount(); bool readOnly_ = false; bool isStepInPrepare_ = false; diff --git a/relational_store/frameworks/native/rdb/include/rd_utils.h b/relational_store/frameworks/native/rdb/include/rd_utils.h index 49b4b8d16e6c93d4c2957998aa47a83db8c6c775..1e759ac4d759ea9b9b611b3efcecdbf4569e1f93 100644 --- a/relational_store/frameworks/native/rdb/include/rd_utils.h +++ b/relational_store/frameworks/native/rdb/include/rd_utils.h @@ -70,6 +70,10 @@ public: static int RdDbGetVersion(GRD_DB *db, GRD_ConfigTypeE type, int &version); static int RdDbSetVersion(GRD_DB *db, GRD_ConfigTypeE type, int version); + + static int RdSqlRegistryThreadPool(GRD_DB *db); +private: + static GRD_ThreadPoolT threadPool_; }; } // namespace NativeRdb diff --git a/relational_store/frameworks/native/rdb/include/rdb_security_manager.h b/relational_store/frameworks/native/rdb/include/rdb_security_manager.h index bf6bb1a47842cb63a027ea1af7c7025caa7c6743..af98a09f562b2037e4e7e54178c4ce0bc3e1d3f1 100644 --- a/relational_store/frameworks/native/rdb/include/rdb_security_manager.h +++ b/relational_store/frameworks/native/rdb/include/rdb_security_manager.h @@ -111,6 +111,10 @@ private: bool LoadSecretKeyFromDisk(const std::string &keyPath, RdbSecretKeyData &keyData); bool IsKeyFileEmpty(const std::string &keyFile); static bool IsKeyExpired(const time_t &createTime); + std::vector GetRootKeyAlias(); + std::string GetBundleNameByAlias(); + std::string GetBundleNameByAlias(const std::vector &rootKeyAlias); + void SetRootKeyAlias(std::vector rootKeyAlias); int32_t HksLoopUpdate(const struct HksBlob *handle, const struct HksParamSet *paramSet, const struct HksBlob *inData, struct HksBlob *outData); int32_t HksEncryptThreeStage(const struct HksBlob *keyAlias, const struct HksParamSet *paramSet, @@ -134,6 +138,7 @@ private: static constexpr uint8_t UNDISTRIBUTED = 0; static constexpr uint8_t DISTRIBUTED = 1; + std::mutex rootKeyMutex_; std::vector rootKeyAlias_{}; std::vector nonce_; std::vector aad_; diff --git a/relational_store/frameworks/native/rdb/include/rdb_service_proxy.h b/relational_store/frameworks/native/rdb/include/rdb_service_proxy.h index a84d99d82e36545cb69f709b63841ef73b9e15af..5496048273d0a2e7e35ff6e78b52eb6ed3a60903 100644 --- a/relational_store/frameworks/native/rdb/include/rdb_service_proxy.h +++ b/relational_store/frameworks/native/rdb/include/rdb_service_proxy.h @@ -81,7 +81,7 @@ public: const PredicatesMemo &predicates, const std::vector &columns) override; int32_t Disable(const RdbSyncerParam ¶m) override; int32_t Enable(const RdbSyncerParam ¶m) override; - int32_t GetPassword(const RdbSyncerParam ¶m, std::vector &key) override; + int32_t GetPassword(const RdbSyncerParam ¶m, std::vector> &key) override; std::pair LockCloudContainer(const RdbSyncerParam ¶m) override; diff --git a/relational_store/frameworks/native/rdb/include/rdb_store_impl.h b/relational_store/frameworks/native/rdb/include/rdb_store_impl.h index 45fba2d2f72996ed5320dec8c88b64118691f605..bdbb2a1f14b84563f54886b73b3f6e0191adf01b 100644 --- a/relational_store/frameworks/native/rdb/include/rdb_store_impl.h +++ b/relational_store/frameworks/native/rdb/include/rdb_store_impl.h @@ -82,12 +82,14 @@ public: RdbStoreImpl(const RdbStoreConfig &config, int &errCode); ~RdbStoreImpl() override; std::pair Insert(const std::string &table, const Row &row, Resolution resolution) override; - std::pair BatchInsert(const std::string &table, const ValuesBuckets &values) override; + std::pair BatchInsert(const std::string &table, const ValuesBuckets &rows) override; + std::pair BatchInsertWithConflictResolution( + const std::string &table, const ValuesBuckets &rows, Resolution resolution) override; std::pair Update(const std::string &table, const Row &row, const std::string &where, const Values &args, Resolution resolution) override; int Delete(int &deletedRows, const std::string &table, const std::string &whereClause, const Values &args) override; std::shared_ptr QuerySql(const std::string &sql, const Values &args) override; - std::shared_ptr QueryByStep(const std::string &sql, const Values &args) override; + std::shared_ptr QueryByStep(const std::string &sql, const Values &args, bool preCount) override; std::shared_ptr RemoteQuery( const std::string &device, const AbsRdbPredicates &predicates, const Fields &columns, int &errCode) override; std::pair> QuerySharingResource( @@ -151,6 +153,7 @@ public: std::string GetName(); std::string GetFileType(); int32_t ExchangeSlaverToMaster(); + void Close(); protected: std::string GetLogTableName(const std::string &tableName) override; @@ -172,10 +175,22 @@ private: std::set tables_; std::set changes_; }; + class SavePointers { + public: + SavePointers(std::shared_ptr pool, std::shared_ptr conn, + ConflictResolution resolution, int &errCode); + ~SavePointers(); + private: + std::shared_ptr pool_; + std::shared_ptr conn_; + ConflictResolution resolution_; + int &errCode_; + }; + class StoreSuspender; static void AfterOpen(const RdbParam ¶m, int32_t retry = 0); int InnerOpen(); - void InitSyncerParam(const RdbStoreConfig &config, bool created); + void InitSyncerParam(const RdbStoreConfig &config); int ExecuteByTrxId(const std::string &sql, int64_t trxId, bool closeConnAfterExecute = false, const std::vector &bindArgs = {}); std::pair HandleDifferentSqlTypes( @@ -184,10 +199,10 @@ private: std::pair BeginExecuteSql(const std::string &sql); int GetDataBasePath(const std::string &databasePath, std::string &backupFilePath); void DoCloudSync(const std::string &table); - static int InnerSync( - const RdbParam ¶m, const Options &option, const Memo &predicates, const AsyncDetail &async); - int InnerBackup( - const std::string &databasePath, const std::vector &destEncryptKey = std::vector()); + static int InnerSync(const RdbParam ¶m, const Options &option, const Memo &predicates, + const AsyncDetail &async); + int InnerBackup(const std::string &databasePath, + const std::vector &destEncryptKey = std::vector()); ModifyTime GetModifyTimeByRowId(const std::string &logTable, std::vector &keys); Uri GetUri(const std::string &event); int SubscribeLocal(const SubscribeOption &option, RdbStoreObserver *observer); @@ -217,6 +232,10 @@ private: bool TryGetMasterSlaveBackupPath(const std::string &srcPath, std::string &destPath, bool isRestore = false); void NotifyDataChange(); int GetDestPath(const std::string &backupPath, std::string &destPath); + std::shared_ptr GetPool() const; + int HandleCloudSyncAfterSetDistributedTables( + const std::vector &tables, const DistributedRdb::DistributedConfig &distributedConfig); + std::pair> GetConn(bool isRead); static constexpr char SCHEME_RDB[] = "rdb://"; static constexpr uint32_t EXPANSION = 2; @@ -233,11 +252,13 @@ private: int64_t vSchema_ = 0; std::atomic newTrxId_ = 1; const RdbStoreConfig config_; + // Can only be modified within the constructor DistributedRdb::RdbSyncerParam syncerParam_; std::string path_; std::string name_; std::string fileType_; mutable std::shared_mutex rwMutex_; + mutable std::shared_mutex poolMutex_; std::mutex mutex_; std::shared_ptr connectionPool_ = nullptr; std::shared_ptr delayNotifier_ = nullptr; diff --git a/relational_store/frameworks/native/rdb/include/rdb_store_manager.h b/relational_store/frameworks/native/rdb/include/rdb_store_manager.h index aacb49afe9f33dbb3c5abe2d2c508797913cc30b..7c2693205a413eb3b91af67084c5556d9e3c410a 100644 --- a/relational_store/frameworks/native/rdb/include/rdb_store_manager.h +++ b/relational_store/frameworks/native/rdb/include/rdb_store_manager.h @@ -34,18 +34,17 @@ public: static RdbStoreManager &GetInstance(); RdbStoreManager(); virtual ~RdbStoreManager(); - std::shared_ptr GetRdbStore(const RdbStoreConfig &config, - int &errCode, int version, RdbOpenCallback &openCallback); + std::shared_ptr GetRdbStore( + const RdbStoreConfig &config, int &errCode, int version, RdbOpenCallback &openCallback); void Clear(); - bool Remove(const std::string &path); - bool Delete(const std::string &path); + bool Remove(const std::string &path, bool shouldClose); + bool Delete(const std::string &path, bool shouldClose); int SetSecurityLabel(const RdbStoreConfig &config); private: using Param = DistributedRdb::RdbSyncerParam; using Info = DistributedRdb::RdbDebugInfo; - int ProcessOpenCallback(RdbStore &rdbStore, - const RdbStoreConfig &config, int version, RdbOpenCallback &openCallback); + int ProcessOpenCallback(RdbStore &rdbStore, int version, RdbOpenCallback &openCallback); bool IsConfigInvalidChanged(const std::string &path, RdbStoreConfig &config); bool IsPermitted(const DistributedRdb::RdbSyncerParam ¶m); int32_t GetParamFromService(DistributedRdb::RdbSyncerParam ¶m); diff --git a/relational_store/frameworks/native/rdb/include/rdb_time_utils.h b/relational_store/frameworks/native/rdb/include/rdb_time_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..3a4797b5003561b8afa01dea1f8ac726988ac4ba --- /dev/null +++ b/relational_store/frameworks/native/rdb/include/rdb_time_utils.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 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 NATIVE_RDB_TIME_UTILS_H +#define NATIVE_RDB_TIME_UTILS_H + +#include +#include +#include + +namespace OHOS { +namespace NativeRdb { + +class RdbTimeUtils { +public: + static std::string GetCurSysTimeWithMs(); + static std::string GetTimeWithMs(time_t sec, int64_t nsec); +}; + +} // namespace NativeRdb +} // namespace OHOS +#endif diff --git a/relational_store/frameworks/native/rdb/include/share_block.h b/relational_store/frameworks/native/rdb/include/share_block.h index 278f9ae393e5cbe53bcd3229a3c44121ec57944c..830344c93d598179b6e86529f25b475982df7f43 100644 --- a/relational_store/frameworks/native/rdb/include/share_block.h +++ b/relational_store/frameworks/native/rdb/include/share_block.h @@ -58,6 +58,15 @@ struct SharedBlockInfo { } }; +int DefAddRow(void *pCtx, int addedRows); +int DefReset(void *pCtx, int startPos); +int DefFinish(void *pCtx, int addedRows, int totalRows); +int DefPutString(void *pCtx, int addedRows, int column, const char *text, int size); +int DefPutLong(void *pCtx, int addedRows, int column, sqlite3_int64 value); +int DefPutDouble(void *pCtx, int addedRows, int column, double value); +int DefPutBlob(void *pCtx, int addedRows, int column, const void *blob, int len); +int DefPutNull(void *pCtx, int addedRows, int column); +int DefPutOther(void *pCtx, int addedRows, int column); int SeriAddRow(void *pCtx, int addedRows); int SeriReset(void *pCtx, int startPos); int SeriFinish(void *pCtx, int addedRows, int totalRows); @@ -83,9 +92,9 @@ FillOneRowResult FillOneRowOfNull( FillOneRowResult FillOneRow( AppDataFwk::SharedBlock *sharedBlock, sqlite3_stmt *statement, int numColumns, int startPos, int addedRows); void FillRow(SharedBlockInfo *info, sqlite3_stmt *stmt); +void DefFillRow(SharedBlockInfo *info, sqlite3_stmt *stmt); int FillSharedBlock(SharedBlockInfo *info, sqlite3_stmt *stmt); bool ResetStatement(SharedBlockInfo *info, sqlite3_stmt *stmt); -int64_t GetCombinedData(int startPos, int totalRows); #ifdef __cplusplus } #endif diff --git a/relational_store/frameworks/native/rdb/include/sqlite_connection.h b/relational_store/frameworks/native/rdb/include/sqlite_connection.h index e80e4824b1b77a9bcbe70d684f105cddfece8b97..caef3af483ca01fe1d7d9f7ca80c72cf8ce4708b 100644 --- a/relational_store/frameworks/native/rdb/include/sqlite_connection.h +++ b/relational_store/frameworks/native/rdb/include/sqlite_connection.h @@ -57,6 +57,7 @@ public: int32_t GetJournalMode() override; std::pair CreateStatement(const std::string &sql, SConn conn) override; bool IsWriter() const override; + bool IsInTrans() const override; int SubscribeTableChanges(const Notifier ¬ifier) override; int GetMaxVariable() const override; int32_t GetDBType() const override; @@ -99,18 +100,13 @@ private: int SetAutoCheckpoint(const RdbStoreConfig &config); int SetWalFile(const RdbStoreConfig &config); int SetWalSyncMode(const std::string &syncMode); + int SetTokenizer(const RdbStoreConfig &config); void LimitPermission(const std::string &dbPath) const; int SetPersistWal(); int SetBusyTimeout(int timeout); int RegDefaultFunctions(sqlite3 *dbHandle); - static void MergeAssets(sqlite3_context *ctx, int argc, sqlite3_value **argv); - static void MergeAsset(sqlite3_context *ctx, int argc, sqlite3_value **argv); - static void CompAssets( - std::map &oldAssets, std::map &newAssets); - static void MergeAsset(ValueObject::Asset &oldAsset, ValueObject::Asset &newAsset); - int SetCustomFunctions(const RdbStoreConfig &config); int SetCustomScalarFunction(const std::string &functionName, int argc, ScalarFunction *function); int32_t UnsubscribeLocalDetail( @@ -132,8 +128,6 @@ private: static constexpr SqliteConnection::Suffix FILE_SUFFIXES[] = { { "", "DB" }, { "-shm", "SHM" }, { "-wal", "WAL" }, { "-journal", "JOURNAL" }, { "-slaveFailure", nullptr }, { "-syncInterrupt", nullptr }, { ".corruptedflg", nullptr } }; - static constexpr const char *MERGE_ASSETS_FUNC = "merge_assets"; - static constexpr const char *MERGE_ASSET_FUNC = "merge_asset"; static constexpr int CHECKPOINT_TIME = 500; static constexpr int DEFAULT_BUSY_TIMEOUT_MS = 2000; static constexpr int BACKUP_PAGES_PRE_STEP = 12800; // 1024 * 4 * 12800 == 50m diff --git a/relational_store/frameworks/native/rdb/include/sqlite_default_function.h b/relational_store/frameworks/native/rdb/include/sqlite_default_function.h new file mode 100644 index 0000000000000000000000000000000000000000..7c7f70d66c6aa1af9a099ad0f3a9849cb3e1b24f --- /dev/null +++ b/relational_store/frameworks/native/rdb/include/sqlite_default_function.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024 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 SQLITE_FUNCTION_REGISTRY_H +#define SQLITE_FUNCTION_REGISTRY_H + +#include + +#include + +#include "value_object.h" + +namespace OHOS { +namespace NativeRdb { +struct SqliteFunction { + const char *name; + int numArgs; + void (*function)(sqlite3_context *, int, sqlite3_value **); +}; + +class SqliteFunctionRegistry { +private: + static void MergeAssets(sqlite3_context *ctx, int argc, sqlite3_value **argv); + static void MergeAsset(sqlite3_context *ctx, int argc, sqlite3_value **argv); + static void CompAssets( + std::map &oldAssets, std::map &newAssets); + static void MergeAsset(ValueObject::Asset &oldAsset, ValueObject::Asset &newAsset); + static void ImportDB(sqlite3_context *ctx, int argc, sqlite3_value **argv); + static void SqliteResultError(sqlite3_context *ctx, const int &errCode, const std::string &msg); + static int32_t IntegrityCheck(sqlite3 *dbHandle); + static int32_t BackUpDB(sqlite3 *source, sqlite3 *dest); + static constexpr SqliteFunction FUNCTIONS[] = { + { "merge_assets", 2, &SqliteFunctionRegistry::MergeAssets }, + { "merge_asset", 2, &SqliteFunctionRegistry::MergeAsset }, + { "import_db_from_path", 1, &SqliteFunctionRegistry::ImportDB }, + }; + +public: + static constexpr std::pair GetFunctions() + { + return { FUNCTIONS, sizeof(FUNCTIONS) / sizeof(FUNCTIONS[0]) }; + }; +}; + +} // namespace NativeRdb +} // namespace OHOS +#endif diff --git a/relational_store/frameworks/native/rdb/include/sqlite_global_config.h b/relational_store/frameworks/native/rdb/include/sqlite_global_config.h index 2395f2c5d2646945d70200202bba59c3a9c21101..1caa28bf0cfbbc7da1cfea786de69f7da72df57a 100644 --- a/relational_store/frameworks/native/rdb/include/sqlite_global_config.h +++ b/relational_store/frameworks/native/rdb/include/sqlite_global_config.h @@ -78,6 +78,8 @@ public: static int GetWalAutoCheckpoint(); static std::string GetDefaultJournalMode(); static int GetDbPath(const RdbStoreConfig &config, std::string &dbPath); + static void Corruption(void *arg, const void *msg); + static std::string GetLastCorruptionMsg(); }; } // namespace NativeRdb diff --git a/relational_store/frameworks/native/rdb/include/sqlite_sql_builder.h b/relational_store/frameworks/native/rdb/include/sqlite_sql_builder.h index e11d96bd6814d660bd2e53eda2625a55697734a3..d4c636a0700f73e38a60b51f1958c914c456e708 100644 --- a/relational_store/frameworks/native/rdb/include/sqlite_sql_builder.h +++ b/relational_store/frameworks/native/rdb/include/sqlite_sql_builder.h @@ -49,7 +49,8 @@ public: const AbsRdbPredicates &predicates, const std::vector &columns, const std::string &logTable); static std::string GetSqlArgs(size_t size); - static BatchRefSqls GenerateSqls(const std::string &table, const ValuesBuckets &buckets, int limit); + static BatchRefSqls GenerateSqls(const std::string &table, const ValuesBuckets &buckets, int limit, + ConflictResolution resolution = ConflictResolution::ON_CONFLICT_REPLACE); static void UpdateAssetStatus(const ValueObject &value, int32_t status); private: diff --git a/relational_store/frameworks/native/rdb/include/sqlite_utils.h b/relational_store/frameworks/native/rdb/include/sqlite_utils.h index 3158a555721b3892bb778ac506a52409cec62c1f..8c8ec18e2be25a4a083ad11c3b2da5ef83e32f09 100644 --- a/relational_store/frameworks/native/rdb/include/sqlite_utils.h +++ b/relational_store/frameworks/native/rdb/include/sqlite_utils.h @@ -18,13 +18,14 @@ #include #include -#include -#include "sqlite3sym.h" +#include "rdb_types.h" +#include "rdb_store_config.h" namespace OHOS { namespace NativeRdb { +using DebugInfo = OHOS::DistributedRdb::RdbDebugInfo; class SqliteUtils { public: static constexpr int STATEMENT_SELECT = 1; @@ -58,7 +59,6 @@ public: static bool RenameFile(const std::string &srcFile, const std::string &destFile); static bool CopyFile(const std::string &srcFile, const std::string &destFile); static std::string Anonymous(const std::string &srcFile); - static std::string AnonySql(const std::string &sql); static ssize_t GetFileSize(const std::string &fileName); static bool IsSlaveDbName(const std::string &fileName); static std::string GetSlavePath(const std::string &name); @@ -70,6 +70,13 @@ public: static const char *HmacAlgoDescription(int32_t hmacAlgo); static const char *KdfAlgoDescription(int32_t kdfAlgo); static const char *EncryptAlgoDescription(int32_t encryptAlgo); + static bool DeleteDirtyFiles(const std::string &backupFilePath); + static std::pair Stat(const std::string &path); + static std::string FomatConfigChg(const std::string &path, const RdbStoreConfig &config, + const DistributedRdb::RdbSyncerParam &lastParam); + static std::string ReadFileHeader(const std::string &filePath); + static std::string FormatDebugInfo(const std::map &debugs, const std::string &header); + static std::string FormatDebugInfoBrief(const std::map &debugs, const std::string &header); private: struct SqlType { @@ -100,12 +107,7 @@ private: static std::string GetAnonymousName(const std::string& fileName); static std::string AnonyDigits(const std::string& fileName); - static bool IsSpecialChar(char c); - static std::vector SplitString(const std::string &input); - static std::string ReplaceMultipleSpaces(const std::string &str); - static std::string AnonyWord(const std::string &word); - static bool Find(const std::string &word, const char *const array[], uint32_t length); - static std::string AnonySqlString(const std::string &input, const char *const array[], uint32_t length); + static std::string GetFileStatInfo(const DebugInfo &debugInfo); }; } // namespace NativeRdb diff --git a/relational_store/frameworks/native/rdb/include/step_result_set.h b/relational_store/frameworks/native/rdb/include/step_result_set.h index 3db6ebde8b8c1fb2bbb64033a766a9c94db580e7..036c16d9456feaeee1e6fc1653f6c5fa70949270 100644 --- a/relational_store/frameworks/native/rdb/include/step_result_set.h +++ b/relational_store/frameworks/native/rdb/include/step_result_set.h @@ -33,7 +33,7 @@ public: using Values = std::vector; using Conn = std::shared_ptr; using Time = std::chrono::steady_clock::time_point; - StepResultSet(Time start, Conn conn, const std::string &sql, const Values &args, bool safe = false); + StepResultSet(Time start, Conn conn, const std::string &sql, const Values &args, bool preCount, bool safe = false); ~StepResultSet() override; int GetColumnType(int columnIndex, ColumnType &columnType) override; int GoToRow(int position) override; diff --git a/relational_store/frameworks/native/rdb/include/trans_db.h b/relational_store/frameworks/native/rdb/include/trans_db.h index de0de5764c8eddfd8a8faafbb838669e874ac9fb..de97806c88c23e204d949a8b096fbd8ee9714494 100644 --- a/relational_store/frameworks/native/rdb/include/trans_db.h +++ b/relational_store/frameworks/native/rdb/include/trans_db.h @@ -26,11 +26,13 @@ public: TransDB(std::shared_ptr conn, const std::string &name); std::pair Insert(const std::string &table, const Row &row, Resolution resolution) override; std::pair BatchInsert(const std::string &table, const RefRows &rows) override; + std::pair BatchInsertWithConflictResolution( + const std::string &table, const ValuesBuckets &rows, Resolution resolution) override; std::pair Update(const std::string &table, const Row &row, const std::string &where, const Values &args, Resolution resolution) override; int Delete(int &deletedRows, const std::string &table, const std::string &whereClause, const Values &args) override; std::shared_ptr QuerySql(const std::string &sql, const Values &args) override; - std::shared_ptr QueryByStep(const std::string &sql, const Values &args) override; + std::shared_ptr QueryByStep(const std::string &sql, const Values &args, bool preCount) override; std::pair Execute(const std::string &sql, const Values &args, int64_t trxId) override; int GetVersion(int &version) override; int SetVersion(int version) override; diff --git a/relational_store/frameworks/native/rdb/include/transaction_impl.h b/relational_store/frameworks/native/rdb/include/transaction_impl.h index c078659fecbf817c42dd84941295611a2487c13d..a3049314deefa9e94c748652073991820c603262 100644 --- a/relational_store/frameworks/native/rdb/include/transaction_impl.h +++ b/relational_store/frameworks/native/rdb/include/transaction_impl.h @@ -36,6 +36,8 @@ public: std::pair Insert(const std::string &table, const Row &row, Resolution resolution) override; std::pair BatchInsert(const std::string &table, const Rows &rows) override; std::pair BatchInsert(const std::string &table, const RefRows &rows) override; + std::pair BatchInsertWithConflictResolution( + const std::string &table, const RefRows &rows, Resolution resolution) override; std::pair Update(const std::string &table, const Row &row, const std::string &where, const Values &args, Resolution resolution) override; std::pair Update( @@ -43,8 +45,9 @@ public: std::pair Delete( const std::string &table, const std::string &whereClause, const Values &args) override; std::pair Delete(const AbsRdbPredicates &predicates) override; - std::shared_ptr QueryByStep(const std::string &sql, const Values &args) override; - std::shared_ptr QueryByStep(const AbsRdbPredicates &predicates, const Fields &columns) override; + std::shared_ptr QueryByStep(const std::string &sql, const Values &args, bool preCount) override; + std::shared_ptr QueryByStep(const AbsRdbPredicates &predicates, const Fields &columns, + bool preCount) override; std::pair Execute(const std::string &sql, const Values &args) override; static std::pair> Create( @@ -53,6 +56,7 @@ public: private: static std::string GetBeginSql(int32_t type); int32_t Begin(int32_t type); + bool IsInTransaction(); int32_t CloseInner(); std::shared_ptr GetStore(); void AddResultSet(std::weak_ptr resultSet); diff --git a/relational_store/frameworks/native/rdb/mock/include/rdb_store_impl.h b/relational_store/frameworks/native/rdb/mock/include/rdb_store_impl.h index 8719b59b2dda4aab4cd31f9b794c9a480302e3f6..8e5d93561ef704d86e02ebf0107b942bd546adce 100644 --- a/relational_store/frameworks/native/rdb/mock/include/rdb_store_impl.h +++ b/relational_store/frameworks/native/rdb/mock/include/rdb_store_impl.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "abs_shared_result_set.h" @@ -31,18 +32,21 @@ #include "sqlite_statement.h" namespace OHOS::NativeRdb { +class DelayNotify; class RdbStoreImpl : public RdbStore { public: RdbStoreImpl(const RdbStoreConfig &config); RdbStoreImpl(const RdbStoreConfig &config, int &errCode); ~RdbStoreImpl() override; std::pair Insert(const std::string &table, const Row &row, Resolution resolution) override; - std::pair BatchInsert(const std::string &table, const ValuesBuckets &values) override; + std::pair BatchInsert(const std::string &table, const ValuesBuckets &rows) override; + std::pair BatchInsertWithConflictResolution( + const std::string &table, const ValuesBuckets &rows, Resolution resolution) override; std::pair Update(const std::string &table, const Row &row, const std::string &where, const Values &args, Resolution resolution) override; int Delete(int &deletedRows, const std::string &table, const std::string &whereClause, const Values &args) override; std::shared_ptr QuerySql(const std::string &sql, const Values &args) override; - std::shared_ptr QueryByStep(const std::string &sql, const Values &args) override; + std::shared_ptr QueryByStep(const std::string &sql, const Values &args, bool preCount) override; int ExecuteSql(const std::string &sql, const Values &args) override; std::pair Execute(const std::string &sql, const Values &args, int64_t trxId) override; int ExecuteAndGetLong(int64_t &outValue, const std::string &sql, const Values &args) override; @@ -80,6 +84,7 @@ public: std::string GetName(); std::string GetFileType(); int32_t ExchangeSlaverToMaster(); + void Close(); private: using Stmt = std::shared_ptr; @@ -96,7 +101,18 @@ private: std::set tables_; std::set changes_; }; + class StoreSuspender { + public: + StoreSuspender(RdbStoreImpl &rdbStore) : rdbStore_(rdbStore) + { + } + ~StoreSuspender() + { + } + private: + const RdbStoreImpl &rdbStore_; + }; int InnerOpen(); void InitSyncerParam(const RdbStoreConfig &config, bool created); int ExecuteByTrxId(const std::string &sql, int64_t trxId, bool closeConnAfterExecute = false, @@ -107,8 +123,8 @@ private: std::pair BeginExecuteSql(const std::string &sql); int GetDataBasePath(const std::string &databasePath, std::string &backupFilePath); void DoCloudSync(const std::string &table); - int InnerBackup( - const std::string &databasePath, const std::vector &destEncryptKey = std::vector()); + int InnerBackup(const std::string& databasePath, + const std::vector &destEncryptKey = std::vector()); std::pair> CreateWritableConn(); std::vector CreateBackupBindArgs( const std::string &databasePath, const std::vector &destEncryptKey); @@ -123,6 +139,10 @@ private: bool TryGetMasterSlaveBackupPath(const std::string &srcPath, std::string &destPath, bool isRestore = false); void NotifyDataChange(); int GetDestPath(const std::string &backupPath, std::string &destPath); + std::shared_ptr GetPool() const; + int HandleCloudSyncAfterSetDistributedTables( + const std::vector &tables, const DistributedRdb::DistributedConfig &distributedConfig); + std::pair> GetConn(bool isRead); static constexpr char SCHEME_RDB[] = "rdb://"; static constexpr uint32_t EXPANSION = 2; @@ -143,8 +163,10 @@ private: std::string path_; std::string name_; std::string fileType_; + mutable std::shared_mutex poolMutex_; std::mutex mutex_; std::shared_ptr connectionPool_ = nullptr; + std::shared_ptr delayNotifier_ = nullptr; std::shared_ptr cloudInfo_ = std::make_shared(); ConcurrentMap attachedInfo_; ConcurrentMap> trxConnMap_ = {}; diff --git a/relational_store/frameworks/native/rdb/mock/include/task_executor.h b/relational_store/frameworks/native/rdb/mock/include/task_executor.h index 41deb916828a4393167c3ea53df62bf3d172952f..5f6426aa54c873d0ba527a524dd68a83ab02fad1 100644 --- a/relational_store/frameworks/native/rdb/mock/include/task_executor.h +++ b/relational_store/frameworks/native/rdb/mock/include/task_executor.h @@ -17,8 +17,8 @@ #include #include #include -namespace OHOS::NativeRdb { -class TaskExecutor { +namespace OHOS { +class ExecutorPool { public: using TaskId = uint64_t; using Task = std::function; @@ -26,50 +26,56 @@ public: static constexpr Duration INVALID_DURATION = std::chrono::milliseconds(0); static constexpr TaskId INVALID_TASK_ID = static_cast(0l); static constexpr uint64_t UNLIMITED_TIMES = std::numeric_limits::max(); - class ExecutorPool { - public: - ExecutorPool(size_t max, size_t min) - { - } - ~ExecutorPool() - { - } + ExecutorPool(size_t max, size_t min) + { + } + ~ExecutorPool() + { + } + + TaskId Execute(Task task) + { + return INVALID_TASK_ID; + } - TaskId Execute(Task task) - { - return INVALID_TASK_ID; - } + TaskId Schedule(Duration delay, Task task) + { + return INVALID_TASK_ID; + } - TaskId Schedule(Duration delay, Task task) - { - return INVALID_TASK_ID; - } + TaskId Schedule(Task task, Duration interval) + { + return INVALID_TASK_ID; + } - TaskId Schedule(Task task, Duration interval) - { - return INVALID_TASK_ID; - } + TaskId Schedule(Task task, Duration delay, Duration interval) + { + return INVALID_TASK_ID; + } - TaskId Schedule(Task task, Duration delay, Duration interval) - { - return INVALID_TASK_ID; - } + TaskId Schedule(Task task, Duration delay, Duration interval, uint64_t times) + { + return INVALID_TASK_ID; + } - TaskId Schedule(Task task, Duration delay, Duration interval, uint64_t times) - { - return INVALID_TASK_ID; - } + bool Remove(TaskId taskId, bool wait = false) + { + return true; + } - bool Remove(TaskId taskId, bool wait = false) - { - return true; - } + TaskId Reset(TaskId taskId, Duration interval) + { + return INVALID_TASK_ID; + } +}; +namespace NativeRdb { +class TaskExecutor { +public: + using TaskId = ExecutorPool::TaskId; + using Task = std::function; + using Duration = std::chrono::steady_clock::duration; + static constexpr TaskId INVALID_TASK_ID = ExecutorPool::INVALID_TASK_ID; - TaskId Reset(TaskId taskId, Duration interval) - { - return INVALID_TASK_ID; - } - }; static TaskExecutor &GetInstance(); std::shared_ptr GetExecutor(); void SetExecutor(std::shared_ptr executor); @@ -79,5 +85,6 @@ private: ~TaskExecutor(); std::shared_ptr pool_; }; -} // namespace OHOS::NativeRdb +} // namespace NativeRdb +} // namespace OHOS #endif // DISTRIBUTED_DATA_TASK_EXECUTOR_H diff --git a/relational_store/frameworks/native/rdb/mock/src/rdb_fault_hiview_reporter.cpp b/relational_store/frameworks/native/rdb/mock/src/rdb_fault_hiview_reporter.cpp index 8ec363bd7d791e159fe24cdd5c951f6528257bce..bf72d265c8c2ee3849b4db6890949d058d02de37 100644 --- a/relational_store/frameworks/native/rdb/mock/src/rdb_fault_hiview_reporter.cpp +++ b/relational_store/frameworks/native/rdb/mock/src/rdb_fault_hiview_reporter.cpp @@ -17,7 +17,7 @@ #include "connection.h" namespace OHOS::NativeRdb { -void RdbFaultHiViewReporter::ReportFault(const RdbCorruptedEvent &eventInfo) +void RdbFaultHiViewReporter::ReportCorruptedOnce(const RdbCorruptedEvent &eventInfo) { (void)eventInfo; } @@ -27,17 +27,11 @@ void RdbFaultHiViewReporter::ReportRestore(const RdbCorruptedEvent &eventInfo, b (void)eventInfo; } -void RdbFaultHiViewReporter::Report(const RdbCorruptedEvent &eventInfo) +void RdbFaultHiViewReporter::ReportCorrupted(const RdbCorruptedEvent &eventInfo) { (void)eventInfo; } -std::string RdbFaultHiViewReporter::GetFileStatInfo(const DebugInfo &debugInfo) -{ - (void)debugInfo; - return ""; -} - bool RdbFaultHiViewReporter::IsReportCorruptedFault(const std::string &dbPath) { return false; @@ -53,12 +47,6 @@ void RdbFaultHiViewReporter::DeleteCorruptedFlag(const std::string &dbPath) (void)dbPath; } -std::string RdbFaultHiViewReporter::GetTimeWithMilliseconds(time_t sec, int64_t nsec) -{ - (void)sec; - (void)nsec; - return ""; -} RdbCorruptedEvent RdbFaultHiViewReporter::Create( const RdbStoreConfig &config, int32_t errCode, const std::string &appendix) { @@ -71,30 +59,54 @@ bool RdbFaultHiViewReporter::RegCollector(Connection::Collector collector) (void)collector; return true; } -void RdbFaultHiViewReporter::Update(RdbCorruptedEvent &eventInfo, const std::map &infos) +void RdbFaultHiViewReporter::Update(std::map &localInfos, + const std::map &infos) { - (void)eventInfo; + (void)localInfos; (void)infos; } -std::string RdbFaultHiViewReporter::GetBundleName(const RdbCorruptedEvent &eventInfo) +std::string RdbFaultHiViewReporter::GetBundleName(const std::string &bundleName, const std::string &storeName) { - (void)eventInfo; + (void)bundleName; + (void)storeName; return ""; } -std::string RdbFaultHiViewReporter::Format(const std::map &debugs, const std::string &header) +void RdbFaultHiViewReporter::ReportFault(const RdbFaultEvent &faultEvent) { - (void)debugs; - (void)header; - return ""; + (void)faultEvent; } -std::string RdbFaultHiViewReporter::FormatBrief( - const std::map &debugs, const std::string &header) +RdbFaultEvent::RdbFaultEvent(const std::string &faultType, int32_t errorCode, + const std::string &bundleName, const std::string &custLog) +{ + (void)faultType; + (void)errorCode; + (void)bundleName; + (void)custLog; +} + +void RdbFaultEvent::Report() const +{ +} + +RdbEmptyBlobEvent::RdbEmptyBlobEvent(const std::string &bundleName) + : RdbFaultEvent("", 0, "", "") +{ +} + +void RdbEmptyBlobEvent::Report() const +{ +} + +RdbFaultDbFileEvent::RdbFaultDbFileEvent(const std::string &faultType, int32_t errorCode, const RdbStoreConfig &config, + const std::string &custLog, bool printDbInfo) : RdbFaultEvent(faultType, errorCode, "", custLog), config_(config) +{ + (void)printDbInfo; +} + +void RdbFaultDbFileEvent::Report() const { - (void)debugs; - (void)header; - return ""; } } // namespace OHOS::NativeRdb \ No newline at end of file diff --git a/relational_store/frameworks/native/rdb/mock/src/rdb_time_utils.cpp b/relational_store/frameworks/native/rdb/mock/src/rdb_time_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2d624012c4fee3257463bc9340854b6b0a4bd072 --- /dev/null +++ b/relational_store/frameworks/native/rdb/mock/src/rdb_time_utils.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 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 "rdb_time_utils.h" + +namespace OHOS::NativeRdb { + +std::string RdbTimeUtils::GetCurSysTimeWithMs() +{ + return ""; +} + +std::string RdbTimeUtils::GetTimeWithMs(time_t sec, int64_t nsec) +{ + (void)sec; + (void)nsec; + return ""; +} +} // namespace OHOS::NativeRdb \ No newline at end of file diff --git a/relational_store/frameworks/native/rdb/mock/src/task_executor.cpp b/relational_store/frameworks/native/rdb/mock/src/task_executor.cpp index f0f6e7cc3e27025421df76fda7179a6128d2abad..a0139a30d4020b756a40b1eb6077f491b1c46fde 100644 --- a/relational_store/frameworks/native/rdb/mock/src/task_executor.cpp +++ b/relational_store/frameworks/native/rdb/mock/src/task_executor.cpp @@ -31,12 +31,12 @@ TaskExecutor &TaskExecutor::GetInstance() return instance; } -std::shared_ptr TaskExecutor::GetExecutor() +std::shared_ptr TaskExecutor::GetExecutor() { return pool_; } -void TaskExecutor::SetExecutor(std::shared_ptr executor) +void TaskExecutor::SetExecutor(std::shared_ptr executor) { pool_ = executor; }; diff --git a/relational_store/frameworks/native/rdb/src/abs_predicates.cpp b/relational_store/frameworks/native/rdb/src/abs_predicates.cpp index b0e366d92f4a87ac8826128fbcdaa08dedc52f06..08b297d123b2f4df97271a45c43f21551e806a1f 100644 --- a/relational_store/frameworks/native/rdb/src/abs_predicates.cpp +++ b/relational_store/frameworks/native/rdb/src/abs_predicates.cpp @@ -70,11 +70,7 @@ AbsPredicates *AbsPredicates::EqualTo(const std::string &field, const ValueObjec flagVal = FLAG[static_cast(location)]; valObj = ValueObject(flagVal); } - if (isNeedAnd) { - whereClause += "AND "; - } else { - isNeedAnd = true; - } + CheckIsNeedAnd(); if (flagVal.empty()) { whereClause += newField + " = ? "; bindArgs.push_back(std::move(valObj)); @@ -425,7 +421,7 @@ AbsPredicates *AbsPredicates::Offset(const int offset) AbsPredicates *AbsPredicates::GroupBy(const std::vector &fields) { if (fields.empty()) { - LOG_WARN("groupBy() fails because fields can't be null."); + LOG_WARN("GroupBy() fails because fields can't be null."); return this; } for (auto &field : fields) { diff --git a/relational_store/frameworks/native/rdb/src/abs_rdb_predicates.cpp b/relational_store/frameworks/native/rdb/src/abs_rdb_predicates.cpp index f11e26b2fd71734e4d8ddb27d0750523e828ded5..2ffa84daef740ce2a86af599f1ad64580157b45d 100644 --- a/relational_store/frameworks/native/rdb/src/abs_rdb_predicates.cpp +++ b/relational_store/frameworks/native/rdb/src/abs_rdb_predicates.cpp @@ -177,6 +177,16 @@ AbsRdbPredicates *AbsRdbPredicates::EqualTo(const std::string &field, const Valu if (auto pval = std::get_if(&value.value)) { predicates_.AddOperation(DistributedRdb::EQUAL_TO, field, *pval); } + if (auto pval = std::get_if(&value.value)) { + predicates_.AddOperation(DistributedRdb::RdbPredicateOperator::ASSETS_ONLY, field, (*pval).name); + } + if (auto pval = std::get_if(&value.value)) { + std::vector names; + for (const auto &asset : *pval) { + names.push_back(asset.name); + } + predicates_.AddOperation(DistributedRdb::RdbPredicateOperator::ASSETS_ONLY, field, names); + } return (AbsRdbPredicates *)AbsPredicates::EqualTo(field, value); } diff --git a/relational_store/frameworks/native/rdb/src/abs_result_set.cpp b/relational_store/frameworks/native/rdb/src/abs_result_set.cpp index 3b32a5c93bb3e80154eb30d4e30f15a5e12340f3..467fdc7189aebdb2cb5e5171b20e650f2a4e87e7 100644 --- a/relational_store/frameworks/native/rdb/src/abs_result_set.cpp +++ b/relational_store/frameworks/native/rdb/src/abs_result_set.cpp @@ -99,7 +99,7 @@ int AbsResultSet::GetRowCount(int &count) } if (isClosed_) { - LOG_ERROR("fail, result set E_ALREADY_CLOSED."); + LOG_ERROR("Fail, result set E_ALREADY_CLOSED."); return E_ALREADY_CLOSED; } @@ -134,7 +134,7 @@ int AbsResultSet::InitColumnNames() auto [errCode, names] = GetColumnNames(); if (errCode != E_OK) { - LOG_DEBUG("ret is %{public}d", errCode); + LOG_DEBUG("Ret is %{public}d", errCode); return errCode; } @@ -161,7 +161,7 @@ int AbsResultSet::GetBlob(int columnIndex, std::vector &blob) int type = object.GetType(); if (type == ValueObject::TYPE_ASSETS || type == ValueObject::TYPE_ASSET || type == ValueObject::TYPE_BIGINT || type == ValueObject::TYPE_VECS) { - LOG_ERROR("type invalid col:%{public}d, type:%{public}d!", columnIndex, type); + LOG_ERROR("Type invalid col:%{public}d, type:%{public}d!", columnIndex, type); return E_INVALID_OBJECT_TYPE; } @@ -179,7 +179,7 @@ int AbsResultSet::GetString(int columnIndex, std::string &value) int type = object.GetType(); if (type == ValueObject::TYPE_ASSETS || type == ValueObject::TYPE_ASSET || type == ValueObject::TYPE_BIGINT || type == ValueObject::TYPE_VECS) { - LOG_ERROR("type invalid col:%{public}d, type:%{public}d!", columnIndex, type); + LOG_ERROR("Type invalid col:%{public}d, type:%{public}d!", columnIndex, type); return E_INVALID_OBJECT_TYPE; } return E_OK; @@ -207,7 +207,7 @@ int AbsResultSet::GetLong(int columnIndex, int64_t &value) int type = object.GetType(); if (type == ValueObject::TYPE_ASSETS || type == ValueObject::TYPE_ASSET || type == ValueObject::TYPE_BIGINT || type == ValueObject::TYPE_VECS) { - LOG_ERROR("type invalid col:%{public}d, type:%{public}d!", columnIndex, type); + LOG_ERROR("Type invalid col:%{public}d, type:%{public}d!", columnIndex, type); return E_INVALID_OBJECT_TYPE; } return E_OK; @@ -224,7 +224,7 @@ int AbsResultSet::GetDouble(int columnIndex, double &value) int type = object.GetType(); if (type == ValueObject::TYPE_ASSETS || type == ValueObject::TYPE_ASSET || type == ValueObject::TYPE_BIGINT || type == ValueObject::TYPE_VECS) { - LOG_ERROR("type invalid col:%{public}d, type:%{public}d!", columnIndex, type); + LOG_ERROR("Type invalid col:%{public}d, type:%{public}d!", columnIndex, type); return E_INVALID_OBJECT_TYPE; } return E_OK; @@ -238,7 +238,7 @@ int AbsResultSet::IsColumnNull(int columnIndex, bool &isNull) ColumnType columnType = ColumnType::TYPE_NULL; int errCode = GetColumnType(columnIndex, columnType); if (errCode != E_OK) { - LOG_ERROR("ret is %{public}d", errCode); + LOG_ERROR("Ret is %{public}d", errCode); return errCode; } isNull = (columnType == ColumnType::TYPE_NULL); @@ -369,7 +369,7 @@ int AbsResultSet::GetColumnCount(int &count) } auto errCode = InitColumnNames(); if (errCode != E_OK) { - LOG_DEBUG("ret is %{public}d", errCode); + LOG_DEBUG("Ret is %{public}d", errCode); return errCode; } count = columnCount_; @@ -407,8 +407,9 @@ int AbsResultSet::GetColumnIndex(const std::string &columnName, int &columnIndex return E_OK; } } - LOG_ERROR("failed, columnName is: %{public}s", SqliteUtils::Anonymous(columnName).c_str()); - return E_ERROR; + LOG_ERROR("Failed, columnName : %{public}s, errCode : %{public}d", + SqliteUtils::Anonymous(columnName).c_str(), errCode); + return E_INVALID_ARGS; } int AbsResultSet::GetColumnName(int columnIndex, std::string &columnName) @@ -421,7 +422,7 @@ int AbsResultSet::GetColumnName(int columnIndex, std::string &columnName) return errCode; } if (columnCount_ <= columnIndex || columnIndex < 0) { - LOG_ERROR("invalid columnIndex %{public}d", columnIndex); + LOG_ERROR("Invalid columnIndex %{public}d", columnIndex); return E_COLUMN_OUT_RANGE; } @@ -463,7 +464,7 @@ int AbsResultSet::GetAsset(int32_t col, ValueObject::Asset &value) } if (valueObject.GetType() != ValueObject::TYPE_ASSET) { - LOG_ERROR("failed, type is %{public}d, col is %{public}d!", valueObject.GetType(), col); + LOG_ERROR("Failed, type is %{public}d, col is %{public}d!", valueObject.GetType(), col); return E_INVALID_OBJECT_TYPE; } value = valueObject; @@ -483,7 +484,7 @@ int AbsResultSet::GetAssets(int32_t col, ValueObject::Assets &value) } if (valueObject.GetType() != ValueObject::TYPE_ASSETS) { - LOG_ERROR("failed, type is %{public}d, col is %{public}d!", valueObject.GetType(), col); + LOG_ERROR("Failed, type is %{public}d, col is %{public}d!", valueObject.GetType(), col); return E_INVALID_OBJECT_TYPE; } value = valueObject; @@ -503,12 +504,13 @@ int AbsResultSet::GetFloat32Array(int32_t col, ValueObject::FloatVector &value) } if (valueObject.GetType() != ValueObject::TYPE_VECS) { - LOG_ERROR("failed, type is %{public}d, col is %{public}d!", valueObject.GetType(), col); + LOG_ERROR("Failed, type is %{public}d, col is %{public}d!", valueObject.GetType(), col); return E_INVALID_OBJECT_TYPE; } value = valueObject; return E_OK; } + std::pair> AbsResultSet::GetColumnNames() { return { E_NOT_SUPPORT, {} }; diff --git a/relational_store/frameworks/native/rdb/src/abs_shared_result_set.cpp b/relational_store/frameworks/native/rdb/src/abs_shared_result_set.cpp index 5e4d9925722efdb6d4b6005ce61bbb97217ed64f..ef776bded27cbc076be838522166e27327a287b9 100644 --- a/relational_store/frameworks/native/rdb/src/abs_shared_result_set.cpp +++ b/relational_store/frameworks/native/rdb/src/abs_shared_result_set.cpp @@ -33,7 +33,8 @@ namespace OHOS { namespace NativeRdb { using namespace OHOS::Rdb; using SharedBlock = AppDataFwk::SharedBlock; -AbsSharedResultSet::AbsSharedResultSet(std::string name) : sharedBlock_(nullptr), sharedBlockName_(std::move(name)) +AbsSharedResultSet::AbsSharedResultSet(std::string name) + : AbsResultSet(true), sharedBlock_(nullptr), sharedBlockName_(std::move(name)) { } @@ -287,7 +288,7 @@ int AbsSharedResultSet::GetCustomerValue(int index, ValueObject &value, SharedBl break; } default: - LOG_ERROR("invalid type is %{public}d, col is %{public}d!", cellUnit->type, index); + LOG_ERROR("Invalid type is %{public}d, col is %{public}d!", cellUnit->type, index); return E_INVALID_OBJECT_TYPE; } return E_OK; @@ -302,7 +303,7 @@ int AbsSharedResultSet::CheckState(int columnIndex) return E_ALREADY_CLOSED; } if (GetBlock() == nullptr) { - LOG_ERROR("sharedBlock is null!"); + LOG_ERROR("SharedBlock is null!"); return E_ERROR; } int count = 0; diff --git a/relational_store/frameworks/native/rdb/src/connection_pool.cpp b/relational_store/frameworks/native/rdb/src/connection_pool.cpp index b672efb62256f1ce761f98a12c9574c48a80555c..5d5c2cbac759fb96bd54333e7c71eaf039576249 100644 --- a/relational_store/frameworks/native/rdb/src/connection_pool.cpp +++ b/relational_store/frameworks/native/rdb/src/connection_pool.cpp @@ -28,6 +28,7 @@ #include "rdb_errno.h" #include "rdb_fault_hiview_reporter.h" #include "rdb_sql_statistic.h" +#include "rdb_security_manager.h" #include "sqlite_global_config.h" #include "sqlite_utils.h" @@ -52,12 +53,15 @@ std::shared_ptr ConnPool::Create(const RdbStoreConfig &config, int &er return nullptr; } std::shared_ptr conn; - for (uint32_t retry = 0; retry < ITERS_COUNT; ++retry) { - std::tie(errCode, conn) = pool->Init(); - if (errCode != E_SQLITE_CORRUPT) { - break; - } + auto originalIter = config.GetIter(); + std::tie(errCode, conn) = pool->Init(); + if (errCode == E_SQLITE_CORRUPT && originalIter == 0) { config.SetIter(ITER_V1); + std::tie(errCode, conn) = pool->Init(); + // TOD: Report if successful + } + if (errCode == E_SQLITE_CORRUPT) { + config.SetIter(originalIter); } std::string dbPath; (void)SqliteGlobalConfig::GetDbPath(config, dbPath); @@ -67,7 +71,8 @@ std::shared_ptr ConnPool::Create(const RdbStoreConfig &config, int &er errCode, config.GetBundleName().c_str(), config.GetModuleName().c_str(), SqliteUtils::Anonymous(dbPath).c_str(), config.GetDBType(), config.GetHaMode(), config.IsEncrypt(), config.GetArea(), config.GetSecurityLevel(), config.GetRoleType(), config.IsReadOnly(), - Reportor::FormatBrief(Connection::Collect(config), SqliteUtils::Anonymous(config.GetName())).c_str()); + SqliteUtils::FormatDebugInfoBrief(Connection::Collect(config), + SqliteUtils::Anonymous(config.GetName())).c_str()); return errCode == E_OK ? pool : nullptr; } @@ -77,28 +82,22 @@ std::pair> ConnPool::HandleDataCorr std::pair> result; auto &[rebuiltType, pool] = result; - errCode = Connection::Repair(storeConfig); - if (errCode == E_OK) { +// RestoreReporter reporter(storeConfig, __FUNCTION__); + int repairErrCode = Connection::Repair(storeConfig); + if (repairErrCode != E_OK && !storeConfig.GetAllowRebuild()) { + return result; + } + if (repairErrCode == E_OK) { rebuiltType = RebuiltType::REPAIRED; +// reporter.SetRestoreType("Repair"); } else if (storeConfig.GetAllowRebuild()) { Connection::Delete(storeConfig); + RdbSecurityManager::GetInstance().DelAllKeyFiles(storeConfig.GetPath()); rebuiltType = RebuiltType::REBUILT; - } else if (storeConfig.IsEncrypt() && storeConfig.GetEncryptKey().empty()) { - errCode = E_INVALID_SECRET_KEY; - return result; - } else { - errCode = E_SQLITE_CORRUPT; - return result; - } - pool = Create(storeConfig, errCode); - if (errCode != E_OK) { - LOG_WARN("failed, type %{public}d db %{public}s encrypt %{public}d error %{public}d, errno", - static_cast(rebuiltType), SqliteUtils::Anonymous(storeConfig.GetName()).c_str(), - storeConfig.IsEncrypt(), errCode, errno); - } else { - Reportor::ReportRestore(Reportor::Create(storeConfig, E_OK, "RestoreType:Rebuild"), false); +// reporter.SetRestoreType("Rebuilt"); } + pool = Create(storeConfig, errCode); return result; } @@ -382,7 +381,7 @@ int ConnPool::ChangeDbFileForRestore(const std::string &newPath, const std::stri CloseAllConnections(); auto [retVal, conn] = Connection::Create(config_, false); if (retVal != E_OK) { - LOG_ERROR("create connection fail, errCode:%{public}d", retVal); + LOG_ERROR("Create connection fail, errCode:%{public}d", retVal); return retVal; } @@ -395,7 +394,7 @@ int ConnPool::ChangeDbFileForRestore(const std::string &newPath, const std::stri conn = nullptr; auto initRes = Init(); if (initRes.first != E_OK) { - LOG_ERROR("init fail, errCode:%{public}d", initRes.first); + LOG_ERROR("Init fail, errCode:%{public}d", initRes.first); return initRes.first; } return retVal; @@ -431,7 +430,7 @@ int ConnPool::RestoreMasterDb(const std::string &newPath, const std::string &bac CloseAllConnections(); Connection::Delete(config_); std::tie(errCode, pool) = Init(); - LOG_WARN("restore failed! rebuild res:%{public}d, path:%{public}s.", errCode, + LOG_WARN("Restore failed! rebuild res:%{public}d, path:%{public}s.", errCode, SqliteUtils::Anonymous(backupPath).c_str()); } return ret == E_OK ? errCode : ret; @@ -574,7 +573,7 @@ std::shared_ptr ConnPool::Container::Acquire(std::chrono::mi }; if (cond_.wait_for(lock, interval, waiter)) { if (nodes_.empty()) { - LOG_ERROR("nodes is empty.count %{public}d max %{public}d total %{public}d left %{public}d right%{public}d", + LOG_ERROR("Nodes is empty.count %{public}d max %{public}d total %{public}d left %{public}d right%{public}d", count_, max_, total_, left_, right_); count_ = 0; return nullptr; @@ -589,6 +588,7 @@ std::shared_ptr ConnPool::Container::Acquire(std::chrono::mi std::pair> ConnPool::Container::Create() { + std::unique_lock lock(mutex_); if (creator_ == nullptr) { return { E_NOT_SUPPORT, nullptr }; } diff --git a/relational_store/frameworks/native/rdb/src/delay_notify.cpp b/relational_store/frameworks/native/rdb/src/delay_notify.cpp index 718c1d9eace133624cbc6d79505436a12f0f0c27..336af2186440633e46e0d421f573b323b8ce3836 100644 --- a/relational_store/frameworks/native/rdb/src/delay_notify.cpp +++ b/relational_store/frameworks/native/rdb/src/delay_notify.cpp @@ -16,6 +16,7 @@ #include "delay_notify.h" #include "logger.h" +#include "task_executor.h" namespace OHOS::NativeRdb { using namespace OHOS::Rdb; DelayNotify::DelayNotify() : pauseCount_(0), task_(nullptr), pool_(nullptr) @@ -27,7 +28,7 @@ DelayNotify::~DelayNotify() if (pool_ == nullptr) { return; } - if (delaySyncTaskId_ != Executor::INVALID_TASK_ID) { + if (delaySyncTaskId_ != TaskExecutor::INVALID_TASK_ID) { pool_->Remove(delaySyncTaskId_); } if (task_ != nullptr && changedData_.tableData.size() > 0) { @@ -47,7 +48,7 @@ void DelayNotify::UpdateNotify(const DistributedRdb::RdbChangedData &changedData { std::lock_guard lock(mutex_); for (auto &[k, v] : changedData.tableData) { - if (!v.isTrackedDataChange) { + if (!v.isTrackedDataChange && !v.isP2pSyncDataChange) { continue; } auto it = changedData_.tableData.find(k); @@ -86,7 +87,7 @@ void DelayNotify::StartTimer() return; } - if (delaySyncTaskId_ == Executor::INVALID_TASK_ID) { + if (delaySyncTaskId_ == TaskExecutor::INVALID_TASK_ID) { delaySyncTaskId_ = pool_->Schedule(std::chrono::milliseconds(autoSyncInterval_), [this]() { ExecuteTask(); }); } else { @@ -125,7 +126,7 @@ void DelayNotify::StopTimer() if (pool_ != nullptr) { pool_->Remove(delaySyncTaskId_); } - delaySyncTaskId_ = Executor::INVALID_TASK_ID; + delaySyncTaskId_ = TaskExecutor::INVALID_TASK_ID; } void DelayNotify::ExecuteTask() diff --git a/relational_store/frameworks/native/rdb/src/grd_api_manager.cpp b/relational_store/frameworks/native/rdb/src/grd_api_manager.cpp index 440f7b27c19986ee574e1684f30a7cfda79b7137..5b401c3ad2fa2fe5c759128549c8f764a842d35f 100644 --- a/relational_store/frameworks/native/rdb/src/grd_api_manager.cpp +++ b/relational_store/frameworks/native/rdb/src/grd_api_manager.cpp @@ -62,6 +62,7 @@ void GRD_DBApiInitEnhance(GRD_APIInfo &GRD_DBApiInfo) GRD_DBApiInfo.DBReKeyApi = (DBReKey)dlsym(g_library, "GRD_DBRekey"); GRD_DBApiInfo.DBGetConfigApi = (DBGetConfig)dlsym(g_library, "GRD_GetConfig"); GRD_DBApiInfo.DBSetConfigApi = (DBSetConfig)dlsym(g_library, "GRD_SetConfig"); + GRD_DBApiInfo.DBSqlRegistryThreadPool = (DBSqlRegistryThreadPool)dlsym(g_library, "GRD_SqlRegistryThreadPool"); #endif } diff --git a/relational_store/frameworks/native/rdb/src/rd_connection.cpp b/relational_store/frameworks/native/rdb/src/rd_connection.cpp index 11327653b94fc402259dc2e6f32a2c381426f68b..79d64fb1392ff9823a2c6bd043193d6c5b862fbe 100644 --- a/relational_store/frameworks/native/rdb/src/rd_connection.cpp +++ b/relational_store/frameworks/native/rdb/src/rd_connection.cpp @@ -54,12 +54,33 @@ std::pair> RdConnection::Create(const RdbSt errCode = connection->InnerOpen(config); if (errCode == E_OK) { conn = connection; + CheckConfig(connection, config); break; } } return result; } +void RdConnection::CheckConfig(std::shared_ptr conn, const RdbStoreConfig &config) +{ + if (config.GetNcandidates() != NCANDIDATES_DEFAULT_NUM) { + ExecuteSet(conn, "diskann_probe_ncandidates", config.GetNcandidates()); + } +} + +void RdConnection::ExecuteSet(std::shared_ptr conn, const std::string ¶mName, int num) +{ + std::string sql = "SET " + paramName + " = " + std::to_string(num); + auto [errCode, stmt] = conn->CreateStatement(sql, conn); + if (errCode != E_OK || stmt == nullptr) { + LOG_ERROR("Create statement failed, paramName: %{public}s, errCode: %{public}d", + paramName.c_str(), errCode); + return; + } + stmt->Step(); + stmt->Finalize(); +} + int32_t RdConnection::Repair(const RdbStoreConfig &config) { std::string dbPath = ""; @@ -152,7 +173,8 @@ int RdConnection::InnerOpen(const RdbStoreConfig &config) std::vector key = config.GetEncryptKey(); std::string configStr = GetConfigStr(key, config.IsEncrypt()); - errCode = RdUtils::RdDbOpen(dbPath.c_str(), configStr.c_str(), GRD_DB_OPEN_CREATE, &dbHandle_); + errCode = RdUtils::RdDbOpen(dbPath.c_str(), configStr.c_str(), + GRD_DB_OPEN_CREATE | GRD_DB_OPEN_IGNORE_DATA_CORRPUPTION, &dbHandle_); if (errCode == E_CHANGE_UNENCRYPTED_TO_ENCRYPTED) { errCode = RdUtils::RdDbRekey(dbPath.c_str(), GetConfigStr({}, false).c_str(), key); if (errCode != E_OK) { @@ -161,7 +183,8 @@ int RdConnection::InnerOpen(const RdbStoreConfig &config) LOG_ERROR("Can not rekey caylay db %{public}d.", errCode); return errCode; } - errCode = RdUtils::RdDbOpen(dbPath.c_str(), configStr.c_str(), GRD_DB_OPEN_CREATE, &dbHandle_); + errCode = RdUtils::RdDbOpen(dbPath.c_str(), configStr.c_str(), + GRD_DB_OPEN_CREATE | GRD_DB_OPEN_IGNORE_DATA_CORRPUPTION, &dbHandle_); } key.assign(key.size(), 0); RdUtils::ClearAndZeroString(configStr); @@ -169,6 +192,11 @@ int RdConnection::InnerOpen(const RdbStoreConfig &config) LOG_ERROR("Can not open rd db %{public}d.", errCode); return errCode; } + errCode = RdUtils::RdSqlRegistryThreadPool(dbHandle_); + if (errCode != E_OK) { + LOG_ERROR("Can not registry ThreadPool rd db %{public}d.", errCode); + return errCode; + } return errCode; } @@ -305,7 +333,7 @@ int32_t RdConnection::Restore( { auto ret = RdUtils::RdDbClose(dbHandle_, 0); if (ret != E_OK) { - LOG_ERROR("close db failed"); + LOG_ERROR("Close db failed"); return ret; } @@ -318,14 +346,14 @@ int32_t RdConnection::Restore( } if (ret != E_OK) { - LOG_ERROR("restore failed, original datapath:%{public}s, restorepath:%{public}s, errcode:%{public}d", + LOG_ERROR("Restore failed, original datapath:%{public}s, restorepath:%{public}s, errcode:%{public}d", config_.GetPath().c_str(), databasePath.c_str(), ret); return ret; } ret = InnerOpen(config_); if (ret != E_OK) { - LOG_ERROR("reopen db failed:%{public}d", ret); + LOG_ERROR("Reopen db failed:%{public}d", ret); return ret; } return ret; @@ -335,5 +363,10 @@ ExchangeStrategy RdConnection::GenerateExchangeStrategy(const SlaveStatus &statu { return ExchangeStrategy::NOT_HANDLE; } + +bool RdConnection::IsInTrans() const +{ + return false; +} } // namespace NativeRdb } // namespace OHOS \ No newline at end of file diff --git a/relational_store/frameworks/native/rdb/src/rd_statement.cpp b/relational_store/frameworks/native/rdb/src/rd_statement.cpp index a34c93dccb38086214bfcfc80a0aa46ead21f325..a390c946f6368230c7046716c1f62ddadd6c7664 100644 --- a/relational_store/frameworks/native/rdb/src/rd_statement.cpp +++ b/relational_store/frameworks/native/rdb/src/rd_statement.cpp @@ -129,7 +129,7 @@ int RdStatement::Prepare(GRD_DB *db, const std::string &newSql) int ret = RdUtils::RdSqlPrepare(db, newSql.c_str(), newSql.length(), &tmpStmt, nullptr); if (ret != E_OK) { if (ret == E_SQLITE_CORRUPT && config_ != nullptr) { - Reportor::ReportFault(Reportor::Create(*config_, ret)); + Reportor::ReportCorruptedOnce(Reportor::Create(*config_, ret)); } if (tmpStmt != nullptr) { (void)RdUtils::RdSqlFinalize(tmpStmt); @@ -142,18 +142,7 @@ int RdStatement::Prepare(GRD_DB *db, const std::string &newSql) stmtHandle_ = tmpStmt; columnCount_ = RdUtils::RdSqlColCnt(tmpStmt); readOnly_ = SqliteUtils::GetSqlStatementType(newSql) == SqliteUtils::STATEMENT_SELECT; - if (readOnly_) { - isStepInPrepare_ = true; - ret = Step(); - if (ret != E_OK && ret != E_NO_MORE_ROWS) { - return ret; - } - GetProperties(); - if (ret == E_NO_MORE_ROWS) { - Reset(); - } - } - return E_OK; + return PreGetColCount(); } int RdStatement::Finalize() @@ -224,14 +213,31 @@ int RdStatement::InnerBindBlobTypeArgs(const ValueObject &arg, uint32_t index) c return ret; } +int RdStatement::PreGetColCount() +{ + if (!isStepInPrepare_ && readOnly_) { + isStepInPrepare_ = true; + int ret = Step(); + if (ret != E_OK && ret != E_NO_MORE_ROWS) { + isStepInPrepare_ = false; + return ret; + } + GetProperties(); + if (ret == E_NO_MORE_ROWS) { + Reset(); + } + } + return E_OK; +} + int RdStatement::IsValid(int index) const { if (stmtHandle_ == nullptr) { - LOG_ERROR("statement already close."); + LOG_ERROR("Statement already close."); return E_ALREADY_CLOSED; } if (index < 0 || index >= columnCount_) { - LOG_ERROR("index (%{public}d) >= columnCount (%{public}d)", index, columnCount_); + LOG_ERROR("Index (%{public}d) >= columnCount (%{public}d)", index, columnCount_); return E_COLUMN_OUT_RANGE; } return E_OK; @@ -282,12 +288,12 @@ int32_t RdStatement::Bind(const std::vector> } } if (ret != E_OK) { - LOG_ERROR("bind ret is %{public}d", ret); + LOG_ERROR("Bind ret is %{public}d", ret); return ret; } index++; } - return E_OK; + return PreGetColCount(); } std::pair RdStatement::Count() @@ -306,7 +312,7 @@ int32_t RdStatement::Step() } int ret = RdUtils::RdSqlStep(stmtHandle_); if (ret == E_SQLITE_CORRUPT && config_ != nullptr) { - Reportor::ReportFault(Reportor::Create(*config_, ret)); + Reportor::ReportCorruptedOnce(Reportor::Create(*config_, ret)); } stepCnt_++; return ret; @@ -421,7 +427,7 @@ std::pair RdStatement::GetColumnType(int32_t index) const case ColumnType::TYPE_FLOAT32_ARRAY: break; default: - LOG_ERROR("invalid type %{public}d.", type); + LOG_ERROR("Invalid type %{public}d.", type); return { E_ERROR, static_cast(ColumnType::TYPE_NULL) }; } return { ret, static_cast(type) }; diff --git a/relational_store/frameworks/native/rdb/src/rd_utils.cpp b/relational_store/frameworks/native/rdb/src/rd_utils.cpp index 2c33cbbbf49ea4422129732c8d6628a865d8c085..395e291134ac1807934c27bf0aa896b5054b6a69 100644 --- a/relational_store/frameworks/native/rdb/src/rd_utils.cpp +++ b/relational_store/frameworks/native/rdb/src/rd_utils.cpp @@ -27,6 +27,7 @@ #include "grd_error.h" #include "logger.h" #include "remote_result_set.h" +#include "task_executor.h" namespace OHOS { namespace NativeRdb { @@ -34,6 +35,8 @@ using namespace OHOS::Rdb; static GRD_APIInfo GRD_KVApiInfo; +GRD_ThreadPoolT RdUtils::threadPool_ = { 0 }; + struct GrdErrnoPair { int32_t grdCode; int kvDbCode; @@ -563,5 +566,31 @@ int RdUtils::RdDbSetVersion(GRD_DB *db, GRD_ConfigTypeE type, int version) return TransferGrdErrno(GRD_KVApiInfo.DBSetConfigApi(db, type, value)); } +static void Schedule(void *func, void *param) +{ + auto pool = TaskExecutor::GetInstance().GetExecutor(); + if (pool == nullptr) { + LOG_ERROR("pool is nullptr"); + return; + } + pool->Execute([func, param]() { + void (*funcPtr)(void *) = reinterpret_cast(func); + funcPtr(param); + }); +} + +int RdUtils::RdSqlRegistryThreadPool(GRD_DB *db) +{ + if (GRD_KVApiInfo.DBSqlRegistryThreadPool == nullptr) { + GRD_KVApiInfo = GetApiInfoInstance(); + } + if (GRD_KVApiInfo.DBSqlRegistryThreadPool == nullptr) { + LOG_ERROR("registry threadPool ptr is nullptr"); + return E_NOT_SUPPORT; + } + RdUtils::threadPool_.schedule = reinterpret_cast(Schedule); + return TransferGrdErrno(GRD_KVApiInfo.DBSqlRegistryThreadPool(db, &threadPool_)); +} + } // namespace NativeRdb } // namespace OHOS diff --git a/relational_store/frameworks/native/rdb/src/rdb_helper.cpp b/relational_store/frameworks/native/rdb/src/rdb_helper.cpp index bb49518ccfdc6ac4ca711b30af0fece55d00f8f4..28178da5e5bc7627a68b34e4e3eaaa815fb83d14 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_helper.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_helper.cpp @@ -47,44 +47,18 @@ void RdbHelper::ClearCache() RdbStoreManager::GetInstance().Clear(); } -static std::vector rdPostFixes = { - "", - ".redo", - ".undo", - ".ctrl", - ".ctrl.dwr", - ".safe", - ".map", -}; - -int DeleteRdFiles(const std::string &dbFileName) -{ - int errCode = E_OK; - for (std::string &postFix : rdPostFixes) { - std::string shmFileName = dbFileName + postFix; - if (access(shmFileName.c_str(), F_OK) == 0) { - int result = remove(shmFileName.c_str()); - if (result < 0) { - LOG_ERROR("RdbHelper DeleteRdbStore failed to delete the shm file err = %{public}d", errno); - errCode = E_REMOVE_FILE; - } - } - } - return errCode; -} - -int RdbHelper::DeleteRdbStore(const std::string &dbFileName) +int RdbHelper::DeleteRdbStore(const std::string &dbFileName, bool shouldClose) { RdbStoreConfig config(dbFileName); config.SetDBType(DB_SQLITE); - int errCodeSqlite = DeleteRdbStore(config); + int errCodeSqlite = DeleteRdbStore(config, shouldClose); config.SetDBType(DB_VECTOR); - int errCodeVector = DeleteRdbStore(config); + int errCodeVector = DeleteRdbStore(config, shouldClose); return (errCodeSqlite == E_OK && errCodeVector == E_OK) ? E_OK : E_REMOVE_FILE; } -int RdbHelper::DeleteRdbStore(const RdbStoreConfig &config) +int RdbHelper::DeleteRdbStore(const RdbStoreConfig &config, bool shouldClose) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); auto dbFile = config.GetPath(); @@ -92,16 +66,39 @@ int RdbHelper::DeleteRdbStore(const RdbStoreConfig &config) return E_INVALID_FILE_PATH; } if (access(dbFile.c_str(), F_OK) == 0) { - RdbStoreManager::GetInstance().Delete(dbFile); + RdbStoreManager::GetInstance().Delete(dbFile, shouldClose); } + Reportor::ReportRestore(Reportor::Create(config, E_OK, "RestoreType:Delete")); Connection::Delete(config); - RdbSecurityManager::GetInstance().DelAllKeyFiles(dbFile); - - Reportor::ReportRestore(Reportor::Create(config, E_OK, "RestoreType:Restore")); LOG_INFO("Delete rdb store, dbType:%{public}d, path %{public}s", config.GetDBType(), SqliteUtils::Anonymous(dbFile).c_str()); return E_OK; } + +bool RdbHelper::IsSupportArkDataDb() +{ +#ifdef ARKDATA_DB_CORE_IS_EXISTS + return true; +#else + return false; +#endif +} + +bool RdbHelper::IsSupportedTokenizer(Tokenizer tokenizer) +{ + if (tokenizer >= TOKENIZER_END) { + return false; + } + if (tokenizer == CUSTOM_TOKENIZER) { +#if !defined(CROSS_PLATFORM) && defined(ARKDATA_DATABASE_CORE_ENABLE) + return true; +#else + LOG_WARN("CUSTOM_TOKENIZER not support this platform."); + return false; +#endif + } + return true; +} } // namespace NativeRdb } // namespace OHOS diff --git a/relational_store/frameworks/native/rdb/src/rdb_manager_impl.cpp b/relational_store/frameworks/native/rdb/src/rdb_manager_impl.cpp index 526e2e080db6d93ac4c9569b1d2a950851cf8cc4..0f3f6982e013bb09941d5ee74dd09113547bf911 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_manager_impl.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_manager_impl.cpp @@ -41,17 +41,17 @@ std::shared_ptr RdbManagerImpl::GetDistributedDataMana { auto manager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); if (manager == nullptr) { - LOG_ERROR("get system ability manager failed."); + LOG_ERROR("Get system ability manager failed."); return nullptr; } auto dataMgr = manager->CheckSystemAbility(DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID); if (dataMgr == nullptr) { - LOG_ERROR("get distributed data manager failed."); + LOG_ERROR("Get distributed data manager failed."); return nullptr; } sptr dataService = new (std::nothrow) RdbStoreDataServiceProxy(dataMgr); if (dataService == nullptr) { - LOG_ERROR("new RdbStoreDataServiceProxy failed."); + LOG_ERROR("New RdbStoreDataServiceProxy failed."); return nullptr; } @@ -66,11 +66,11 @@ static void LinkToDeath(const sptr &remote) sptr deathRecipient = new (std::nothrow) RdbManagerImpl::ServiceDeathRecipient(&manager); if (deathRecipient == nullptr) { - LOG_ERROR("new ServiceDeathRecipient failed."); + LOG_ERROR("New ServiceDeathRecipient failed."); return; } if (!remote->AddDeathRecipient(deathRecipient)) { - LOG_ERROR("add death recipient failed."); + LOG_ERROR("Add death recipient failed."); } } @@ -80,7 +80,7 @@ RdbManagerImpl::RdbManagerImpl() RdbManagerImpl::~RdbManagerImpl() { - LOG_INFO("destroy."); + LOG_INFO("Destroy."); } RdbManagerImpl &RdbManagerImpl::GetInstance() @@ -104,13 +104,13 @@ std::pair> RdbManagerImpl::GetRdbService(co distributedDataMgr_ = GetDistributedDataManager(param.bundleName_); } if (distributedDataMgr_ == nullptr) { - LOG_ERROR("get distributed data manager failed."); + LOG_ERROR("Get distributed data manager failed."); return { E_SERVICE_NOT_FOUND, nullptr }; } auto remote = distributedDataMgr_->GetFeatureInterface(DistributedRdb::RdbService::SERVICE_NAME); if (remote == nullptr) { - LOG_ERROR("get rdb service failed."); + LOG_ERROR("Get rdb service failed."); return { E_NOT_SUPPORT, nullptr }; } @@ -124,7 +124,7 @@ std::pair> RdbManagerImpl::GetRdbService(co } if (rdbService == nullptr || rdbService->InitNotifier(param) != RDB_OK) { - LOG_ERROR("init notifier failed."); + LOG_ERROR("Init notifier failed."); return { E_ERROR, nullptr }; } @@ -138,7 +138,7 @@ std::pair> RdbManagerImpl::GetRdbService(co void RdbManagerImpl::OnRemoteDied() { - LOG_INFO("rdb service has dead!"); + LOG_INFO("Rdb service has dead!"); if (rdbService_ == nullptr) { ResetServiceHandle(); return; @@ -176,12 +176,12 @@ sptr RdbStoreDataServiceProxy::GetFeatureInterface(const std::str LOG_DEBUG("%{public}s", name.c_str()); MessageParcel data; if (!data.WriteInterfaceToken(RdbStoreDataServiceProxy::GetDescriptor())) { - LOG_ERROR("write descriptor failed."); + LOG_ERROR("Write descriptor failed."); return nullptr; } if (!ITypesUtil::Marshal(data, name)) { - LOG_ERROR("write descriptor failed."); + LOG_ERROR("Write descriptor failed."); return nullptr; } @@ -196,7 +196,7 @@ sptr RdbStoreDataServiceProxy::GetFeatureInterface(const std::str sptr remoteObject; if (!ITypesUtil::Unmarshal(reply, remoteObject)) { - LOG_ERROR("remote object is nullptr."); + LOG_ERROR("Remote object is nullptr."); return nullptr; } return remoteObject; @@ -206,12 +206,12 @@ int32_t RdbStoreDataServiceProxy::RegisterDeathObserver(const std::string &bundl { MessageParcel data; if (!data.WriteInterfaceToken(RdbStoreDataServiceProxy::GetDescriptor())) { - LOG_ERROR("write descriptor failed."); + LOG_ERROR("Write descriptor failed."); return E_ERROR; } if (!ITypesUtil::Marshal(data, bundleName, observer)) { - LOG_ERROR("write descriptor failed."); + LOG_ERROR("Write descriptor failed."); return E_ERROR; } diff --git a/relational_store/frameworks/native/rdb/src/rdb_security_manager.cpp b/relational_store/frameworks/native/rdb/src/rdb_security_manager.cpp index dd8279e75ed03788bac19d7beba9947db74569f9..e90da835779a1fef9ad87ba6263428832edf130f 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_security_manager.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_security_manager.cpp @@ -33,10 +33,12 @@ #include "rdb_sql_utils.h" #include "sqlite_utils.h" #include "string_utils.h" +#include "rdb_fault_hiview_reporter.h" namespace OHOS { namespace NativeRdb { using namespace OHOS::Rdb; +using Reportor = RdbFaultHiViewReporter; RdbPassword::RdbPassword() = default; @@ -100,6 +102,33 @@ bool RdbPassword::IsValid() const return size_ != 0; } +std::vector RdbSecurityManager::GetRootKeyAlias() +{ + std::lock_guard lock(rootKeyMutex_); + return rootKeyAlias_; +} + +void RdbSecurityManager::SetRootKeyAlias(std::vector rootKeyAlias) +{ + std::lock_guard lock(rootKeyMutex_); + rootKeyAlias_ = std::move(rootKeyAlias); +} + +std::string RdbSecurityManager::GetBundleNameByAlias() +{ + auto rootKeyAlias = GetRootKeyAlias(); + return GetBundleNameByAlias(rootKeyAlias); +} + +std::string RdbSecurityManager::GetBundleNameByAlias(const std::vector &rootKeyAlias) +{ + auto prefixLen = strlen(RDB_ROOT_KEY_ALIAS_PREFIX); + if (rootKeyAlias.size() > prefixLen) { + return std::string(rootKeyAlias.begin() + prefixLen, rootKeyAlias.end()); + } + return ""; +} + int32_t RdbSecurityManager::HksLoopUpdate(const struct HksBlob *handle, const struct HksParamSet *paramSet, const struct HksBlob *inData, struct HksBlob *outData) { @@ -116,8 +145,10 @@ int32_t RdbSecurityManager::HksLoopUpdate(const struct HksBlob *handle, const st input.size = end - input.data + 1; break; } - - if (HksUpdate(handle, paramSet, &input, &output) != HKS_SUCCESS) { + auto result = HksUpdate(handle, paramSet, &input, &output); + if (result != HKS_SUCCESS) { + Reportor::ReportFault(RdbFaultEvent(FT_EX_HUKS, E_WORK_KEY_FAIL, GetBundleNameByAlias(), + "HksUpdate ret=" + std::to_string(result))); LOG_ERROR("HksUpdate Failed."); return HKS_FAILURE; } @@ -127,7 +158,10 @@ int32_t RdbSecurityManager::HksLoopUpdate(const struct HksBlob *handle, const st input.data += MAX_UPDATE_SIZE; } output.size = input.size * TIMES; - if (HksFinish(handle, paramSet, &input, &output) != HKS_SUCCESS) { + auto result = HksFinish(handle, paramSet, &input, &output); + if (result != HKS_SUCCESS) { + Reportor::ReportFault(RdbFaultEvent(FT_EX_HUKS, E_WORK_KEY_FAIL, GetBundleNameByAlias(), + "HksFinish ret=" + std::to_string(result))); LOG_ERROR("HksFinish Failed."); return HKS_FAILURE; } @@ -142,6 +176,8 @@ int32_t RdbSecurityManager::HksEncryptThreeStage(const struct HksBlob *keyAlias, struct HksBlob handleBlob = { sizeof(uint64_t), handle }; int32_t result = HksInit(keyAlias, paramSet, &handleBlob, nullptr); if (result != HKS_SUCCESS) { + Reportor::ReportFault(RdbFaultEvent(FT_EX_HUKS, E_WORK_KEY_ENCRYPT_FAIL, + GetBundleNameByAlias(), "HksInit ret=" + std::to_string(result))); LOG_ERROR("HksEncrypt failed with error %{public}d", result); return result; } @@ -155,6 +191,8 @@ int32_t RdbSecurityManager::HksDecryptThreeStage(const struct HksBlob *keyAlias, struct HksBlob handleBlob = { sizeof(uint64_t), handle }; int32_t result = HksInit(keyAlias, paramSet, &handleBlob, nullptr); if (result != HKS_SUCCESS) { + Reportor::ReportFault(RdbFaultEvent(FT_EX_HUKS, E_WORK_KEY_DECRYPT_FAIL, GetBundleNameByAlias(), + "HksInit ret=" + std::to_string(result))); LOG_ERROR("HksEncrypt failed with error %{public}d", result); return result; } @@ -182,6 +220,7 @@ bool RdbSecurityManager::SaveSecretKeyToFile(const std::string &keyFile, const s { LOG_INFO("begin keyFile%{public}s.", SqliteUtils::Anonymous(keyFile).c_str()); if (!HasRootKey()) { + Reportor::ReportFault(RdbFaultEvent(FT_OPEN, E_ROOT_KEY_NOT_LOAD, GetBundleNameByAlias(), "not root key")); LOG_ERROR("Root key not exists!"); return false; } @@ -192,6 +231,7 @@ bool RdbSecurityManager::SaveSecretKeyToFile(const std::string &keyFile, const s keyData.secretKey = EncryptWorkKey(key); if (keyData.secretKey.empty()) { + Reportor::ReportFault(RdbFaultEvent(FT_OPEN, E_WORK_KEY_FAIL, GetBundleNameByAlias(), "key is empty")); LOG_ERROR("Key size is 0"); key.assign(key.size(), 0); return false; @@ -218,6 +258,10 @@ bool RdbSecurityManager::SaveSecretKeyToDisk(const std::string &keyPath, RdbSecr std::lock_guard lock(mutex_); ret = SaveBufferToFile(keyPath, secretKeyInChar); } + if (!ret) { + Reportor::ReportFault(RdbFaultEvent(FT_EX_FILE, E_WORK_KEY_FAIL, GetBundleNameByAlias(), + "save fail errno=" + std::to_string(errno))); + } return ret; } @@ -229,6 +273,8 @@ int RdbSecurityManager::GenerateRootKey(const std::vector &rootKeyAlias struct HksParamSet *params = nullptr; int32_t ret = HksInitParamSet(¶ms); if (ret != HKS_SUCCESS) { + Reportor::ReportFault(RdbFaultEvent(FT_EX_HUKS, E_ROOT_KEY_FAULT, GetBundleNameByAlias(rootKeyAlias), + "generator root key, HksInitParamSet ret=" + std::to_string(ret))); LOG_ERROR("HksInitParamSet()-client failed with error %{public}d", ret); return ret; } @@ -245,6 +291,8 @@ int RdbSecurityManager::GenerateRootKey(const std::vector &rootKeyAlias ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); if (ret != HKS_SUCCESS) { + Reportor::ReportFault(RdbFaultEvent(FT_EX_HUKS, E_ROOT_KEY_FAULT, GetBundleNameByAlias(rootKeyAlias), + "HksAddParams ret=" + std::to_string(ret))); LOG_ERROR("HksAddParams-client failed with error %{public}d", ret); HksFreeParamSet(¶ms); return ret; @@ -252,6 +300,8 @@ int RdbSecurityManager::GenerateRootKey(const std::vector &rootKeyAlias ret = HksBuildParamSet(¶ms); if (ret != HKS_SUCCESS) { + Reportor::ReportFault(RdbFaultEvent(FT_EX_HUKS, E_ROOT_KEY_FAULT, GetBundleNameByAlias(rootKeyAlias), + "HksBuildParamSet ret=" + std::to_string(ret))); LOG_ERROR("HksBuildParamSet-client failed with error %{public}d", ret); HksFreeParamSet(¶ms); return ret; @@ -260,6 +310,8 @@ int RdbSecurityManager::GenerateRootKey(const std::vector &rootKeyAlias ret = HksGenerateKey(&rootKeyName, params, nullptr); HksFreeParamSet(¶ms); if (ret != HKS_SUCCESS) { + Reportor::ReportFault(RdbFaultEvent(FT_EX_HUKS, E_ROOT_KEY_FAULT, GetBundleNameByAlias(rootKeyAlias), + "HksGenerateKey ret=" + std::to_string(ret))); LOG_ERROR("HksGenerateKey-client failed with error %{public}d", ret); } return ret; @@ -267,28 +319,32 @@ int RdbSecurityManager::GenerateRootKey(const std::vector &rootKeyAlias std::vector RdbSecurityManager::EncryptWorkKey(std::vector &key) { + std::vector rootKeyAlias = GetRootKeyAlias(); struct HksBlob blobAad = { uint32_t(aad_.size()), aad_.data() }; struct HksBlob blobNonce = { uint32_t(nonce_.size()), nonce_.data() }; - struct HksBlob rootKeyName = { uint32_t(rootKeyAlias_.size()), rootKeyAlias_.data() }; + struct HksBlob rootKeyName = { uint32_t(rootKeyAlias.size()), rootKeyAlias.data() }; struct HksBlob plainKey = { uint32_t(key.size()), key.data() }; struct HksParamSet *params = nullptr; int32_t ret = HksInitParamSet(¶ms); if (ret != HKS_SUCCESS) { + Reportor::ReportFault(RdbFaultEvent(FT_EX_HUKS, E_WORK_KEY_ENCRYPT_FAIL, GetBundleNameByAlias(rootKeyAlias), + "HksInitParamSet ret=" + std::to_string(ret))); LOG_ERROR("HksInitParamSet() failed with error %{public}d", ret); return {}; } - struct HksParam hksParam[] = { - { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, + struct HksParam hksParam[] = {{ .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_ENCRYPT }, { .tag = HKS_TAG_DIGEST, .uint32Param = 0 }, { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, { .tag = HKS_TAG_NONCE, .blob = blobNonce }, { .tag = HKS_TAG_ASSOCIATED_DATA, .blob = blobAad }, - { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE }, - }; + { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE }}; + ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); if (ret != HKS_SUCCESS) { + Reportor::ReportFault(RdbFaultEvent(FT_EX_HUKS, E_WORK_KEY_ENCRYPT_FAIL, GetBundleNameByAlias(rootKeyAlias), + "HksAddParams ret=" + std::to_string(ret))); LOG_ERROR("HksAddParams failed with error %{public}d", ret); HksFreeParamSet(¶ms); return {}; @@ -296,6 +352,8 @@ std::vector RdbSecurityManager::EncryptWorkKey(std::vector &ke ret = HksBuildParamSet(¶ms); if (ret != HKS_SUCCESS) { + Reportor::ReportFault(RdbFaultEvent(FT_EX_HUKS, E_WORK_KEY_ENCRYPT_FAIL, GetBundleNameByAlias(rootKeyAlias), + "HksBuildParamSet ret=" + std::to_string(ret))); LOG_ERROR("HksBuildParamSet failed with error %{public}d", ret); HksFreeParamSet(¶ms); return {}; @@ -315,14 +373,17 @@ std::vector RdbSecurityManager::EncryptWorkKey(std::vector &ke bool RdbSecurityManager::DecryptWorkKey(std::vector &source, std::vector &key) { + std::vector rootKeyAlias = GetRootKeyAlias(); struct HksBlob blobAad = { uint32_t(aad_.size()), &(aad_[0]) }; struct HksBlob blobNonce = { uint32_t(nonce_.size()), &(nonce_[0]) }; - struct HksBlob rootKeyName = { uint32_t(rootKeyAlias_.size()), &(rootKeyAlias_[0]) }; + struct HksBlob rootKeyName = { uint32_t(rootKeyAlias.size()), &(rootKeyAlias[0]) }; struct HksBlob encryptedKeyBlob = { uint32_t(source.size() - AEAD_LEN), source.data() }; struct HksBlob blobAead = { AEAD_LEN, source.data() + source.size() - AEAD_LEN }; struct HksParamSet *params = nullptr; int32_t ret = HksInitParamSet(¶ms); if (ret != HKS_SUCCESS) { + Reportor::ReportFault(RdbFaultEvent(FT_EX_HUKS, E_WORK_KEY_DECRYPT_FAIL, GetBundleNameByAlias(rootKeyAlias), + "HksInitParamSet ret=" + std::to_string(ret))); LOG_ERROR("HksInitParamSet() failed with error %{public}d", ret); return false; } @@ -339,6 +400,8 @@ bool RdbSecurityManager::DecryptWorkKey(std::vector &source, std::vecto }; ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); if (ret != HKS_SUCCESS) { + Reportor::ReportFault(RdbFaultEvent(FT_EX_HUKS, E_WORK_KEY_DECRYPT_FAIL, GetBundleNameByAlias(rootKeyAlias), + "HksAddParams ret=" + std::to_string(ret))); LOG_ERROR("HksAddParams failed with error %{public}d", ret); HksFreeParamSet(¶ms); return false; @@ -346,6 +409,8 @@ bool RdbSecurityManager::DecryptWorkKey(std::vector &source, std::vecto ret = HksBuildParamSet(¶ms); if (ret != HKS_SUCCESS) { + Reportor::ReportFault(RdbFaultEvent(FT_EX_HUKS, E_WORK_KEY_DECRYPT_FAIL, GetBundleNameByAlias(rootKeyAlias), + "HksBuildParamSet ret=" + std::to_string(ret))); LOG_ERROR("HksBuildParamSet failed with error %{public}d", ret); HksFreeParamSet(¶ms); return false; @@ -379,8 +444,8 @@ int32_t RdbSecurityManager::Init(const std::string &bundleName) if (ret == HKS_SUCCESS) { if (!HasRootKey()) { hasRootKey_ = true; - rootKeyAlias_ = std::move(rootKeyAlias); } + SetRootKeyAlias(std::move(rootKeyAlias)); break; } retryCount++; @@ -437,7 +502,12 @@ bool RdbSecurityManager::InitPath(const std::string &fileDir) return true; } umask(DEFAULT_UMASK); - if (MkDir(fileDir, (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) != 0 && errno != EEXIST) { + auto ret = MkDir(fileDir, (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)); + if (ret != 0 && errno != EEXIST) { + Reportor::ReportFault(RdbFaultEvent(FT_EX_FILE, E_WORK_KEY_FAIL, + RdbSecurityManager::GetInstance().GetBundleNameByAlias(), + "mkdir err, ret=" + std::to_string(ret) + ",errno=" + std::to_string(errno) + + ",fileDir=" + SqliteUtils::Anonymous(fileDir))); LOG_ERROR("mkdir error:%{public}d, dbDir:%{public}s", errno, SqliteUtils::Anonymous(fileDir).c_str()); return false; } @@ -446,19 +516,27 @@ bool RdbSecurityManager::InitPath(const std::string &fileDir) RdbPassword RdbSecurityManager::LoadSecretKeyFromFile(const std::string &keyFile) { - if (access(keyFile.c_str(), F_OK) != 0) { - LOG_ERROR("Not exists. errno:%{public}d, file:%{public}s", errno, SqliteUtils::Anonymous(keyFile).c_str()); + auto ret = access(keyFile.c_str(), F_OK); + if (ret != 0) { + auto anonymousFile = SqliteUtils::Anonymous(keyFile); + Reportor::ReportFault(RdbFaultEvent(FT_EX_FILE, E_WORK_KEY_DECRYPT_FAIL, GetBundleNameByAlias(), + "access " + anonymousFile + " fail, ret=" + std::to_string(ret) + ",errno=" + std::to_string(errno))); + LOG_ERROR("Not exists. errno:%{public}d, file:%{public}s", errno, anonymousFile.c_str()); return {}; } RdbSecretKeyData keyData; if (!LoadSecretKeyFromDisk(keyFile, keyData)) { + Reportor::ReportFault(RdbFaultEvent(FT_OPEN, E_WORK_KEY_DECRYPT_FAIL, GetBundleNameByAlias(), + "LoadSecretKeyFromDisk fail,errno=" + std::to_string(errno))); LOG_ERROR("Load key failed."); return {}; } std::vector key; if (!DecryptWorkKey(keyData.secretKey, key)) { + Reportor::ReportFault(RdbFaultEvent(FT_OPEN, E_WORK_KEY_DECRYPT_FAIL, GetBundleNameByAlias(), + "DecryptWorkKey fail,errno=" + std::to_string(errno))); LOG_ERROR("Decrypt key failed!"); return {}; } @@ -477,6 +555,8 @@ bool RdbSecurityManager::LoadSecretKeyFromDisk(const std::string &keyPath, RdbSe { std::lock_guard lock(mutex_); if (!LoadBufferFromFile(keyPath, content) || content.empty()) { + Reportor::ReportFault(RdbFaultEvent(FT_EX_FILE, E_WORK_KEY_DECRYPT_FAIL, GetBundleNameByAlias(), + "LoadBufferFromFile fail, errno=" + std::to_string(errno))); LOG_ERROR("LoadBufferFromFile failed!"); return false; } @@ -624,16 +704,15 @@ bool RdbSecurityManager::IsKeyFileEmpty(const std::string &keyFile) int32_t RdbSecurityManager::RestoreKeyFile(const std::string &dbPath, const std::vector &key) { + if (key.empty()) { + LOG_ERROR("key is empty! Path:%{public}s.", SqliteUtils::Anonymous(dbPath).c_str()); + return E_ERROR; + } KeyFiles keyFiles(dbPath); keyFiles.Lock(); auto &keyFile = keyFiles.GetKeyFile(PUB_KEY_FILE); auto &reKeyFile = keyFiles.GetKeyFile(PUB_KEY_FILE_NEW_KEY); - { - std::lock_guard lock(mutex_); - SqliteUtils::DeleteFile(keyFile); - SqliteUtils::DeleteFile(reKeyFile); - } - if (!SaveSecretKeyToFile(keyFile, key)) { + if (!SaveSecretKeyToFile(reKeyFile, key) && !SaveSecretKeyToFile(keyFile, key)) { LOG_ERROR("failed, save key err:%{public}d, file:%{public}s.", errno, SqliteUtils::Anonymous(keyFile).c_str()); } keyFiles.Unlock(); diff --git a/relational_store/frameworks/native/rdb/src/rdb_service_proxy.cpp b/relational_store/frameworks/native/rdb/src/rdb_service_proxy.cpp index dd8690a8bcd8ae63ef9deed7044b5445f2299191..fdb7fc8a55f032f378f2772ea9f1187747acbad5 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_service_proxy.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_service_proxy.cpp @@ -296,7 +296,13 @@ std::pair> RdbServiceProxy: LOG_ERROR("read remote object is null."); return { RDB_ERROR, nullptr }; } - sptr instance = new NativeRdb::ResultSetProxy(remote); + sptr instance = new(std::nothrow) NativeRdb::ResultSetProxy(remote); + if (instance == nullptr) { + LOG_ERROR("instance object is null.bundleName:%{public}s, storeName:%{public}s, device:%{public}.6s", + param.bundleName_.c_str(), SqliteUtils::Anonymous(param.storeName_).c_str(), + SqliteUtils::Anonymous(device).c_str()); + return { RDB_ERROR, nullptr }; + } return { RDB_OK, std::shared_ptr(instance.GetRefPtr(), [holder = instance](const auto *) {}) }; } @@ -371,7 +377,12 @@ std::pair> RdbServiceProxy: remote != nullptr ? "not" : ""); return { RDB_ERROR, {} }; } - sptr instance = new NativeRdb::ResultSetProxy(remote); + sptr instance = new(std::nothrow) NativeRdb::ResultSetProxy(remote); + if (instance == nullptr) { + LOG_ERROR("instance object is null.bundleName:%{public}s, storeName:%{public}s", + param.bundleName_.c_str(), SqliteUtils::Anonymous(param.storeName_).c_str()); + return { RDB_ERROR, nullptr }; + } return { RDB_OK, std::shared_ptr(instance.GetRefPtr(), [instance](const auto *) {}) }; } @@ -544,7 +555,7 @@ int32_t RdbServiceProxy::Enable(const RdbSyncerParam ¶m) return status; } -int32_t RdbServiceProxy::GetPassword(const RdbSyncerParam ¶m, std::vector &key) +int32_t RdbServiceProxy::GetPassword(const RdbSyncerParam ¶m, std::vector> &key) { MessageParcel reply; int32_t status = IPC_SEND(static_cast(RdbServiceCode::RDB_SERVICE_CMD_GET_PASSWORD), reply, param); diff --git a/relational_store/frameworks/native/rdb/src/rdb_sql_utils.cpp b/relational_store/frameworks/native/rdb/src/rdb_sql_utils.cpp index a0834c8b7740fc393bbcc12fd754a9fcfff31c40..a46970ed240a32c21abafedf9ef6a8bcd535459b 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_sql_utils.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_sql_utils.cpp @@ -66,6 +66,21 @@ int RdbSqlUtils::CreateDirectory(const std::string &databaseDir) return E_OK; } +std::pair RdbSqlUtils::GetCustomDatabasePath( + const std::string &rootDir, const std::string &name, const std::string &customDir) +{ + std::string databasePath; + databasePath.append(rootDir).append("/").append(customDir).append("/").append(name); + + struct stat fileStat; + if (stat(databasePath.c_str(), &fileStat) != 0) { + LOG_ERROR("File state error. path: %{public}s, errno: %{public}d", + SqliteUtils::Anonymous(databasePath).c_str(), errno); + return std::make_pair("", E_INVALID_FILE_PATH); + } + return std::make_pair(databasePath, E_OK); +} + /** * @brief get custom data base path. */ diff --git a/relational_store/frameworks/native/rdb/src/rdb_store.cpp b/relational_store/frameworks/native/rdb/src/rdb_store.cpp index 75109659fc9185d0159e1e87b124a395c6409557..f97c56c44e0f27729a236f844e640af3cc317d74 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_store.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_store.cpp @@ -156,6 +156,12 @@ std::pair RdbStore::BatchInsert(const std::string &table, const Re return { E_NOT_SUPPORT, -1 }; } +std::pair RdbStore::BatchInsertWithConflictResolution( + const std::string &table, const RdbStore::RefRows &rows, RdbStore::Resolution resolution) +{ + return { E_NOT_SUPPORT, -1 }; +} + std::pair RdbStore::Update( const std::string &table, const Row &row, const std::string &where, const Values &args, Resolution resolution) { @@ -255,7 +261,8 @@ std::shared_ptr RdbStore::QueryByStep(const std::string &sql, const O return QueryByStep(sql, ToValues(args)); } -std::shared_ptr RdbStore::QueryByStep(const AbsRdbPredicates &predicates, const RdbStore::Fields &columns) +std::shared_ptr RdbStore::QueryByStep(const AbsRdbPredicates &predicates, const RdbStore::Fields &columns, + bool preCount) { std::string sql; if (predicates.HasSpecificField()) { @@ -265,7 +272,7 @@ std::shared_ptr RdbStore::QueryByStep(const AbsRdbPredicates &predica } else { sql = SqliteSqlBuilder::BuildQueryString(predicates, columns); } - return QueryByStep(sql, predicates.GetBindArgs()); + return QueryByStep(sql, predicates.GetBindArgs(), preCount); } std::shared_ptr RdbStore::RemoteQuery( diff --git a/relational_store/frameworks/native/rdb/src/rdb_store_config.cpp b/relational_store/frameworks/native/rdb/src/rdb_store_config.cpp index 0ef113d9cf7aa2d5cf07cee4cb235d1c494317f3..81c05797a7ef01d9e1deb81fd15d2d4dd3d74b91 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_store_config.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_store_config.cpp @@ -22,6 +22,7 @@ #include "rdb_security_manager.h" #include "string_utils.h" #include "sqlite_global_config.h" +#include "rdb_fault_hiview_reporter.h" namespace OHOS::NativeRdb { using namespace OHOS::Rdb; @@ -392,6 +393,8 @@ int32_t RdbStoreConfig::GenerateEncryptedKey() const using KeyFileType = RdbSecurityManager::KeyFileType; auto errCode = RdbSecurityManager::GetInstance().Init(name); if (errCode != E_OK) { + RdbFaultHiViewReporter::ReportFault(RdbFaultDbFileEvent(FT_OPEN, E_ROOT_KEY_FAULT, *this, + "gen root key fail ret=" + std::to_string(errCode))); LOG_ERROR("generate root encrypt key failed, bundleName_:%{public}s", bundleName_.c_str()); return errCode; } @@ -422,17 +425,17 @@ void RdbStoreConfig::ClearEncryptKey() void RdbStoreConfig::SetScalarFunction(const std::string &functionName, int argc, ScalarFunction function) { - customScalarFunctions.try_emplace(functionName, ScalarFunctionInfo(function, argc)); + customScalarFunctions_.try_emplace(functionName, ScalarFunctionInfo(function, argc)); } void RdbStoreConfig::SetScalarFunctions(const std::map functions) { - customScalarFunctions = functions; + customScalarFunctions_ = functions; } std::map RdbStoreConfig::GetScalarFunctions() const { - return customScalarFunctions; + return customScalarFunctions_; } void RdbStoreConfig::SetDataGroupId(const std::string &DataGroupId) @@ -596,6 +599,17 @@ void RdbStoreConfig::SetPromiseInfo(PromiseInfo promiseInfo) promiseInfo_ = promiseInfo; } + +Tokenizer RdbStoreConfig::GetTokenizer() const +{ + return tokenizer_; +} + +void RdbStoreConfig::SetTokenizer(Tokenizer tokenizer) +{ + tokenizer_ = tokenizer; +} + ssize_t RdbStoreConfig::GetWalLimitSize() const { return walLimitSize_; @@ -641,6 +655,16 @@ RdbStoreConfig::CryptoParam RdbStoreConfig::GetCryptoParam() const return cryptoParam_; } +int RdbStoreConfig::GetNcandidates() const +{ + return ncandidates_; +} + +void RdbStoreConfig::SetNcandidates(int ncandidates) +{ + ncandidates_ = ncandidates; +} + RdbStoreConfig::CryptoParam::CryptoParam() = default; RdbStoreConfig::CryptoParam::~CryptoParam() @@ -671,25 +695,25 @@ bool RdbStoreConfig::CryptoParam::IsValid() const (cryptoPageSize & (cryptoPageSize - 1)) == 0; } -std::string RdbStoreConfig::Format(const RdbStoreConfig &cacheConfig, const RdbStoreConfig &incomingConfig) +std::string RdbStoreConfig::FormatCfg(const RdbStoreConfig &first, const RdbStoreConfig &second) { std::stringstream oss; - oss << " isEncrypt:" << static_cast(cacheConfig.IsEncrypt()) << "->" - << static_cast(incomingConfig.IsEncrypt()) << ","; - oss << " securityLevel:" << static_cast(cacheConfig.securityLevel_) << "->" - << static_cast(incomingConfig.securityLevel_) << ","; - oss << " area:" << cacheConfig.area_ << "->" << incomingConfig.area_ << ","; - oss << " storageMode:" << static_cast(cacheConfig.storageMode_) << "->" - << static_cast(incomingConfig.storageMode_) << ","; - oss << " journalMode:" << cacheConfig.journalMode_ << "->" << incomingConfig.journalMode_ << ","; - oss << " syncMode:" << cacheConfig.syncMode_ << "->" << incomingConfig.syncMode_ << ","; - oss << " databaseFileType:" << cacheConfig.databaseFileType << "->" << incomingConfig.databaseFileType << ","; - oss << " journalSize:" << cacheConfig.journalSize_ << "->" << incomingConfig.journalSize_ << ","; - oss << " pageSize:" << cacheConfig.pageSize_ << "->" << incomingConfig.pageSize_ << ","; - oss << " customDir:" << cacheConfig.customDir_ << "->" << incomingConfig.customDir_ << ","; - oss << " haMode:" << cacheConfig.haMode_ << "->" << incomingConfig.haMode_ << ","; - oss << " dbType:" << cacheConfig.dbType_ << "->" << incomingConfig.dbType_ << ","; - + oss << " storageMode:" << static_cast(first.storageMode_) << "->" + << static_cast(second.storageMode_) << ","; + oss << " journalMode:" << first.journalMode_ << "->" << second.journalMode_ << ","; + oss << " syncMode:" << first.syncMode_ << "->" << second.syncMode_ << ","; + oss << " databaseFileType:" << first.databaseFileType << "->" << second.databaseFileType << ","; + oss << " isEncrypt:" << first.IsEncrypt() << "->" << second.IsEncrypt() << ","; + oss << " readOnly_:" << first.readOnly_ << "->" << second.readOnly_ << ","; + oss << " securityLevel:" << static_cast(first.securityLevel_) << "->" + << static_cast(second.securityLevel_) << ","; + oss << " journalSize:" << first.journalSize_ << "->" << second.journalSize_ << ","; + oss << " pageSize:" << first.pageSize_ << "->" << second.pageSize_ << ","; + oss << " dbType:" << first.dbType_ << "->" << second.dbType_ << ","; + oss << " customDir:" << first.customDir_ << "->" << second.customDir_ << ","; + oss << " haMode:" << first.haMode_ << "->" << second.haMode_ << ","; + oss << " pluginLibs size:" << first.pluginLibs_.size() << "->" << second.pluginLibs_.size() << ","; + oss << " area:" << first.area_ << "->" << second.area_ << ","; return oss.str(); } } // namespace OHOS::NativeRdb diff --git a/relational_store/frameworks/native/rdb/src/rdb_store_impl.cpp b/relational_store/frameworks/native/rdb/src/rdb_store_impl.cpp index 2628b48b72a2f1210c2f5cb1b39170f3fb4cb7c3..eaae4fc9a7b67b60e2fc914aa3b055e23a1a5ee9 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_store_impl.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_store_impl.cpp @@ -27,6 +27,8 @@ #include #include "cache_result_set.h" +#include "connection_pool.h" +#include "delay_notify.h" #include "directory_ex.h" #include "logger.h" #include "rdb_common.h" @@ -48,8 +50,7 @@ #include "traits.h" #include "transaction.h" #include "values_buckets.h" -#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) -#include "delay_notify.h" +#if !defined(CROSS_PLATFORM) #include "raw_data_parser.h" #include "rdb_device_manager_adapter.h" #include "rdb_manager_impl.h" @@ -81,7 +82,7 @@ static constexpr const char *ROLLBACK_TRANSACTION_SQL = "rollback;"; static constexpr const char *BACKUP_RESTORE = "backup.restore"; constexpr int64_t TIME_OUT = 1500; -void RdbStoreImpl::InitSyncerParam(const RdbStoreConfig &config, bool created) +void RdbStoreImpl::InitSyncerParam(const RdbStoreConfig &config) { syncerParam_.bundleName_ = config.GetBundleName(); syncerParam_.hapName_ = config.GetModuleName(); @@ -100,9 +101,6 @@ void RdbStoreImpl::InitSyncerParam(const RdbStoreConfig &config, bool created) syncerParam_.uids_ = config.GetPromiseInfo().uids_; syncerParam_.user_ = config.GetPromiseInfo().user_; syncerParam_.permissionNames_ = config.GetPromiseInfo().permissionNames_; - if (created) { - syncerParam_.infos_ = Connection::Collect(config); - } } int RdbStoreImpl::InnerOpen() @@ -122,6 +120,47 @@ int RdbStoreImpl::InnerOpen() return E_OK; } +void RdbStoreImpl::Close() +{ + { + std::unique_lock lock(poolMutex_); + if (connectionPool_) { + connectionPool_->CloseAllConnections(); + connectionPool_.reset(); + } + } + { + std::lock_guard guard(mutex_); + for (auto &it : transactions_) { + auto trans = it.lock(); + if (trans != nullptr) { + trans->Close(); + } + } + transactions_ = {}; + } +} + +std::shared_ptr RdbStoreImpl::GetPool() const +{ + std::shared_lock lock(poolMutex_); + return connectionPool_; +} + +std::pair> RdbStoreImpl::GetConn(bool isRead) +{ + auto pool = GetPool(); + if (pool == nullptr) { + return { E_ALREADY_CLOSED, nullptr }; + } + + auto connection = pool->AcquireConnection(isRead); + if (connection == nullptr) { + return { E_DATABASE_BUSY, nullptr }; + } + return { E_OK, connection }; +} + #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) void RdbStoreImpl::AfterOpen(const RdbParam ¶m, int32_t retry) { @@ -151,7 +190,7 @@ RdbStore::ModifyTime RdbStoreImpl::GetModifyTime( const std::string &table, const std::string &columnName, std::vector &keys) { if (table.empty() || columnName.empty() || keys.empty()) { - LOG_ERROR("invalid para."); + LOG_ERROR("Invalid para."); return {}; } @@ -169,7 +208,7 @@ RdbStore::ModifyTime RdbStoreImpl::GetModifyTime( tmp[columnName] = value; auto hashKey = DistributedDB::RelationalStoreManager::CalcPrimaryKeyHash(tmp); if (hashKey.empty()) { - LOG_DEBUG("hash key fail."); + LOG_DEBUG("Hash key fail."); continue; } hashKeys.emplace_back(ValueObject(hashKey)); @@ -182,10 +221,10 @@ RdbStore::ModifyTime RdbStoreImpl::GetModifyTime( sql.append(" where hash_key in ("); sql.append(SqliteSqlBuilder::GetSqlArgs(hashKeys.size())); sql.append(")"); - auto resultSet = QueryByStep(sql, hashKeys); + auto resultSet = QueryByStep(sql, hashKeys, true); int count = 0; if (resultSet == nullptr || resultSet->GetRowCount(count) != E_OK || count <= 0) { - LOG_ERROR("get resultSet err."); + LOG_ERROR("Get resultSet err."); return {}; } return { resultSet, keyMap, false }; @@ -206,10 +245,10 @@ RdbStore::ModifyTime RdbStoreImpl::GetModifyTimeByRowId(const std::string &logTa RawDataParser::Convert(key, value); args.emplace_back(ValueObject(value)); } - auto resultSet = QueryByStep(sql, args); + auto resultSet = QueryByStep(sql, args, true); int count = 0; if (resultSet == nullptr || resultSet->GetRowCount(count) != E_OK || count <= 0) { - LOG_ERROR("get resultSet err."); + LOG_ERROR("Get resultSet err."); return {}; } return ModifyTime(resultSet, {}, true); @@ -218,16 +257,16 @@ RdbStore::ModifyTime RdbStoreImpl::GetModifyTimeByRowId(const std::string &logTa int RdbStoreImpl::CleanDirtyData(const std::string &table, uint64_t cursor) { if (isReadOnly_ || (config_.GetDBType() == DB_VECTOR)) { - LOG_ERROR("not support. table:%{public}s, isRead:%{public}d, dbType:%{public}d", + LOG_ERROR("Not support. table:%{public}s, isRead:%{public}d, dbType:%{public}d.", SqliteUtils::Anonymous(table).c_str(), isReadOnly_, config_.GetDBType()); return E_NOT_SUPPORT; } - auto connection = connectionPool_->AcquireConnection(false); - if (connection == nullptr) { - LOG_ERROR("db is busy. table:%{public}s", SqliteUtils::Anonymous(table).c_str()); - return E_DATABASE_BUSY; + auto [errCode, conn] = GetConn(false); + if (errCode != E_OK) { + LOG_ERROR("The database is busy or closed."); + return errCode; } - int errCode = connection->CleanDirtyData(table, cursor); + errCode = conn->CleanDirtyData(table, cursor); return errCode; } @@ -269,7 +308,7 @@ std::shared_ptr RdbStoreImpl::RemoteQuery( return nullptr; } if (err != E_OK) { - LOG_ERROR("RdbStoreImpl::RemoteQuery get service failed"); + LOG_ERROR("RdbStoreImpl::RemoteQuery get service failed."); errCode = err; return nullptr; } @@ -305,20 +344,32 @@ int RdbStoreImpl::SetDistributedTables( if (errCode != E_OK) { return errCode; } + syncerParam_.asyncDownloadAsset_ = distributedConfig.asyncDownloadAsset; int32_t errorCode = service->SetDistributedTables( syncerParam_, tables, distributedConfig.references, distributedConfig.isRebuild, type); if (type == DistributedRdb::DISTRIBUTED_DEVICE) { int SYNC_DATA_INDEX = 500; - Reportor::Report(Reportor::Create(config_, SYNC_DATA_INDEX, "RdbDeviceToDeviceDataSync")); + Reportor::ReportCorrupted(Reportor::Create(config_, SYNC_DATA_INDEX, "RdbDeviceToDeviceDataSync")); } if (errorCode != E_OK) { - LOG_ERROR("Fail to set distributed tables, error=%{public}d", errorCode); + LOG_ERROR("Fail to set distributed tables, error=%{public}d.", errorCode); return errorCode; } if (type != DistributedRdb::DISTRIBUTED_CLOUD) { return E_OK; } - auto conn = connectionPool_->AcquireConnection(false); + + return HandleCloudSyncAfterSetDistributedTables(tables, distributedConfig); +} + +int RdbStoreImpl::HandleCloudSyncAfterSetDistributedTables( + const std::vector &tables, const DistributedRdb::DistributedConfig &distributedConfig) +{ + auto pool = GetPool(); + if (pool == nullptr) { + return E_ALREADY_CLOSED; + } + auto conn = pool->AcquireConnection(false); if (conn != nullptr) { auto strategy = conn->GenerateExchangeStrategy(slaveStatus_); if (strategy == ExchangeStrategy::BACKUP) { @@ -435,7 +486,7 @@ int RdbStoreImpl::SubscribeLocal(const SubscribeOption &option, RdbStoreObserver auto &list = localObservers_.find(option.event)->second; for (auto it = list.begin(); it != list.end(); it++) { if ((*it)->getObserver() == observer) { - LOG_ERROR("duplicate subscribe."); + LOG_ERROR("Duplicate subscribe."); return E_OK; } } @@ -451,7 +502,7 @@ int RdbStoreImpl::SubscribeLocalShared(const SubscribeOption &option, RdbStoreOb auto &list = localSharedObservers_.find(option.event)->second; for (auto it = list.begin(); it != list.end(); it++) { if ((*it)->getObserver() == observer) { - LOG_ERROR("duplicate subscribe."); + LOG_ERROR("Duplicate subscribe."); return E_OK; } } @@ -474,13 +525,15 @@ int RdbStoreImpl::SubscribeLocalShared(const SubscribeOption &option, RdbStoreOb int32_t RdbStoreImpl::SubscribeLocalDetail( const SubscribeOption &option, const std::shared_ptr &observer) { - auto connection = connectionPool_->AcquireConnection(false); - if (connection == nullptr) { - return E_DATABASE_BUSY; + auto [errCode, conn] = GetConn(false); + if (errCode != E_OK) { + LOG_ERROR("Get connection failed, errCode:%{public}d.", errCode); + return errCode; } - int32_t errCode = connection->Subscribe(option.event, observer); + + errCode = conn->Subscribe(option.event, observer); if (errCode != E_OK) { - LOG_ERROR("subscribe local detail observer failed. db name:%{public}s errCode:%{public}" PRId32, + LOG_ERROR("Subscribe local detail observer failed. db name:%{public}s errCode:%{public}." PRId32, SqliteUtils::Anonymous(config_.GetName()).c_str(), errCode); } return errCode; @@ -607,13 +660,15 @@ int RdbStoreImpl::UnSubscribeLocalSharedAll(const SubscribeOption &option) int32_t RdbStoreImpl::UnsubscribeLocalDetail( const SubscribeOption &option, const std::shared_ptr &observer) { - auto connection = connectionPool_->AcquireConnection(false); - if (connection == nullptr) { - return E_DATABASE_BUSY; + auto [errCode, conn] = GetConn(false); + if (errCode != E_OK) { + LOG_ERROR("Get connection failed, errCode:%{public}d.", errCode); + return errCode; } - int32_t errCode = connection->Unsubscribe(option.event, observer); + + errCode = conn->Unsubscribe(option.event, observer); if (errCode != E_OK) { - LOG_ERROR("unsubscribe local detail observer failed. db name:%{public}s errCode:%{public}" PRId32, + LOG_ERROR("Unsubscribe local detail observer failed. db name:%{public}s errCode:%{public}." PRId32, SqliteUtils::Anonymous(config_.GetName()).c_str(), errCode); } return errCode; @@ -748,28 +803,20 @@ void RdbStoreImpl::InitDelayNotifier() int RdbStoreImpl::RegisterDataChangeCallback() { - if (!config_.IsSearchable()) { - return E_OK; - } - if (isReadOnly_ || (config_.GetDBType() == DB_VECTOR)) { return E_NOT_SUPPORT; } InitDelayNotifier(); - auto callBack = [delayNotifier = delayNotifier_](const std::set &tables) { - DistributedRdb::RdbChangedData rdbChangedData; - for (const auto &table : tables) { - rdbChangedData.tableData[table].isTrackedDataChange = true; - } + auto callBack = [delayNotifier = delayNotifier_](const DistributedRdb::RdbChangedData &rdbChangedData) { if (delayNotifier != nullptr) { delayNotifier->UpdateNotify(rdbChangedData); } }; - auto connection = connectionPool_->AcquireConnection(false); - if (connection == nullptr) { - return E_DATABASE_BUSY; + auto [errCode, conn] = GetConn(false); + if (errCode != E_OK) { + return errCode; } - return connection->SubscribeTableChanges(callBack); + return conn->SubscribeTableChanges(callBack); } int RdbStoreImpl::GetHashKeyForLockRow(const AbsRdbPredicates &predicates, std::vector> &hashKeys) @@ -791,7 +838,7 @@ int RdbStoreImpl::GetHashKeyForLockRow(const AbsRdbPredicates &predicates, std:: auto result = QuerySql(sql, predicates.GetBindArgs()); if (result == nullptr) { - return E_ERROR; + return E_ALREADY_CLOSED ; } int count = 0; if (result->GetRowCount(count) != E_OK) { @@ -878,13 +925,35 @@ int32_t RdbStoreImpl::UnlockCloudContainer() } return errCode; } + +class RdbStoreImpl::StoreSuspender { +public: + StoreSuspender(RdbStoreImpl &rdbStore) : rdbStore_(rdbStore) + { + auto [err, service] = RdbMgr::GetInstance().GetRdbService(rdbStore_.syncerParam_); + if (service != nullptr) { + service->Disable(rdbStore_.syncerParam_); + } + service_ = service; + } + ~StoreSuspender() + { + if (service_ != nullptr) { + service_->Enable(rdbStore_.syncerParam_); + } + } + +private: + const RdbStoreImpl &rdbStore_; + std::shared_ptr service_; +}; #endif RdbStoreImpl::RdbStoreImpl(const RdbStoreConfig &config) : isMemoryRdb_(config.IsMemoryRdb()), config_(config), name_(config.GetName()), fileType_(config.GetDatabaseFileType()) { - path_ = (config.GetRoleType() != OWNER) ? config.GetVisitorDir() : config.GetPath(); + SqliteGlobalConfig::GetDbPath(config_, path_); isReadOnly_ = config.IsReadOnly() || config.GetRoleType() == VISITOR; } @@ -893,44 +962,33 @@ RdbStoreImpl::RdbStoreImpl(const RdbStoreConfig &config, int &errCode) fileType_(config.GetDatabaseFileType()) { isReadOnly_ = config.IsReadOnly() || config.GetRoleType() == VISITOR; - path_ = (config.GetRoleType() != OWNER) ? config.GetVisitorDir() : config.GetPath(); + SqliteGlobalConfig::GetDbPath(config_, path_); bool created = access(path_.c_str(), F_OK) != 0; connectionPool_ = ConnectionPool::Create(config_, errCode); + InitSyncerParam(config_); if (connectionPool_ == nullptr && (errCode == E_SQLITE_CORRUPT || errCode == E_INVALID_SECRET_KEY) && - !isReadOnly_) { + !isReadOnly_ && config.GetRoleType() == OWNER) { LOG_ERROR("database corrupt, errCode:0x%{public}x, %{public}s, %{public}s", errCode, SqliteUtils::Anonymous(name_).c_str(), - Reportor::FormatBrief(Connection::Collect(config_), "master").c_str()); -#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) - RdbParam param; - param.bundleName_ = config_.GetBundleName(); - param.storeName_ = config_.GetName(); - auto [err, service] = RdbMgr::GetInstance().GetRdbService(param); - if (service != nullptr) { - service->Disable(param); - } -#endif - config_.SetIter(0); - if (config_.IsEncrypt()) { - auto key = config_.GetEncryptKey(); - RdbSecurityManager::GetInstance().RestoreKeyFile(path_, key); - key.assign(key.size(), 0); + SqliteUtils::FormatDebugInfoBrief(Connection::Collect(config_), "master").c_str()); + StoreSuspender suspender(*this); + // rebuild should use the original config + std::shared_ptr pool; + std::tie(rebuild_, pool) = ConnectionPool::HandleDataCorruption(config_, errCode); + if (pool != nullptr) { + connectionPool_ = pool; } - std::tie(rebuild_, connectionPool_) = ConnectionPool::HandleDataCorruption(config_, errCode); created = true; -#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) - if (service != nullptr) { - service->Enable(param); - } -#endif } if (connectionPool_ == nullptr || errCode != E_OK) { connectionPool_ = nullptr; - LOG_ERROR("Create connPool failed, err is %{public}d, path:%{public}s", errCode, - SqliteUtils::Anonymous(path_).c_str()); + LOG_ERROR("Create connPool failed, err is %{public}d, rebuildType:%{public}d, path:%{public}s", errCode, + rebuild_, SqliteUtils::Anonymous(path_).c_str()); return; } - InitSyncerParam(config_, created); + if (created) { + syncerParam_.infos_ = Connection::Collect(config); + } InnerOpen(); } @@ -1013,45 +1071,121 @@ std::pair RdbStoreImpl::BatchInsert(const std::string &table, cons } SqlStatistic sqlStatistic("", SqlStatistic::Step::STEP_TOTAL); - auto connection = connectionPool_->AcquireConnection(false); - if (connection == nullptr) { + auto pool = GetPool(); + if (pool == nullptr) { + return { E_ALREADY_CLOSED, -1 }; + } + auto conn = pool->AcquireConnection(false); + if (conn == nullptr) { return { E_DATABASE_BUSY, -1 }; } - auto executeSqlArgs = SqliteSqlBuilder::GenerateSqls(table, rows, connection->GetMaxVariable()); + auto executeSqlArgs = SqliteSqlBuilder::GenerateSqls(table, rows, conn->GetMaxVariable()); if (executeSqlArgs.empty()) { LOG_ERROR("empty, table=%{public}s, values:%{public}zu, max number:%{public}d.", table.c_str(), rows.RowSize(), - connection->GetMaxVariable()); + conn->GetMaxVariable()); return { E_INVALID_ARGS, -1 }; } -#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) PauseDelayNotify pauseDelayNotify(delayNotifier_); -#endif for (const auto &[sql, bindArgs] : executeSqlArgs) { - auto [errCode, statement] = GetStatement(sql, connection); + auto [errCode, statement] = GetStatement(sql, conn); if (statement == nullptr) { - LOG_ERROR("statement is nullptr, errCode:0x%{public}x, args:%{public}zu, table:%{public}s, sql:%{public}s", - errCode, bindArgs.size(), table.c_str(), SqliteUtils::AnonySql(sql).c_str()); + LOG_ERROR("statement is nullptr, errCode:0x%{public}x, args:%{public}zu, table:%{public}s, " + "app self can check the SQL", + errCode, bindArgs.size(), table.c_str()); return { E_OK, -1 }; } for (const auto &args : bindArgs) { auto errCode = statement->Execute(args); if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { - connectionPool_->Dump(true, "BATCH"); + pool->Dump(true, "BATCH"); return { errCode, -1 }; } if (errCode != E_OK) { - LOG_ERROR("failed, errCode:%{public}d,args:%{public}zu,table:%{public}s,sql:%{public}s", errCode, - bindArgs.size(), table.c_str(), SqliteUtils::AnonySql(sql).c_str()); + LOG_ERROR("failed, errCode:%{public}d,args:%{public}zu,table:%{public}s,app self can check the SQL", + errCode, bindArgs.size(), table.c_str()); return { E_OK, -1 }; } } } - connection = nullptr; + conn = nullptr; DoCloudSync(table); return { E_OK, int64_t(rows.RowSize()) }; } +std::pair RdbStoreImpl::BatchInsertWithConflictResolution( + const std::string &table, const ValuesBuckets &rows, Resolution resolution) +{ + if (isReadOnly_ || (config_.GetDBType() == DB_VECTOR)) { + return { E_NOT_SUPPORT, -1 }; + } + + if (rows.RowSize() == 0) { + return { E_OK, 0 }; + } + + SqlStatistic sqlStatistic("", SqlStatistic::Step::STEP_TOTAL); + auto pool = GetPool(); + if (pool == nullptr) { + return { E_ALREADY_CLOSED, -1 }; + } + auto conn = pool->AcquireConnection(false); + if (conn == nullptr) { + return { E_DATABASE_BUSY, -1 }; + } + + auto sqlArgs = SqliteSqlBuilder::GenerateSqls(table, rows, conn->GetMaxVariable(), resolution); + if (sqlArgs.empty()) { + LOG_ERROR("empty, table=%{public}s, values:%{public}zu, max number:%{public}d.", table.c_str(), rows.RowSize(), + conn->GetMaxVariable()); + return { E_INVALID_ARGS, -1 }; + } + + for (const auto &[sql, bindArgs] : sqlArgs) { + auto [errCode, statement] = GetStatement(sql, conn); + if (statement == nullptr) { + LOG_ERROR("statement is nullptr, errCode:0x%{public}x, args:%{public}zu, table:%{public}s, " + "app self can check the SQL", + errCode, bindArgs.size(), table.c_str()); + return { errCode, -1 }; + } + for (const auto &args : bindArgs) { + auto errCode = statement->Execute(args); + if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { + pool->Dump(true, "BATCH"); + return { errCode, -1 }; + } + if (errCode != E_OK) { + LOG_ERROR("failed, errCode:%{public}d,args:%{public}zu,table:%{public}s,app self can check the SQL", + errCode, bindArgs.size(), table.c_str()); + return { E_OK, -1 }; + } + } + } + auto &[sql, bindArgs] = sqlArgs.front(); + auto [errCode, statement] = GetStatement(sql, conn); + if (statement == nullptr) { + LOG_ERROR("statement is nullptr, errCode:0x%{public}x, args:%{public}zu, table:%{public}s, " + "app self can check the SQL", errCode, bindArgs.size(), table.c_str()); + return { errCode, -1 }; + } + PauseDelayNotify pauseDelayNotify(delayNotifier_); + auto args = std::ref(bindArgs.front()); + errCode = statement->Execute(args); + if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { + pool->Dump(true, "BATCH"); + return { errCode, -1 }; + } + if (errCode != E_OK) { + LOG_ERROR("failed,errCode:%{public}d,table:%{public}s,args:%{public}zu,resolution:%{public}d.", errCode, + table.c_str(), args.get().size(), static_cast(resolution)); + return { errCode, errCode == E_SQLITE_CONSTRAINT ? int64_t(statement->Changes()) : -1 }; + } + conn = nullptr; + DoCloudSync(table); + return { E_OK, int64_t(statement->Changes()) }; +} + std::pair RdbStoreImpl::Update( const std::string &table, const Row &row, const std::string &where, const Values &args, Resolution resolution) { @@ -1140,7 +1274,12 @@ std::shared_ptr RdbStoreImpl::QuerySql(const std::string &sq SqlStatistic sqlStatistic("", SqlStatistic::Step::STEP_TOTAL); #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) auto start = std::chrono::steady_clock::now(); - return std::make_shared(start, connectionPool_->AcquireRef(true), sql, bindArgs, path_); + auto pool = GetPool(); + if (pool == nullptr) { + LOG_ERROR("Database already closed."); + return nullptr; + } + return std::make_shared(start, pool->AcquireRef(true), sql, bindArgs, path_); #else (void)sql; (void)bindArgs; @@ -1148,11 +1287,20 @@ std::shared_ptr RdbStoreImpl::QuerySql(const std::string &sq #endif } -std::shared_ptr RdbStoreImpl::QueryByStep(const std::string &sql, const Values &args) +std::shared_ptr RdbStoreImpl::QueryByStep(const std::string &sql, const Values &args, bool preCount) { SqlStatistic sqlStatistic("", SqlStatistic::Step::STEP_TOTAL); auto start = std::chrono::steady_clock::now(); - return std::make_shared(start, connectionPool_->AcquireRef(true), sql, args); + auto pool = GetPool(); + if (pool == nullptr) { + LOG_ERROR("Database already closed."); + return nullptr; + } +#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) + return std::make_shared(start, connectionPool_->AcquireRef(true), sql, args, preCount); +#else + return std::make_shared(start, connectionPool_->AcquireRef(true), sql, args, false); +#endif } int RdbStoreImpl::Count(int64_t &outValue, const AbsRdbPredicates &predicates) @@ -1179,11 +1327,15 @@ int RdbStoreImpl::ExecuteSql(const std::string &sql, const Values &args) if (statement == nullptr) { return errCode; } + auto pool = GetPool(); + if (pool == nullptr) { + return E_ALREADY_CLOSED; + } errCode = statement->Execute(args); if (errCode != E_OK) { - LOG_ERROR("failed,error:0x%{public}x sql:%{public}s.", errCode, SqliteUtils::AnonySql(sql).c_str()); + LOG_ERROR("failed,error:0x%{public}x app self can check the SQL.", errCode); if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { - connectionPool_->Dump(true, "EXECUTE"); + pool->Dump(true, "EXECUTE"); } return errCode; } @@ -1194,11 +1346,11 @@ int RdbStoreImpl::ExecuteSql(const std::string &sql, const Values &args) auto [err, version] = statement->ExecuteForValue(); statement = nullptr; if (vSchema_ < static_cast(version)) { - LOG_INFO("db:%{public}s exe DDL schema<%{public}" PRIi64 "->%{public}" PRIi64 "> sql:%{public}s.", - SqliteUtils::Anonymous(name_).c_str(), vSchema_, static_cast(version), - SqliteUtils::AnonySql(sql).c_str()); + LOG_INFO("db:%{public}s exe DDL schema<%{public}" PRIi64 "->%{public}" PRIi64 + "> app self can check the SQL.", + SqliteUtils::Anonymous(name_).c_str(), vSchema_, static_cast(version)); vSchema_ = version; - errCode = connectionPool_->RestartReaders(); + errCode = pool->RestartReaders(); } } statement = nullptr; @@ -1218,7 +1370,7 @@ std::pair RdbStoreImpl::Execute(const std::string &sql, co SqlStatistic sqlStatistic("", SqlStatistic::Step::STEP_TOTAL); int sqlType = SqliteUtils::GetSqlStatementType(sql); if (!SqliteUtils::IsSupportSqlForExecute(sqlType)) { - LOG_ERROR("Not support the sqlType: %{public}d, sql: %{public}s", sqlType, SqliteUtils::AnonySql(sql).c_str()); + LOG_ERROR("Not support the sqlType: %{public}d, app self can check the SQL", sqlType); return { E_NOT_SUPPORT_THE_SQL, object }; } @@ -1226,21 +1378,25 @@ std::pair RdbStoreImpl::Execute(const std::string &sql, co return { ExecuteByTrxId(sql, trxId, false, args), ValueObject() }; } - auto connect = connectionPool_->AcquireConnection(false); - if (connect == nullptr) { + auto pool = GetPool(); + if (pool == nullptr) { + return { E_ALREADY_CLOSED, object }; + } + auto conn = pool->AcquireConnection(false); + if (pool == nullptr) { return { E_DATABASE_BUSY, object }; } - auto [errCode, statement] = GetStatement(sql, connect); + auto [errCode, statement] = GetStatement(sql, conn); if (errCode != E_OK) { return { errCode, object }; } errCode = statement->Execute(args); if (errCode != E_OK) { - LOG_ERROR("failed,error:0x%{public}x sql:%{public}s.", errCode, SqliteUtils::AnonySql(sql).c_str()); + LOG_ERROR("failed,error:0x%{public}x app self can check the SQL.", errCode); if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { - connectionPool_->Dump(true, "EXECUTE"); + pool->Dump(true, "EXECUTE"); } return { errCode, object }; } @@ -1272,21 +1428,26 @@ std::pair RdbStoreImpl::HandleDifferentSqlTypes( } if (statement->GetColumnCount() > 1) { - LOG_ERROR("Not support the sql:%{public}s, column count more than 1", SqliteUtils::AnonySql(sql).c_str()); + LOG_ERROR("Not support the sql:app self can check the SQL, column count more than 1"); return { E_NOT_SUPPORT_THE_SQL, object }; } } + auto pool = GetPool(); + if (pool == nullptr) { + return { E_ALREADY_CLOSED, object }; + } + if (sqlType == SqliteUtils::STATEMENT_DDL) { statement->Reset(); statement->Prepare("PRAGMA schema_version"); auto [err, version] = statement->ExecuteForValue(); if (vSchema_ < static_cast(version)) { - LOG_INFO("db:%{public}s exe DDL schema<%{public}" PRIi64 "->%{public}" PRIi64 "> sql:%{public}s.", - SqliteUtils::Anonymous(name_).c_str(), vSchema_, static_cast(version), - SqliteUtils::AnonySql(sql).c_str()); + LOG_INFO("db:%{public}s exe DDL schema<%{public}" PRIi64 "->%{public}" PRIi64 + "> app self can check the SQL.", + SqliteUtils::Anonymous(name_).c_str(), vSchema_, static_cast(version)); vSchema_ = version; - errCode = connectionPool_->RestartReaders(); + errCode = pool->RestartReaders(); } } return { errCode, object }; @@ -1303,7 +1464,7 @@ int RdbStoreImpl::ExecuteAndGetLong(int64_t &outValue, const std::string &sql, c } auto [err, object] = statement->ExecuteForValue(args); if (err != E_OK) { - LOG_ERROR("failed, sql %{public}s, ERROR is %{public}d.", SqliteUtils::AnonySql(sql).c_str(), err); + LOG_ERROR("failed, app self can check the SQL, ERROR is %{public}d.", err); } outValue = object; return err; @@ -1321,7 +1482,7 @@ int RdbStoreImpl::ExecuteAndGetString(std::string &outValue, const std::string & ValueObject object; std::tie(errCode, object) = statement->ExecuteForValue(args); if (errCode != E_OK) { - LOG_ERROR("failed, sql %{public}s, ERROR is %{public}d.", SqliteUtils::AnonySql(sql).c_str(), errCode); + LOG_ERROR("failed, app self can check the SQL, ERROR is %{public}d.", errCode); } outValue = static_cast(object); return errCode; @@ -1341,17 +1502,20 @@ int RdbStoreImpl::ExecuteForLastInsertedRowId(int64_t &outValue, const std::stri errCode = statement->Execute(args); if (errCode != E_OK) { if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { - connectionPool_->Dump(true, "INSERT"); + auto pool = GetPool(); + if (pool != nullptr) { + pool->Dump(true, "INSERT"); + } } return errCode; } auto beginResult = std::chrono::steady_clock::now(); outValue = statement->Changes() > 0 ? statement->LastInsertRowId() : -1; auto allEnd = std::chrono::steady_clock::now(); - int64_t totalCostTime = std::chrono::duration_cast(begin - allEnd).count(); + int64_t totalCostTime = std::chrono::duration_cast(allEnd - begin).count(); if (totalCostTime >= TIME_OUT) { int64_t prepareCost = std::chrono::duration_cast(beginExec - begin).count(); - int64_t execCost = std::chrono::duration_cast(beginExec - beginResult).count(); + int64_t execCost = std::chrono::duration_cast(beginResult - beginExec).count(); int64_t resultCost = std::chrono::duration_cast(allEnd - beginResult).count(); LOG_WARN("total[%{public}" PRId64 "] stmt[%{public}" PRId64 "] exec[%{public}" PRId64 "] result[%{public}" PRId64 "] " @@ -1371,14 +1535,17 @@ int RdbStoreImpl::ExecuteForChangedRowCount(int64_t &outValue, const std::string return errCode; } errCode = statement->Execute(args); - if (errCode != E_OK) { - if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { - connectionPool_->Dump(true, "UPG DEL"); + if (errCode == E_OK) { + outValue = statement->Changes(); + return E_OK; + } + if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { + auto pool = GetPool(); + if (pool != nullptr) { + pool->Dump(true, "UPG DEL"); } - return errCode; } - outValue = statement->Changes(); - return E_OK; + return errCode; } int RdbStoreImpl::GetDataBasePath(const std::string &databasePath, std::string &backupFilePath) @@ -1443,16 +1610,9 @@ int RdbStoreImpl::Backup(const std::string &databasePath, const std::vectorAcquireConnection(false); - if (conn == nullptr) { - return E_BASE; - } - - return conn->Backup(databasePath, destEncryptKey, false, slaveStatus_); + auto [errCode, conn] = GetConn(false); + return errCode != E_OK ? errCode : conn->Backup(databasePath, destEncryptKey, false, slaveStatus_); } if (config_.GetHaMode() != HAMode::SINGLE && SqliteUtils::IsSlaveDbName(databasePath)) { - auto conn = connectionPool_->AcquireConnection(false); - return conn == nullptr ? E_BASE : conn->Backup(databasePath, {}, false, slaveStatus_); + auto [errCode, conn] = GetConn(false); + return errCode != E_OK ? errCode : conn->Backup(databasePath, {}, false, slaveStatus_); } auto [result, conn] = CreateWritableConn(); @@ -1558,7 +1717,11 @@ std::pair RdbStoreImpl::BeginExecuteSql(const std:: } bool assumeReadOnly = SqliteUtils::IsSqlReadOnly(type); - auto conn = connectionPool_->AcquireConnection(assumeReadOnly); + auto pool = GetPool(); + if (pool == nullptr) { + return { E_ALREADY_CLOSED, nullptr }; + } + auto conn = pool->AcquireConnection(assumeReadOnly); if (conn == nullptr) { return { E_DATABASE_BUSY, nullptr }; } @@ -1579,7 +1742,7 @@ std::pair RdbStoreImpl::BeginExecuteSql(const std:: bool RdbStoreImpl::IsHoldingConnection() { - return connectionPool_ != nullptr; + return GetPool() != nullptr; } int RdbStoreImpl::SetDefaultEncryptSql( @@ -1655,7 +1818,11 @@ int RdbStoreImpl::SetDefaultEncryptAlgo(const ConnectionPool::SharedConn &conn, int RdbStoreImpl::AttachInner(const RdbStoreConfig &config, const std::string &attachName, const std::string &dbPath, const std::vector &key, int32_t waitTime) { - auto [conn, readers] = connectionPool_->AcquireAll(waitTime); + auto pool = GetPool(); + if (pool == nullptr) { + return E_ALREADY_CLOSED; + } + auto [conn, readers] = pool->AcquireAll(waitTime); if (conn == nullptr) { return E_DATABASE_BUSY; } @@ -1663,10 +1830,10 @@ int RdbStoreImpl::AttachInner(const RdbStoreConfig &config, const std::string &a if (config_.GetStorageMode() != StorageMode::MODE_MEMORY && conn->GetJournalMode() == static_cast(JournalMode::MODE_WAL)) { // close first to prevent the connection from being put back. - connectionPool_->CloseAllConnections(); + pool->CloseAllConnections(); conn = nullptr; readers.clear(); - auto [err, newConn] = connectionPool_->DisableWal(); + auto [err, newConn] = pool->DisableWal(); if (err != E_OK) { return err; } @@ -1753,7 +1920,11 @@ std::pair RdbStoreImpl::Detach(const std::string &attachName, return { E_OK, attachedInfo_.Size() }; } - auto [connection, readers] = connectionPool_->AcquireAll(waitTime); + auto pool = GetPool(); + if (pool == nullptr) { + return { E_ALREADY_CLOSED, 0 }; + } + auto [connection, readers] = pool->AcquireAll(waitTime); if (connection == nullptr) { return { E_DATABASE_BUSY, 0 }; } @@ -1778,10 +1949,10 @@ std::pair RdbStoreImpl::Detach(const std::string &attachName, } statement = nullptr; // close first to prevent the connection from being put back. - connectionPool_->CloseAllConnections(); + pool->CloseAllConnections(); connection = nullptr; readers.clear(); - errCode = connectionPool_->EnableWal(); + errCode = pool->EnableWal(); return { errCode, 0 }; } @@ -1824,13 +1995,17 @@ int RdbStoreImpl::SetVersion(int version) int RdbStoreImpl::BeginTransaction() { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - std::lock_guard lockGuard(connectionPool_->GetTransactionStackMutex()); + auto pool = GetPool(); + if (pool == nullptr) { + return E_ALREADY_CLOSED; + } + std::lock_guard lockGuard(pool->GetTransactionStackMutex()); if (isReadOnly_ || (config_.GetDBType() == DB_VECTOR)) { return E_NOT_SUPPORT; } // size + 1 means the number of transactions in process - size_t transactionId = connectionPool_->GetTransactionStack().size() + 1; - BaseTransaction transaction(connectionPool_->GetTransactionStack().size()); + size_t transactionId = pool->GetTransactionStack().size() + 1; + BaseTransaction transaction(pool->GetTransactionStack().size()); auto [errCode, statement] = GetStatement(transaction.GetTransactionStr()); if (statement == nullptr) { return errCode; @@ -1838,14 +2013,14 @@ int RdbStoreImpl::BeginTransaction() errCode = statement->Execute(); if (errCode != E_OK) { if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { - connectionPool_->Dump(true, "BEGIN"); + pool->Dump(true, "BEGIN"); } LOG_ERROR("transaction id: %{public}zu, storeName: %{public}s, errCode: %{public}d", transactionId, SqliteUtils::Anonymous(name_).c_str(), errCode); return errCode; } - connectionPool_->SetInTransaction(true); - connectionPool_->GetTransactionStack().push(transaction); + pool->SetInTransaction(true); + pool->GetTransactionStack().push(transaction); // 1 means the number of transactions in process if (transactionId > 1) { LOG_WARN("transaction id: %{public}zu, storeName: %{public}s, errCode: %{public}d", transactionId, @@ -1863,7 +2038,11 @@ std::pair RdbStoreImpl::BeginTrans() } int64_t tmpTrxId = 0; - auto [errCode, connection] = connectionPool_->CreateTransConn(false); + auto pool = GetPool(); + if (pool == nullptr) { + return { E_ALREADY_CLOSED, 0 }; + } + auto [errCode, connection] = pool->CreateTransConn(false); if (connection == nullptr) { LOG_ERROR("Get null connection, storeName: %{public}s errCode:0x%{public}x.", SqliteUtils::Anonymous(name_).c_str(), errCode); @@ -1884,26 +2063,30 @@ std::pair RdbStoreImpl::BeginTrans() int RdbStoreImpl::RollBack() { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - std::lock_guard lockGuard(connectionPool_->GetTransactionStackMutex()); + auto pool = GetPool(); + if (pool == nullptr) { + return E_ALREADY_CLOSED; + } + std::lock_guard lockGuard(pool->GetTransactionStackMutex()); if (isReadOnly_ || (config_.GetDBType() == DB_VECTOR)) { return E_NOT_SUPPORT; } - size_t transactionId = connectionPool_->GetTransactionStack().size(); + size_t transactionId = pool->GetTransactionStack().size(); - if (connectionPool_->GetTransactionStack().empty()) { + if (pool->GetTransactionStack().empty()) { LOG_ERROR("transaction id: %{public}zu, storeName: %{public}s", transactionId, SqliteUtils::Anonymous(name_).c_str()); return E_NO_TRANSACTION_IN_SESSION; } - BaseTransaction transaction = connectionPool_->GetTransactionStack().top(); - connectionPool_->GetTransactionStack().pop(); - if (transaction.GetType() != TransType::ROLLBACK_SELF && !connectionPool_->GetTransactionStack().empty()) { - connectionPool_->GetTransactionStack().top().SetChildFailure(true); + BaseTransaction transaction = pool->GetTransactionStack().top(); + pool->GetTransactionStack().pop(); + if (transaction.GetType() != TransType::ROLLBACK_SELF && !pool->GetTransactionStack().empty()) { + pool->GetTransactionStack().top().SetChildFailure(true); } auto [errCode, statement] = GetStatement(transaction.GetRollbackStr()); if (statement == nullptr) { if (errCode == E_DATABASE_BUSY) { - Reportor::Report(Reportor::Create(config_, errCode, "ErrorType: RollBusy")); + Reportor::ReportCorrupted(Reportor::Create(config_, errCode, "ErrorType: RollBusy")); } // size + 1 means the number of transactions in process LOG_ERROR("transaction id: %{public}zu, storeName: %{public}s", transactionId + 1, @@ -1913,14 +2096,14 @@ int RdbStoreImpl::RollBack() errCode = statement->Execute(); if (errCode != E_OK) { if (errCode == E_SQLITE_BUSY || errCode == E_SQLITE_LOCKED) { - Reportor::Report(Reportor::Create(config_, errCode, "ErrorType: RollBusy")); + Reportor::ReportCorrupted(Reportor::Create(config_, errCode, "ErrorType: RollBusy")); } LOG_ERROR("failed, id: %{public}zu, storeName: %{public}s, errCode: %{public}d", transactionId, SqliteUtils::Anonymous(name_).c_str(), errCode); return errCode; } - if (connectionPool_->GetTransactionStack().empty()) { - connectionPool_->SetInTransaction(false); + if (pool->GetTransactionStack().empty()) { + pool->SetInTransaction(false); } // 1 means the number of transactions in process if (transactionId > 1) { @@ -1981,27 +2164,31 @@ int RdbStoreImpl::RollBack(int64_t trxId) int RdbStoreImpl::Commit() { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - std::lock_guard lockGuard(connectionPool_->GetTransactionStackMutex()); + auto pool = GetPool(); + if (pool == nullptr) { + return E_ALREADY_CLOSED; + } + std::lock_guard lockGuard(pool->GetTransactionStackMutex()); if (isReadOnly_ || (config_.GetDBType() == DB_VECTOR)) { return E_NOT_SUPPORT; } - size_t transactionId = connectionPool_->GetTransactionStack().size(); + size_t transactionId = pool->GetTransactionStack().size(); - if (connectionPool_->GetTransactionStack().empty()) { + if (pool->GetTransactionStack().empty()) { return E_OK; } - BaseTransaction transaction = connectionPool_->GetTransactionStack().top(); + BaseTransaction transaction = pool->GetTransactionStack().top(); std::string sqlStr = transaction.GetCommitStr(); if (sqlStr.size() <= 1) { LOG_WARN("id: %{public}zu, storeName: %{public}s, sql: %{public}s", transactionId, SqliteUtils::Anonymous(name_).c_str(), sqlStr.c_str()); - connectionPool_->GetTransactionStack().pop(); + pool->GetTransactionStack().pop(); return E_OK; } auto [errCode, statement] = GetStatement(sqlStr); if (statement == nullptr) { if (errCode == E_DATABASE_BUSY) { - Reportor::Report(Reportor::Create(config_, errCode, "ErrorType: CommitBusy")); + Reportor::ReportCorrupted(Reportor::Create(config_, errCode, "ErrorType: CommitBusy")); } LOG_ERROR("id: %{public}zu, storeName: %{public}s, statement error", transactionId, SqliteUtils::Anonymous(name_).c_str()); @@ -2010,19 +2197,19 @@ int RdbStoreImpl::Commit() errCode = statement->Execute(); if (errCode != E_OK) { if (errCode == E_SQLITE_BUSY || errCode == E_SQLITE_LOCKED) { - Reportor::Report(Reportor::Create(config_, errCode, "ErrorType: CommitBusy")); + Reportor::ReportCorrupted(Reportor::Create(config_, errCode, "ErrorType: CommitBusy")); } LOG_ERROR("failed, id: %{public}zu, storeName: %{public}s, errCode: %{public}d", transactionId, SqliteUtils::Anonymous(name_).c_str(), errCode); return errCode; } - connectionPool_->SetInTransaction(false); + pool->SetInTransaction(false); // 1 means the number of transactions in process if (transactionId > 1) { LOG_WARN("id: %{public}zu, storeName: %{public}s, errCode: %{public}d", transactionId, SqliteUtils::Anonymous(name_).c_str(), errCode); } - connectionPool_->GetTransactionStack().pop(); + pool->GetTransactionStack().pop(); return E_OK; } @@ -2037,7 +2224,11 @@ bool RdbStoreImpl::IsInTransaction() if (isReadOnly_ || (config_.GetDBType() == DB_VECTOR)) { return false; } - return connectionPool_->IsInTransaction(); + auto pool = GetPool(); + if (pool == nullptr) { + return false; + } + return pool->IsInTransaction(); } int RdbStoreImpl::CheckAttach(const std::string &sql) @@ -2144,14 +2335,14 @@ int RdbStoreImpl::ConfigLocale(const std::string &localeStr) { if (!isOpen_) { LOG_ERROR("The connection pool has been closed."); - return E_ERROR; + return E_ALREADY_CLOSED; } - if (connectionPool_ == nullptr) { - LOG_ERROR("connectionPool_ is null."); - return E_ERROR; + auto pool = GetPool(); + if (pool == nullptr) { + return E_ALREADY_CLOSED; } - return connectionPool_->ConfigLocale(localeStr); + return pool->ConfigLocale(localeStr); } int RdbStoreImpl::GetDestPath(const std::string &backupPath, std::string &destPath) @@ -2163,11 +2354,6 @@ int RdbStoreImpl::GetDestPath(const std::string &backupPath, std::string &destPa std::string tempPath = destPath + ".tmp"; if (access(tempPath.c_str(), F_OK) == E_OK) { destPath = tempPath; - } else { - auto walFile = destPath + "-wal"; - if (access(walFile.c_str(), F_OK) == E_OK) { - return E_ERROR; - } } if (access(destPath.c_str(), F_OK) != E_OK) { @@ -2184,46 +2370,42 @@ int RdbStoreImpl::Restore(const std::string &backupPath, const std::vectorDisable(syncerParam_); +// RestoreReporter reporter(config_, __FUNCTION__); + { + StoreSuspender suspender(*this); + errCode = pool->ChangeDbFileForRestore(path_, destPath, newKey, slaveStatus_); } -#endif - bool corrupt = Reportor::IsReportCorruptedFault(path_); - int errCode = connectionPool_->ChangeDbFileForRestore(path_, destPath, newKey, slaveStatus_); keyFiles.Unlock(); #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) SecurityPolicy::SetSecurityLabel(config_); - if (service != nullptr) { - service->Enable(syncerParam_); - if (errCode == E_OK) { - auto syncerParam = syncerParam_; - syncerParam.infos_ = Connection::Collect(config_); - service->AfterOpen(syncerParam); - NotifyDataChange(); - } + auto [code, service] = RdbMgr::GetInstance().GetRdbService(syncerParam_); + if (service != nullptr && errCode == E_OK) { + auto syncerParam = syncerParam_; + syncerParam.infos_ = Connection::Collect(config_); + service->AfterOpen(syncerParam); + NotifyDataChange(); } #endif if (errCode == E_OK) { ExchangeSlaverToMaster(); - Reportor::ReportRestore(Reportor::Create(config_, E_OK), corrupt); +// Reportor::ReportRestore(Reportor::Create(config_, E_OK), corrupt); rebuild_ = RebuiltType::NONE; } DoCloudSync(""); @@ -2254,7 +2436,11 @@ std::pair> RdbStoreImpl::GetStatement( std::pair> RdbStoreImpl::GetStatement(const std::string &sql, bool read) const { - auto conn = connectionPool_->AcquireConnection(read); + auto pool = GetPool(); + if (pool == nullptr) { + return { E_ALREADY_CLOSED, nullptr }; + } + auto conn = pool->AcquireConnection(read); if (conn == nullptr) { return { E_DATABASE_BUSY, nullptr }; } @@ -2315,9 +2501,9 @@ int32_t RdbStoreImpl::ExchangeSlaverToMaster() if (isReadOnly_ || rebuild_ != RebuiltType::NONE) { return E_OK; } - auto conn = connectionPool_->AcquireConnection(false); - if (conn == nullptr) { - return E_DATABASE_BUSY; + auto [errCode, conn] = GetConn(false); + if (errCode != E_OK) { + return errCode; } auto strategy = conn->GenerateExchangeStrategy(slaveStatus_); if (strategy != ExchangeStrategy::NOT_HANDLE) { @@ -2346,7 +2532,11 @@ std::pair> RdbStoreImpl::CreateTransaction return { E_NOT_SUPPORT, nullptr }; } - auto [errCode, conn] = connectionPool_->CreateTransConn(); + auto pool = GetPool(); + if (pool == nullptr) { + return { E_ALREADY_CLOSED, nullptr }; + } + auto [errCode, conn] = pool->CreateTransConn(); if (conn == nullptr) { return { errCode, nullptr }; } @@ -2354,7 +2544,7 @@ std::pair> RdbStoreImpl::CreateTransaction std::tie(errCode, trans) = Transaction::Create(type, conn, config_.GetName()); if (trans == nullptr) { if (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { - connectionPool_->Dump(true, "TRANS"); + pool->Dump(true, "TRANS"); } return { errCode, nullptr }; } @@ -2417,4 +2607,31 @@ std::set RdbStoreImpl::CloudTables::Steal() } return result; } -} // namespace OHOS::NativeRdb \ No newline at end of file + +RdbStoreImpl::SavePointers::SavePointers(std::shared_ptr pool, std::shared_ptr conn, + ConflictResolution resolution, int &errCode) + : pool_(pool), conn_(conn), resolution_(resolution), errCode_(errCode) +{ + std::lock_guard lockGuard(pool->GetTransactionStackMutex()); + size_t transactionId = pool->GetTransactionStack().size() + 1; + BaseTransaction transaction(pool->GetTransactionStack().size()); + auto [code, statement] = conn->CreateStatement(transaction.GetTransactionStr(), conn); + if (statement != nullptr) { + errCode = code; + return; + } + errCode = statement->Execute(); +} + +RdbStoreImpl::SavePointers::~SavePointers() +{ + if (errCode_ == E_OK) { + // commit() + } + if (errCode_ != E_SQLITE_CONSTRAINT || (resolution_ == ConflictResolution::ON_CONFLICT_ABORT || + resolution_ == ConflictResolution::ON_CONFLICT_REPLACE || + resolution_ == ConflictResolution::ON_CONFLICT_NONE)) { + // rollback(); + } +} +} // namespace OHOS::NativeRdb diff --git a/relational_store/frameworks/native/rdb/src/rdb_store_manager.cpp b/relational_store/frameworks/native/rdb/src/rdb_store_manager.cpp index 09f742a14f0d664fbf2ad4d73a9632a78d61dee4..f828e7080ab7e01ff561c75d53f1973c27bf2a8d 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_store_manager.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_store_manager.cpp @@ -72,13 +72,11 @@ std::shared_ptr RdbStoreManager::GetStoreFromCache(const RdbStoreC auto oldConfig = rdbStore->GetConfig(); if (oldConfig != config) { storeCache_.erase(it); - LOG_INFO("app[%{public}s:%{public}s] path[%{public}s]" - " cfg[%{public}d,%{public}d,%{public}d,%{public}d,%{public}d,%{public}d,%{public}d,%{public}s]" - " %{public}s", + LOG_WARN("app[%{public}s:%{public}s] path[%{public}s] cfg[%{public}s] debug[%{public}s]", config.GetBundleName().c_str(), config.GetModuleName().c_str(), SqliteUtils::Anonymous(path).c_str(), - config.GetDBType(), config.GetHaMode(), config.IsEncrypt(), config.GetArea(), config.GetSecurityLevel(), - config.GetRoleType(), config.IsReadOnly(), config.GetCustomDir().c_str(), - Reportor::FormatBrief(Connection::Collect(config), SqliteUtils::Anonymous(config.GetName())).c_str()); + RdbStoreConfig::FormatCfg(oldConfig, config).c_str(), + SqliteUtils::FormatDebugInfoBrief(Connection::Collect(config), SqliteUtils::Anonymous(config.GetName())) + .c_str()); return nullptr; } return rdbStore; @@ -87,7 +85,7 @@ std::shared_ptr RdbStoreManager::GetStoreFromCache(const RdbStoreC std::shared_ptr RdbStoreManager::GetRdbStore( const RdbStoreConfig &config, int &errCode, int version, RdbOpenCallback &openCallback) { - // TOD this lock should only work on storeCache_, add one more lock for connectionpool + // TOD this lock should only work on storeCache_, add one more lock for connectionPool errCode = E_OK; std::lock_guard lock(mutex_); if (config.GetRoleType() == VISITOR_WRITE && !IsPermitted(GetSyncParam(config))) { @@ -108,28 +106,28 @@ std::shared_ptr RdbStoreManager::GetRdbStore( if (errCode != E_OK && modifyConfig != config) { LOG_WARN("Failed to GetRdbStore using modifyConfig. path:%{public}s, rc=%{public}d", SqliteUtils::Anonymous(path).c_str(), errCode); - rdbStore = std::make_shared(config, errCode); // retry with input config + rdbStore = std::make_shared(config, errCode); // retry with input config } if (errCode != E_OK) { - LOG_ERROR("GetRdbStore failed. path:%{public}s, rc=%{public}d", - SqliteUtils::Anonymous(path).c_str(), errCode); + LOG_ERROR("GetRdbStore failed. path:%{public}s, rc=%{public}d", SqliteUtils::Anonymous(path).c_str(), errCode); return nullptr; } - if (modifyConfig.GetRoleType() == OWNER && !modifyConfig.IsReadOnly()) { - errCode = SetSecurityLabel(modifyConfig); + if (rdbStore->GetConfig().GetRoleType() == OWNER && !rdbStore->GetConfig().IsReadOnly()) { + errCode = SetSecurityLabel(rdbStore->GetConfig()); if (errCode != E_OK) { return nullptr; } (void)rdbStore->ExchangeSlaverToMaster(); - errCode = ProcessOpenCallback(*rdbStore, modifyConfig, version, openCallback); + errCode = ProcessOpenCallback(*rdbStore, version, openCallback); if (errCode != E_OK) { LOG_ERROR("fail, storeName:%{public}s path:%{public}s ProcessOpenCallback errCode:%{public}d", - SqliteUtils::Anonymous(modifyConfig.GetName()).c_str(), - SqliteUtils::Anonymous(modifyConfig.GetPath()).c_str(), errCode); + SqliteUtils::Anonymous(rdbStore->GetConfig().GetName()).c_str(), + SqliteUtils::Anonymous(rdbStore->GetConfig().GetPath()).c_str(), errCode); return nullptr; } } + configCache_.Set(path, GetSyncParam(rdbStore->GetConfig())); storeCache_.insert_or_assign(std::move(path), rdbStore); return rdbStore; } @@ -140,23 +138,27 @@ bool RdbStoreManager::IsConfigInvalidChanged(const std::string &path, RdbStoreCo LOG_WARN("Config has no bundleName, path: %{public}s", SqliteUtils::Anonymous(path).c_str()); return false; } - Param lastParam; + Param lastParam = GetSyncParam(config); if (!configCache_.Get(path, lastParam) && GetParamFromService(lastParam) != E_OK) { LOG_WARN("Not found config cache, path: %{public}s", SqliteUtils::Anonymous(path).c_str()); return false; }; - bool isLevelInvalidChange = (static_cast(config.GetSecurityLevel()) > lastParam.level_); - bool isEncryptInvalidChange = (config.IsEncrypt() != lastParam.isEncrypt_); - bool isAreaInvalidChange = (config.GetArea() != lastParam.area_); - if (isLevelInvalidChange || isEncryptInvalidChange || isAreaInvalidChange) { - LOG_WARN("Store config invalid change, storePath %{public}s, securitylevel: %{public}d -> %{public}d, " - "area: %{public}d -> %{public}d, isEncrypt: %{public}d -> %{public}d", - SqliteUtils::Anonymous(path).c_str(), lastParam.level_, static_cast(config.GetSecurityLevel()), - lastParam.area_, config.GetArea(), lastParam.isEncrypt_, config.IsEncrypt()); - if (isEncryptInvalidChange) { - config.SetEncryptStatus(lastParam.isEncrypt_); - } + // The lastParam is possible that the same named db parameters of different paths when GetParamFromService + if (lastParam.customDir_ != config.GetCustomDir() || lastParam.hapName_ != config.GetModuleName() || + lastParam.area_ != config.GetArea()) { + LOG_WARN("Diff db with the same name! customDir:%{public}s -> %{public}s, hapName:%{public}s -> %{public}s," + "area:%{public}d -> %{public}d.", lastParam.customDir_.c_str(), config.GetCustomDir().c_str(), + lastParam.hapName_.c_str(), config.GetModuleName().c_str(), lastParam.area_, config.GetArea()); + return false; + } + if (config.GetSecurityLevel() != SecurityLevel::LAST && + static_cast(config.GetSecurityLevel()) > lastParam.level_) { + LOG_WARN("Illegal change, storePath %{public}s, securityLevel: %{public}d -> %{public}d", + SqliteUtils::Anonymous(path).c_str(), lastParam.level_, static_cast(config.GetSecurityLevel())); } + + // Reset the first effective attribute + config.SetEncryptStatus(lastParam.isEncrypt_); return false; } @@ -200,7 +202,7 @@ int32_t RdbStoreManager::GetParamFromService(DistributedRdb::RdbSyncerParam &par bool RdbStoreManager::IsPermitted(const DistributedRdb::RdbSyncerParam ¶m) { -#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) +#if !defined(CROSS_PLATFORM) auto [err, service] = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(param); if (err == E_NOT_SUPPORT) { return false; @@ -229,23 +231,25 @@ void RdbStoreManager::Clear() storeCache_.clear(); } -bool RdbStoreManager::Remove(const std::string &path) +bool RdbStoreManager::Remove(const std::string &path, bool shouldClose) { std::lock_guard lock(mutex_); configCache_.Delete(path); - if (storeCache_.find(path) != storeCache_.end()) { - if (storeCache_[path].lock()) { - LOG_INFO("store in use by %{public}ld holders", storeCache_[path].lock().use_count()); + auto it = storeCache_.find(path); + if (it != storeCache_.end()) { + auto rdbStore = it->second.lock(); + LOG_INFO("store in use by %{public}ld holders", storeCache_[path].lock().use_count()); + if (rdbStore && shouldClose) { + rdbStore->Close(); } - storeCache_.erase(path); // clean invalid store ptr + storeCache_.erase(it); // clean invalid store ptr return true; } return false; } -int RdbStoreManager::ProcessOpenCallback( - RdbStore &rdbStore, const RdbStoreConfig &config, int version, RdbOpenCallback &openCallback) +int RdbStoreManager::ProcessOpenCallback(RdbStore &rdbStore, int version, RdbOpenCallback &openCallback) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int errCode = E_OK; @@ -283,7 +287,7 @@ int RdbStoreManager::ProcessOpenCallback( return openCallback.OnOpen(rdbStore); } -bool RdbStoreManager::Delete(const std::string &path) +bool RdbStoreManager::Delete(const std::string &path, bool shouldClose) { #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) auto tokens = StringUtils::Split(path, "/"); @@ -293,17 +297,17 @@ bool RdbStoreManager::Delete(const std::string &path) auto [err, service] = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(param); if (err != E_OK || service == nullptr) { LOG_DEBUG("GetRdbService failed, err is %{public}d.", err); - return Remove(path); + return Remove(path, shouldClose); } err = service->Delete(param); if (err != E_OK) { LOG_ERROR("service delete store, storeName:%{public}s, err = %{public}d", SqliteUtils::Anonymous(param.storeName_).c_str(), err); - return Remove(path); + return Remove(path, shouldClose); } } #endif - return Remove(path); + return Remove(path, shouldClose); } int RdbStoreManager::SetSecurityLabel(const RdbStoreConfig &config) diff --git a/relational_store/frameworks/native/rdb/src/rdb_time_utils.cpp b/relational_store/frameworks/native/rdb/src/rdb_time_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d04319f1a242fe94566fb511f9496e8b65c8549b --- /dev/null +++ b/relational_store/frameworks/native/rdb/src/rdb_time_utils.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 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 "rdb_time_utils.h" +#include +#include +#include + +namespace OHOS::NativeRdb { + +constexpr int MAX_TIME_BUF_LEN = 32; +constexpr int MILLISECONDS_LEN = 3; +constexpr int NANO_TO_MILLI = 1000000; +constexpr int MILLI_PRE_SEC = 1000; + +std::string RdbTimeUtils::GetCurSysTimeWithMs() +{ + auto now = std::chrono::system_clock::now(); + std::time_t time = std::chrono::system_clock::to_time_t(now); + std::chrono::nanoseconds nsec = std::chrono::duration_cast(now.time_since_epoch()); + return GetTimeWithMs(time, nsec.count()); +} + +std::string RdbTimeUtils::GetTimeWithMs(time_t sec, int64_t nsec) +{ + std::tm *t = std::localtime(&sec); + std::stringstream oss; + oss << std::put_time(t, "%Y-%m-%d %H:%M:%S") << '.' << std::setfill('0') << std::setw(MILLISECONDS_LEN) + << (nsec / NANO_TO_MILLI) % MILLI_PRE_SEC; + return oss.str(); +} + +} // namespace OHOS::NativeRdb \ No newline at end of file diff --git a/relational_store/frameworks/native/rdb/src/rdb_types_util.cpp b/relational_store/frameworks/native/rdb/src/rdb_types_util.cpp index bd50fb2e4d516a9f7f2d85fa83554e362892591f..e6953d6b3b511ac57c2286b85b215845f491985d 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_types_util.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_types_util.cpp @@ -20,7 +20,8 @@ bool Marshalling(const SyncerParam &input, MessageParcel &data) { return ITypesUtil::Marshal(data, input.bundleName_, input.hapName_, input.storeName_, input.area_, input.level_, input.type_, input.isEncrypt_, input.password_, input.customDir_, input.isAutoClean_, input.isSearchable_, - input.haMode_, input.infos_, input.tokenIds_, input.uids_, input.user_, input.permissionNames_); + input.haMode_, input.infos_, input.tokenIds_, input.uids_, input.user_, input.permissionNames_, + input.asyncDownloadAsset_); } template<> bool Unmarshalling(SyncerParam &output, MessageParcel &data) @@ -28,7 +29,7 @@ bool Unmarshalling(SyncerParam &output, MessageParcel &data) return ITypesUtil::Unmarshal(data, output.bundleName_, output.hapName_, output.storeName_, output.area_, output.level_, output.type_, output.isEncrypt_, output.password_, output.customDir_, output.isAutoClean_, output.isSearchable_, output.haMode_, output.infos_, output.tokenIds_, output.uids_, output.user_, - output.permissionNames_); + output.permissionNames_, output.asyncDownloadAsset_); } template<> @@ -196,12 +197,12 @@ bool Unmarshalling(RdbChangedData &output, MessageParcel &data) template<> bool Marshalling(const RdbProperties &input, MessageParcel &data) { - return Marshal(data, input.isTrackedDataChange); + return Marshal(data, input.isTrackedDataChange, input.isP2pSyncDataChange); } template<> bool Unmarshalling(RdbProperties &output, MessageParcel &data) { - return Unmarshal(data, output.isTrackedDataChange); + return Unmarshal(data, output.isTrackedDataChange, output.isP2pSyncDataChange); } template<> diff --git a/relational_store/frameworks/native/rdb/src/share_block.cpp b/relational_store/frameworks/native/rdb/src/share_block.cpp index f4f4d1220c9cbb734839e330c869aa839622b7db..bd83211a5b34ceda4bafd264a98cbfa9cb38b275 100644 --- a/relational_store/frameworks/native/rdb/src/share_block.cpp +++ b/relational_store/frameworks/native/rdb/src/share_block.cpp @@ -32,6 +32,7 @@ const int ERROR_STATUS = -1; const unsigned int SLEEP_TIME = 1000; // move to the highest 32 bits of 64 bits number const int RETRY_TIME = 50; +const int PRINT_RETRY_TIMES = 10; int SeriAddRow(void *pCtx, int addedRows) { @@ -99,20 +100,26 @@ int SharedBlockSetColumnNum(AppDataFwk::SharedBlock *sharedBlock, int columnNum) int FillSharedBlockOpt(SharedBlockInfo *info, sqlite3_stmt *stmt) { SharedBlockSerializerInfo serializer(info->sharedBlock, stmt, info->columnNum, info->startPos); - Sqlite3SharedBlockMethods sqliteBlock = { 1, &serializer, info->isCountAllRows, info->startPos, info->requiredPos, - SeriAddRow, SeriReset, SeriFinish, SeriPutString, SeriPutLong, SeriPutDouble, SeriPutBlob, SeriPutNull, - SeriPutOther }; + Sqlite3SharedBlockMethods sqliteBlock = + (info->sharedBlock != nullptr) + ? Sqlite3SharedBlockMethods{ 1, &serializer, info->isCountAllRows, info->startPos, info->requiredPos, + SeriAddRow, SeriReset, SeriFinish, SeriPutString, SeriPutLong, SeriPutDouble, SeriPutBlob, + SeriPutNull, SeriPutOther } + : Sqlite3SharedBlockMethods{ 1, &serializer, true, 0, 0, DefAddRow, DefReset, DefFinish, DefPutString, + DefPutLong, DefPutDouble, DefPutBlob, DefPutNull, DefPutOther }; + auto db = sqlite3_db_handle(stmt); - int err = sqlite3_db_config(db, SQLITE_DBCONFIG_SET_SHAREDBLOCK, stmt, &sqliteBlock); - if (err != SQLITE_OK) { - LOG_ERROR("set sqlite shared block methods error. err=%{public}d, errno=%{public}d", err, errno); - return SQLiteError::ErrNo(err); + int cfgErr = sqlite3_db_config(db, SQLITE_DBCONFIG_SET_SHAREDBLOCK, stmt, &sqliteBlock); + if (cfgErr != SQLITE_OK) { + LOG_ERROR("set sqlite shared block methods error. err=%{public}d, errno=%{public}d", cfgErr, errno); + return SQLiteError::ErrNo(cfgErr); } int retryCount = 0; + int errCode = SQLITE_OK; while (true) { - err = sqlite3_step(stmt); - if (err == SQLITE_LOCKED || err == SQLITE_BUSY) { - LOG_WARN("Database locked, retrying err=%{public}d, errno=%{public}d", err, errno); + errCode = sqlite3_step(stmt); + if (errCode == SQLITE_LOCKED || errCode == SQLITE_BUSY) { + LOG_WARN("Database locked, retrying errCode=%{public}d, errno=%{public}d", errCode, errno); if (retryCount <= RETRY_TIME) { usleep(SLEEP_TIME); retryCount++; @@ -125,11 +132,15 @@ int FillSharedBlockOpt(SharedBlockInfo *info, sqlite3_stmt *stmt) info->startPos = serializer.GetStartPos(); info->addedRows = serializer.GetAddedRows(); - err = sqlite3_db_config(db, SQLITE_DBCONFIG_SET_SHAREDBLOCK, stmt, nullptr); - if (err != SQLITE_OK) { - LOG_ERROR("clear sqlite shared block methods error. err=%{public}d, errno=%{public}d", err, errno); + if (errCode == SQLITE_DONE || errCode == SQLITE_ROW) { + errCode = SQLITE_OK; + } + + cfgErr = sqlite3_db_config(db, SQLITE_DBCONFIG_SET_SHAREDBLOCK, stmt, nullptr); + if (cfgErr != SQLITE_OK || (errCode != SQLITE_OK) || retryCount > PRINT_RETRY_TIMES) { + LOG_ERROR("failed, cfgErr=%{public}d errCode=%{public}d retry=%{public}d", cfgErr, errCode, retryCount); } - return SQLiteError::ErrNo(err); + return SQLiteError::ErrNo(errCode); } int FillSharedBlock(SharedBlockInfo *info, sqlite3_stmt *stmt) @@ -138,6 +149,7 @@ int FillSharedBlock(SharedBlockInfo *info, sqlite3_stmt *stmt) info->totalRows = info->addedRows = 0; bool isFull = false; bool hasException = false; + auto fillRow = info->sharedBlock == nullptr ? DefFillRow : FillRow; while (!hasException && (!isFull || info->isCountAllRows)) { int err = sqlite3_step(stmt); if (err == SQLITE_ROW) { @@ -146,7 +158,7 @@ int FillSharedBlock(SharedBlockInfo *info, sqlite3_stmt *stmt) if (info->startPos >= info->totalRows || isFull) { continue; } - FillRow(info, stmt); + fillRow(info, stmt); isFull = info->isFull; hasException = info->hasException; } else if (err == SQLITE_DONE) { @@ -330,10 +342,62 @@ bool ResetStatement(SharedBlockInfo *info, sqlite3_stmt *stmt) LOG_ERROR("startPos %{public}d > actual rows %{public}d", info->startPos, info->totalRows); } - if (info->totalRows > 0 && info->addedRows == 0) { + if ((info->totalRows > 0 && info->addedRows == 0) && info->sharedBlock != nullptr) { + LOG_WARN("over 2MB[%{public}d, %{public}d]", info->totalRows, info->addedRows); return false; } return true; } + +int DefAddRow(void *pCtx, int addedRows) +{ + return SQLITE_FULL; +} + +int DefReset(void *pCtx, int startPos) +{ + return SQLITE_OK; +} + +int DefFinish(void *pCtx, int addedRows, int totalRows) +{ + auto *serializer = static_cast(pCtx); + return serializer->Finish(addedRows, totalRows); +} + +int DefPutString(void *pCtx, int addedRows, int column, const char *text, int size) +{ + return SQLITE_FULL; +} + +int DefPutLong(void *pCtx, int addedRows, int column, sqlite3_int64 value) +{ + return SQLITE_FULL; +} + +int DefPutDouble(void *pCtx, int addedRows, int column, double value) +{ + return SQLITE_FULL; +} + +int DefPutBlob(void *pCtx, int addedRows, int column, const void *blob, int len) +{ + return SQLITE_FULL; +} + +int DefPutNull(void *pCtx, int addedRows, int column) +{ + return SQLITE_FULL; +} + +int DefPutOther(void *pCtx, int addedRows, int column) +{ + return SQLITE_FULL; +} + +void DefFillRow(SharedBlockInfo *info, sqlite3_stmt *stmt) +{ + info->isFull = true; +} } // namespace NativeRdb } // namespace OHOS \ No newline at end of file diff --git a/relational_store/frameworks/native/rdb/src/sqlite_connection.cpp b/relational_store/frameworks/native/rdb/src/sqlite_connection.cpp index 631b0313c83261570b24aa987028d06003af066a..a1565b344b269e20b68dd552263d07549bd37d02 100644 --- a/relational_store/frameworks/native/rdb/src/sqlite_connection.cpp +++ b/relational_store/frameworks/native/rdb/src/sqlite_connection.cpp @@ -16,23 +16,16 @@ #define LOG_TAG "SqliteConnection" #include "sqlite_connection.h" +#include #include #include +#include #include #include #include #include -#include "sqlite3.h" -#include "value_object.h" - -#ifdef RDB_SUPPORT_ICU -#include -#endif - -#include - #include "logger.h" #include "raw_data_parser.h" #include "rdb_errno.h" @@ -41,9 +34,12 @@ #include "rdb_sql_statistic.h" #include "rdb_store_config.h" #include "relational_store_client.h" +#include "sqlite3.h" #include "sqlite_errno.h" +#include "sqlite_default_function.h" #include "sqlite_global_config.h" #include "sqlite_utils.h" +#include "value_object.h" #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) #include "rdb_manager_impl.h" #include "relational/relational_store_sqlite_ext.h" @@ -58,8 +54,6 @@ using RdbKeyFile = RdbSecurityManager::KeyFileType; using Reportor = RdbFaultHiViewReporter; constexpr const char *INTEGRITIES[] = { nullptr, "PRAGMA quick_check", "PRAGMA integrity_check" }; constexpr SqliteConnection::Suffix SqliteConnection::FILE_SUFFIXES[]; -constexpr const char *SqliteConnection::MERGE_ASSETS_FUNC; -constexpr const char *SqliteConnection::MERGE_ASSET_FUNC; constexpr int SqliteConnection::DEFAULT_BUSY_TIMEOUT_MS; constexpr int SqliteConnection::BACKUP_PAGES_PRE_STEP; // 1024 * 4 * 12800 == 50m constexpr int SqliteConnection::BACKUP_PRE_WAIT_TIME; @@ -108,34 +102,31 @@ int32_t SqliteConnection::Delete(const std::string &path) std::map SqliteConnection::Collect(const RdbStoreConfig &config) { std::map collection; + if (config.IsMemoryRdb()) { + return collection; + } std::string path; - Info info; SqliteGlobalConfig::GetDbPath(config, path); for (auto &suffix : FILE_SUFFIXES) { if (suffix.debug_ == nullptr) { continue; } auto file = path + suffix.suffix_; - struct stat fileStat; - if (stat(file.c_str(), &fileStat) != 0) { - continue; + std::pair fileInfo = SqliteUtils::Stat(file); + if (fileInfo.first == E_OK) { + collection.insert(std::pair{ suffix.debug_, fileInfo.second }); } - info.inode_ = fileStat.st_ino; - info.oldInode_ = 0; - info.atime_.sec_ = fileStat.st_atime; - info.mtime_.sec_ = fileStat.st_mtime; - info.ctime_.sec_ = fileStat.st_ctime; -#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) - info.atime_.nsec_ = fileStat.st_atim.tv_nsec; - info.mtime_.nsec_ = fileStat.st_mtim.tv_nsec; - info.ctime_.nsec_ = fileStat.st_ctim.tv_nsec; -#endif - info.size_ = fileStat.st_size; - info.dev_ = fileStat.st_dev; - info.mode_ = fileStat.st_mode; - info.uid_ = fileStat.st_uid; - info.gid_ = fileStat.st_gid; - collection.insert(std::pair{ suffix.debug_, info }); + } + RdbSecurityManager::KeyFiles keyFiles(path); + std::string keyPath = keyFiles.GetKeyFile(RdbSecurityManager::PUB_KEY_FILE); + std::pair fileInfo = SqliteUtils::Stat(keyPath); + if (fileInfo.first == E_OK) { + collection.insert(std::pair{ "key", fileInfo.second }); + } + std::string newKeyPath = keyFiles.GetKeyFile(RdbSecurityManager::PUB_KEY_FILE_NEW_KEY); + fileInfo = SqliteUtils::Stat(newKeyPath); + if (fileInfo.first == E_OK) { + collection.insert(std::pair{ "newKey", fileInfo.second }); } return collection; } @@ -162,14 +153,14 @@ std::pair> SqliteConnection::CreateSl "%{public}s,[%{public}d,%{public}d,%{public}d,%{public}d]", config.GetDBType(), config.GetHaMode(), config.IsEncrypt(), config.GetArea(), config.GetSecurityLevel(), config.GetRoleType(), config.IsReadOnly(), - Reportor::FormatBrief(bugInfo, SqliteUtils::Anonymous(config.GetName())).c_str(), - Reportor::FormatBrief(Connection::Collect(config_), "master").c_str(), isSlaveExist, isSlaveLockExist, - hasFailure, walOverLimit); + SqliteUtils::FormatDebugInfoBrief(bugInfo, SqliteUtils::Anonymous(config.GetName())).c_str(), + SqliteUtils::FormatDebugInfoBrief(Connection::Collect(config_), "master").c_str(), isSlaveExist, + isSlaveLockExist, hasFailure, walOverLimit); if (config.GetHaMode() == HAMode::MANUAL_TRIGGER && (slaveOpenPolicy == SlaveOpenPolicy::OPEN_IF_DB_VALID && (!isSlaveExist || isSlaveLockExist || hasFailure || walOverLimit))) { if (walOverLimit) { SqliteUtils::SetSlaveInvalid(config_.GetPath()); - Reportor::Report(Reportor::Create(config, E_SQLITE_ERROR, "ErrorType: slaveWalOverLimit")); + Reportor::ReportCorrupted(Reportor::Create(config, E_SQLITE_ERROR, "ErrorType: slaveWalOverLimit")); } return result; } @@ -239,10 +230,12 @@ int SqliteConnection::InnerOpen(const RdbStoreConfig &config) if (errCode != E_OK) { return errCode; } + SetTokenizer(config); #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) bool isDbFileExist = access(dbPath.c_str(), F_OK) == 0; if (!isDbFileExist && (!config.IsCreateNecessary())) { + Reportor::ReportFault(RdbFaultDbFileEvent(FT_EX_FILE, E_DB_NOT_EXIST, config, "db not exist")); LOG_ERROR("db not exist errno is %{public}d", errno); return E_DB_NOT_EXIST; } @@ -252,6 +245,7 @@ int SqliteConnection::InnerOpen(const RdbStoreConfig &config) : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX); errCode = OpenDatabase(dbPath, openFileFlags); if (errCode != E_OK) { + Reportor::ReportFault(RdbFaultDbFileEvent(FT_OPEN, errCode, config, "", true)); return errCode; } @@ -275,7 +269,7 @@ int SqliteConnection::InnerOpen(const RdbStoreConfig &config) LOG_ERROR("%{public}s integrity check result is %{public}s, sql:%{public}s", SqliteUtils::Anonymous(config.GetName()).c_str(), static_cast(checkResult).c_str(), sql); - Reportor::ReportFault(Reportor::Create(config, errCode, static_cast(checkResult))); + Reportor::ReportCorruptedOnce(Reportor::Create(config, errCode, static_cast(checkResult))); } } } @@ -300,6 +294,9 @@ int32_t SqliteConnection::OpenDatabase(const std::string &dbPath, int openFileFl } } #endif + if (errCode == SQLITE_NOTADB) { + Reportor::ReportFault(RdbFaultDbFileEvent(FT_OPEN, E_SQLITE_NOT_DB, config_, "", true)); + } return SQLiteError::ErrNo(errCode); } return E_OK; @@ -360,11 +357,7 @@ int SqliteConnection::SetCustomScalarFunction(const std::string &functionName, i int SqliteConnection::Configure(const RdbStoreConfig &config, std::string &dbPath) { - if (config.GetStorageMode() == StorageMode::MODE_MEMORY) { - return E_OK; - } - - if (config.GetRoleType() == VISITOR) { + if (config.GetStorageMode() == StorageMode::MODE_MEMORY || config.GetRoleType() == VISITOR) { return E_OK; } @@ -414,6 +407,7 @@ int SqliteConnection::Configure(const RdbStoreConfig &config, std::string &dbPat if (errCode != E_OK) { return errCode; } + return LoadExtension(config, dbHandle_); } @@ -460,8 +454,7 @@ std::pair> SqliteConnection::CreateStatement( slaveStmt->config_ = &slaveConnection_->config_; errCode = slaveStmt->Prepare(slaveConnection_->dbHandle_, sql); if (errCode != E_OK) { - LOG_WARN( - "prepare slave stmt failed:%{public}d, sql:%{public}s", errCode, SqliteUtils::AnonySql(sql).c_str()); + LOG_WARN("prepare slave stmt failed:%{public}d, app self can check the SQL", errCode); SqliteUtils::SetSlaveInvalid(config_.GetPath()); return { E_OK, statement }; } @@ -483,13 +476,14 @@ int SqliteConnection::SubscribeTableChanges(const Connection::Notifier ¬ifier } hasClientObserver_ = true; int32_t status = RegisterClientObserver(dbHandle_, [notifier](const ClientChangedData &clientData) { - std::set tables; + DistributedRdb::RdbChangedData rdbChangedData; for (auto &[key, val] : clientData.tableData) { - if (val.isTrackedDataChange) { - tables.insert(key); + if (val.isTrackedDataChange || val.isP2pSyncDataChange) { + rdbChangedData.tableData[key].isTrackedDataChange = val.isTrackedDataChange; + rdbChangedData.tableData[key].isP2pSyncDataChange = val.isP2pSyncDataChange; } } - notifier(tables); + notifier(rdbChangedData); }); if (status != E_OK) { LOG_ERROR("RegisterClientObserver error, status:%{public}d", status); @@ -701,21 +695,20 @@ int SqliteConnection::RegDefaultFunctions(sqlite3 *dbHandle) if (dbHandle == nullptr) { return SQLITE_OK; } - // The number of parameters is 2 - int errCode = sqlite3_create_function_v2(dbHandle, MERGE_ASSETS_FUNC, 2, SQLITE_UTF8 | SQLITE_DETERMINISTIC, - nullptr, &MergeAssets, nullptr, nullptr, nullptr); - if (errCode != SQLITE_OK) { - LOG_ERROR("register function mergeAssets failed, errCode=%{public}d, errno=%{public}d", errCode, errno); - return errCode; - } - // The number of parameters is 2 - errCode = sqlite3_create_function_v2(dbHandle, MERGE_ASSET_FUNC, 2, SQLITE_UTF8 | SQLITE_DETERMINISTIC, nullptr, - &MergeAsset, nullptr, nullptr, nullptr); - if (errCode != SQLITE_OK) { - LOG_ERROR("register function mergeAsset failed, errCode=%{public}d, errno=%{public}d", errCode, errno); - return errCode; + + auto [funcs, funcCount] = SqliteFunctionRegistry::GetFunctions(); + + for (size_t i = 0; i < funcCount; i++) { + const SqliteFunction& func = funcs[i]; + int errCode = sqlite3_create_function_v2(dbHandle, func.name, func.numArgs, + SQLITE_UTF8 | SQLITE_DETERMINISTIC, nullptr, func.function, nullptr, nullptr, nullptr); + if (errCode != SQLITE_OK) { + LOG_ERROR("register function %{public}s failed, errCode=0x%{public}x, errno=%{public}d", func.name, + errCode, errno); + return SQLiteError::ErrNo(errCode); + } } - return SQLITE_OK; + return E_OK; } int SqliteConnection::SetJournalMode(const RdbStoreConfig &config) @@ -726,8 +719,9 @@ int SqliteConnection::SetJournalMode(const RdbStoreConfig &config) auto [errCode, object] = ExecuteForValue("PRAGMA journal_mode"); if (errCode != E_OK) { - LOG_ERROR("SqliteConnection SetJournalMode fail to get journal mode : %{public}d", errCode); - return errCode; + LOG_ERROR("SetJournalMode fail to get journal mode : %{public}d, errno %{public}d", errCode, errno); + // errno: 28 No space left on device + return (errCode == E_SQLITE_IOERR && sqlite3_system_errno(dbHandle_) == 28) ? E_SQLITE_IOERR_FULL : errCode; } if (config.GetJournalMode().compare(static_cast(object)) == 0) { @@ -805,6 +799,20 @@ int SqliteConnection::SetAutoCheckpoint(const RdbStoreConfig &config) return errCode; } +int SqliteConnection::SetTokenizer(const RdbStoreConfig &config) +{ + auto tokenizer = config.GetTokenizer(); + if (tokenizer == NONE_TOKENIZER || tokenizer == CUSTOM_TOKENIZER) { + return E_OK; + } + if (tokenizer == ICU_TOKENIZER) { + sqlite3_config(SQLITE_CONFIG_ENABLE_ICU, 1); + return E_OK; + } + LOG_ERROR("fail to set Tokenizer: %{public}d", tokenizer); + return E_INVALID_ARGS; +} + int SqliteConnection::SetWalFile(const RdbStoreConfig &config) { if (!IsWriter()) { @@ -862,8 +870,8 @@ std::pair SqliteConnection::ExecuteForValue( ValueObject object; std::tie(errCode, object) = statement->ExecuteForValue(bindArgs); if (errCode != E_OK) { - LOG_ERROR("execute sql failed, errCode:%{public}d, sql:%{public}s, args size:%{public}zu", - SQLiteError::ErrNo(errCode), SqliteUtils::AnonySql(sql).c_str(), bindArgs.size()); + LOG_ERROR("execute sql failed, errCode:%{public}d, app self can check the SQL, args size:%{public}zu", + SQLiteError::ErrNo(errCode), bindArgs.size()); } return { errCode, object }; } @@ -897,63 +905,19 @@ void SqliteConnection::LimitPermission(const std::string &dbPath) const } } -#ifdef RDB_SUPPORT_ICU -int Collate8Compare(void *p, int n1, const void *v1, int n2, const void *v2) -{ - UCollator *coll = reinterpret_cast(p); - UCharIterator i1; - UCharIterator i2; - UErrorCode status = U_ZERO_ERROR; - - uiter_setUTF8(&i1, (const char *)v1, n1); - uiter_setUTF8(&i2, (const char *)v2, n2); - - UCollationResult result = ucol_strcollIter(coll, &i1, &i2, &status); - - if (U_FAILURE(status)) { - LOG_ERROR("Ucol strcoll error."); - } - - if (result == UCOL_LESS) { - return -1; - } else if (result == UCOL_GREATER) { - return 1; - } - return 0; -} - -void LocalizedCollatorDestroy(UCollator *collator) -{ - ucol_close(collator); -} -#endif - -/** - * The database locale. - */ int SqliteConnection::ConfigLocale(const std::string &localeStr) { -#ifdef RDB_SUPPORT_ICU - std::unique_lock lock(mutex_); - UErrorCode status = U_ZERO_ERROR; - UCollator *collator = ucol_open(localeStr.c_str(), &status); - if (U_FAILURE(status)) { - LOG_ERROR("Can not open collator."); - return E_ERROR; + static void *handle = dlopen("librelational_store_icu.z.so", RTLD_LAZY); + if (handle == nullptr) { + LOG_ERROR("dlopen(librelational_store_icu) failed(%{public}d)!", errno); + return E_NOT_SUPPORT; } - ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_PRIMARY, &status); - if (U_FAILURE(status)) { - LOG_ERROR("Set attribute of collator failed."); + auto func = reinterpret_cast(dlsym(handle, "ConfigICULocal")); + if (func == nullptr) { + LOG_ERROR("dlsym(librelational_store_icu) failed(%{public}d)!", errno); return E_ERROR; } - - int err = sqlite3_create_collation_v2( - dbHandle_, "LOCALES", SQLITE_UTF8, collator, Collate8Compare, (void (*)(void *))LocalizedCollatorDestroy); - if (err != SQLITE_OK) { - LOG_ERROR("SCreate collator in sqlite3 failed."); - return err; - } -#endif + func(dbHandle_, localeStr); return E_OK; } @@ -972,7 +936,7 @@ int SqliteConnection::CleanDirtyData(const std::string &table, uint64_t cursor) int SqliteConnection::TryCheckPoint(bool timeout) { - if (!isWriter_) { + if (!isWriter_ || config_.IsMemoryRdb()) { return E_NOT_SUPPORT; } @@ -1000,6 +964,8 @@ int SqliteConnection::TryCheckPoint(bool timeout) int errCode = sqlite3_wal_checkpoint_v2(dbHandle_, nullptr, SQLITE_CHECKPOINT_TRUNCATE, nullptr, nullptr); (void)sqlite3_busy_timeout(dbHandle_, DEFAULT_BUSY_TIMEOUT_MS); if (errCode != SQLITE_OK) { + Reportor::ReportFault(RdbFaultDbFileEvent(FT_CP, E_CHECK_POINT_FAIL, config_, + "LOG:cp fail, errcode=" + std::to_string(errCode), true)); LOG_WARN("sqlite3_wal_checkpoint_v2 failed err:%{public}d,size:%{public}zd,wal:%{public}s.", errCode, size, SqliteUtils::Anonymous(walName).c_str()); return SQLiteError::ErrNo(errCode); @@ -1009,142 +975,24 @@ int SqliteConnection::TryCheckPoint(bool timeout) int SqliteConnection::LimitWalSize() { - if (!isConfigured_ || !isWriter_) { + if (!isConfigured_ || !isWriter_ || config_.IsMemoryRdb()) { return E_OK; } std::string walName = sqlite3_filename_wal(sqlite3_db_filename(dbHandle_, "main")); ssize_t fileSize = SqliteUtils::GetFileSize(walName); if (fileSize < 0 || fileSize > config_.GetWalLimitSize()) { - LOG_ERROR("The WAL file size exceeds the limit, %{public}s size is %{public}zd", - SqliteUtils::Anonymous(walName).c_str(), fileSize); + std::stringstream ss; + ss << "The WAL file size exceeds the limit,name=" << SqliteUtils::Anonymous(walName).c_str() + << ",file size=" << fileSize + << ",limit size=" << config_.GetWalLimitSize(); + LOG_ERROR("%{public}s", ss.str().c_str()); + Reportor::ReportFault(RdbFaultDbFileEvent(FT_OPEN, E_WAL_SIZE_OVER_LIMIT, config_, ss.str())); return E_WAL_SIZE_OVER_LIMIT; } return E_OK; } -void SqliteConnection::MergeAssets(sqlite3_context *ctx, int argc, sqlite3_value **argv) -{ - // 2 is the number of parameters - if (ctx == nullptr || argc != 2 || argv == nullptr) { - LOG_ERROR("Parameter does not meet restrictions."); - return; - } - std::map assets; - auto data = static_cast(sqlite3_value_blob(argv[0])); - if (data != nullptr) { - int len = sqlite3_value_bytes(argv[0]); - RawDataParser::ParserRawData(data, len, assets); - } - std::map newAssets; - data = static_cast(sqlite3_value_blob(argv[1])); - if (data != nullptr) { - int len = sqlite3_value_bytes(argv[1]); - RawDataParser::ParserRawData(data, len, newAssets); - } - CompAssets(assets, newAssets); - auto blob = RawDataParser::PackageRawData(assets); - sqlite3_result_blob(ctx, blob.data(), blob.size(), SQLITE_TRANSIENT); -} - -void SqliteConnection::MergeAsset(sqlite3_context *ctx, int argc, sqlite3_value **argv) -{ - // 2 is the number of parameters - if (ctx == nullptr || argc != 2 || argv == nullptr) { - LOG_ERROR("Parameter does not meet restrictions."); - return; - } - ValueObject::Asset asset; - size_t size = 0; - auto data = static_cast(sqlite3_value_blob(argv[0])); - if (data != nullptr) { - int len = sqlite3_value_bytes(argv[0]); - size = RawDataParser::ParserRawData(data, len, asset); - } - ValueObject::Asset newAsset; - data = static_cast(sqlite3_value_blob(argv[1])); - if (data != nullptr) { - int len = sqlite3_value_bytes(argv[1]); - RawDataParser::ParserRawData(data, len, newAsset); - } - - if (size == 0) { - asset = std::move(newAsset); - if (asset.status != AssetValue::Status::STATUS_DELETE) { - asset.status = AssetValue::Status::STATUS_INSERT; - } - } else if (asset.name == newAsset.name) { - MergeAsset(asset, newAsset); - } else { - LOG_WARN("name change! old:%{public}s, new:%{public}s", SqliteUtils::Anonymous(asset.name).c_str(), - SqliteUtils::Anonymous(newAsset.name).c_str()); - } - auto blob = RawDataParser::PackageRawData(asset); - sqlite3_result_blob(ctx, blob.data(), blob.size(), SQLITE_TRANSIENT); -} - -void SqliteConnection::CompAssets( - std::map &assets, std::map &newAssets) -{ - auto oldIt = assets.begin(); - auto newIt = newAssets.begin(); - for (; oldIt != assets.end() && newIt != newAssets.end();) { - if (oldIt->first == newIt->first) { - MergeAsset(oldIt->second, newIt->second); - oldIt++; - newIt = newAssets.erase(newIt); - continue; - } - if (oldIt->first < newIt->first) { - ++oldIt; - continue; - } - newIt++; - } - for (auto &[key, value] : newAssets) { - value.status = ValueObject::Asset::Status::STATUS_INSERT; - assets.insert(std::pair{ key, std::move(value) }); - } -} - -void SqliteConnection::MergeAsset(ValueObject::Asset &oldAsset, ValueObject::Asset &newAsset) -{ - using Status = ValueObject::Asset::Status; - if (newAsset.status == Status::STATUS_DELETE) { - oldAsset.status = Status::STATUS_DELETE; - oldAsset.hash = ""; - oldAsset.modifyTime = ""; - oldAsset.size = ""; - return; - } - auto status = static_cast(oldAsset.status); - switch (status) { - case Status::STATUS_UNKNOWN: // fallthrough - case Status::STATUS_NORMAL: // fallthrough - case Status::STATUS_ABNORMAL: // fallthrough - case Status::STATUS_INSERT: // fallthrough - case Status::STATUS_UPDATE: // fallthrough - if (oldAsset.modifyTime != newAsset.modifyTime || oldAsset.size != newAsset.size || - oldAsset.uri != newAsset.uri || oldAsset.path != newAsset.path) { - if (oldAsset.modifyTime != newAsset.modifyTime || oldAsset.size != newAsset.size || - oldAsset.uri == newAsset.uri || oldAsset.path == newAsset.path) { - oldAsset.expiresTime = newAsset.expiresTime; - oldAsset.hash = newAsset.hash; - oldAsset.status = Status::STATUS_UPDATE; - } - oldAsset.version = newAsset.version; - oldAsset.uri = newAsset.uri; - oldAsset.createTime = newAsset.createTime; - oldAsset.modifyTime = newAsset.modifyTime; - oldAsset.size = newAsset.size; - oldAsset.path = newAsset.path; - } - return; - default: - return; - } -} - int32_t SqliteConnection::Subscribe(const std::string &event, const std::shared_ptr &observer) { if (!isWriter_ || observer == nullptr) { @@ -1280,11 +1128,16 @@ int32_t SqliteConnection::Restore( int SqliteConnection::LoadExtension(const RdbStoreConfig &config, sqlite3 *dbHandle) { - if (config.GetPluginLibs().empty() || dbHandle == nullptr) { + auto pluginLibs = config.GetPluginLibs(); + if (config.GetTokenizer() == CUSTOM_TOKENIZER) { + pluginLibs.push_back("libcustomtokenizer.z.so"); + } + if (pluginLibs.empty() || dbHandle == nullptr) { return E_OK; } - if (config.GetPluginLibs().size() > SqliteUtils::MAX_LOAD_EXTENSION_COUNT) { - LOG_ERROR("failed, size %{public}zu is too large", config.GetPluginLibs().size()); + if (pluginLibs.size() > + SqliteUtils::MAX_LOAD_EXTENSION_COUNT + (config.GetTokenizer() == CUSTOM_TOKENIZER ? 1 : 0)) { + LOG_ERROR("failed, size %{public}zu is too large", pluginLibs.size()); return E_INVALID_ARGS; } int err = sqlite3_db_config( @@ -1293,18 +1146,17 @@ int SqliteConnection::LoadExtension(const RdbStoreConfig &config, sqlite3 *dbHan LOG_ERROR("enable failed, err=%{public}d, errno=%{public}d", err, errno); return SQLiteError::ErrNo(err); } - for (auto &path : config.GetPluginLibs()) { + for (auto &path : pluginLibs) { if (path.empty()) { continue; } - if (access(path.c_str(), F_OK) != 0) { - LOG_ERROR("no file, errno:%{public}d %{public}s", errno, SqliteUtils::Anonymous(path).c_str()); - return E_INVALID_FILE_PATH; - } err = sqlite3_load_extension(dbHandle, path.c_str(), nullptr, nullptr); if (err != SQLITE_OK) { LOG_ERROR("load error. err=%{public}d, errno=%{public}d, errmsg:%{public}s, lib=%{public}s", err, errno, sqlite3_errmsg(dbHandle), SqliteUtils::Anonymous(path).c_str()); + if (access(path.c_str(), F_OK) != 0) { + return E_INVALID_FILE_PATH; + } break; } } @@ -1331,23 +1183,28 @@ int SqliteConnection::SetServiceKey(const RdbStoreConfig &config, int32_t errCod param.isSearchable_ = config.IsSearchable(); param.haMode_ = config.GetHaMode(); param.password_ = {}; - std::vector key; + std::vector> keys; #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) auto [svcErr, service] = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(param); if (svcErr != E_OK) { return errCode; } - svcErr = service->GetPassword(param, key); + svcErr = service->GetPassword(param, keys); if (svcErr != RDB_OK) { return errCode; } #endif - errCode = SetEncryptKey(key, config); - if (errCode == E_OK) { - config.RestoreEncryptKey(key); + for (const auto &key : keys) { + errCode = SetEncryptKey(key, config); + if (errCode == E_OK) { + config.RestoreEncryptKey(key); + break; + } + } + for (auto &key : keys) { + key.assign(key.size(), 0); } - key.assign(key.size(), 0); return errCode; } @@ -1396,7 +1253,7 @@ int SqliteConnection::SqliteNativeBackup(bool isRestore, SlaveStatus &curStatus) (void)SqliteConnection::Delete(slaveConfig.GetPath()); } curStatus = SlaveStatus::BACKUP_INTERRUPT; - Reportor::Report(Reportor::Create(slaveConfig, SQLiteError::ErrNo(rc), "ErrorType: slaveBackupInterrupt")); + Reportor::ReportCorrupted(Reportor::Create(slaveConfig, SQLiteError::ErrNo(rc), "ErrorType: slaveBackup")); } return rc == E_CANCEL ? E_CANCEL : SQLiteError::ErrNo(rc); } @@ -1536,13 +1393,13 @@ std::pair> SqliteConnection::InnerCre return result; } - RdbStoreConfig slaveCfg = connection->GetSlaveRdbStoreConfig(config); errCode = connection->InnerOpen(config); if (errCode != E_OK) { return result; } conn = connection; if (isWrite && config.GetHaMode() != HAMode::SINGLE) { + RdbStoreConfig slaveCfg = connection->GetSlaveRdbStoreConfig(config); auto [err, slaveConn] = connection->CreateSlaveConnection(slaveCfg, SlaveOpenPolicy::OPEN_IF_DB_VALID); if (err == E_OK) { conn->slaveConnection_ = slaveConn; @@ -1559,7 +1416,8 @@ int SqliteConnection::VeritySlaveIntegrity() RdbStoreConfig slaveCfg = GetSlaveRdbStoreConfig(config_); std::map bugInfo = Connection::Collect(slaveCfg); - LOG_INFO("%{public}s", Reportor::FormatBrief(bugInfo, SqliteUtils::Anonymous(slaveCfg.GetName())).c_str()); + LOG_INFO("%{public}s", SqliteUtils::FormatDebugInfoBrief(bugInfo, + SqliteUtils::Anonymous(slaveCfg.GetName())).c_str()); if (SqliteUtils::IsSlaveInterrupted(config_.GetPath())) { return E_SQLITE_CORRUPT; @@ -1638,6 +1496,12 @@ int SqliteConnection::CopyDb(const RdbStoreConfig &config, const std::string &sr return E_SQLITE_CORRUPT; } conn = nullptr; + + auto walFile = srcPath + "-wal"; + if (SqliteUtils::GetFileSize(walFile) != 0) { + LOG_ERROR("Wal file exist."); + return E_SQLITE_CORRUPT; + } SqliteUtils::DeleteFile(srcPath + "-shm"); SqliteUtils::DeleteFile(srcPath + "-wal"); Connection::Delete(config); @@ -1702,5 +1566,10 @@ int32_t SqliteConnection::Restore(const RdbStoreConfig &config, const std::strin Connection::Delete(slaveConfig.GetPath()); return E_OK; } + +bool SqliteConnection::IsInTrans() const +{ + return sqlite3_get_autocommit(dbHandle_) == 0; +} } // namespace NativeRdb } // namespace OHOS \ No newline at end of file diff --git a/relational_store/frameworks/native/rdb/src/sqlite_default_function.cpp b/relational_store/frameworks/native/rdb/src/sqlite_default_function.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b09ebb63f4815c1cf7b812b2776b4b3b72cac780 --- /dev/null +++ b/relational_store/frameworks/native/rdb/src/sqlite_default_function.cpp @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2024 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 "SqliteFunctionRegistry" + +#include "sqlite_default_function.h" + +#include + +#include + +#include "logger.h" +#include "raw_data_parser.h" +#include "sqlite_connection.h" +#include "sqlite_errno.h" +#include "sqlite_utils.h" + +#if !defined(CROSS_PLATFORM) +#include "relational/relational_store_sqlite_ext.h" +#endif + +namespace OHOS { +namespace NativeRdb { +using namespace OHOS::Rdb; + +static constexpr int BACKUP_PAGES_PRE_STEP = 12800; // 1024 * 4 * 12800 == 50m +static constexpr int BACKUP_MAX_RETRY_COUNT = 10000; +static constexpr int BACKUP_MAX_TIME = 10000; +static constexpr int BACKUP_SLEEP_TIME = 1000; + +void SqliteFunctionRegistry::MergeAssets(sqlite3_context *ctx, int argc, sqlite3_value **argv) +{ + // 2 is the number of parameters + if (ctx == nullptr || argc != 2 || argv == nullptr) { + LOG_ERROR("Parameter does not meet restrictions. ctx: %{public}d, argc: %{public}d, argv: %{public}d", + ctx == nullptr, argc, argv == nullptr); + return; + } + std::map assets; + auto data = static_cast(sqlite3_value_blob(argv[0])); + if (data != nullptr) { + int len = sqlite3_value_bytes(argv[0]); + RawDataParser::ParserRawData(data, len, assets); + } + std::map newAssets; + data = static_cast(sqlite3_value_blob(argv[1])); + if (data != nullptr) { + int len = sqlite3_value_bytes(argv[1]); + RawDataParser::ParserRawData(data, len, newAssets); + } + CompAssets(assets, newAssets); + auto blob = RawDataParser::PackageRawData(assets); + sqlite3_result_blob(ctx, blob.data(), blob.size(), SQLITE_TRANSIENT); +} + +void SqliteFunctionRegistry::MergeAsset(sqlite3_context *ctx, int argc, sqlite3_value **argv) +{ + // 2 is the number of parameters + if (ctx == nullptr || argc != 2 || argv == nullptr) { + LOG_ERROR("Parameter does not meet restrictions. ctx: %{public}d, argc: %{public}d, argv: %{public}d", + ctx == nullptr, argc, argv == nullptr); + return; + } + ValueObject::Asset asset; + size_t size = 0; + auto data = static_cast(sqlite3_value_blob(argv[0])); + if (data != nullptr) { + int len = sqlite3_value_bytes(argv[0]); + size = RawDataParser::ParserRawData(data, len, asset); + } + ValueObject::Asset newAsset; + data = static_cast(sqlite3_value_blob(argv[1])); + if (data != nullptr) { + int len = sqlite3_value_bytes(argv[1]); + RawDataParser::ParserRawData(data, len, newAsset); + } + + if (size == 0) { + asset = std::move(newAsset); + if (asset.status != AssetValue::Status::STATUS_DELETE) { + asset.status = AssetValue::Status::STATUS_INSERT; + } + } else if (asset.name == newAsset.name) { + MergeAsset(asset, newAsset); + } else { + LOG_WARN("name change! old:%{public}s, new:%{public}s", SqliteUtils::Anonymous(asset.name).c_str(), + SqliteUtils::Anonymous(newAsset.name).c_str()); + } + auto blob = RawDataParser::PackageRawData(asset); + sqlite3_result_blob(ctx, blob.data(), blob.size(), SQLITE_TRANSIENT); +} + +void SqliteFunctionRegistry::CompAssets( + std::map &assets, std::map &newAssets) +{ + auto oldIt = assets.begin(); + auto newIt = newAssets.begin(); + for (; oldIt != assets.end() && newIt != newAssets.end();) { + if (oldIt->first == newIt->first) { + MergeAsset(oldIt->second, newIt->second); + oldIt++; + newIt = newAssets.erase(newIt); + continue; + } + if (oldIt->first < newIt->first) { + ++oldIt; + continue; + } + newIt++; + } + for (auto &[key, value] : newAssets) { + value.status = ValueObject::Asset::Status::STATUS_INSERT; + assets.insert(std::pair{ key, std::move(value) }); + } +} + +void SqliteFunctionRegistry::MergeAsset(ValueObject::Asset &oldAsset, ValueObject::Asset &newAsset) +{ + using Status = ValueObject::Asset::Status; + if (newAsset.status == Status::STATUS_DELETE) { + oldAsset.status = Status::STATUS_DELETE; + oldAsset.hash = ""; + oldAsset.modifyTime = ""; + oldAsset.size = ""; + return; + } + auto status = static_cast(oldAsset.status); + switch (status) { + case Status::STATUS_UNKNOWN: // fallthrough + case Status::STATUS_NORMAL: // fallthrough + case Status::STATUS_ABNORMAL: // fallthrough + case Status::STATUS_INSERT: // fallthrough + case Status::STATUS_UPDATE: // fallthrough + if (oldAsset.modifyTime != newAsset.modifyTime || oldAsset.size != newAsset.size || + oldAsset.uri != newAsset.uri || oldAsset.path != newAsset.path) { + if (oldAsset.modifyTime != newAsset.modifyTime || oldAsset.size != newAsset.size || + oldAsset.uri == newAsset.uri || oldAsset.path == newAsset.path) { + oldAsset.expiresTime = newAsset.expiresTime; + oldAsset.hash = newAsset.hash; + oldAsset.status = Status::STATUS_UPDATE; + } + oldAsset.version = newAsset.version; + oldAsset.uri = newAsset.uri; + oldAsset.createTime = newAsset.createTime; + oldAsset.modifyTime = newAsset.modifyTime; + oldAsset.size = newAsset.size; + oldAsset.path = newAsset.path; + } + return; + default: + return; + } +} + +void SqliteFunctionRegistry::SqliteResultError(sqlite3_context *ctx, const int &errCode, const std::string &errMsg) +{ + sqlite3_result_error(ctx, errMsg.c_str(), -1); + sqlite3_result_error_code(ctx, errCode); +} + +void SqliteFunctionRegistry::ImportDB(sqlite3_context *ctx, int argc, sqlite3_value **argv) +{ + if (ctx == nullptr || argc != 1 || argv == nullptr) { + LOG_ERROR("Parameter does not meet restrictions. ctx: %{public}d, argc: %{public}d, argv: %{public}d", + ctx == nullptr, argc, argv == nullptr); + SqliteResultError(ctx, SQLITE_ERROR, "invalid param"); + return; + } + std::string path; + auto data = static_cast(sqlite3_value_blob(argv[0])); + if (data != nullptr) { + path = std::string(data, sqlite3_value_bytes(argv[0])); + } + + struct stat fileStat; + if (stat(path.c_str(), &fileStat) != 0) { + if (errno != ENOENT) { + LOG_ERROR( + "File stat error. path: %{public}s, error: %{public}d", SqliteUtils::Anonymous(path).c_str(), errno); + } + SqliteResultError(ctx, SQLITE_CANTOPEN, "backup failed"); + return; + } + + sqlite3 *sourceDbHandle = nullptr; + int32_t errCode = + sqlite3_open_v2(path.c_str(), &sourceDbHandle, SQLITE_OPEN_READONLY | SQLITE_OPEN_FULLMUTEX, nullptr); + + auto source = std::shared_ptr(sourceDbHandle, [&ctx, &errCode, &path](auto *handle) { + sqlite3_close(handle); + if (errCode == SQLITE_OK || errCode == SQLITE_DONE) { + return; + } + LOG_ERROR("Error during backup. path: %{public}s, errCode: %{public}d, errno: %{public}d", + SqliteUtils::Anonymous(path).c_str(), errCode, errno); + SqliteResultError(ctx, errCode, "backup failed"); + }); + if (errCode != SQLITE_OK) { + return; + } + errCode = IntegrityCheck(sourceDbHandle); + if (errCode != SQLITE_OK) { + return; + } + errCode = BackUpDB(sourceDbHandle, sqlite3_context_db_handle(ctx)); + if (errCode != SQLITE_DONE) { + return; + } + sqlite3_result_null(ctx); +} + +int32_t SqliteFunctionRegistry::IntegrityCheck(sqlite3 *dbHandle) +{ + int32_t errCode = SQLITE_OK; + + errCode = sqlite3_exec( + dbHandle, "PRAGMA integrity_check", + [](void *data, int argc, char **argv, char **colNames) -> int { + if (argc > 0) { + std::string result = argv[0] ? argv[0] : ""; + if (result == "ok") { + return 0; + } + } + return 1; + }, + nullptr, nullptr); + if (errCode != SQLITE_OK) { + LOG_ERROR("Integrity check failed. error: %{public}d.", errCode); + return SQLITE_CORRUPT; + } + return SQLITE_OK; +} + +int32_t SqliteFunctionRegistry::BackUpDB(sqlite3 *source, sqlite3 *dest) +{ + sqlite3_backup *pBackup = sqlite3_backup_init(dest, "main", source, "main"); + if (pBackup == nullptr) { + return SQLITE_BUSY; + } + + int retryCount = 0; + int32_t errCode = SQLITE_OK; + + auto startTime = std::chrono::steady_clock::now(); + do { + errCode = sqlite3_backup_step(pBackup, BACKUP_PAGES_PRE_STEP); + if (errCode == SQLITE_BUSY || errCode == SQLITE_LOCKED) { + retryCount++; + } else { + retryCount = 0; + } + + if (retryCount > BACKUP_MAX_RETRY_COUNT) { + sqlite3_backup_finish(pBackup); + return SQLITE_ERROR; + } + + auto now = std::chrono::steady_clock::now(); + auto elapsedTime = now - startTime; + if (std::chrono::duration_cast(elapsedTime).count() > BACKUP_MAX_TIME) { + startTime = now; + sqlite3_sleep(BACKUP_SLEEP_TIME); + } + } while (sqlite3_backup_pagecount(pBackup) != 0 && + (errCode == SQLITE_OK || errCode == SQLITE_BUSY || errCode == SQLITE_LOCKED)); + (void)sqlite3_backup_finish(pBackup); + if (errCode != SQLITE_DONE) { + LOG_ERROR("Backup failed! error:%{public}d.", errCode); + } + return errCode; +} + +} // namespace NativeRdb +} // namespace OHOS \ No newline at end of file diff --git a/relational_store/frameworks/native/rdb/src/sqlite_global_config.cpp b/relational_store/frameworks/native/rdb/src/sqlite_global_config.cpp index 7f1a0b49215e2351bf006fc96bef43ba259aa2ab..665a049c3e86f1354e5c42feb2d1f33c2b85661c 100644 --- a/relational_store/frameworks/native/rdb/src/sqlite_global_config.cpp +++ b/relational_store/frameworks/native/rdb/src/sqlite_global_config.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "logger.h" #include "rdb_errno.h" @@ -32,6 +33,10 @@ namespace OHOS { namespace NativeRdb { using namespace OHOS::Rdb; using namespace std::chrono; + +static std::string g_lastCorruptionMsg; +static std::mutex g_corruptionMutex; + void SqliteGlobalConfig::InitSqliteGlobalConfig() { static SqliteGlobalConfig globalConfig; @@ -45,6 +50,8 @@ SqliteGlobalConfig::SqliteGlobalConfig() sqlite3_config(SQLITE_CONFIG_LOG, &Log, GlobalExpr::CALLBACK_LOG_SWITCH ? reinterpret_cast(1) : NULL); + sqlite3_config(SQLITE_CONFIG_CORRUPTION, &Corruption, nullptr); + sqlite3_soft_heap_limit(GlobalExpr::SOFT_HEAP_LIMIT); sqlite3_initialize(); @@ -54,6 +61,12 @@ SqliteGlobalConfig::~SqliteGlobalConfig() { } +void SqliteGlobalConfig::Corruption(void *arg, const void *msg) +{ + std::lock_guard lockGuard(g_corruptionMutex); + g_lastCorruptionMsg = (const char *)msg; +} + void SqliteGlobalConfig::Log(const void *data, int err, const char *msg) { bool verboseLog = (data != nullptr); @@ -107,14 +120,18 @@ std::string SqliteGlobalConfig::GetDefaultJournalMode() int SqliteGlobalConfig::GetDbPath(const RdbStoreConfig &config, std::string &dbPath) { std::string path; - if (config.GetRoleType() == VISITOR) { + if (config.GetRoleType() == OWNER) { + path = config.GetPath(); + } else if (config.GetRoleType() == VISITOR || config.GetRoleType() == VISITOR_WRITE) { path = config.GetVisitorDir(); } else { - path = config.GetPath(); + LOG_ERROR("not support Role, storeName:%{public}s, role:%{public}d", + SqliteUtils::Anonymous(config.GetName()).c_str(), config.GetRoleType()); + return E_NOT_SUPPORT; } if (config.GetStorageMode() == StorageMode::MODE_MEMORY) { - if (config.GetRoleType() == VISITOR) { + if (config.GetRoleType() != OWNER) { LOG_ERROR("not support MODE_MEMORY, storeName:%{public}s, role:%{public}d", SqliteUtils::Anonymous(config.GetName()).c_str(), config.GetRoleType()); return E_NOT_SUPPORT; @@ -128,5 +145,13 @@ int SqliteGlobalConfig::GetDbPath(const RdbStoreConfig &config, std::string &dbP } return E_OK; } + +std::string SqliteGlobalConfig::GetLastCorruptionMsg() +{ + std::lock_guard lockGuard(g_corruptionMutex); + std::string msg = g_lastCorruptionMsg; + g_lastCorruptionMsg = ""; + return msg; +} } // namespace NativeRdb } // namespace OHOS diff --git a/relational_store/frameworks/native/rdb/src/sqlite_shared_result_set.cpp b/relational_store/frameworks/native/rdb/src/sqlite_shared_result_set.cpp index 51ba993b2bc24811bd03ce6a5d3417c09e32ec53..682e818b2ff74df55ae1f5b6e6ab89f10f5aa15f 100644 --- a/relational_store/frameworks/native/rdb/src/sqlite_shared_result_set.cpp +++ b/relational_store/frameworks/native/rdb/src/sqlite_shared_result_set.cpp @@ -55,7 +55,7 @@ SqliteSharedResultSet::SqliteSharedResultSet( } statement_ = statement; auto countBegin = steady_clock::now(); - rowCount_ = InitRowCount(); + std::tie(lastErr_, rowCount_) = statement->Count(); auto endTime = steady_clock::now(); int64_t totalCost = duration_cast(endTime - start).count(); if (totalCost >= TIME_OUT) { @@ -69,33 +69,9 @@ SqliteSharedResultSet::SqliteSharedResultSet( } } -int SqliteSharedResultSet::InitRowCount() -{ - if (statement_ == nullptr) { - return NO_COUNT; - } - int32_t count = NO_COUNT; - int32_t status = E_OK; - int32_t retry = 0; - do { - status = statement_->Step(); - if (status == E_SQLITE_BUSY || status == E_SQLITE_LOCKED) { - retry++; - usleep(RETRY_INTERVAL); - continue; - } - count++; - } while (status == E_OK || ((status == E_SQLITE_BUSY || status == E_SQLITE_LOCKED) && retry < MAX_RETRY_TIMES)); - if (status != E_NO_MORE_ROWS) { - lastErr_ = status; - count = NO_COUNT; - } - statement_->Reset(); - return count; -} - std::pair, int> SqliteSharedResultSet::PrepareStep() { + std::lock_guard lockGuard(globalMtx_); if (conn_ == nullptr) { LOG_ERROR("Already close."); lastErr_ = E_ALREADY_CLOSED; @@ -183,10 +159,12 @@ int SqliteSharedResultSet::OnGo(int oldPosition, int newPosition) "fail, result set has been closed, ret %{public}d, sql %{public}s", E_ALREADY_CLOSED, qrySql_.c_str()); return E_ALREADY_CLOSED; } - if (GetBlock() == nullptr) { + auto sharedBlock = GetBlock(); + if (sharedBlock == nullptr) { return E_ERROR; } - if ((uint32_t)newPosition < GetBlock()->GetStartPos() || (uint32_t)newPosition >= GetBlock()->GetLastPos() || + + if ((uint32_t)newPosition < sharedBlock->GetStartPos() || (uint32_t)newPosition >= sharedBlock->GetLastPos() || oldPosition == rowCount_) { return FillBlock(newPosition); } @@ -271,6 +249,7 @@ int32_t SqliteSharedResultSet::ExecuteForSharedBlock(AppDataFwk::SharedBlock *bl LOG_ERROR("SetColumnNum %{public}d.", code); return E_ERROR; } + std::lock_guard lockGuard(globalMtx_); errCode = statement->FillBlockInfo(&blockInfo); if (errCode != E_OK) { LOG_ERROR("Fill shared block failed, ret is %{public}d", errCode); diff --git a/relational_store/frameworks/native/rdb/src/sqlite_sql_builder.cpp b/relational_store/frameworks/native/rdb/src/sqlite_sql_builder.cpp index b8cb526b5103b9988b33137d73957e885e976d99..d7eed08bcda6e2487278a672b705342a2ff25446 100644 --- a/relational_store/frameworks/native/rdb/src/sqlite_sql_builder.cpp +++ b/relational_store/frameworks/native/rdb/src/sqlite_sql_builder.cpp @@ -299,13 +299,18 @@ std::string SqliteSqlBuilder::GetSqlArgs(size_t size) } SqliteSqlBuilder::BatchRefSqls SqliteSqlBuilder::GenerateSqls( - const std::string &table, const ValuesBuckets &buckets, int limit) + const std::string &table, const ValuesBuckets &buckets, int limit, ConflictResolution resolution) { auto [fields, values] = buckets.GetFieldsAndValues(); auto columnSize = fields->size(); auto rowSize = buckets.RowSize(); std::vector> args(columnSize * rowSize, nullRef_); - std::string sql = "INSERT OR REPLACE INTO " + table + " ("; + auto conflictClause = SqliteUtils::GetConflictClause(static_cast(resolution)); + if (conflictClause == nullptr) { + return BatchRefSqls(); + } + std::string sql; + sql.append("INSERT").append(conflictClause).append(" INTO ").append(table).append("("); size_t columnIndex = 0; for (auto &field : *fields) { for (size_t row = 0; row < rowSize; ++row) { diff --git a/relational_store/frameworks/native/rdb/src/sqlite_statement.cpp b/relational_store/frameworks/native/rdb/src/sqlite_statement.cpp index f9af140b4ccd9c0b5b7f41192bcac4e37acdf4a0..f2d1f37184f9ef94cc80ba956ef25781d17b379a 100644 --- a/relational_store/frameworks/native/rdb/src/sqlite_statement.cpp +++ b/relational_store/frameworks/native/rdb/src/sqlite_statement.cpp @@ -79,7 +79,12 @@ int SqliteStatement::Prepare(sqlite3 *dbHandle, const std::string &newSql) int ret = SQLiteError::ErrNo(errCode); if (config_ != nullptr && (errCode == SQLITE_CORRUPT || (errCode == SQLITE_NOTADB && config_->GetIter() != 0))) { - Reportor::ReportFault(Reportor::Create(*config_, ret)); + Reportor::ReportCorruptedOnce(Reportor::Create(*config_, ret, + (errCode == SQLITE_CORRUPT ? SqliteGlobalConfig::GetLastCorruptionMsg() : ""))); + } + if (config_ != nullptr) { + Reportor::ReportFault(RdbFaultDbFileEvent(FT_CURD, + (errCode == SQLITE_NOTADB ? E_SQLITE_NOT_DB : ret), *config_, "", true)); } PrintInfoForDbError(ret, newSql); return ret; @@ -254,27 +259,15 @@ int SqliteStatement::Bind(const std::vector &args) std::pair SqliteStatement::Count() { - int32_t count = INVALID_COUNT; - int32_t status = E_OK; - int32_t retry = 0; - do { - status = Step(); - if (status == E_SQLITE_BUSY || status == E_SQLITE_LOCKED) { - retry++; - usleep(RETRY_INTERVAL); - continue; - } - count++; - } while (status == E_OK || ((status == E_SQLITE_BUSY || status == E_SQLITE_LOCKED) && retry < MAX_RETRY_TIMES)); - if (status != E_NO_MORE_ROWS) { - Reset(); - return { status, INVALID_COUNT }; - } - if (retry > 0) { - LOG_WARN("locked, retry=%{public}d, sql=%{public}s", retry, sql_.c_str()); + SharedBlockInfo info(nullptr); + info.isCountAllRows = true; + info.isFull = true; + info.totalRows = -1; + auto errCode = FillBlockInfo(&info); + if (errCode != E_OK) { + return { errCode, INVALID_COUNT }; } - Reset(); - return { E_OK, count }; + return { errCode, info.totalRows }; } int SqliteStatement::Step() @@ -298,7 +291,11 @@ int SqliteStatement::InnerStep() auto errCode = sqlite3_step(stmt_); int ret = SQLiteError::ErrNo(errCode); if (config_ != nullptr && (errCode == SQLITE_CORRUPT || (errCode == SQLITE_NOTADB && config_->GetIter() != 0))) { - Reportor::ReportFault(Reportor::Create(*config_, ret)); + Reportor::ReportCorruptedOnce(Reportor::Create(*config_, ret, + (errCode == SQLITE_CORRUPT ? SqliteGlobalConfig::GetLastCorruptionMsg() : ""))); + } + if (config_ != nullptr && ret != E_OK && !config_->GetBundleName().empty()) { + Reportor::ReportFault(RdbFaultDbFileEvent(FT_CURD, ret, *config_, "", true)); } PrintInfoForDbError(ret, sql_); return ret; @@ -378,7 +375,9 @@ int32_t SqliteStatement::Execute(const std::vector #include #include #include #include -#include -#include #include #include #include #include -#include +#include +#include #include #include "logger.h" #include "rdb_errno.h" #include "rdb_store_config.h" +#include "rdb_time_utils.h" #include "string_utils.h" + namespace OHOS { namespace NativeRdb { using namespace OHOS::Rdb; @@ -45,15 +45,7 @@ constexpr int32_t FILE_PATH_MINI_SIZE = 6; constexpr int32_t AREA_MINI_SIZE = 4; constexpr int32_t AREA_OFFSET_SIZE = 5; constexpr int32_t PRE_OFFSET_SIZE = 1; -constexpr int32_t MIN_ANONYMIZE_LENGTH = 2; -constexpr int32_t MAX_ANONYMIZE_LENGTH = 4; - -constexpr const char *SQL_ARRAY[] = { "AS", "GROUPBY", "GROUP", "BY", "LIMIT", "COUNT", "AVERAGE", "SELECT", "FROM", - "WHERE", "DISTRICT", "INSERT", "INTO", "VALUES", "CREATE", "TABLE", "DATABASE", "VIEW", "INDEX", "TRIGGER", - "PROCEDURE", "IF", "NOT", "EXISTS", "INT", "PRIMARY", "KEY", "TEXT", "BLOB", "REAL", "ASSET", "ASSETS", "NULL", - "INTEGER", "UNLIMITED", "UNION", "UPDATE", "SET", "WHERE", "AND", "OR", "DELETE", "FROM", "DROP", "PRAGMA", - "ALTER", "ADD", "COLUMN", "MODIFY" }; -constexpr const uint32_t SQL_ARRAY_LENGTH = 49; +constexpr int32_t DISPLAY_BYTE = 2; constexpr SqliteUtils::SqlType SqliteUtils::SQL_TYPE_MAP[]; constexpr const char *SqliteUtils::ON_CONFLICT_CLAUSE[]; @@ -73,9 +65,7 @@ int SqliteUtils::GetSqlStatementType(const std::string &sql) /* analyze the sql type through first 3 characters */ std::string prefixSql = StrToUpper(sql.substr(pos, 3)); SqlType type = { prefixSql.c_str(), STATEMENT_OTHER }; - auto comp = [](const SqlType &first, const SqlType &second) { - return strcmp(first.sql, second.sql) < 0; - }; + auto comp = [](const SqlType &first, const SqlType &second) { return strcmp(first.sql, second.sql) < 0; }; auto it = std::lower_bound(SQL_TYPE_MAP, SQL_TYPE_MAP + TYPE_SIZE, type, comp); if (it < SQL_TYPE_MAP + TYPE_SIZE && !comp(type, *it)) { return it->type; @@ -249,95 +239,6 @@ std::string SqliteUtils::Anonymous(const std::string &srcFile) return srcFile.substr(0, pre + PRE_OFFSET_SIZE) + "***" + path + fileName; } -bool SqliteUtils::IsSpecialChar(char c) -{ - return (c == ' ' || c == '.' || c == ',' || c == '!' || c == '?' || c == ':' || c == '(' || c == ')' || c == ';'); -} - -std::vector SqliteUtils::SplitString(const std::string &input) -{ - std::vector result; - std::string word; - for (char c : input) { - if (!SqliteUtils::IsSpecialChar(c)) { - word += c; - } else { - if (!word.empty()) { - result.push_back(word); - word.clear(); - } - result.push_back(std::string(1, c)); - } - } - if (!word.empty()) { - result.push_back(word); - } - return result; -} - -std::string SqliteUtils::ReplaceMultipleSpaces(const std::string &str) -{ - std::string result = str; - if (result.empty()) { - return result; - } - - result.erase(0, result.find_first_not_of(" ")); - result.erase(result.find_last_not_of(" ") + 1); - return std::regex_replace(result, std::regex(" +"), " "); -} - -std::string SqliteUtils::AnonyWord(const std::string &word) -{ - std::string anonyWord = word; - if (word.size() == 1 && std::isdigit(word[0])) { - anonyWord[0] = '*'; - } else if (word.size() >= MIN_ANONYMIZE_LENGTH && word.size() <= MAX_ANONYMIZE_LENGTH) { - anonyWord[0] = '*'; - } else { - int length = anonyWord.length() - 3; - for (int i = 0; i < length; i++) { - anonyWord[i] = '*'; - } - } - return anonyWord; -} - -bool SqliteUtils::Find(const std::string &word, const char *const array[], uint32_t length) -{ - for (uint32_t i = 0; i < length; i++) { - if (word == array[i]) { - return true; - } - } - return false; -} - -std::string SqliteUtils::AnonySqlString(const std::string &input, const char *const array[], uint32_t length) -{ - std::vector words = SqliteUtils::SplitString(input); - std::string result; - for (const std::string &word : words) { - if (word.empty() || word.find_first_of("\r\n") != std::string::npos) { - continue; - } - std::string anonyWord = word; - std::string upperWord = SqliteUtils::StrToUpper(word); - bool found = Find(upperWord, array, length); - if (!found) { - anonyWord = SqliteUtils::AnonyWord(anonyWord); - } - result += anonyWord; - } - return result; -} - -std::string SqliteUtils::AnonySql(const std::string &sql) -{ - std::string replaceSql = SqliteUtils::ReplaceMultipleSpaces(sql); - return SqliteUtils::AnonySqlString(replaceSql, SQL_ARRAY, SQL_ARRAY_LENGTH); -} - ssize_t SqliteUtils::GetFileSize(const std::string &fileName) { struct stat fileStat; @@ -455,5 +356,106 @@ void SqliteUtils::SetSlaveValid(const std::string &dbPath) std::remove((dbPath + SLAVE_INTERRUPT).c_str()); std::remove((dbPath + SLAVE_FAILURE).c_str()); } + +bool SqliteUtils::DeleteDirtyFiles(const std::string &backupFilePath) +{ + auto res = DeleteFile(backupFilePath); + res = DeleteFile(backupFilePath + "-shm") && res; + res = DeleteFile(backupFilePath + "-wal") && res; + return res; +} + +std::pair SqliteUtils::Stat(const std::string &path) +{ + DistributedRdb::RdbDebugInfo info; + struct stat fileStat; + if (stat(path.c_str(), &fileStat) != 0) { + return std::pair{ E_ERROR, info }; + } + info.inode_ = fileStat.st_ino; + info.oldInode_ = 0; + info.atime_.sec_ = fileStat.st_atime; + info.mtime_.sec_ = fileStat.st_mtime; + info.ctime_.sec_ = fileStat.st_ctime; +#if !defined(CROSS_PLATFORM) + info.atime_.nsec_ = fileStat.st_atim.tv_nsec; + info.mtime_.nsec_ = fileStat.st_mtim.tv_nsec; + info.ctime_.nsec_ = fileStat.st_ctim.tv_nsec; +#endif + info.size_ = fileStat.st_size; + info.dev_ = fileStat.st_dev; + info.mode_ = fileStat.st_mode; + info.uid_ = fileStat.st_uid; + info.gid_ = fileStat.st_gid; + return std::pair{ E_OK, info }; +} + +std::string SqliteUtils::FomatConfigChg(const std::string &path, const RdbStoreConfig &config, + const DistributedRdb::RdbSyncerParam &lastParam) +{ + std::stringstream ss; + ss << "CFG_CHG:Store config invalid change, storePath=" << SqliteUtils::Anonymous(path).c_str() + << ",securityLevel:" << lastParam.level_ << "->" << static_cast(config.GetSecurityLevel()) + << ",area:" << lastParam.area_ << "->" << config.GetArea() + << ",isEncrypt:" << lastParam.isEncrypt_ << "->" << config.IsEncrypt(); + return ss.str(); +} + +std::string SqliteUtils::ReadFileHeader(const std::string &filePath) +{ + constexpr int MAX_SIZE = 98; + std::ifstream file(filePath, std::ios::binary); + uint8_t data[MAX_SIZE] = { 0 }; + if (file.is_open()) { + file.read(reinterpret_cast(data), MAX_SIZE); + file.close(); + } + std::stringstream ss; + for (int i = 0; i < MAX_SIZE; i++) { + ss << std::hex << std::setw(DISPLAY_BYTE) << std::setfill('0') << static_cast(data[i]); + } + return "DB_HEAD:" + ss.str(); +} + +std::string SqliteUtils::GetFileStatInfo(const DebugInfo &debugInfo) +{ + std::stringstream oss; + const uint32_t permission = 0777; + oss << " dev:0x" << std::hex << debugInfo.dev_ << " ino:0x" << std::hex << debugInfo.inode_; + if (debugInfo.inode_ != debugInfo.oldInode_ && debugInfo.oldInode_ != 0) { + oss << "<>0x" << std::hex << debugInfo.oldInode_; + } + oss << " mode:0" << std::oct << (debugInfo.mode_ & permission) << " size:" << std::dec << debugInfo.size_ + << " uid:" << std::dec << debugInfo.uid_ << " gid:" << std::dec << debugInfo.gid_ + << " atim:" << RdbTimeUtils::GetTimeWithMs(debugInfo.atime_.sec_, debugInfo.atime_.nsec_) + << " mtim:" << RdbTimeUtils::GetTimeWithMs(debugInfo.mtime_.sec_, debugInfo.mtime_.nsec_) + << " ctim:" << RdbTimeUtils::GetTimeWithMs(debugInfo.ctime_.sec_, debugInfo.ctime_.nsec_); + return oss.str(); +} + +std::string SqliteUtils::FormatDebugInfo(const std::map &debugs, const std::string &header) +{ + if (debugs.empty()) { + return ""; + } + std::string appendix = header; + for (auto &[name, debugInfo] : debugs) { + appendix += "\n" + name + " :" + GetFileStatInfo(debugInfo); + } + return appendix; +} + +std::string SqliteUtils::FormatDebugInfoBrief(const std::map &debugs, const std::string &header) +{ + if (debugs.empty()) { + return ""; + } + std::stringstream oss; + oss << header << ":"; + for (auto &[name, debugInfo] : debugs) { + oss << "<" << name << ",0x" << std::hex << debugInfo.inode_ << "," << std::dec << debugInfo.size_ << ">"; + } + return oss.str(); +} } // namespace NativeRdb } // namespace OHOS diff --git a/relational_store/frameworks/native/rdb/src/step_result_set.cpp b/relational_store/frameworks/native/rdb/src/step_result_set.cpp index def9504bdff2901b1ec3ae036b22dbfb0e92bc20..a5d44afe8110e577aab61229a08ef33abefcff6e 100644 --- a/relational_store/frameworks/native/rdb/src/step_result_set.cpp +++ b/relational_store/frameworks/native/rdb/src/step_result_set.cpp @@ -31,8 +31,8 @@ namespace NativeRdb { using namespace OHOS::Rdb; constexpr int64_t TIME_OUT = 1500; -StepResultSet::StepResultSet(Time start, Conn conn, const std::string &sql, const Values &args, bool safe) - : AbsResultSet(safe), conn_(std::move(conn)), sql_(sql), args_(args) +StepResultSet::StepResultSet(Time start, Conn conn, const std::string &sql, const Values &args, + bool preCount, bool safe) : AbsResultSet(safe), conn_(std::move(conn)), sql_(sql), args_(args) { if (conn_ == nullptr) { isClosed_ = true; @@ -50,7 +50,11 @@ StepResultSet::StepResultSet(Time start, Conn conn, const std::string &sql, cons if (statement == nullptr) { return; } - std::tie(lastErr_, rowCount_) = statement->Count(); + if (preCount) { + std::tie(lastErr_, rowCount_) = statement->Count(); + } else { + isSupportCountRow_ = false; + } if (lastErr_ == E_NOT_SUPPORT && rowCount_ == Statement::INVALID_COUNT) { isSupportCountRow_ = false; lastErr_ = E_OK; @@ -121,12 +125,9 @@ int StepResultSet::PrepareStep() std::pair> StepResultSet::GetColumnNames() { - int errCode = PrepareStep(); - if (errCode != E_OK) { - LOG_ERROR("get all column names Step ret %{public}d", errCode); - return { errCode, {} }; + if (lastErr_ != E_OK) { + return { lastErr_, {} }; } - auto statement = GetStatement(); if (statement == nullptr) { LOG_ERROR("Statement is nullptr."); @@ -179,6 +180,10 @@ int StepResultSet::GoToRow(int position) return E_ALREADY_CLOSED; } + if (lastErr_ != E_OK) { + return lastErr_; + } + if (isSupportCountRow_ && position >= rowCount_) { rowPos_ = (position >= rowCount_ && rowCount_ != 0) ? rowCount_ : rowPos_; LOG_ERROR("position[%{public}d] rowCount[%{public}d] rowPos_[%{public}d]!", position, rowCount_, rowPos_); @@ -213,11 +218,6 @@ int StepResultSet::GoToNextRow() return E_ALREADY_CLOSED; } - int errCode = PrepareStep(); - if (errCode != E_OK) { - return errCode; - } - auto statement = GetStatement(); if (statement == nullptr) { LOG_ERROR("Statement is nullptr."); @@ -225,7 +225,7 @@ int StepResultSet::GoToNextRow() } int retryCount = 0; - errCode = statement->Step(); + auto errCode = statement->Step(); while (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) { // The table is locked, retry diff --git a/relational_store/frameworks/native/rdb/src/trans_db.cpp b/relational_store/frameworks/native/rdb/src/trans_db.cpp index d66c14148480cf22f71fdd3754d03ade64923713..030a45d6e4d07c94b119cc95a783e73f68cb6692 100644 --- a/relational_store/frameworks/native/rdb/src/trans_db.cpp +++ b/relational_store/frameworks/native/rdb/src/trans_db.cpp @@ -85,23 +85,62 @@ std::pair TransDB::BatchInsert(const std::string &table, const Ref LOG_ERROR("empty,table=%{public}s,rows:%{public}zu,max:%{public}d.", table.c_str(), rows.RowSize(), maxArgs_); return { E_INVALID_ARGS, -1 }; } - + if (batchInfo.size() != 1 || batchInfo.front().second.size() != 1) { + auto [fields, values] = rows.GetFieldsAndValues(); + LOG_WARN("too much args, table=%{public}s, rows:%{public}zu, fields:%{public}zu, max:%{public}d.", + table.c_str(), rows.RowSize(), fields != nullptr ? fields->size() : 0, maxArgs_); + } + int64_t changes = 0; for (const auto &[sql, batchArgs] : batchInfo) { auto [errCode, statement] = GetStatement(sql); if (statement == nullptr) { - return { errCode, -1 }; + return { errCode, changes }; } for (const auto &args : batchArgs) { errCode = statement->Execute(args); + if (errCode == E_SQLITE_CONSTRAINT || errCode == E_OK) { + changes += statement->Changes(); + } if (errCode == E_OK) { continue; } LOG_ERROR("failed(0x%{public}x) db:%{public}s table:%{public}s args:%{public}zu", errCode, SqliteUtils::Anonymous(name_).c_str(), table.c_str(), args.size()); - return { errCode, -1 }; + return { errCode, changes }; } } - return { E_OK, int64_t(rows.RowSize()) }; + return { E_OK, changes }; +} + +std::pair TransDB::BatchInsertWithConflictResolution( + const std::string &table, const ValuesBuckets &rows, Resolution resolution) +{ + if (rows.RowSize() == 0) { + return { E_OK, 0 }; + } + + auto sqlArgs = SqliteSqlBuilder::GenerateSqls(table, rows, maxArgs_, resolution); + if (sqlArgs.size() != 1 || sqlArgs.front().second.size() != 1) { + auto [fields, values] = rows.GetFieldsAndValues(); + LOG_ERROR("invalid args, table=%{public}s, rows:%{public}zu, fields:%{public}zu, max:%{public}d.", + table.c_str(), rows.RowSize(), fields != nullptr ? fields->size() : 0, maxArgs_); + return { E_INVALID_ARGS, -1 }; + } + auto &[sql, bindArgs] = sqlArgs.front(); + auto [errCode, statement] = GetStatement(sql); + if (statement == nullptr) { + LOG_ERROR("statement is nullptr, errCode:0x%{public}x, args:%{public}zu, table:%{public}s.", errCode, + bindArgs.size(), table.c_str()); + return { errCode, -1 }; + } + auto args = std::ref(bindArgs.front()); + errCode = statement->Execute(args); + if (errCode != E_OK) { + LOG_ERROR("failed,errCode:%{public}d,table:%{public}s,args:%{public}zu,resolution:%{public}d.", errCode, + table.c_str(), args.get().size(), static_cast(resolution)); + return { errCode, errCode == E_SQLITE_CONSTRAINT ? int64_t(statement->Changes()) : -1 }; + } + return { E_OK, int64_t(statement->Changes()) }; } std::pair TransDB::Update( @@ -142,10 +181,10 @@ std::pair TransDB::Update( } errCode = statement->Execute(totalArgs); - if (errCode != E_OK) { - return { errCode, 0 }; + if (errCode == E_SQLITE_CONSTRAINT || errCode == E_OK) { + return { errCode, int32_t(statement->Changes()) }; } - return { errCode, int32_t(statement->Changes()) }; + return { errCode, 0 }; } int TransDB::Delete(int &deletedRows, const std::string &table, const std::string &whereClause, const Values &args) @@ -184,10 +223,10 @@ std::shared_ptr TransDB::QuerySql(const std::string &sql, co #endif } -std::shared_ptr TransDB::QueryByStep(const std::string &sql, const Values &args) +std::shared_ptr TransDB::QueryByStep(const std::string &sql, const Values &args, bool preCount) { auto start = std::chrono::steady_clock::now(); - return std::make_shared(start, conn_.lock(), sql, args, true); + return std::make_shared(start, conn_.lock(), sql, args, true, true); } std::pair TransDB::Execute(const std::string &sql, const Values &args, int64_t trxId) @@ -196,7 +235,7 @@ std::pair TransDB::Execute(const std::string &sql, const V ValueObject object; int sqlType = SqliteUtils::GetSqlStatementType(sql); if (!SqliteUtils::IsSupportSqlForExecute(sqlType) && !SqliteUtils::IsSpecial(sqlType)) { - LOG_ERROR("Not support the sql:%{public}s", SqliteUtils::AnonySql(sql).c_str()); + LOG_ERROR("Not support the sql:app self can check the SQL"); return { E_INVALID_ARGS, object }; } @@ -207,7 +246,7 @@ std::pair TransDB::Execute(const std::string &sql, const V errCode = statement->Execute(args); if (errCode != E_OK) { - LOG_ERROR("failed,sql:%{public}s, error:0x%{public}x.", SqliteUtils::AnonySql(sql).c_str(), errCode); + LOG_ERROR("failed,app self can check the SQL, error:0x%{public}x.", errCode); return { errCode, object }; } @@ -232,9 +271,9 @@ std::pair TransDB::Execute(const std::string &sql, const V statement->Prepare("PRAGMA schema_version"); auto [err, version] = statement->ExecuteForValue(); if (vSchema_ < static_cast(version)) { - LOG_INFO("db:%{public}s exe DDL schema<%{public}" PRIi64 "->%{public}" PRIi64 "> sql:%{public}s.", - SqliteUtils::Anonymous(name_).c_str(), vSchema_, static_cast(version), - SqliteUtils::AnonySql(sql).c_str()); + LOG_INFO("db:%{public}s exe DDL schema<%{public}" PRIi64 "->%{public}" PRIi64 + "> app self can check the SQL.", + SqliteUtils::Anonymous(name_).c_str(), vSchema_, static_cast(version)); vSchema_ = version; } } diff --git a/relational_store/frameworks/native/rdb/src/transaction_impl.cpp b/relational_store/frameworks/native/rdb/src/transaction_impl.cpp index 3da0bf912096fdc011b4fe8ba6e54d6461838c59..4b260c005e3c705822f7f46cc1530f3c663bfc09 100644 --- a/relational_store/frameworks/native/rdb/src/transaction_impl.cpp +++ b/relational_store/frameworks/native/rdb/src/transaction_impl.cpp @@ -31,12 +31,10 @@ const int32_t TransactionImpl::regCreator_ = Transaction::RegisterCreator(Transa TransactionImpl::TransactionImpl(std::shared_ptr connection, const std::string &name) : name_(name), connection_(std::move(connection)) { - LOG_INFO("constructor name=%{public}s", name_.c_str()); } TransactionImpl::~TransactionImpl() { - LOG_INFO("destructor name=%{public}s", name_.c_str()); CloseInner(); } @@ -66,7 +64,6 @@ std::string TransactionImpl::GetBeginSql(int32_t type) int32_t TransactionImpl::Begin(int32_t type) { - LOG_INFO("type=%{public}d", static_cast(type)); std::lock_guard lock(mutex_); store_ = std::make_shared(connection_, name_); if (store_ == nullptr) { @@ -92,6 +89,16 @@ int32_t TransactionImpl::Begin(int32_t type) return E_OK; } +bool TransactionImpl::IsInTransaction() +{ + std::lock_guard lock(mutex_); + if (connection_ == nullptr) { + LOG_ERROR("connection already closed"); + return false; + } + return connection_->IsInTrans(); +} + int32_t TransactionImpl::Commit() { std::lock_guard lock(mutex_); @@ -172,7 +179,12 @@ std::pair TransactionImpl::Insert(const std::string &table, const LOG_ERROR("transaction already close"); return { E_ALREADY_CLOSED, -1 }; } - return store->Insert(table, row, resolution); + auto [errCode, rows] = store->Insert(table, row, resolution); + if (resolution == Resolution::ON_CONFLICT_ROLLBACK && errCode == E_SQLITE_CONSTRAINT && !IsInTransaction()) { + LOG_WARN("transaction already rollback, start close!"); + CloseInner(); + } + return { errCode, rows }; } std::pair TransactionImpl::BatchInsert(const std::string &table, const Rows &rows) @@ -197,6 +209,22 @@ std::pair TransactionImpl::BatchInsert(const std::string &table, c return store->BatchInsert(table, rows); } +std::pair TransactionImpl::BatchInsertWithConflictResolution( + const std::string &table, const RefRows &rows, Resolution resolution) +{ + auto store = GetStore(); + if (store == nullptr) { + LOG_ERROR("transaction already close"); + return { E_ALREADY_CLOSED, -1 }; + } + auto [errCode, changes] = store->BatchInsertWithConflictResolution(table, rows, resolution); + if (resolution == Resolution::ON_CONFLICT_ROLLBACK && errCode == E_SQLITE_CONSTRAINT && !IsInTransaction()) { + LOG_WARN("transaction already rollback, start close!"); + CloseInner(); + } + return { errCode, changes }; +} + std::pair TransactionImpl::Update( const std::string &table, const Row &row, const std::string &where, const Values &args, Resolution resolution) { @@ -205,7 +233,12 @@ std::pair TransactionImpl::Update( LOG_ERROR("transaction already close"); return { E_ALREADY_CLOSED, -1 }; } - return store->Update(table, row, where, args, resolution); + auto [errCode, rows] = store->Update(table, row, where, args, resolution); + if (resolution == Resolution::ON_CONFLICT_ROLLBACK && errCode == E_SQLITE_CONSTRAINT && !IsInTransaction()) { + LOG_WARN("transaction already rollback, start close!"); + CloseInner(); + } + return { errCode, rows }; } std::pair TransactionImpl::Update( @@ -216,8 +249,13 @@ std::pair TransactionImpl::Update( LOG_ERROR("transaction already close"); return { E_ALREADY_CLOSED, -1 }; } - return store->Update( + auto [errCode, rows] = store->Update( predicates.GetTableName(), row, predicates.GetWhereClause(), predicates.GetBindArgs(), resolution); + if (resolution == Resolution::ON_CONFLICT_ROLLBACK && errCode == E_SQLITE_CONSTRAINT && !IsInTransaction()) { + LOG_WARN("transaction already rollback, start close!"); + CloseInner(); + } + return { errCode, rows }; } std::pair TransactionImpl::Delete( @@ -251,7 +289,7 @@ void TransactionImpl::AddResultSet(std::weak_ptr resultSet) resultSets_.push_back(std::move(resultSet)); } -std::shared_ptr TransactionImpl::QueryByStep(const std::string &sql, const Values &args) +std::shared_ptr TransactionImpl::QueryByStep(const std::string &sql, const Values &args, bool preCount) { auto store = GetStore(); if (store == nullptr) { @@ -265,7 +303,8 @@ std::shared_ptr TransactionImpl::QueryByStep(const std::string &sql, return resultSet; } -std::shared_ptr TransactionImpl::QueryByStep(const AbsRdbPredicates &predicates, const Fields &columns) +std::shared_ptr TransactionImpl::QueryByStep(const AbsRdbPredicates &predicates, + const Fields &columns, bool preCount) { auto store = GetStore(); if (store == nullptr) { diff --git a/relational_store/frameworks/native/rdb_data_share_adapter/src/rdb_utils.cpp b/relational_store/frameworks/native/rdb_data_share_adapter/src/rdb_utils.cpp index 4439bfb03100ff68f8a9301d7a1ac3f5a5fa3b59..adec2f5a97f0b1192f2b3011430b973d83842424 100644 --- a/relational_store/frameworks/native/rdb_data_share_adapter/src/rdb_utils.cpp +++ b/relational_store/frameworks/native/rdb_data_share_adapter/src/rdb_utils.cpp @@ -90,6 +90,11 @@ void RdbUtils::NotEqualTo(const OperationItem &item, RdbPredicates &predicates) void RdbUtils::GreaterThan(const OperationItem &item, RdbPredicates &predicates) { + // 2 is the number of argument item.singleParams + if (item.singleParams.size() < 2) { + LOG_ERROR("SingleParams is missing elements, size is %{public}zu", item.singleParams.size()); + return; + } predicates.GreaterThan(item.GetSingle(0), ToValueObject(item.singleParams[1])); } diff --git a/relational_store/interfaces/inner_api/cloud_data/BUILD.gn b/relational_store/interfaces/inner_api/cloud_data/BUILD.gn index 716079d7873016e89bb89b4df1cf1d0c0e6340de..55203a32dce1ff7d089e0df7ec5660e7c5cb430f 100644 --- a/relational_store/interfaces/inner_api/cloud_data/BUILD.gn +++ b/relational_store/interfaces/inner_api/cloud_data/BUILD.gn @@ -18,7 +18,11 @@ config("cloud_public_config") { "${distributeddata_base_path}/relational_store/*", ] - include_dirs = [ "include" ] + include_dirs = [ + "include", + "${relational_store_innerapi_path}/common_type/include", + "${relational_store_innerapi_path}/rdb/include", + ] } ohos_static_library("cloud_data_inner") { diff --git a/relational_store/interfaces/inner_api/gdb/BUILD.gn b/relational_store/interfaces/inner_api/gdb/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..ec43b43e3d4ce1615a8ed444c74f79e3436a2bc6 --- /dev/null +++ b/relational_store/interfaces/inner_api/gdb/BUILD.gn @@ -0,0 +1,79 @@ +# Copyright (c) 2024 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. + +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/relational_store/relational_store.gni") + +config("common_public_config") { + visibility = [ ":*" ] +} + +ohos_shared_library("framework_graphstore") { + configs = [ ":common_public_config" ] + sanitize = { + boundary_sanitize = true + ubsan = true + cfi = true + cfi_cross_dso = true + debug = false + } + include_dirs = [ + "${relational_store_common_path}/include", + "${relational_store_native_path}/gdb/adapter/include", + "${relational_store_native_path}/gdb/include", + "${relational_store_native_path}/rdb/include", + "${relational_store_innerapi_path}/gdb/include", + "${relational_store_innerapi_path}/rdb/include", + ] + sources = [ + "${relational_store_native_path}/gdb/adapter/src/grd_adapter.cpp", + "${relational_store_native_path}/gdb/adapter/src/grd_adapter_manager.cpp", + "${relational_store_native_path}/gdb/src/connection.cpp", + "${relational_store_native_path}/gdb/src/connection_pool.cpp", + "${relational_store_native_path}/gdb/src/db_helper.cpp", + "${relational_store_native_path}/gdb/src/db_store_impl.cpp", + "${relational_store_native_path}/gdb/src/db_store_manager.cpp", + "${relational_store_native_path}/gdb/src/edge.cpp", + "${relational_store_native_path}/gdb/src/full_result.cpp", + "${relational_store_native_path}/gdb/src/gdb_utils.cpp", + "${relational_store_native_path}/gdb/src/graph_connection.cpp", + "${relational_store_native_path}/gdb/src/graph_statement.cpp", + "${relational_store_native_path}/gdb/src/path.cpp", + "${relational_store_native_path}/gdb/src/path_segment.cpp", + "${relational_store_native_path}/gdb/src/store_config.cpp", + "${relational_store_native_path}/gdb/src/trans_db.cpp", + "${relational_store_native_path}/gdb/src/transaction.cpp", + "${relational_store_native_path}/gdb/src/transaction_impl.cpp", + "${relational_store_native_path}/gdb/src/vertex.cpp", + "${relational_store_native_path}/rdb/src/rdb_security_manager.cpp", + "${relational_store_native_path}/rdb/src/rdb_store_config.cpp", + "${relational_store_native_path}/rdb/src/rdb_time_utils.cpp", + "${relational_store_native_path}/rdb/src/sqlite_utils.cpp", + "${relational_store_native_path}/rdb/src/string_utils.cpp", + ] + deps = [] + external_deps = [ + "c_utils:utils", + "file_api:securitylabel", + "hilog:libhilog", + "hisysevent:libhisysevent", + "hitrace:hitrace_meter", + "huks:libhukssdk", + "json:nlohmann_json_static", + ] + if (arkdata_db_core_is_exists) { + defines = [ "ARKDATA_DB_CORE_IS_EXISTS" ] + } + subsystem_name = "distributeddatamgr" + part_name = "relational_store" +} diff --git a/relational_store/interfaces/inner_api/gdb/include/gdb_helper.h b/relational_store/interfaces/inner_api/gdb/include/gdb_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..8f0d71b70e006a28b3e44f26f948dfb83235fed7 --- /dev/null +++ b/relational_store/interfaces/inner_api/gdb/include/gdb_helper.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 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_INTERFACE_GDB_DB_HELPER_H +#define OHOS_DISTRIBUTED_DATA_INTERFACE_GDB_DB_HELPER_H +#include + +#include "gdb_store_config.h" +#include "gdb_store.h" +#include "rdb_visibility.h" + +namespace OHOS::DistributedDataAip { +class API_EXPORT GDBHelper { +public: + API_EXPORT static std::shared_ptr GetDBStore(const StoreConfig &config, int &errCode); + API_EXPORT static int DeleteDBStore(const StoreConfig &config); +}; +} // namespace OHOS::DistributedDataAip +#endif //OHOS_DISTRIBUTED_DATA_INTERFACE_GDB_DB_HELPER_H diff --git a/relational_store/interfaces/inner_api/gdb/include/gdb_store.h b/relational_store/interfaces/inner_api/gdb/include/gdb_store.h new file mode 100644 index 0000000000000000000000000000000000000000..4d3b3c8f3f96a64e37a8cb7991c8b07d40affef4 --- /dev/null +++ b/relational_store/interfaces/inner_api/gdb/include/gdb_store.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 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_INTERFACE_GDB_DB_STORE_H +#define OHOS_DISTRIBUTED_DATA_INTERFACE_GDB_DB_STORE_H +#include "rdb_visibility.h" +#include "result.h" +#include "transaction.h" + +namespace OHOS::DistributedDataAip { +class API_EXPORT DBStore { +public: + API_EXPORT virtual std::pair> QueryGql(const std::string &gql) = 0; + API_EXPORT virtual std::pair> ExecuteGql(const std::string &gql) = 0; + API_EXPORT virtual std::pair> CreateTransaction() = 0; + API_EXPORT virtual int32_t Close() = 0; + + virtual ~DBStore() = default; +}; +} // namespace OHOS::DistributedDataAip +#endif //OHOS_DISTRIBUTED_DATA_INTERFACE_GDB_DB_STORE_H diff --git a/relational_store/interfaces/inner_api/gdb/include/gdb_store_config.h b/relational_store/interfaces/inner_api/gdb/include/gdb_store_config.h new file mode 100644 index 0000000000000000000000000000000000000000..362f8e0b4bf54531fa5c71832602508f02272c36 --- /dev/null +++ b/relational_store/interfaces/inner_api/gdb/include/gdb_store_config.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2024 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_INTERFACE_GDB_STORE_CONFIG_H +#define OHOS_DISTRIBUTED_DATA_INTERFACE_GDB_STORE_CONFIG_H + +#include +#include +#include + +#include "rdb_store_config.h" +#include "rdb_visibility.h" + +namespace OHOS::DistributedDataAip { +enum SecurityLevel : int32_t { + S1 = 1, + S2, + S3, + S4, + LAST, +}; + +enum class DBType : int { + /** + * The graph database. + */ + DB_GRAPH, + + /** + * The vector database. + */ + DB_VECTOR, + /** + * The BUTT of database. + */ + DB_BUTT +}; + +class API_EXPORT StoreConfig { +public: + API_EXPORT StoreConfig() = default; + API_EXPORT ~StoreConfig(); + API_EXPORT StoreConfig(std::string name, std::string path, DBType dbType = DBType::DB_GRAPH, bool isEncrypt = false, + const std::vector &encryptKey = std::vector()); + API_EXPORT void SetName(std::string name); + API_EXPORT void SetPath(std::string path); + API_EXPORT void SetDbType(DBType dbType); + API_EXPORT void SetEncryptStatus(bool status); + API_EXPORT void SetSecurityLevel(int32_t securityLevel); + API_EXPORT bool IsEncrypt() const; + API_EXPORT std::string GetJson() const; + API_EXPORT std::string GetFullPath() const; + API_EXPORT std::string GetPath() const; + API_EXPORT std::string GetName() const; + API_EXPORT int32_t GetSecurityLevel() const; + API_EXPORT DBType GetDbType() const; + API_EXPORT void SetIter(int32_t iter) const; + API_EXPORT int32_t GetIter() const; + API_EXPORT int GetWriteTime() const; + API_EXPORT void SetWriteTime(int timeout); + API_EXPORT int GetReadTime() const; + API_EXPORT void SetReadTime(int timeout); + API_EXPORT int GetReadConSize() const; + API_EXPORT void SetReadConSize(int readConSize); + API_EXPORT std::vector GetEncryptKey() const; + API_EXPORT int SetBundleName(const std::string &bundleName); + API_EXPORT std::string GetBundleName() const; + void GenerateEncryptedKey() const; + std::vector GetNewEncryptKey() const; + void ChangeEncryptKey() const; + +private: + std::string name_; + std::string path_; + std::string bundleName_; + DBType dbType_ = DBType::DB_GRAPH; + bool isEncrypt_ = false; + mutable std::vector encryptKey_{}; + mutable std::vector newEncryptKey_{}; + int32_t pageSize_ = 4; + int32_t defaultIsolationLevel_ = 3; // serialization + mutable int32_t iter_ = 0; + int32_t writeTimeout_ = 2; // seconds + int32_t readTimeout_ = 1; // seconds + int32_t readConSize_ = 4; + int32_t securityLevel_ = SecurityLevel::S1; + + [[maybe_unused]] int32_t redoFlushByTrx_ = 0; + [[maybe_unused]] int32_t redoPubBufSize_ = 1024; + [[maybe_unused]] int32_t maxConnNum_ = 100; + [[maybe_unused]] int32_t bufferPoolSize_ = 1024; + [[maybe_unused]] int32_t crcCheckEnable_ = 1; + std::string bufferPoolPolicy_ = "BUF_PRIORITY_TABLE"; + + [[maybe_unused]] int32_t sharedModeEnable_ = 0; + [[maybe_unused]] int32_t MetaInfoBak_ = 0; + [[maybe_unused]] int32_t dbFileSize_ = 128 * 1024 * 1024; + + static constexpr int MAX_TIMEOUT = 300; // seconds + static constexpr int MIN_TIMEOUT = 1; // seconds + void ClearEncryptKey(); +}; +} // namespace OHOS::DistributedDataAip +#endif //OHOS_DISTRIBUTED_DATA_INTERFACE_GDB_STORE_CONFIG_H \ No newline at end of file diff --git a/relational_store/interfaces/inner_api/gdb/include/result.h b/relational_store/interfaces/inner_api/gdb/include/result.h new file mode 100644 index 0000000000000000000000000000000000000000..4873c278eec9b1deefa250296cfd7e6d3c64bd98 --- /dev/null +++ b/relational_store/interfaces/inner_api/gdb/include/result.h @@ -0,0 +1,40 @@ +/* +* Copyright (c) 2024 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_INTERFACE_GDB_RESULT_H +#define OHOS_DISTRIBUTED_DATA_INTERFACE_GDB_RESULT_H + +#include +#include +#include +#include +#include +#include + +#include "edge.h" +#include "path.h" +#include "vertex.h" +#include "rdb_visibility.h" + +namespace OHOS::DistributedDataAip { +using GraphValue = std::variant, + std::shared_ptr, std::shared_ptr, std::shared_ptr, std::nullptr_t>; + +class API_EXPORT Result { +public: + API_EXPORT virtual std::vector> GetAllData() const = 0; +}; +} // namespace OHOS::DistributedDataAip +#endif //OHOS_DISTRIBUTED_DATA_INTERFACE_GDB_RESULT_H \ No newline at end of file diff --git a/relational_store/interfaces/inner_api/gdb/include/transaction.h b/relational_store/interfaces/inner_api/gdb/include/transaction.h new file mode 100644 index 0000000000000000000000000000000000000000..01a6775320ae989a76b34ee8d2da41f264a1b515 --- /dev/null +++ b/relational_store/interfaces/inner_api/gdb/include/transaction.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025 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 ARKDATA_INTELLIGENCE_PLATFORM_TRANSACTION_H +#define ARKDATA_INTELLIGENCE_PLATFORM_TRANSACTION_H + +#include +#include +#include +#include + +#include "gdb_store_config.h" +#include "result.h" + +namespace OHOS::DistributedDataAip { +class Connection; +class Transaction { +public: + using Creator = std::function>(std::shared_ptr conn)>; + + static std::pair> Create(std::shared_ptr conn); + static int32_t RegisterCreator(Creator creator); + + virtual ~Transaction() = default; + + virtual int32_t Commit() = 0; + virtual int32_t Rollback() = 0; + virtual int32_t Close() = 0; + + /** + * @brief Queries data in the database based on GQL statement. + * + * @param gql Indicates the GQL statement to execute. + */ + virtual std::pair> Query(const std::string &gql) = 0; + + /** + * @brief Executes an GQL statement. + * + * @param gql Indicates the GQL statement to execute. + */ + virtual std::pair> Execute(const std::string &gql) = 0; + +private: + static inline Creator creator_; +}; +} // namespace OHOS::DistributedDataAip +#endif diff --git a/relational_store/interfaces/inner_api/rdb/BUILD.gn b/relational_store/interfaces/inner_api/rdb/BUILD.gn index cd53a4a93a285d854a04a7903f09837c24d72345..13e7d14538df3103e5480fbb18f93b46deb079f6 100644 --- a/relational_store/interfaces/inner_api/rdb/BUILD.gn +++ b/relational_store/interfaces/inner_api/rdb/BUILD.gn @@ -22,6 +22,7 @@ base_sources = [ "${relational_store_native_path}/rdb/src/cache_result_set.cpp", "${relational_store_native_path}/rdb/src/connection.cpp", "${relational_store_native_path}/rdb/src/connection_pool.cpp", + "${relational_store_native_path}/rdb/src/delay_notify.cpp", "${relational_store_native_path}/rdb/src/raw_data_parser.cpp", "${relational_store_native_path}/rdb/src/rdb_helper.cpp", "${relational_store_native_path}/rdb/src/rdb_local_db_observer.cpp", @@ -34,6 +35,7 @@ base_sources = [ "${relational_store_native_path}/rdb/src/rdb_store_impl.cpp", "${relational_store_native_path}/rdb/src/rdb_store_manager.cpp", "${relational_store_native_path}/rdb/src/sqlite_connection.cpp", + "${relational_store_native_path}/rdb/src/sqlite_default_function.cpp", "${relational_store_native_path}/rdb/src/sqlite_global_config.cpp", "${relational_store_native_path}/rdb/src/sqlite_sql_builder.cpp", "${relational_store_native_path}/rdb/src/sqlite_statement.cpp", @@ -52,6 +54,7 @@ if (!is_ohos) { base_sources += [ "${relational_store_mock_path}/frameworks/native/rdb/mock.cpp", "${relational_store_native_path}/rdb/mock/src/rdb_fault_hiview_reporter.cpp", + "${relational_store_native_path}/rdb/mock/src/rdb_time_utils.cpp", ] } @@ -59,6 +62,7 @@ if (is_ohos && !build_ohos_sdk) { config("native_rdb_config") { visibility = [ ":*" ] + cflags = [ "-Wno-c99-designator" ] include_dirs = [ "include", "${relational_store_common_path}/include", @@ -73,16 +77,11 @@ if (is_ohos && !build_ohos_sdk) { "RDB_TRACE_ON", ] - if (relational_store_rdb_support_icu) { - include_dirs += [ - "//third_party/icu/icu4c/source", - "//third_party/icu/icu4c/source/i18n", - "//third_party/icu/icu4c/source/common", - ] - defines += [ "RDB_SUPPORT_ICU" ] - } - defines += [ "SQLITE_DISTRIBUTE_RELATIONAL" ] + if (!defined(global_parts_info) || + defined(global_parts_info.distributeddatamgr_arkdata_database_core)) { + defines += [ "ARKDATA_DATABASE_CORE_ENABLE" ] + } include_dirs += [ "${kvstore_path}/common", "${kvstore_interface_path}", @@ -102,11 +101,6 @@ if (is_ohos && !build_ohos_sdk) { ] } - base_deps = [ - "//third_party/icu/icu4c:shared_icui18n", - "//third_party/icu/icu4c:shared_icuuc", - ] - ohos_shared_library("native_rdb") { branch_protector_ret = "pac_ret" sanitize = { @@ -122,16 +116,12 @@ if (is_ohos && !build_ohos_sdk) { configs = [ ":native_rdb_config" ] - deps = base_deps - - deps += [ "//third_party/sqlite:sqlite" ] ldflags = [ "-Wl,--exclude-libs,ALL" ] cflags_cc = [ "-fvisibility=hidden" ] sources += [ "${relational_store_native_path}/dfx/src/rdb_fault_hiview_reporter.cpp", "${relational_store_native_path}/dfx/src/rdb_radar_reporter.cpp", "${relational_store_native_path}/rdb/src/abs_shared_result_set.cpp", - "${relational_store_native_path}/rdb/src/delay_notify.cpp", "${relational_store_native_path}/rdb/src/grd_api_manager.cpp", "${relational_store_native_path}/rdb/src/rd_connection.cpp", "${relational_store_native_path}/rdb/src/rd_statement.cpp", @@ -139,6 +129,7 @@ if (is_ohos && !build_ohos_sdk) { "${relational_store_native_path}/rdb/src/rdb_manager_impl.cpp", "${relational_store_native_path}/rdb/src/rdb_notifier_stub.cpp", "${relational_store_native_path}/rdb/src/rdb_service_proxy.cpp", + "${relational_store_native_path}/rdb/src/rdb_time_utils.cpp", "${relational_store_native_path}/rdb/src/rdb_types_util.cpp", "${relational_store_native_path}/rdb/src/result_set_proxy.cpp", "${relational_store_native_path}/rdb/src/security_policy.cpp", @@ -164,14 +155,18 @@ if (is_ohos && !build_ohos_sdk) { "hisysevent:libhisysevent", "hitrace:hitrace_meter", "huks:libhukssdk", - "icu:shared_icui18n", - "icu:shared_icuuc", "ipc:ipc_core", "kv_store:database_utils", "kv_store:distributeddb", "samgr:samgr_proxy", + "sqlite:sqlite", + "sqlite:sqliteicu", ] + if (arkdata_db_core_is_exists) { + defines = [ "ARKDATA_DB_CORE_IS_EXISTS" ] + } + public_configs = [ ":native_rdb_public_config" ] innerapi_tags = [ "platformsdk", @@ -194,16 +189,12 @@ if (is_ohos && !build_ohos_sdk) { configs = [ ":native_rdb_config" ] - deps = base_deps - - deps += [ "//third_party/sqlite:sqlite" ] ldflags = [ "-Wl,--exclude-libs,ALL" ] sources += [ "${relational_store_native_path}/dfx/src/rdb_fault_hiview_reporter.cpp", "${relational_store_native_path}/dfx/src/rdb_radar_reporter.cpp", "${relational_store_native_path}/rdb/src/abs_shared_result_set.cpp", - "${relational_store_native_path}/rdb/src/delay_notify.cpp", "${relational_store_native_path}/rdb/src/grd_api_manager.cpp", "${relational_store_native_path}/rdb/src/rd_connection.cpp", "${relational_store_native_path}/rdb/src/rd_statement.cpp", @@ -211,6 +202,7 @@ if (is_ohos && !build_ohos_sdk) { "${relational_store_native_path}/rdb/src/rdb_manager_impl.cpp", "${relational_store_native_path}/rdb/src/rdb_notifier_stub.cpp", "${relational_store_native_path}/rdb/src/rdb_service_proxy.cpp", + "${relational_store_native_path}/rdb/src/rdb_time_utils.cpp", "${relational_store_native_path}/rdb/src/rdb_types_util.cpp", "${relational_store_native_path}/rdb/src/result_set_proxy.cpp", "${relational_store_native_path}/rdb/src/security_policy.cpp", @@ -240,6 +232,8 @@ if (is_ohos && !build_ohos_sdk) { "kv_store:database_utils", "kv_store:distributeddb", "samgr:samgr_proxy", + "sqlite:sqlite", + "sqlite:sqliteicu", ] public_configs = [ ":native_rdb_public_config" ] @@ -271,15 +265,6 @@ if (is_ohos && !build_ohos_sdk) { "SQLITE_HAS_CODEC", ] - if (relational_store_rdb_support_icu) { - include_dirs += [ - "//third_party/icu/icu4c/source", - "//third_party/icu/icu4c/source/i18n", - "//third_party/icu/icu4c/source/common", - ] - defines += [ "RDB_SUPPORT_ICU" ] - } - defines += [ "WINDOWS_PLATFORM", "CROSS_PLATFORM", @@ -303,25 +288,19 @@ if (is_ohos && !build_ohos_sdk) { ] } - base_deps = [ - "//third_party/icu/icu4c:shared_icui18n", - "//third_party/icu/icu4c:shared_icuuc", - ] - ohos_shared_library("native_rdb") { part_name = "relational_store" sources = base_sources configs = [ ":native_rdb_config" ] - deps = base_deps - sources += [ + "${relational_store_mock_path}/frameworks/native/win32/dlfcn.cpp", "${relational_store_native_path}/rdb/mock/src/rdb_radar_reporter.cpp", "${relational_store_native_path}/rdb/mock/src/task_executor.cpp", ] - deps += [ + deps = [ "${relational_store_innerapi_path}/appdatafwk:relational_common_base", "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog_windows", "//third_party/sqlite:sqlite_sdk", @@ -339,14 +318,12 @@ if (is_ohos && !build_ohos_sdk) { configs = [ ":native_rdb_config" ] - deps = base_deps - sources += [ "${relational_store_native_path}/rdb/mock/src/rdb_radar_reporter.cpp", "${relational_store_native_path}/rdb/mock/src/task_executor.cpp", ] - deps += [ + deps = [ "${relational_store_innerapi_path}/appdatafwk:relational_common_base", "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog_windows", "//third_party/sqlite:sqlite_sdk", @@ -380,15 +357,6 @@ if (is_ohos && !build_ohos_sdk) { "SQLITE_HAS_CODEC", ] - if (relational_store_rdb_support_icu) { - include_dirs += [ - "//third_party/icu/icu4c/source", - "//third_party/icu/icu4c/source/i18n", - "//third_party/icu/icu4c/source/common", - ] - defines += [ "RDB_SUPPORT_ICU" ] - } - defines += [ "MAC_PLATFORM", "CROSS_PLATFORM", @@ -410,24 +378,18 @@ if (is_ohos && !build_ohos_sdk) { ] } - base_deps = [ - "//third_party/icu/icu4c:shared_icui18n", - "//third_party/icu/icu4c:shared_icuuc", - ] - ohos_shared_library("native_rdb") { part_name = "relational_store" sources = base_sources configs = [ ":native_rdb_config" ] - deps = base_deps - sources += [ "${relational_store_native_path}/rdb/mock/src/rdb_radar_reporter.cpp", "${relational_store_native_path}/rdb/mock/src/task_executor.cpp", ] - deps += [ + + deps = [ "${relational_store_innerapi_path}/appdatafwk:relational_common_base", "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog_mac", "//third_party/sqlite:sqlite_sdk", @@ -444,13 +406,12 @@ if (is_ohos && !build_ohos_sdk) { configs = [ ":native_rdb_config" ] - deps = base_deps - sources += [ "${relational_store_native_path}/rdb/mock/src/rdb_radar_reporter.cpp", "${relational_store_native_path}/rdb/mock/src/task_executor.cpp", ] - deps += [ + + deps = [ "${relational_store_innerapi_path}/appdatafwk:relational_common_base", "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog_mac", "//third_party/sqlite:sqlite_sdk", @@ -466,6 +427,7 @@ if (is_ohos && !build_ohos_sdk) { config("native_rdb_config") { visibility = [ ":*" ] + cflags = [ "-Wno-c99-designator" ] include_dirs = [ "${relational_store_mock_path}/frameworks/native/rdb", "${distributedfile_path}/mod_securitylabel", @@ -482,15 +444,6 @@ if (is_ohos && !build_ohos_sdk) { "RELATIONAL_STORE", "SQLITE_HAS_CODEC", ] - - if (relational_store_rdb_support_icu) { - include_dirs += [ - "//third_party/icu/icu4c/source", - "//third_party/icu/icu4c/source/i18n", - "//third_party/icu/icu4c/source/common", - ] - defines += [ "RDB_SUPPORT_ICU" ] - } } config("native_rdb_public_config") { @@ -508,10 +461,11 @@ if (is_ohos && !build_ohos_sdk) { ] } - base_deps = [ "${plugins_path}/libs/icu:icu_android" ] - ohos_source_set("native_rdb") { - defines = [ "ANDROID_PLATFORM" ] + defines = [ + "ANDROID_PLATFORM", + "CROSS_PLATFORM", + ] part_name = "relational_store" @@ -519,14 +473,12 @@ if (is_ohos && !build_ohos_sdk) { configs = [ ":native_rdb_config" ] - deps = base_deps - sources += [ "${relational_store_native_path}/rdb/mock/src/rdb_radar_reporter.cpp", "${relational_store_native_path}/rdb/mock/src/task_executor.cpp", "${relational_store_native_path}/rdb/src/security_policy.cpp", ] - deps += [ + deps = [ "${relational_store_innerapi_path}/appdatafwk:relational_common_base", "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog_android", "//third_party/sqlite:sqlite_static", @@ -556,15 +508,6 @@ if (is_ohos && !build_ohos_sdk) { "RELATIONAL_STORE", "SQLITE_HAS_CODEC", ] - - if (relational_store_rdb_support_icu) { - include_dirs += [ - "//third_party/icu/icu4c/source", - "//third_party/icu/icu4c/source/i18n", - "//third_party/icu/icu4c/source/common", - ] - defines += [ "RDB_SUPPORT_ICU" ] - } } config("native_rdb_public_config") { @@ -581,8 +524,6 @@ if (is_ohos && !build_ohos_sdk) { ] } - base_deps = [ "${plugins_path}/libs/icu:icu_ios" ] - ohos_source_set("native_rdb") { defines = [ "IOS_PLATFORM", @@ -594,14 +535,12 @@ if (is_ohos && !build_ohos_sdk) { configs = [ ":native_rdb_config" ] - deps = base_deps - sources += [ "${relational_store_native_path}/rdb/mock/src/rdb_radar_reporter.cpp", "${relational_store_native_path}/rdb/mock/src/task_executor.cpp", "${relational_store_native_path}/rdb/src/security_policy.cpp", ] - deps += [ + deps = [ "${relational_store_innerapi_path}/appdatafwk:relational_common_base", "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog_ios", "//third_party/sqlite:sqlite_static", diff --git a/relational_store/interfaces/inner_api/rdb/include/abs_result_set.h b/relational_store/interfaces/inner_api/rdb/include/abs_result_set.h index 4abff006cf27d27bfbc0141bffdbaaadb69b9842..3a43896bbe072ebd5db1341af75ec489515c2280 100644 --- a/relational_store/interfaces/inner_api/rdb/include/abs_result_set.h +++ b/relational_store/interfaces/inner_api/rdb/include/abs_result_set.h @@ -295,7 +295,6 @@ public: * Calling this method on the result set will release all of its resources and makes it ineffective. */ API_EXPORT int Close() override; - protected: /** * @brief Constructor. diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_errno.h b/relational_store/interfaces/inner_api/rdb/include/rdb_errno.h index fe0a7b823e1c484716c5ad3bc763d4a0f6c95cd7..a7a220bfb587d1a889ce558859c7bbe78469ec39 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_errno.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_errno.h @@ -410,10 +410,65 @@ static constexpr int E_CANCEL = (E_BASE + 0x49); */ static constexpr int E_INVALID_SECRET_KEY = (E_BASE + 0x4a); +/** + * @brief No space left on device + */ +static constexpr int E_SQLITE_IOERR_FULL = (E_BASE + 0x4b); + /** * @brief Do not use except relational_store */ static constexpr int E_INNER_WARNING = (E_BASE + 0x4c); + +/** + * @brief This is not a database file. + */ +static constexpr int E_SQLITE_NOT_DB = (E_BASE + 0x4d); + +/** + * @brief The root key of the encrypted database is faulty. + */ +static constexpr int E_ROOT_KEY_FAULT = (E_BASE + 0x4e); + +/** + * @brief The root key of the encrypted database cannot be loaded. + */ +static constexpr int E_ROOT_KEY_NOT_LOAD = (E_BASE + 0x4f); + +/** + * @brief The working key of the encrypted database is faulty. + */ +static constexpr int E_WORK_KEY_FAIL = (E_BASE + 0x50); + +/** + * @brief Failed to encrypt the working key. + */ +static constexpr int E_WORK_KEY_ENCRYPT_FAIL = (E_BASE + 0x51); + +/** + * @brief Failed to decrypt the working key. + */ +static constexpr int E_WORK_KEY_DECRYPT_FAIL = (E_BASE + 0x52); + +/** + * @brief Failed to open the sqlite database using the working key. + */ +static constexpr int E_SET_ENCRYPT_FAIL = (E_BASE + 0x53); + +/** + * @brief Failed to open the sqlite database using the working new key. + */ +static constexpr int E_SET_NEW_ENCRYPT_FAIL = (E_BASE + 0x54); + +/** + * @brief Failed to open the sqlite database using the working service key. + */ +static constexpr int E_SET_SERVICE_ENCRYPT_FAIL = (E_BASE + 0x55); + +/** + * @brief Database WAL file check point failed. + */ +static constexpr int E_CHECK_POINT_FAIL = (E_BASE + 0x56); } // namespace NativeRdb } // namespace OHOS diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_helper.h b/relational_store/interfaces/inner_api/rdb/include/rdb_helper.h index 40e9ffd06a97170139a9c7eb509a96cb85d4814a..bf425e1d90397b648ba4a7d84ccd1d2be5ecfb40 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_helper.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_helper.h @@ -50,14 +50,28 @@ public: * * @param path Indicates the database path. */ - API_EXPORT static int DeleteRdbStore(const std::string &path); + API_EXPORT static int DeleteRdbStore(const std::string &path, bool shouldClose = true); - API_EXPORT static int DeleteRdbStore(const RdbStoreConfig &config); + API_EXPORT static int DeleteRdbStore(const RdbStoreConfig &config, bool shouldClose = true); /** * @brief Clear Cache. */ API_EXPORT static void ClearCache(); + + /** + * @brief Checks whether the vector database is supported. + * + * @return Returns {@code true} if the vector database is supported; returns {@code false} otherwise. + */ + API_EXPORT static bool IsSupportArkDataDb(); + + /** + * @brief Checks whether the custom tokenizer is supported. + * + * @return Returns {@code true} if the custom tokenizer is supported; returns {@code false} otherwise. + */ + API_EXPORT static bool IsSupportedTokenizer(Tokenizer tokenizer); }; } // namespace NativeRdb } // namespace OHOS diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_service.h b/relational_store/interfaces/inner_api/rdb/include/rdb_service.h index 7643b92283198e62e92b79e858fdb0d91510ee9b..74986a9adff343373e23cef8e804a1784e61350b 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_service.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_service.h @@ -82,7 +82,7 @@ public: virtual int32_t Enable(const RdbSyncerParam ¶m) = 0; - virtual int32_t GetPassword(const RdbSyncerParam ¶m, std::vector &password) = 0; + virtual int32_t GetPassword(const RdbSyncerParam ¶m, std::vector> &password) = 0; virtual std::pair LockCloudContainer(const RdbSyncerParam ¶m) = 0; diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_sql_utils.h b/relational_store/interfaces/inner_api/rdb/include/rdb_sql_utils.h index 35f7b41ba7a6411cad898db29de7d3a8fbb1cd99..fb5475c94d1ee5530a72a4d5c69af1c345171df2 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_sql_utils.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_sql_utils.h @@ -32,6 +32,12 @@ public: static std::pair GetDefaultDatabasePath( const std::string &baseDir, const std::string &name, const std::string &customDir = ""); + /** + * @brief get custom rootDir data base path. + */ + static std::pair GetCustomDatabasePath(const std::string &rootDir, const std::string &name, + const std::string &customDir); + /** * @brief get default data base path. */ diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_store.h b/relational_store/interfaces/inner_api/rdb/include/rdb_store.h index 83232012f3d0c8273dd7645034746954064914ba..03f56597aa712f0bf26686fae6860a90dfdbbb37 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_store.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_store.h @@ -197,6 +197,16 @@ public: */ virtual std::pair BatchInsert(const std::string &table, const RefRows &rows); + /** + * @brief Inserts a batch of data into the target table with conflict resolution. + * + * @param table Indicates the target table. + * @param values Indicates the rows of data {@link ValuesBuckets} to be inserted into the table. + * @param resolution Indicates the {@link ConflictResolution} to insert data into the table. + */ + virtual std::pair BatchInsertWithConflictResolution( + const std::string &table, const RefRows &rows, Resolution resolution); + /** * @brief Updates data in the database based on specified conditions. * @@ -356,16 +366,20 @@ public: * * @param sql Indicates the SQL statement to execute. * @param args Indicates the selection arguments. + * @param preCount IIndicates whether to calculate the count during query. */ - virtual std::shared_ptr QueryByStep(const std::string &sql, const Values &args = {}) = 0; + virtual std::shared_ptr QueryByStep(const std::string &sql, const Values &args = {}, + bool preCount = true) = 0; /** * @brief Queries data in the database based on specified conditions. * * @param predicates Indicates the specified query condition by the instance object of {@link AbsRdbPredicates}. * @param columns Indicates the columns to query. If the value is empty array, the query applies to all columns. + * @param preCount IIndicates whether to calculate the count during query. */ - virtual std::shared_ptr QueryByStep(const AbsRdbPredicates &predicates, const Fields &columns = {}); + virtual std::shared_ptr QueryByStep(const AbsRdbPredicates &predicates, const Fields &columns = {}, + bool preCount = true); /** * @brief Queries remote data in the database based on specified conditions before Synchronizing Data. diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_store_config.h b/relational_store/interfaces/inner_api/rdb/include/rdb_store_config.h index bc023157a29a5420682a110807c9f4dd38b92bb9..5c69c3a8d4ad2b8923ff1d8ed921d1e8661bee5b 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_store_config.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_store_config.h @@ -191,6 +191,13 @@ enum EncryptAlgo : int32_t { AES_256_CBC }; +enum Tokenizer : int32_t { + NONE_TOKENIZER = 0, + ICU_TOKENIZER, + CUSTOM_TOKENIZER, + TOKENIZER_END +}; + /** * @brief Use DistributedType replace OHOS::DistributedRdb::RdbDistributedType. */ @@ -343,6 +350,10 @@ public: */ API_EXPORT void SetEncryptStatus(const bool status); + API_EXPORT Tokenizer GetTokenizer() const; + + API_EXPORT void SetTokenizer(Tokenizer tokenizer); + /** * @brief Checks whether the database is encrypt. */ @@ -595,25 +606,23 @@ public: */ bool operator==(const RdbStoreConfig &config) const { - if (this->customScalarFunctions.size() != config.customScalarFunctions.size()) { + if (customScalarFunctions_.size() != config.customScalarFunctions_.size()) { return false; } - auto iter1 = this->customScalarFunctions.begin(); - auto iter2 = config.customScalarFunctions.begin(); - for (; iter1 != this->customScalarFunctions.end(); ++iter1, ++iter2) { + auto iter1 = customScalarFunctions_.begin(); + auto iter2 = config.customScalarFunctions_.begin(); + for (; iter1 != customScalarFunctions_.end(); ++iter1, ++iter2) { if (iter1->first != iter2->first) { return false; } } - return this->path_ == config.path_ && this->storageMode_ == config.storageMode_ && - this->journalMode_ == config.journalMode_ && this->syncMode_ == config.syncMode_ && - this->databaseFileType == config.databaseFileType && IsEncrypt() == config.IsEncrypt() && - this->securityLevel_ == config.securityLevel_ && this->journalSize_ == config.journalSize_ && - this->pageSize_ == config.pageSize_ && this->dbType_ == config.dbType_ && - this->customDir_ == config.customDir_ && this->pluginLibs_ == config.pluginLibs_ && - this->haMode_ == config.haMode_; + return path_ == config.path_ && storageMode_ == config.storageMode_ && journalMode_ == config.journalMode_ && + syncMode_ == config.syncMode_ && databaseFileType == config.databaseFileType && + IsEncrypt() == config.IsEncrypt() && securityLevel_ == config.securityLevel_ && + journalSize_ == config.journalSize_ && pageSize_ == config.pageSize_ && dbType_ == config.dbType_ && + customDir_ == config.customDir_ && pluginLibs_ == config.pluginLibs_ && haMode_ == config.haMode_; } /** @@ -703,7 +712,11 @@ public: void EnableRekey(bool enable); - static std::string Format(const RdbStoreConfig &cacheConfig, const RdbStoreConfig &incomingConfig); + int GetNcandidates() const; + + void SetNcandidates(int ncandidates); + + static std::string FormatCfg(const RdbStoreConfig &first, const RdbStoreConfig &second); private: void ClearEncryptKey(); @@ -727,6 +740,7 @@ private: int32_t haMode_ = HAMode::SINGLE; SecurityLevel securityLevel_ = SecurityLevel::LAST; RoleType role_ = OWNER; + Tokenizer tokenizer_ = Tokenizer::NONE_TOKENIZER; DistributedType distributedType_ = DistributedRdb::RdbDistributedType::RDB_DEVICE_COLLABORATION; StorageMode storageMode_; IntegrityCheck checkType_ = IntegrityCheck::NONE; @@ -747,8 +761,9 @@ private: std::string dataGroupId_; std::string customDir_; mutable std::vector newEncryptKey_{}; - std::map customScalarFunctions; + std::map customScalarFunctions_; std::vector pluginLibs_{}; + int ncandidates_ = 128; static constexpr int MAX_TIMEOUT = 300; // seconds static constexpr int MIN_TIMEOUT = 1; // seconds diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_types.h b/relational_store/interfaces/inner_api/rdb/include/rdb_types.h index cfb74bcd458be8b128fd7fc9a5ca50a4b7ccbf6b..c0e784c2fb92ff05213725a60869394c0d53586d 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_types.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_types.h @@ -72,6 +72,7 @@ struct RdbSyncerParam { std::vector uids_; std::string user_; std::vector permissionNames_ = {}; + bool asyncDownloadAsset_ = false; ~RdbSyncerParam() { password_.assign(password_.size(), 0); @@ -113,6 +114,7 @@ struct DistributedConfig { bool autoSync = true; std::vector references = {}; bool isRebuild = false; + bool asyncDownloadAsset = false; }; enum Progress { @@ -188,6 +190,7 @@ enum RdbPredicateOperator { INDEXED_BY, NOT_CONTAINS, NOT_LIKE, + ASSETS_ONLY, OPERATOR_MAX }; @@ -301,6 +304,7 @@ struct Field { struct RdbChangeProperties { bool isTrackedDataChange = false; + bool isP2pSyncDataChange = false; }; struct RdbChangedData { diff --git a/relational_store/interfaces/inner_api/rdb/include/transaction.h b/relational_store/interfaces/inner_api/rdb/include/transaction.h index 774dc645c7b80629b896ef355f07f0187924ee87..a6ad73686fc0ccd9fa4c842fa2e81c0fc4edd9a6 100644 --- a/relational_store/interfaces/inner_api/rdb/include/transaction.h +++ b/relational_store/interfaces/inner_api/rdb/include/transaction.h @@ -100,7 +100,7 @@ public: * @brief Inserts a batch of data into the target table. * * @param table Indicates the target table. - * @param rows Indicates the rows of data {@link ValuesBucket} to be inserted into the table. + * @param rows Indicates the rows of data {@link Rows} to be inserted into the table. */ virtual std::pair BatchInsert(const std::string &table, const Rows &rows) = 0; @@ -108,9 +108,18 @@ public: * @brief Inserts a batch of data into the target table. * * @param table Indicates the target table. - * @param values Indicates the rows of data {@link ValuesBuckets} to be inserted into the table. + * @param rows Indicates the rows of data {@link RefRows} to be inserted into the table. */ virtual std::pair BatchInsert(const std::string &table, const RefRows &rows) = 0; + /** + * @brief Inserts a batch of data into the target table. + * + * @param table Indicates the target table. + * @param rows Indicates the rows of data {@link RefRows} to be inserted into the table. + * @param resolution Indicates the {@link ConflictResolution} to insert data into the table. + */ + virtual std::pair BatchInsertWithConflictResolution( + const std::string &table, const RefRows &rows, Resolution resolution) = 0; /** * @brief Updates data in the database based on specified conditions. @@ -156,16 +165,20 @@ public: * * @param sql Indicates the SQL statement to execute. * @param args Indicates the selection arguments. + * @param preCount IIndicates whether to calculate the count during query. */ - virtual std::shared_ptr QueryByStep(const std::string &sql, const Values &args = {}) = 0; + virtual std::shared_ptr QueryByStep(const std::string &sql, const Values &args = {}, + bool preCount = true) = 0; /** * @brief Queries data in the database based on specified conditions. * * @param predicates Indicates the specified query condition by the instance object of {@link AbsRdbPredicates}. * @param columns Indicates the columns to query. If the value is empty array, the query applies to all columns. + * @param preCount IIndicates whether to calculate the count during query. */ - virtual std::shared_ptr QueryByStep(const AbsRdbPredicates &predicates, const Fields &columns = {}) = 0; + virtual std::shared_ptr QueryByStep(const AbsRdbPredicates &predicates, const Fields &columns = {}, + bool preCount = true) = 0; /** * @brief Executes an SQL statement that contains specified parameters and diff --git a/relational_store/interfaces/inner_api/rdb/mock/include/rdb_store_config.h b/relational_store/interfaces/inner_api/rdb/mock/include/rdb_store_config.h index fa1d035d053437b5f478d6d7207df7b1f977db59..68f155cbbbd115d3d9c0dec0d7ff3201aff1724a 100644 --- a/relational_store/interfaces/inner_api/rdb/mock/include/rdb_store_config.h +++ b/relational_store/interfaces/inner_api/rdb/mock/include/rdb_store_config.h @@ -104,6 +104,13 @@ enum EncryptAlgo : int32_t { AES_256_CBC }; +enum Tokenizer : int32_t { + NONE_TOKENIZER = 0, + ICU_TOKENIZER, + CUSTOM_TOKENIZER, + TOKENIZER_END +}; + using ScalarFunction = std::function &)>; @@ -209,6 +216,8 @@ public: void SetCustomDir(const std::string &customDir); std::string GetCustomDir() const; + Tokenizer GetTokenizer() const; + void SetTokenizer(Tokenizer tokenizer); void SetVisitorDir(const std::string &visitorDir); std::string GetVisitorDir() const; bool operator==(const RdbStoreConfig &config) const @@ -265,6 +274,8 @@ public: CryptoParam GetCryptoParam() const; void SetJournalMode(const std::string &journalMode); void EnableRekey(bool enable); + int GetNcandidates() const; + void SetNcandidates(int ncandidates); static std::string Format(const RdbStoreConfig &cacheConfig, const RdbStoreConfig &incomingConfig); private: @@ -292,6 +303,7 @@ private: DistributedType distributedType_ = DistributedType::RDB_DEVICE_COLLABORATION; StorageMode storageMode_; IntegrityCheck checkType_ = IntegrityCheck::NONE; + Tokenizer tokenizer_ = Tokenizer::NONE_TOKENIZER; CryptoParam cryptoParam_; std::string name_; std::string path_; @@ -311,6 +323,7 @@ private: mutable std::vector newEncryptKey_{}; std::map customScalarFunctions; std::vector pluginLibs_{}; + int ncandidates_ = 128; static constexpr int MAX_TIMEOUT = 300; // seconds static constexpr int MIN_TIMEOUT = 1; // seconds diff --git a/relational_store/interfaces/ndk/include/oh_cursor.h b/relational_store/interfaces/ndk/include/oh_cursor.h index 7b6bb86de486de6e5b43892838091a6def91adb9..fffedc9f0998cad90844e3b6cfe6a7c306073861 100644 --- a/relational_store/interfaces/ndk/include/oh_cursor.h +++ b/relational_store/interfaces/ndk/include/oh_cursor.h @@ -37,56 +37,16 @@ * @since 10 */ -#include +#include #include - -#include - +#include #include "data_asset.h" +#include "oh_data_value.h" + #ifdef __cplusplus extern "C" { #endif -/** - * @brief Indicates the column type. - * - * @since 10 - */ -typedef enum OH_ColumnType { - /** - * Indicates the column type is NULL. - */ - TYPE_NULL = 0, - /** - * Indicates the column type is INT64. - */ - TYPE_INT64, - /** - * Indicates the column type is REAL. - */ - TYPE_REAL, - /** - * Indicates the column type is TEXT. - */ - TYPE_TEXT, - /** - * Indicates the column type is BLOB. - */ - TYPE_BLOB, - /** - * Indicates the column type is {@link Data_Asset}. - * - * @since 11 - */ - TYPE_ASSET, - /** - * Indicates the column type is array of {@link Data_Asset}. - * - * @since 11 - */ - TYPE_ASSETS -} OH_ColumnType; - /** * @brief Define the OH_Cursor structure type. * @@ -301,6 +261,57 @@ typedef struct OH_Cursor { int (*getAssetsCount)(OH_Cursor *cursor, int32_t columnIndex, uint32_t *count); } OH_Cursor; +/** + * @brief Get float array data size of the requested column from OH_Cursor object. + * + * @param value Represents a pointer to an instance of OH_Cursor. + * @param columnIndex Indicates the zero-based column index. + * @param length Represents the size of float array. It is an output parameter. + * @return Returns the status code of the execution. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_ERROR} database common error. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_SQLITE_CORRUPT} database corrupted. + * Returns {@link RDB_E_STEP_RESULT_CLOSED} the result set has been closed. + * Returns {@link RDB_E_ALREADY_CLOSED} database already closed. + * Returns {@link RDB_E_SQLITE_PERM} SQLite: Access permission denied. + * Returns {@link RDB_E_SQLITE_BUSY} SQLite: The database file is locked. + * Returns {@link RDB_E_SQLITE_LOCKED} SQLite: A table in the database is locked. + * Returns {@link RDB_E_SQLITE_NOMEM} SQLite: The database is out of memory. + * Returns {@link RDB_E_SQLITE_IOERR} SQLite: Some kind of disk I/O error occurred. + * Returns {@link RDB_E_SQLITE_TOO_BIG} SQLite: TEXT or BLOB exceeds size limit. + * Returns {@link RDB_E_SQLITE_MISMATCH} SQLite: Data type mismatch. + * @since 16 + */ +int OH_Cursor_GetFloatVectorCount(OH_Cursor *cursor, int32_t columnIndex, size_t *length); + +/** + * @brief Obtains the value of the requested column as a float array. + * + * @param value Represents a pointer to an instance of OH_Cursor. + * @param val Represents a pointer to float array. The caller needs to apply for data memory. + * This function only fills data. Otherwise, the execution fails. + * @param inLen Represents the size of val. It can be obtained through the OH_Cursor_GetFloatVectorCount function. + * @param outLen Represents the actual amount of data obtained. It is an output parameter. + * @return Returns the status code of the execution. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_ERROR} database common error. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_SQLITE_CORRUPT} database corrupted. + * Returns {@link RDB_E_STEP_RESULT_CLOSED} the result set has been closed. + * Returns {@link RDB_E_ALREADY_CLOSED} database already closed. + * Returns {@link RDB_E_SQLITE_PERM} SQLite: Access permission denied. + * Returns {@link RDB_E_SQLITE_BUSY} SQLite: The database file is locked. + * Returns {@link RDB_E_SQLITE_LOCKED} SQLite: A table in the database is locked. + * Returns {@link RDB_E_SQLITE_NOMEM} SQLite: The database is out of memory. + * Returns {@link RDB_E_SQLITE_IOERR} SQLite: Some kind of disk I/O error occurred. + * Returns {@link RDB_E_SQLITE_TOO_BIG} SQLite: TEXT or BLOB exceeds size limit. + * Returns {@link RDB_E_SQLITE_MISMATCH} SQLite: Data type mismatch. + * @see OH_Cursor_GetFloatVectorCount. + * @since 16 + */ +int OH_Cursor_GetFloatVector(OH_Cursor *cursor, int32_t columnIndex, float *val, size_t inLen, size_t *outLen); + #ifdef __cplusplus }; #endif diff --git a/relational_store/interfaces/ndk/include/oh_data_value.h b/relational_store/interfaces/ndk/include/oh_data_value.h new file mode 100644 index 0000000000000000000000000000000000000000..59d4de3357277de5781af1a400d4685333619e61 --- /dev/null +++ b/relational_store/interfaces/ndk/include/oh_data_value.h @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2024 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. + */ + +/** + * @addtogroup RDB + * @{ + * + * @brief The relational database (RDB) store manages data based on relational models. + * With the underlying SQLite database, the RDB store provides a complete mechanism for managing local databases. + * To satisfy different needs in complicated scenarios, the RDB store offers a series of APIs for performing operations + * such as adding, deleting, modifying, and querying data, and supports direct execution of SQL statements. + * + * @since 10 + */ + +/** + * @file oh_data_value.h + * + * @brief Provides functions and enumerations related to the data value. + * + * @kit ArkData + * @library libnative_rdb_ndk.z.so + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * + * @since 16 + */ + +#ifndef OH_DATA_VALUE_H +#define OH_DATA_VALUE_H + +#include +#include "data_asset.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Indicates the column type. + * + * @since 10 + */ +typedef enum OH_ColumnType { + /** + * @brief Indicates the column type is NULL. + * + * @since 10 Moved from oh_cursor.h file. + */ + TYPE_NULL = 0, + /** + * @brief Indicates the column type is INT64. + * + * @since 10 Moved from oh_cursor.h file. + */ + TYPE_INT64, + /** + * @brief Indicates the column type is REAL. + * + * @since 10 Moved from oh_cursor.h file. + */ + TYPE_REAL, + /** + * @brief Indicates the column type is TEXT. + * + * @since 10 Moved from oh_cursor.h file. + */ + TYPE_TEXT, + /** + * @brief Indicates the column type is BLOB. + * + * @since 10 Moved from oh_cursor.h file. + */ + TYPE_BLOB, + /** + * @brief Indicates the column type is {@link Data_Asset}. + * + * @since 11 Moved from oh_cursor.h file. + */ + TYPE_ASSET, + /** + * @brief Indicates the column type is array of {@link Data_Asset}. + * + * @since 11 Moved from oh_cursor.h file. + */ + TYPE_ASSETS, + /** + * @brief Indicates the column type is FLOAT VECTOR. + * + * @since 16 + */ + TYPE_FLOAT_VECTOR, + /** + * @brief Indicates that the column type is a number whose length is greater than 64 bits. + * + * @since 16 + */ + TYPE_UNLIMITED_INT, +} OH_ColumnType; + +/** + * @brief Define the OH_Data_Value structure type. + * + * @since 16 + */ +typedef struct OH_Data_Value OH_Data_Value; + +/** + * @brief Creates an OH_Data_Value instance object. + * + * @return Returns a pointer to OH_Data_Value instance when the execution is successful. + * Otherwise, nullptr is returned. The memory must be released through the OH_Value_Destroy + * interface after the use is complete. + * @see OH_Value_Destroy. + * @since 16 + */ +OH_Data_Value *OH_Value_Create(); + +/** + * @brief Destroys an OH_Data_Value instance object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Value_Destroy(OH_Data_Value *value); + +/** + * @brief Set empty data to the OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Value_PutNull(OH_Data_Value *value); + +/** + * @brief Set integer data to the OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param val Represents a integer data. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Value_PutInt(OH_Data_Value *value, int64_t val); + +/** + * @brief Set decimal data to the OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param val Represents a decimal data. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Value_PutReal(OH_Data_Value *value, double val); + +/** + * @brief Set string data to the OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param val Represents a string data. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Value_PutText(OH_Data_Value *value, const char *val); + +/** + * @brief Set binary data to the OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param val Represents a binary data. + * @param length Represents the size of binary data. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Value_PutBlob(OH_Data_Value *value, const unsigned char *val, size_t length); + +/** + * @brief Set Data_Asset data to the OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param val Represents a pointer to an instance of Data_Asset. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Value_PutAsset(OH_Data_Value *value, const Data_Asset *val); + +/** + * @brief Set multiple Data_Asset data to the OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param val Represents a pointer to multiple Data_Asset. + * @param length Represents the count of multiple data. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Value_PutAssets(OH_Data_Value *value, const Data_Asset * const * val, size_t length); + +/** + * @brief Set float array data to the OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param val Represents a pointer to float array. + * @param length Represents the size of float array. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Value_PutFloatVector(OH_Data_Value *value, const float *val, size_t length); + +/** + * @brief Set an integer of any length data to the OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param sign Represents 0 is positive integer, 1 is negative integer. + * @param trueForm Represents a pointer to integer array. + * @param length Represents the size of integer array. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Value_PutUnlimitedInt(OH_Data_Value *value, int sign, const uint64_t *trueForm, size_t length); + +/** + * @brief Get data type from OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param type Represents the parameter of the data type. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Value_GetType(OH_Data_Value *value, OH_ColumnType *type); + +/** + * @brief Check whether the data is empty from OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param val Represents empty data flag. It is an output parameter. Ture is empty, false is not empty. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Value_IsNull(OH_Data_Value *value, bool *val); + +/** + * @brief Get integer data from OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param val Represents a pointer to an integer data. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @since 16 + */ +int OH_Value_GetInt(OH_Data_Value *value, int64_t *val); + +/** + * @brief Get decimal data from OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param val Represents a pointer to an decimal data. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @since 16 + */ +int OH_Value_GetReal(OH_Data_Value *value, double *val); + +/** + * @brief Get string data from OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param val Represents a pointer to a string data. It is an output parameter. + * The caller does not need to apply for memory and release memory. The life cycle of val follows value. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @since 16 + */ +int OH_Value_GetText(OH_Data_Value *value, const char **val); + +/** + * @brief Get binary data from OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param val Represents a pointer to a binary data. It is an output parameter. + * The caller does not need to apply for memory and release memory. The life cycle of val follows value. + * @param length Represents the size of binary array. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @since 16 + */ +int OH_Value_GetBlob(OH_Data_Value *value, const uint8_t **val, size_t *length); + +/** + * @brief Get Data_Asset data from OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param val Represents a pointer to an instance of Data_Asset. The caller needs to apply for data memory. + * This function only fills data. Otherwise, the execution fails. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @since 16 + */ +int OH_Value_GetAsset(OH_Data_Value *value, Data_Asset *val); + +/** + * @brief Get multiple Data_Asset size from OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param length Represents the size of Data_Asset array. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @since 16 + */ +int OH_Value_GetAssetsCount(OH_Data_Value *value, size_t *length); + +/** + * @brief Get multiple Data_Asset data from OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param val Represents a pointer to Data_Asset array. The caller needs to apply for data memory. + * This function only fills data. Otherwise, the execution fails. + * @param inLen Represents the size of val. It can be obtained through the OH_Value_GetAssetsCount function. + * @param outLen Represents the actual amount of data obtained. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @see OH_Value_GetAssetsCount. + * @since 16 + */ +int OH_Value_GetAssets(OH_Data_Value *value, Data_Asset **val, size_t inLen, size_t *outLen); + +/** + * @brief Get float array data size from OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param length Represents the size of float array. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @since 16 + */ +int OH_Value_GetFloatVectorCount(OH_Data_Value *value, size_t *length); + +/** + * @brief Get float array from OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param val Represents a pointer to float array. The caller needs to apply for data memory. + * This function only fills data. Otherwise, the execution fails. + * @param inLen Represents the size of val. It can be obtained through the OH_Value_GetFloatVectorCount function. + * @param outLen Represents the actual amount of data obtained. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @see OH_Value_GetFloatVectorCount. + * @since 16 + */ +int OH_Value_GetFloatVector(OH_Data_Value *value, float *val, size_t inLen, size_t *outLen); + +/** + * @brief Get an integer of any length data size from OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param length Represents the size of integer array. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @since 16 + */ +int OH_Value_GetUnlimitedIntBand(OH_Data_Value *value, size_t *length); + +/** + * @brief Get an integer of any length data from OH_Data_Value object. + * + * @param value Represents a pointer to an instance of OH_Data_Value. + * @param sign Represents 0 is positive integer, 1 is negative integer. It is an output parameter. + * @param trueForm Represents a pointer to integer array. The caller needs to apply for data memory. + * This function only fills data. Otherwise, the execution fails. + * @param inLen Represents the size of trueForm. It can be obtained through the OH_Value_GetUnlimitedIntBand function. + * @param outLen Represents the actual amount of data obtained. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @see OH_Value_GetUnlimitedIntBand. + * @since 16 + */ +int OH_Value_GetUnlimitedInt(OH_Data_Value *value, int *sign, uint64_t *trueForm, size_t inLen, size_t *outLen); + +#ifdef __cplusplus +}; +#endif +#endif +/** @} */ \ No newline at end of file diff --git a/relational_store/interfaces/ndk/include/oh_data_values.h b/relational_store/interfaces/ndk/include/oh_data_values.h new file mode 100644 index 0000000000000000000000000000000000000000..6f16bd72bce6eaf8c959c8bb3bcd7385a0b2ad6a --- /dev/null +++ b/relational_store/interfaces/ndk/include/oh_data_values.h @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2024 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. + */ + +/** + * @addtogroup RDB + * @{ + * + * @brief The relational database (RDB) store manages data based on relational models. + * With the underlying SQLite database, the RDB store provides a complete mechanism for managing local databases. + * To satisfy different needs in complicated scenarios, the RDB store offers a series of APIs for performing operations + * such as adding, deleting, modifying, and querying data, and supports direct execution of SQL statements. + * + * @since 10 + */ + +/** + * @file oh_data_values.h + * + * @brief Provides functions and enumerations related to the data values. + * + * @kit ArkData + * @library libnative_rdb_ndk.z.so + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * + * @since 16 + */ +#ifndef OH_DATA_VALUES_H +#define OH_DATA_VALUES_H +#include + +#include "data_asset.h" +#include "oh_data_value.h" +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Define the OH_Data_Values structure type. + * + * @since 16 + */ +typedef struct OH_Data_Values OH_Data_Values; + +/** + * @brief Creates an OH_Data_Values instance object. + * + * @return Returns a pointer to OH_Data_Values instance when the execution is successful. + * Otherwise, nullptr is returned. The memory must be released through the OH_Values_Destroy + * interface after the use is complete. + * @see OH_Values_Destroy. + * @since 16 + */ +OH_Data_Values *OH_Values_Create(); + +/** + * @brief Destroys an OH_Data_Values instance object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Values_Destroy(OH_Data_Values *values); + +/** + * @brief Add OH_Data_Value data to the OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param val Represents a pointer to an instance of OH_Data_Value. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Values_Put(OH_Data_Values *values, const OH_Data_Value *val); + +/** + * @brief Add empty data to the OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Values_PutNull(OH_Data_Values *values); + +/** + * @brief Add integer data to the OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param val Represents a integer data. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Values_PutInt(OH_Data_Values *values, int64_t val); + +/** + * @brief Add decimal data to the OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param val Represents a decimal data. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Values_PutReal(OH_Data_Values *values, double val); + +/** + * @brief Add string data to the OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param val Represents a string data. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Values_PutText(OH_Data_Values *values, const char *val); + +/** + * @brief Add binary data to the OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param val Represents a binary data. + * @param length Represents the size of binary data. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Values_PutBlob(OH_Data_Values *values, const unsigned char *val, size_t length); + +/** + * @brief Add Data_Asset data to the OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param val Represents a pointer to an instance of Data_Asset. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Values_PutAsset(OH_Data_Values *values, const Data_Asset *val); + +/** + * @brief Add multiple Data_Asset data to the OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param val Represents a pointer to multiple Data_Asset. + * @param length Represents the count of multiple data. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Values_PutAssets(OH_Data_Values *values, const Data_Asset * const * val, size_t length); + +/** + * @brief Add float array data to the OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param val Represents a pointer to float array. + * @param length Represents the size of float array. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Values_PutFloatVector(OH_Data_Values *values, const float *val, size_t length); + +/** + * @brief Add an integer of any length data to the OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param sign Represents 0 is positive integer, 1 is negative integer. + * @param trueForm Represents a pointer to integer array. + * @param length Represents the size of integer array. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Values_PutUnlimitedInt(OH_Data_Values *values, int sign, const uint64_t *trueForm, size_t length); + +/** + * @brief Get data count from OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param count Represents the count of data in values. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Values_Count(OH_Data_Values *values, size_t *count); + +/** + * @brief Get data type from OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param index Represents the zero-based index of target data in values. + * @param type Represents the parameter of the data type. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Values_GetType(OH_Data_Values *values, int index, OH_ColumnType *type); + +/** + * @brief Get OH_Data_Value data from OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param index Represents the zero-based index of target data in values. + * @param val Represents a pointer to an instance of OH_Data_Value. It is an output parameter. + * The caller does not need to apply for memory and release memory. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Values_Get(OH_Data_Values *values, int index, OH_Data_Value **val); + +/** + * @brief Check whether the data is empty from OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param index Represents the zero-based index of target data in values. + * @param val Represents empty data flag. It is an output parameter. Ture is empty, false is not empty. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_Values_IsNull(OH_Data_Values *values, int index, bool *val); + +/** + * @brief Get integer data from OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param index Represents the zero-based index of target data in values. + * @param val Represents a pointer to an integer data. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @since 16 + */ +int OH_Values_GetInt(OH_Data_Values *values, int index, int64_t *val); + +/** + * @brief Get decimal data from OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param index Represents the zero-based index of target data in values. + * @param val Represents a pointer to an decimal data. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @since 16 + */ +int OH_Values_GetReal(OH_Data_Values *values, int index, double *val); + +/** + * @brief Get string data from OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param index Represents the zero-based index of target data in values. + * @param val Represents a pointer to a string data. It is an output parameter. + * The caller does not need to apply for memory and release memory. + * The life cycle of val follows the value of index in values. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @since 16 + */ +int OH_Values_GetText(OH_Data_Values *values, int index, const char **val); + +/** + * @brief Get binary data from OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param index Represents the zero-based index of target data in values. + * @param val Represents a pointer to a binary data. It is an output parameter. + * The caller does not need to apply for memory and release memory. + * The life cycle of val follows the value of index in values. + * @param length Represents the size of binary array. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @since 16 + */ +int OH_Values_GetBlob(OH_Data_Values *values, int index, const uint8_t **val, size_t *length); + +/** + * @brief Get Data_Asset data from OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param index Represents the zero-based index of target data in values. + * @param val Represents a pointer to an instance of Data_Asset. The caller needs to apply for data memory. + * This function only fills data. Otherwise, the execution fails. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @since 16 + */ +int OH_Values_GetAsset(OH_Data_Values *values, int index, Data_Asset *val); + +/** + * @brief Get multiple Data_Asset size from OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param index Represents the zero-based index of target data in values. + * @param length Represents the size of Data_Asset array. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @since 16 + */ +int OH_Values_GetAssetsCount(OH_Data_Values *values, int index, size_t *length); + +/** + * @brief Get multiple Data_Asset data from OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param index Represents the zero-based index of target data in values. + * @param val Represents a pointer to Data_Asset array. The caller needs to apply for data memory. + * This function only fills data. Otherwise, the execution fails. + * @param inLen Represents the size of val. It can be obtained through the OH_Values_GetAssetsCount function. + * @param outLen Represents the actual amount of data obtained. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @see OH_Values_GetAssetsCount. + * @since 16 + */ +int OH_Values_GetAssets(OH_Data_Values *values, int index, Data_Asset **val, size_t inLen, size_t *outLen); + +/** + * @brief Get float array data size from OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param index Represents the zero-based index of target data in values. + * @param length Represents the size of float array. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @since 16 + */ +int OH_Values_GetFloatVectorCount(OH_Data_Values *values, int index, size_t *length); + +/** + * @brief Get float array from OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param index Represents the zero-based index of target data in values. + * @param val Represents a pointer to float array. The caller needs to apply for data memory. + * This function only fills data. Otherwise, the execution fails. + * @param inLen Represents the size of val. It can be obtained through the OH_Values_GetFloatVectorCount function. + * @param outLen Represents the actual amount of data obtained. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @see OH_Values_GetFloatVectorCount. + * @since 16 + */ +int OH_Values_GetFloatVector(OH_Data_Values *values, int index, float *val, size_t inLen, size_t *outLen); + +/** + * @brief Get an integer of any length data size from OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param index Represents the zero-based index of target data in values. + * @param length Represents the size of integer array. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @since 16 + */ +int OH_Values_GetUnlimitedIntBand(OH_Data_Values *values, int index, size_t *length); + +/** + * @brief Get an integer of any length data from OH_Data_Values object. + * + * @param values Represents a pointer to an instance of OH_Data_Values. + * @param index Represents the zero-based index of target data in values. + * @param sign Represents 0 is positive integer, 1 is negative integer. It is an output parameter. + * @param trueForm Represents a pointer to integer array. The caller needs to apply for data memory. + * This function only fills data. Otherwise, the execution fails. + * @param inLen Represents the size of trueForm. It can be obtained through the OH_Values_GetUnlimitedIntBand function. + * @param outLen Represents the actual amount of data obtained. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_DATA_TYPE_NULL} the content stored in parameter value is null. + * Returns {@link RDB_E_TYPE_MISMATCH} storage data type mismatch. + * @see OH_Values_GetUnlimitedIntBand. + * @since 16 + */ +int OH_Values_GetUnlimitedInt(OH_Data_Values *values, int index, int *sign, uint64_t *trueForm, size_t inLen, + size_t *outLen); + +#ifdef __cplusplus +}; +#endif +#endif +/** @} */ \ No newline at end of file diff --git a/relational_store/interfaces/ndk/include/oh_data_values_buckets.h b/relational_store/interfaces/ndk/include/oh_data_values_buckets.h new file mode 100644 index 0000000000000000000000000000000000000000..e3cb1bcdb17bae741b10a6b983f69a6ac374d484 --- /dev/null +++ b/relational_store/interfaces/ndk/include/oh_data_values_buckets.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2024 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. + */ + +/** + * @addtogroup RDB + * @{ + * + * @brief The relational database (RDB) store manages data based on relational models. + * With the underlying SQLite database, the RDB store provides a complete mechanism for managing local databases. + * To satisfy different needs in complicated scenarios, the RDB store offers a series of APIs for performing operations + * such as adding, deleting, modifying, and querying data, and supports direct execution of SQL statements. + * + * @since 10 + */ + +/** + * @file oh_data_values_buckets.h + * + * @brief Provides functions and enumerations related to the data value buckets. + * + * @kit ArkData + * @library libnative_rdb_ndk.z.so + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * + * @since 16 + */ + + +#ifndef OH_VALUES_BUCKETS_H +#define OH_VALUES_BUCKETS_H +#include "oh_values_bucket.h" +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Define the OH_Data_VBuckets structure type. + * + * @since 16 + */ +typedef struct OH_Data_VBuckets OH_Data_VBuckets; + +/** + * @brief Creates an OH_Data_VBuckets instance object. + * + * @return Returns a pointer to OH_Data_VBuckets instance when the execution is successful. + * Otherwise, nullptr is returned. The memory must be released through the OH_VBuckets_Destroy + * interface after the use is complete. + * @see OH_VBuckets_Destroy. + * @since 16 + */ +OH_Data_VBuckets *OH_VBuckets_Create(); + +/** + * @brief Destroys an OH_Data_VBuckets instance object. + * + * @param buckets Represents a pointer to an instance of OH_Data_VBuckets. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_VBuckets_Destroy(OH_Data_VBuckets *buckets); + +/** + * @brief Add an OH_VBucket to OH_Data_VBuckets object. + * + * @param buckets Represents a pointer to an instance of OH_Data_VBuckets. + * @param row Represents a pointer to an instance of OH_VBucket. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_VBuckets_PutRow(OH_Data_VBuckets *buckets, const OH_VBucket *row); + +/** + * @brief Add an OH_Data_VBuckets to OH_Data_VBuckets object. + * + * @param buckets Represents a pointer to an instance of OH_Data_VBuckets. + * @param rows Represents a pointer to an instance of OH_Data_VBuckets. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_VBuckets_PutRows(OH_Data_VBuckets *buckets, const OH_Data_VBuckets *rows); + +/** + * @brief Add an OH_Data_VBuckets to OH_Data_VBuckets object. + * + * @param buckets Represents a pointer to an instance of OH_Data_VBuckets. + * @param count Represents the count of OH_VBucket in OH_Data_VBuckets. It is an output parameter. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_VBuckets_RowCount(OH_Data_VBuckets *buckets, size_t *count); + +#ifdef __cplusplus +}; +#endif +#endif +/** @} */ diff --git a/relational_store/interfaces/ndk/include/oh_rdb_transaction.h b/relational_store/interfaces/ndk/include/oh_rdb_transaction.h new file mode 100644 index 0000000000000000000000000000000000000000..d8960c5239756fb97eaa9e9e964bf3aaf072e478 --- /dev/null +++ b/relational_store/interfaces/ndk/include/oh_rdb_transaction.h @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2024 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. + */ + +/** + * @addtogroup RDB + * @{ + * + * @brief The relational database (RDB) store manages data based on relational models. + * With the underlying SQLite database, the RDB store provides a complete mechanism for managing local databases. + * To satisfy different needs in complicated scenarios, the RDB store offers a series of APIs for performing operations + * such as adding, deleting, modifying, and querying data, and supports direct execution of SQL statements. + * + * @since 10 + */ + +/** + * @file oh_rdb_transaction.h + * + * @brief Provides database transaction related functions and enumerations. + * + * @kit ArkData + * @library libnative_rdb_ndk.z.so + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * + * @since 16 + */ + +#ifndef OH_RDB_TRANSACTION_H +#define OH_RDB_TRANSACTION_H +#include "oh_cursor.h" +#include "oh_predicates.h" +#include "oh_data_values.h" +#include "oh_values_bucket.h" +#include "oh_data_values_buckets.h" +#include "oh_rdb_types.h" +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Indicates relation database transaction type. + * + * @since 16 + */ +typedef enum OH_RDB_TransType { + /** + * @brief Indicates the transaction does not actually start until the database is first accessed. It's a default. + */ + RDB_TRANS_DEFERRED = 0, + /** + * @brief Indicates the database connection to start a new write immediately, without waiting for a write statement. + */ + RDB_TRANS_IMMEDIATE, + /** + * @brief Indicates it is similar to RDB_TRANS_IMMEDIATE in that a write transaction is started immediately. + * RDB_TRANS_EXCLUSIVE and RDB_TRANS_IMMEDIATE are the same in WAL mode, but in other journaling modes, + * EXCLUSIVE prevents other database connections from reading the database while the transaction is underway. + */ + RDB_TRANS_EXCLUSIVE, + /** + * The largest value for rdb transaction type. + */ + RDB_TRANS_BUTT, +} OH_RDB_TransType; + +/** + * @brief Define the OH_RDB_TransOptions structure type. + * + * @since 16 + */ +typedef struct OH_RDB_TransOptions OH_RDB_TransOptions; + +/** + * @brief Define the OH_Rdb_Transaction structure type. + * + * @since 16 + */ +typedef struct OH_Rdb_Transaction OH_Rdb_Transaction; + +/** + * @brief Creates an OH_RDB_TransOptions instance object. + * + * @return Returns a pointer to OH_RDB_TransOptions instance when the execution is successful. + * Otherwise, nullptr is returned. The memory must be released through the OH_RdbTrans_DestroyOptions + * interface after the use is complete. + * @see OH_RdbTrans_DestroyOptions. + * @since 16 + */ +OH_RDB_TransOptions *OH_RdbTrans_CreateOptions(); + +/** + * @brief Destroys an OH_RDB_TransOptions instance object. + * + * @param opitons Represents a pointer to an instance of OH_RDB_TransOptions. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_RdbTrans_DestroyOptions(OH_RDB_TransOptions *opitons); + +/** + * @brief Sets integer data to the opitons object. + * + * @param opitons Represents a pointer to an instance of OH_RDB_TransOptions. + * @param type Represents relation database transaction type. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_RdbTransOption_SetType(OH_RDB_TransOptions *opitons, OH_RDB_TransType type); + +/** + * @brief Commits a transaction of a relational database. + * + * @param trans Represents a pointer to an instance of OH_Rdb_Transaction. + * @return Returns the status code of the execution. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_ERROR} database common error. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_ALREADY_CLOSED} database already closed. + * Returns {@link RDB_E_SQLITE_FULL} SQLite: The database is full. + * Returns {@link RDB_E_SQLITE_CORRUPT} database corrupted. + * Returns {@link RDB_E_SQLITE_PERM} SQLite: Access permission denied. + * Returns {@link RDB_E_SQLITE_BUSY} SQLite: The database file is locked. + * Returns {@link RDB_E_SQLITE_NOMEM} SQLite: The database is out of memory. + * Returns {@link RDB_E_SQLITE_READONLY} SQLite: SQLite: Attempt to write a readonly database. + * Returns {@link RDB_E_SQLITE_IOERR} SQLite: Some kind of disk I/O error occurred. + * @since 16 + */ +int OH_RdbTrans_Commit(OH_Rdb_Transaction *trans); + +/** + * @brief Roll back a transaction of a relational database. + * + * @param trans Represents a pointer to an instance of OH_Rdb_Transaction. + * @return Returns the status code of the execution. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_ERROR} database common error. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_ALREADY_CLOSED} database already closed. + * Returns {@link RDB_E_SQLITE_FULL} SQLite: The database is full. + * Returns {@link RDB_E_SQLITE_CORRUPT} database corrupted. + * Returns {@link RDB_E_SQLITE_PERM} SQLite: Access permission denied. + * Returns {@link RDB_E_SQLITE_BUSY} SQLite: The database file is locked. + * Returns {@link RDB_E_SQLITE_NOMEM} SQLite: The database is out of memory. + * Returns {@link RDB_E_SQLITE_READONLY} SQLite: Attempt to write a readonly database. + * Returns {@link RDB_E_SQLITE_IOERR} SQLite: Some kind of disk I/O error occurred. + * @since 16 + */ +int OH_RdbTrans_Rollback(OH_Rdb_Transaction *trans); + +/** + * @brief Inserts a row of data into the target table. + * + * @param trans Represents a pointer to an instance of OH_Rdb_Transaction. + * @param table Represents the target table. + * @param row Represents the row data to be inserted into the table. + * @param rowId Represents row line number when insert successfully. + * @return Returns the status code of the execution. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_ERROR} database common error. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_ALREADY_CLOSED} database already closed. + * Returns {@link RDB_E_WAL_SIZE_OVER_LIMIT} the WAL file size over default limit. + * Returns {@link RDB_E_SQLITE_FULL} SQLite: The database is full. + * Returns {@link RDB_E_SQLITE_CORRUPT} database corrupted. + * Returns {@link RDB_E_SQLITE_PERM} SQLite: Access permission denied. + * Returns {@link RDB_E_SQLITE_BUSY} SQLite: The database file is locked. + * Returns {@link RDB_E_SQLITE_LOCKED} SQLite: A table in the database is locked. + * Returns {@link RDB_E_SQLITE_NOMEM} SQLite: The database is out of memory. + * Returns {@link RDB_E_SQLITE_READONLY} SQLite: Attempt to write a readonly database. + * Returns {@link RDB_E_SQLITE_IOERR} SQLite: Some kind of disk I/O error occurred. + * Returns {@link RDB_E_SQLITE_TOO_BIG} SQLite: TEXT or BLOB exceeds size limit. + * Returns {@link RDB_E_SQLITE_MISMATCH} SQLite: Data type mismatch. + + * @since 16 + */ +int OH_RdbTrans_Insert(OH_Rdb_Transaction *trans, const char *table, const OH_VBucket *row, int64_t *rowId); + +/** + * @brief Inserts a batch of data into the target table. + * + * @param trans Represents a pointer to an instance of OH_Rdb_Transaction. + * @param table Represents the target table. + * @param rows Represents the rows data to be inserted into the table. + * @param resolution Represents the resolution when conflict occurs. + * @param changes Represents the number of successful insertions. + * @return Returns the status code of the execution. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_ERROR} database common error. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_ALREADY_CLOSED} database already closed. + * Returns {@link RDB_E_WAL_SIZE_OVER_LIMIT} the WAL file size over default limit. + * Returns {@link RDB_E_SQLITE_FULL} SQLite: The database is full. + * Returns {@link RDB_E_SQLITE_CORRUPT} database corrupted. + * Returns {@link RDB_E_SQLITE_PERM} SQLite: Access permission denied. + * Returns {@link RDB_E_SQLITE_BUSY} SQLite: The database file is locked. + * Returns {@link RDB_E_SQLITE_LOCKED} SQLite: A table in the database is locked. + * Returns {@link RDB_E_SQLITE_NOMEM} SQLite: The database is out of memory. + * Returns {@link RDB_E_SQLITE_READONLY} SQLite: Attempt to write a readonly database. + * Returns {@link RDB_E_SQLITE_IOERR} SQLite: Some kind of disk I/O error occurred. + * Returns {@link RDB_E_SQLITE_TOO_BIG} SQLite: TEXT or BLOB exceeds size limit. + * Returns {@link RDB_E_SQLITE_MISMATCH} SQLite: Data type mismatch. + * Returns {@link RDB_E_SQLITE_CONSTRAINT} SQLite: Abort due to constraint violation. + * @since 16 + */ +int OH_RdbTrans_BatchInsert(OH_Rdb_Transaction *trans, const char *table, const OH_Data_VBuckets *rows, + Rdb_ConflictResolution resolution, int64_t *changes); + +/** + * @brief Updates data in the database based on specified conditions. + * + * @param trans Represents a pointer to an instance of OH_Rdb_Transaction. + * @param row Represents the row data to be updated into the table. + * @param predicates Represents the specified update condition by the instance object of OH_Predicates. + * @param changes Represents the number of successful insertions. + * @return Returns the status code of the execution. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_ERROR} database common error. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_ALREADY_CLOSED} database already closed. + * Returns {@link RDB_E_WAL_SIZE_OVER_LIMIT} the WAL file size over default limit. + * Returns {@link RDB_E_SQLITE_FULL} SQLite: The database is full. + * Returns {@link RDB_E_SQLITE_CORRUPT} database corrupted. + * Returns {@link RDB_E_SQLITE_PERM} SQLite: Access permission denied. + * Returns {@link RDB_E_SQLITE_BUSY} SQLite: The database file is locked. + * Returns {@link RDB_E_SQLITE_LOCKED} SQLite: A table in the database is locked. + * Returns {@link RDB_E_SQLITE_NOMEM} SQLite: The database is out of memory. + * Returns {@link RDB_E_SQLITE_READONLY} SQLite: Attempt to write a readonly database. + * Returns {@link RDB_E_SQLITE_IOERR} SQLite: Some kind of disk I/O error occurred. + * Returns {@link RDB_E_SQLITE_TOO_BIG} SQLite: TEXT or BLOB exceeds size limit. + * Returns {@link RDB_E_SQLITE_MISMATCH} SQLite: Data type mismatch. + * @since 16 + */ +int OH_RdbTrans_Update(OH_Rdb_Transaction *trans, const OH_VBucket *row, const OH_Predicates *predicates, + int64_t *changes); + +/** + * @brief Deletes data from the database based on specified conditions + * + * @param trans Represents a pointer to an instance of OH_Rdb_Transaction. + * @param predicates Represents the specified update condition by the instance object of OH_Predicates. + * @param changes Represents the number of successfully Deleted. + * @return Returns the status code of the execution. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_ERROR} database common error. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_ALREADY_CLOSED} database already closed. + * Returns {@link RDB_E_WAL_SIZE_OVER_LIMIT} the WAL file size over default limit. + * Returns {@link RDB_E_SQLITE_FULL} SQLite: The database is full. + * Returns {@link RDB_E_SQLITE_CORRUPT} database corrupted. + * Returns {@link RDB_E_SQLITE_PERM} SQLite: Access permission denied. + * Returns {@link RDB_E_SQLITE_BUSY} SQLite: The database file is locked. + * Returns {@link RDB_E_SQLITE_LOCKED} SQLite: A table in the database is locked. + * Returns {@link RDB_E_SQLITE_NOMEM} SQLite: The database is out of memory. + * Returns {@link RDB_E_SQLITE_READONLY} SQLite: Attempt to write a readonly database. + * Returns {@link RDB_E_SQLITE_IOERR} SQLite: Some kind of disk I/O error occurred. + * Returns {@link RDB_E_SQLITE_TOO_BIG} SQLite: TEXT or BLOB exceeds size limit. + * Returns {@link RDB_E_SQLITE_MISMATCH} SQLite: Data type mismatch. + * @since 16 + */ +int OH_RdbTrans_Delete(OH_Rdb_Transaction *trans, const OH_Predicates *predicates, int64_t *changes); + +/** + * @brief Queries data in the database based on specified conditions. + * + * @param trans Represents a pointer to an instance of OH_Rdb_Transaction. + * @param predicates Represents the specified update condition by the instance object of OH_Predicates. + * @param columns Represents the columns to query. If the value is empty array, the query applies to all columns. + * @param len Represents the number of columns elements. + * @return If the operation is successful, a pointer to the instance of the OH_Cursor structure is returned. + * If database has closed or the database does not respond, nullptr is returned. + * @since 16 + */ +OH_Cursor *OH_RdbTrans_Query(OH_Rdb_Transaction *trans, const OH_Predicates *predicates, const char *columns[], + int len); + +/** + * @brief Queries data in the database based on SQL statement. + * + * @param trans Represents a pointer to an instance of OH_Rdb_Transaction. + * @param sql Represents the SQL statement to execute. + * @param args Represents a pointer to an instance of OH_Data_Values and it is the selection arguments. + * @return If the operation is successful, a pointer to the instance of the OH_Cursor structure is returned. + * If database has closed or the database does not respond, nullptr is returned. + * @since 16 + */ +OH_Cursor *OH_RdbTrans_QuerySql(OH_Rdb_Transaction *trans, const char *sql, const OH_Data_Values *args); + +/** + * @brief Executes an SQL statement that contains specified parameters. + * + * @param trans Represents a pointer to an instance of OH_Rdb_Transaction. + * @param sql Represents the SQL statement to execute. + * @param args Represents the values of the parameters in the SQL statement. + * @param result Represents a pointer to OH_Data_Value instance when the execution is successful. + * The memory must be released through the OH_Value_Destroy interface after the use is complete. + * @return Returns the status code of the execution. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_ERROR} database common error. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_ALREADY_CLOSED} database already closed. + * Returns {@link RDB_E_WAL_SIZE_OVER_LIMIT} the WAL file size over default limit. + * Returns {@link RDB_E_SQLITE_FULL} SQLite: The database is full. + * Returns {@link RDB_E_SQLITE_CORRUPT} database corrupted. + * Returns {@link RDB_E_SQLITE_PERM} SQLite: Access permission denied. + * Returns {@link RDB_E_SQLITE_BUSY} SQLite: The database file is locked. + * Returns {@link RDB_E_SQLITE_LOCKED} SQLite: A table in the database is locked. + * Returns {@link RDB_E_SQLITE_NOMEM} SQLite: The database is out of memory. + * Returns {@link RDB_E_SQLITE_READONLY} SQLite: Attempt to write a readonly database. + * Returns {@link RDB_E_SQLITE_IOERR} SQLite: Some kind of disk I/O error occurred. + * Returns {@link RDB_E_SQLITE_TOO_BIG} SQLite: TEXT or BLOB exceeds size limit. + * Returns {@link RDB_E_SQLITE_MISMATCH} SQLite: Data type mismatch. + * @see OH_Value_Destroy. + * @since 16 + */ +int OH_RdbTrans_Execute(OH_Rdb_Transaction *trans, const char *sql, const OH_Data_Values *args, OH_Data_Value **result); + +/** + * @brief Destroys an OH_Rdb_Transaction instance object. + * + * @param trans Represents a pointer to an instance of OH_Rdb_Transaction. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * @since 16 + */ +int OH_RdbTrans_Destroy(OH_Rdb_Transaction *trans); + +#ifdef __cplusplus +}; +#endif +#endif // OH_RDB_TRANSACTION_H +/** @} */ diff --git a/relational_store/interfaces/ndk/include/oh_rdb_types.h b/relational_store/interfaces/ndk/include/oh_rdb_types.h new file mode 100644 index 0000000000000000000000000000000000000000..5080ae645fbcfbea0461c87fe3a07bed42855d64 --- /dev/null +++ b/relational_store/interfaces/ndk/include/oh_rdb_types.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025 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. + */ + +/** + * @addtogroup RDB + * @{ + * + * @brief The relational database (RDB) store manages data based on relational models. + * With the underlying SQLite database, the RDB store provides a complete mechanism for managing local databases. + * To satisfy different needs in complicated scenarios, the RDB store offers a series of APIs for performing operations + * such as adding, deleting, modifying, and querying data, and supports direct execution of SQL statements. + * + * @since 10 + */ + +/** + * @file oh_rdb_types.h + * + * @brief Provides type define related to the data value. + * + * @kit ArkData + * @library libnative_rdb_ndk.z.so + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * + * @since 16 + */ + +#ifndef OH_RDB_TYPES_H +#define OH_RDB_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Describe the security area of the database. + * + * @since 16 + */ +typedef enum Rdb_ConflictResolution { + /** + * @brief Implements no operation when conflict occurs. + */ + RDB_CONFLICT_NONE = 1, + /** + * @brief Implements rollback operation when conflict occurs. + */ + RDB_CONFLICT_ROLLBACK, + /** + * @brief Implements abort operation when conflict occurs. + */ + RDB_CONFLICT_ABORT, + /** + * @brief Implements fail operation when conflict occurs. + */ + RDB_CONFLICT_FAIL, + /** + * @brief Implements ignore operation when conflict occurs. + */ + RDB_CONFLICT_IGNORE, + /** + * @brief Implements replace operation when conflict occurs. + */ + RDB_CONFLICT_REPLACE, +} Rdb_ConflictResolution; + +#ifdef __cplusplus +}; +#endif +#endif +/** @} */ \ No newline at end of file diff --git a/relational_store/interfaces/ndk/include/oh_value_object.h b/relational_store/interfaces/ndk/include/oh_value_object.h index f8ddd1a6691917c54514a505cca3a43543df5dad..2db29f87a273e290c0216c65dca2e86c20a3bb39 100644 --- a/relational_store/interfaces/ndk/include/oh_value_object.h +++ b/relational_store/interfaces/ndk/include/oh_value_object.h @@ -37,7 +37,7 @@ * @since 10 */ -#include +#include #ifdef __cplusplus extern "C" { #endif diff --git a/relational_store/interfaces/ndk/include/oh_values_bucket.h b/relational_store/interfaces/ndk/include/oh_values_bucket.h index 932be9bc275886a2bd5390a39341fad6e9f701a9..faecc97e3e50c927e34d43afe8b4bcab84545651 100644 --- a/relational_store/interfaces/ndk/include/oh_values_bucket.h +++ b/relational_store/interfaces/ndk/include/oh_values_bucket.h @@ -169,6 +169,37 @@ int OH_VBucket_PutAsset(OH_VBucket *bucket, const char *field, Data_Asset *value * @since 11 */ int OH_VBucket_PutAssets(OH_VBucket *bucket, const char *field, Data_Asset **value, uint32_t count); + +/** + * @brief Put the float vector to the OH_VBucket object. + * + * @param bucket Represents a pointer to an {@link OH_VBucket} instance. + * @param field Represents the name of the column. + * @param vec Represents a pointer to float array. + * @param len Represents the size of float array. + * @return Returns the status code of the execution. + * {@link RDB_OK} - success. + * {@link RDB_E_INVALID_ARGS} - The error code for common invalid args. + * @see OH_VBucket. + * @since 16 + */ +int OH_VBucket_PutFloatVector(OH_VBucket *bucket, const char *field, const float *vec, size_t len); + +/** + * @brief Put the an integer of any length to the OH_VBucket object. + * + * @param bucket Represents a pointer to an {@link OH_VBucket} instance. + * @param field Represents the name of the column. + * @param sign Represents 0 is positive integer, 1 is negative integer. + * @param trueForm Represents a pointer to integer array. + * @param len Represents the size of integer array. + * @return Returns the status code of the execution. + * {@link RDB_OK} - success. + * {@link RDB_E_INVALID_ARGS} - The error code for common invalid args. + * @see OH_VBucket. + * @since 16 + */ +int OH_VBucket_PutUnlimitedInt(OH_VBucket *bucket, const char *field, int sign, const uint64_t *trueForm, size_t len); #ifdef __cplusplus }; #endif diff --git a/relational_store/interfaces/ndk/include/relational_store.h b/relational_store/interfaces/ndk/include/relational_store.h index da7f7f96736e26c2964b30c74ca3c4a803dfaa26..6eb5d353261e55062ec98bfac19f7883054025a8 100644 --- a/relational_store/interfaces/ndk/include/relational_store.h +++ b/relational_store/interfaces/ndk/include/relational_store.h @@ -41,6 +41,8 @@ #include "oh_predicates.h" #include "oh_value_object.h" #include "oh_values_bucket.h" +#include "oh_rdb_transaction.h" +#include "oh_rdb_types.h" #ifdef __cplusplus extern "C" { @@ -183,6 +185,26 @@ typedef enum Rdb_DBType { DBTYPE_BUTT = 64, } Rdb_DBType; +/** + * @brief Define Rdb_Tokenizer type. + * + * @since 16 + */ +typedef enum Rdb_Tokenizer { + /** + * @brief Means not using tokenizer. + */ + RDB_NONE_TOKENIZER = 1, + /** + * @brief Means using native icu tokenizer. + */ + RDB_ICU_TOKENIZER = 2, + /** + * @brief Means using self-developed enhance tokenizer. + */ + RDB_CUSTOM_TOKENIZER = 3, +} Rdb_Tokenizer; + /** * @brief Create OH_Rdb_ConfigV2 which is used to open store * @@ -308,6 +330,30 @@ int OH_Rdb_SetArea(OH_Rdb_ConfigV2 *config, int area); * @since 14 */ int OH_Rdb_SetDbType(OH_Rdb_ConfigV2 *config, int dbType); +/** + * @brief Check if a tokenizer is supported or not. + * + * @param tokenizer the tokenizer type of {@Link Rdb_Tokenizer}. + * @param isSupported Pointer to the Boolean value obtained. + * @return Returns the status code of the execution. + * {@link RDB_OK} indicates the operation is successful. + * {@link RDB_E_INVALID_ARGS} indicates invalid args are passed in. + * @since 16 + */ +int OH_Rdb_IsTokenizerSupported(Rdb_Tokenizer tokenizer, bool *isSupported); + + +/** + * @brief Set property tokenizer into config + * @param config Represents a pointer to {@link OH_Rdb_ConfigV2} instance. + * @param tokenizer Indicates the tokenizer {@link Rdb_Tokenizer} of the database + * @return Returns the status code of the execution. Successful execution returns RDB_OK, + * {@link RDB_OK} - success. + * {@link RDB_E_INVALID_ARGS} - The error code for common invalid args. + * {@link RDB_E_NOT_SUPPORTED} - The error code for not support tokenizer. + * @since 16 + */ +int OH_Rdb_SetTokenizer(OH_Rdb_ConfigV2 *config, Rdb_Tokenizer tokenizer); /** * @brief Get support db type list @@ -440,6 +486,36 @@ int OH_Rdb_DeleteStoreV2(const OH_Rdb_ConfigV2 *config); */ int OH_Rdb_Insert(OH_Rdb_Store *store, const char *table, OH_VBucket *valuesBucket); +/** + * @brief Inserts a batch of data into the target table. + * + * @param store Represents a pointer to an {@link OH_Rdb_Store} instance. + * @param table Represents the target table. + * @param rows Represents the rows data to be inserted into the table. + * @param resolution Represents the resolution when conflict occurs. + * @param changes Represents the number of successful insertions. + * @return Returns the status code of the execution. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_ERROR} database common error. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_ALREADY_CLOSED} database already closed. + * Returns {@link RDB_E_WAL_SIZE_OVER_LIMIT} the WAL file size over default limit. + * Returns {@link RDB_E_SQLITE_FULL} SQLite: The database is full. + * Returns {@link RDB_E_SQLITE_CORRUPT} database corrupted. + * Returns {@link RDB_E_SQLITE_PERM} SQLite: Access permission denied. + * Returns {@link RDB_E_SQLITE_BUSY} SQLite: The database file is locked. + * Returns {@link RDB_E_SQLITE_LOCKED} SQLite: A table in the database is locked. + * Returns {@link RDB_E_SQLITE_NOMEM} SQLite: The database is out of memory. + * Returns {@link RDB_E_SQLITE_READONLY} SQLite: Attempt to write a readonly database. + * Returns {@link RDB_E_SQLITE_IOERR} SQLite: Some kind of disk I/O error occurred. + * Returns {@link RDB_E_SQLITE_TOO_BIG} SQLite: TEXT or BLOB exceeds size limit. + * Returns {@link RDB_E_SQLITE_MISMATCH} SQLite: Data type mismatch. + * Returns {@link RDB_E_SQLITE_CONSTRAINT} SQLite: Abort due to constraint violation. + * @since 16 + */ +int OH_Rdb_BatchInsert(OH_Rdb_Store *store, const char *table, + const OH_Data_VBuckets *rows, Rdb_ConflictResolution resolution, int64_t *changes); + /** * @brief Updates data in the database based on specified conditions. * @@ -1244,6 +1320,75 @@ int OH_Rdb_UnlockRow(OH_Rdb_Store *store, OH_Predicates *predicates); */ OH_Cursor *OH_Rdb_QueryLockedRow( OH_Rdb_Store *store, OH_Predicates *predicates, const char *const *columnNames, int length); + +/** + * @brief Creates an OH_Rdb_Transaction instance object. + * + * @param store Represents a pointer to an instance of OH_Rdb_Store. + * @param options Represents a pointer to an instance of OH_RDB_TransOptions. + * @param trans Represents a pointer to OH_Rdb_Transaction instance when the execution is successful. + * Otherwise, nullptr is returned. The memory must be released through the OH_RdbTrans_Destroy + * interface after the use is complete. + * @return Returns the error code. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_ERROR} database common error. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_ALREADY_CLOSED} database already closed. + * Returns {@link RDB_E_DATABASE_BUSY} database does not respond. + * Returns {@link RDB_E_SQLITE_FULL} SQLite: The database is full. + * Returns {@link RDB_E_SQLITE_CORRUPT} database corrupted. + * Returns {@link RDB_E_SQLITE_PERM} SQLite: Access permission denied. + * Returns {@link RDB_E_SQLITE_BUSY} SQLite: The database file is locked. + * Returns {@link RDB_E_SQLITE_NOMEM} SQLite: The database is out of memory. + * Returns {@link RDB_E_SQLITE_IOERR} SQLite: Some kind of disk I/O error occurred. + * Returns {@link RDB_E_SQLITE_CANT_OPEN} SQLite: Unable to open the database file. + * @see OH_RdbTrans_Destroy. + * @since 16 + */ +int OH_Rdb_CreateTransaction(OH_Rdb_Store *store, const OH_RDB_TransOptions *options, OH_Rdb_Transaction **trans); + +/** + * @brief Executes an SQL statement. + * + * @param store Represents a pointer to an {@link OH_Rdb_Store} instance. + * @param sql Indicates the SQL statement to execute. + * @param args Represents the values of the parameters in the SQL statement. + * @param result Represents a pointer to OH_Data_Value instance when the execution is successful. + * The memory must be released through the OH_Value_Destroy interface after the use is complete. + * @return Returns the status code of the execution. + * Returns {@link RDB_OK} if the execution is successful. + * Returns {@link RDB_E_ERROR} database common error. + * Returns {@link RDB_E_INVALID_ARGS} if invalid input parameter. + * Returns {@link RDB_E_ALREADY_CLOSED} database already closed. + * Returns {@link RDB_E_WAL_SIZE_OVER_LIMIT} the WAL file size over default limit. + * Returns {@link RDB_E_SQLITE_FULL} SQLite: The database is full. + * Returns {@link RDB_E_SQLITE_CORRUPT} database corrupted. + * Returns {@link RDB_E_SQLITE_PERM} SQLite: Access permission denied. + * Returns {@link RDB_E_SQLITE_BUSY} SQLite: The database file is locked. + * Returns {@link RDB_E_SQLITE_LOCKED} SQLite: A table in the database is locked. + * Returns {@link RDB_E_SQLITE_NOMEM} SQLite: The database is out of memory. + * Returns {@link RDB_E_SQLITE_READONLY} SQLite: Attempt to write a readonly database. + * Returns {@link RDB_E_SQLITE_IOERR} SQLite: Some kind of disk I/O error occurred. + * Returns {@link RDB_E_SQLITE_TOO_BIG} SQLite: TEXT or BLOB exceeds size limit. + * Returns {@link RDB_E_SQLITE_MISMATCH} SQLite: Data type mismatch. + * @see OH_Value_Destroy. + * @since 16 + */ +int OH_Rdb_ExecuteV2(OH_Rdb_Store *store, const char *sql, const OH_Data_Values *args, OH_Data_Value **result); + +/** + * @brief Queries data in the database based on an SQL statement. + * + * @param store Represents a pointer to an {@link OH_Rdb_Store} instance. + * @param sql Indicates the SQL statement to execute. + * @param args Represents a pointer to an instance of OH_Data_Values and it is the selection arguments. + * @return If the query is successful, a pointer to the instance of the @link OH_Cursor} structure is returned. + * If sql statement is invalid or the memory allocate failed, nullptr is returned. + * @see OH_Rdb_Store. + * @since 16 + */ +OH_Cursor *OH_Rdb_ExecuteQueryV2(OH_Rdb_Store *store, const char *sql, const OH_Data_Values *args); + #ifdef __cplusplus }; #endif diff --git a/relational_store/interfaces/ndk/include/relational_store_error_code.h b/relational_store/interfaces/ndk/include/relational_store_error_code.h index d1318ec3e59a0a2d01905bf7073070b032beb5c8..ce09a43873b23f048dfcfdde9d37a2cd0a1d1f16 100644 --- a/relational_store/interfaces/ndk/include/relational_store_error_code.h +++ b/relational_store/interfaces/ndk/include/relational_store_error_code.h @@ -310,7 +310,119 @@ typedef enum OH_Rdb_ErrCode { /** * @brief The key parameter is invalid. */ - RDB_E_INVALID_SECRET_KEY = (E_BASE + 49) + RDB_E_INVALID_SECRET_KEY = (E_BASE + 49), + + /** + * @brief Database already closed. + * + * @since 16 + */ + RDB_E_ALREADY_CLOSED = (E_BASE + 50), + + /** + * @brief The database does not respond. + * + * @since 16 + */ + RDB_E_DATABASE_BUSY = (E_BASE + 51), + + /** + * @brief Database corrupted. + * + * @since 16 + */ + RDB_E_SQLITE_CORRUPT = (E_BASE + 52), + + /** + * @brief SQLite: Access permission denied. + * + * @since 16 + */ + RDB_E_SQLITE_PERM = (E_BASE + 53), + + /** + * @brief SQLite: The database file is locked. + * + * @since 16 + */ + RDB_E_SQLITE_BUSY = (E_BASE + 54), + + /** + * @brief SQLite: A table in the database is locked. + * + * @since 16 + */ + RDB_E_SQLITE_LOCKED = (E_BASE + 55), + + /** + * @brief SQLite: The database is out of memory. + * + * @since 16 + */ + RDB_E_SQLITE_NOMEM = (E_BASE + 56), + + /** + * @brief SQLite: Attempt to write a readonly database. + * + * @since 16 + */ + RDB_E_SQLITE_READONLY = (E_BASE + 57), + + /** + * @brief SQLite: Some kind of disk I/O error occurred. + * + * @since 16 + */ + RDB_E_SQLITE_IOERR = (E_BASE + 58), + + /** + * @brief SQLite: The database is full. + * + * @since 16 + */ + RDB_E_SQLITE_FULL = (E_BASE + 59), + + /** + * @brief SQLite: Unable to open the database file. + * + * @since 16 + */ + RDB_E_SQLITE_CANT_OPEN = (E_BASE + 60), + + /** + * @brief SQLite: TEXT or BLOB exceeds size limit. + * + * @since 16 + */ + RDB_E_SQLITE_TOO_BIG = (E_BASE + 61), + + /** + * @brief SQLite: Data type mismatch. + * + * @since 16 + */ + RDB_E_SQLITE_MISMATCH = (E_BASE + 62), + + /** + * @brief Data value type is null. + * + * @since 16 + */ + RDB_E_DATA_TYPE_NULL = (E_BASE + 63), + + /** + * @brief Data value type mismatch. + * + * @since 16 + */ + RDB_E_TYPE_MISMATCH = (E_BASE + 64), + + /** + * @brief Data value type is null. + * + * @since 16 + */ + RDB_E_SQLITE_CONSTRAINT = (E_BASE + 65), } OH_Rdb_ErrCode; #ifdef __cplusplus diff --git a/relational_store/interfaces/ndk/libnative_rdb.ndk.json b/relational_store/interfaces/ndk/libnative_rdb.ndk.json index 3bee76ad56c06f6c8080319846127266649f7cde..6c5479a425cb9bc4e3622bac344ed7e29c02fc11 100644 --- a/relational_store/interfaces/ndk/libnative_rdb.ndk.json +++ b/relational_store/interfaces/ndk/libnative_rdb.ndk.json @@ -44,5 +44,9 @@ {"name":"OH_Data_Asset_DestroyMultiple"}, {"name":"OH_Rdb_LockRow"}, {"name":"OH_Rdb_UnlockRow"}, - {"name":"OH_Rdb_QueryLockedRow"} + {"name":"OH_Rdb_QueryLockedRow"}, + {"name":"OH_Rdb_ExecuteV2"}, + {"name":"OH_Rdb_ExecuteQueryV2"}, + {"name":"OH_Cursor_GetFloatVectorCount"}, + {"name":"OH_Cursor_GetFloatVector"} ] \ No newline at end of file diff --git a/relational_store/interfaces/ndk/src/BUILD.gn b/relational_store/interfaces/ndk/src/BUILD.gn index cd526623aaa186d825801b34768551ef59512cab..9ce64297c43a634e087092728c919c7f5d2d3080 100644 --- a/relational_store/interfaces/ndk/src/BUILD.gn +++ b/relational_store/interfaces/ndk/src/BUILD.gn @@ -33,6 +33,11 @@ ohos_shared_library("native_rdb_ndk") { sources = [ "convertor_error_code.cpp", "modify_time_cursor.cpp", + "oh_data_utils.cpp", + "oh_data_value.cpp", + "oh_data_values.cpp", + "oh_data_values_buckets.cpp", + "oh_rdb_transaction.cpp", "relational_asset.cpp", "relational_cursor.cpp", "relational_predicates.cpp", diff --git a/relational_store/interfaces/ndk/src/convertor_error_code.cpp b/relational_store/interfaces/ndk/src/convertor_error_code.cpp index fed34adb35177f83eb531c22898a0ab303e8715e..2cddcfb737faeaddf4238c7204bfea7b044968fb 100644 --- a/relational_store/interfaces/ndk/src/convertor_error_code.cpp +++ b/relational_store/interfaces/ndk/src/convertor_error_code.cpp @@ -22,11 +22,6 @@ namespace OHOS::RdbNdk { -struct NdkErrorCode { - int nativeCode; - int ndkCode; -}; - static constexpr NdkErrorCode ERROR_CODE_MAP[] = { { OHOS::NativeRdb::E_OK, RDB_OK }, { OHOS::NativeRdb::E_ERROR, RDB_E_ERROR }, @@ -80,17 +75,50 @@ static constexpr NdkErrorCode ERROR_CODE_MAP[] = { { OHOS::NativeRdb::E_NOT_SUPPORT, RDB_E_NOT_SUPPORTED }, }; -int ConvertorErrorCode::NativeToNdk(int nativeErrCode) +static constexpr NdkErrorCode INTERFACE_CODE_MAP[] = { + { OHOS::NativeRdb::E_OK, RDB_OK }, + { OHOS::NativeRdb::E_ERROR, RDB_E_ERROR }, + { OHOS::NativeRdb::E_INVALID_ARGS, RDB_E_INVALID_ARGS }, + { OHOS::NativeRdb::E_INVALID_OBJECT_TYPE, RDB_E_INVALID_ARGS }, + { OHOS::NativeRdb::E_ALREADY_CLOSED, RDB_E_ALREADY_CLOSED}, + { OHOS::NativeRdb::E_DATABASE_BUSY, RDB_E_DATABASE_BUSY }, + { OHOS::NativeRdb::E_WAL_SIZE_OVER_LIMIT, RDB_E_WAL_SIZE_OVER_LIMIT }, + { OHOS::NativeRdb::E_SQLITE_FULL, RDB_E_SQLITE_FULL }, + { OHOS::NativeRdb::E_SQLITE_CORRUPT, RDB_E_SQLITE_CORRUPT }, + { OHOS::NativeRdb::E_SQLITE_PERM, RDB_E_SQLITE_PERM }, + { OHOS::NativeRdb::E_SQLITE_BUSY, RDB_E_SQLITE_BUSY }, + { OHOS::NativeRdb::E_SQLITE_LOCKED, RDB_E_SQLITE_LOCKED }, + { OHOS::NativeRdb::E_SQLITE_NOMEM, RDB_E_SQLITE_NOMEM }, + { OHOS::NativeRdb::E_SQLITE_READONLY, RDB_E_SQLITE_READONLY }, + { OHOS::NativeRdb::E_SQLITE_IOERR, RDB_E_SQLITE_IOERR }, + { OHOS::NativeRdb::E_SQLITE_CANTOPEN, RDB_E_SQLITE_CANT_OPEN }, + { OHOS::NativeRdb::E_SQLITE_TOOBIG, RDB_E_SQLITE_TOO_BIG }, + { OHOS::NativeRdb::E_SQLITE_CONSTRAINT, RDB_E_SQLITE_CONSTRAINT }, + { OHOS::NativeRdb::E_SQLITE_MISMATCH, RDB_E_SQLITE_MISMATCH }, + { OHOS::NativeRdb::E_SQLITE_IOERR_FULL, RDB_E_SQLITE_IOERR }, +}; + +int ConvertorErrorCode::ConvertCode(const NdkErrorCode *codeMap, int count, int innerCode) { - auto errorCode = NdkErrorCode{ nativeErrCode, -1 }; - auto iter = std::lower_bound(ERROR_CODE_MAP, ERROR_CODE_MAP + sizeof(ERROR_CODE_MAP) / sizeof(ERROR_CODE_MAP[0]), - errorCode, [](const NdkErrorCode &errorCode1, const NdkErrorCode &errorCode2) { + auto errorCode = NdkErrorCode{ innerCode, -1 }; + auto iter = std::lower_bound(codeMap, codeMap + count, errorCode, + [](const NdkErrorCode &errorCode1, const NdkErrorCode &errorCode2) { return errorCode1.nativeCode < errorCode2.nativeCode; }); - if (iter < ERROR_CODE_MAP + sizeof(ERROR_CODE_MAP) / sizeof(ERROR_CODE_MAP[0]) && - iter->nativeCode == nativeErrCode) { + if (iter < codeMap + count && iter->nativeCode == innerCode) { return iter->ndkCode; } return RDB_E_ERROR; } -} // namespace OHOS::RdbNdk \ No newline at end of file +int ConvertorErrorCode::NativeToNdk(int nativeErrCode) +{ + int count = static_cast(sizeof(ERROR_CODE_MAP) / sizeof(ERROR_CODE_MAP[0])); + return ConvertCode(ERROR_CODE_MAP, count, nativeErrCode); +} + +int ConvertorErrorCode::GetInterfaceCode(int nativeErrCode) +{ + int count = static_cast(sizeof(INTERFACE_CODE_MAP) / sizeof(INTERFACE_CODE_MAP[0])); + return ConvertCode(INTERFACE_CODE_MAP, count, nativeErrCode); +} +} \ No newline at end of file diff --git a/relational_store/interfaces/ndk/src/convertor_error_code.h b/relational_store/interfaces/ndk/src/convertor_error_code.h index a8c992a7d2fd5664a65e293ae55999b5a13572de..aa596ffbf090af4616aa95f202e2fabec27a249e 100644 --- a/relational_store/interfaces/ndk/src/convertor_error_code.h +++ b/relational_store/interfaces/ndk/src/convertor_error_code.h @@ -15,6 +15,11 @@ #ifndef CONVERATOR_ERROR_CODE_H #define CONVERATOR_ERROR_CODE_H namespace OHOS::RdbNdk { + +struct NdkErrorCode { + int nativeCode; + int ndkCode; +}; class ConvertorErrorCode final { private: ConvertorErrorCode() = default; @@ -22,6 +27,9 @@ private: public: static int NativeToNdk(int nativeErrCode); + static int GetInterfaceCode(int nativeErrCode); +private: + static int ConvertCode(const NdkErrorCode *codeMap, int count, int innerCode); }; } // namespace OHOS::RdbNdk #endif // CONVERATOR_ERROR_CODE_H \ No newline at end of file diff --git a/relational_store/interfaces/ndk/src/oh_data_define.h b/relational_store/interfaces/ndk/src/oh_data_define.h new file mode 100644 index 0000000000000000000000000000000000000000..425b9412d40f0b68bc8a385159a33fdef05841c3 --- /dev/null +++ b/relational_store/interfaces/ndk/src/oh_data_define.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024 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 OH_DATA_DEFINE_H +#define OH_DATA_DEFINE_H + +#include +#include "value_object.h" +#include "oh_values_bucket.h" +#include "transaction.h" +#include "oh_predicates.h" +#include "oh_rdb_transaction.h" + +struct OH_Rdb_Transaction { + static constexpr int64_t OH_RDB_TRANS_ID = 0x10000000; + int64_t id = OH_RDB_TRANS_ID; + + std::shared_ptr trans_; + bool IsValid() const; +}; + +struct OH_RDB_TransOptions { + static constexpr int64_t OH_TRANS_OPTION_ID = 0x10001000; + int64_t id = OH_TRANS_OPTION_ID; + + OH_RDB_TransType type_; + bool IsValid() const; +}; + +struct OH_Data_Value { + static constexpr int64_t OH_VALUE_ID = 0x10002000; + int64_t id = OH_VALUE_ID; + + OHOS::NativeRdb::ValueObject value_; + bool IsValid() const; +}; + +struct OH_Data_Values { + static constexpr int64_t OH_VALUES_ID = 0x10003000; + int64_t id = OH_VALUES_ID; + + std::vector values_; + bool IsValid() const; +}; + +struct OH_Data_VBuckets { + static constexpr int64_t OH_VBUCKETS_ID = 0x10004000; + int64_t id = OH_VBUCKETS_ID; + + std::vector rows_; + bool IsValid() const; +}; +#endif diff --git a/relational_store/interfaces/ndk/src/oh_data_utils.cpp b/relational_store/interfaces/ndk/src/oh_data_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3166aeeeaff299ebc9647f3a9c7cbe05f51ffaf0 --- /dev/null +++ b/relational_store/interfaces/ndk/src/oh_data_utils.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 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 "oh_data_utils.h" + +namespace OHOS::RdbNdk { +NativeRdb::ConflictResolution Utils::ConvertConflictResolution(Rdb_ConflictResolution resolution) +{ + switch (resolution) { + case RDB_CONFLICT_NONE: + return NativeRdb::ConflictResolution::ON_CONFLICT_NONE; + case RDB_CONFLICT_ROLLBACK: + return NativeRdb::ConflictResolution::ON_CONFLICT_ROLLBACK; + case RDB_CONFLICT_ABORT: + return NativeRdb::ConflictResolution::ON_CONFLICT_ABORT; + case RDB_CONFLICT_FAIL: + return NativeRdb::ConflictResolution::ON_CONFLICT_FAIL; + case RDB_CONFLICT_IGNORE: + return NativeRdb::ConflictResolution::ON_CONFLICT_IGNORE; + case RDB_CONFLICT_REPLACE: + return NativeRdb::ConflictResolution::ON_CONFLICT_REPLACE; + default: + return NativeRdb::ConflictResolution::ON_CONFLICT_NONE; + } +} +} // namespace OHOS::RdbNdk \ No newline at end of file diff --git a/relational_store/interfaces/ndk/src/oh_data_utils.h b/relational_store/interfaces/ndk/src/oh_data_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..29813f8123be3b8ff99407da7f43e8ce6602673a --- /dev/null +++ b/relational_store/interfaces/ndk/src/oh_data_utils.h @@ -0,0 +1,25 @@ +/* +* Copyright (c) 2025 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 OH_DATA_UTILS_H +#define OH_DATA_UTILS_H +#include "oh_rdb_types.h" +#include "rdb_common.h" +namespace OHOS::RdbNdk { +class Utils { +public: + static NativeRdb::ConflictResolution ConvertConflictResolution(Rdb_ConflictResolution resolution); +}; +} // namespace OHOS::RdbNdk +#endif // OH_DATA_UTILS_H \ No newline at end of file diff --git a/relational_store/interfaces/ndk/src/oh_data_value.cpp b/relational_store/interfaces/ndk/src/oh_data_value.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c2993bb2578976087fae465f6b877578ea3399a --- /dev/null +++ b/relational_store/interfaces/ndk/src/oh_data_value.cpp @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2024 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 "DataValue" + +#include "oh_data_value.h" +#include "oh_data_define.h" +#include "relational_store_error_code.h" +#include "relational_asset.h" +#include "logger.h" + +using namespace OHOS::RdbNdk; +using namespace OHOS::NativeRdb; + +constexpr int32_t TO_OH_TYPE[] = { + OH_ColumnType::TYPE_NULL, + OH_ColumnType::TYPE_INT64, + OH_ColumnType::TYPE_REAL, + OH_ColumnType::TYPE_TEXT, + OH_ColumnType::TYPE_INT64, + OH_ColumnType::TYPE_BLOB, + OH_ColumnType::TYPE_ASSET, + OH_ColumnType::TYPE_ASSETS, + OH_ColumnType::TYPE_FLOAT_VECTOR, + OH_ColumnType::TYPE_UNLIMITED_INT, +}; + +static constexpr int32_t TO_OH_TYPE_SIZE = sizeof(TO_OH_TYPE) / sizeof(TO_OH_TYPE[0]); + +static int CheckValueType(const OH_Data_Value *value, int32_t type) +{ + if (value == nullptr || !value->IsValid()) { + return RDB_E_INVALID_ARGS; + } + int32_t valueType = value->value_.GetType(); + if (valueType == ValueObject::TYPE_NULL && type == ValueObject::TYPE_NULL) { + return RDB_OK; + } + if (valueType == ValueObject::TYPE_NULL) { + LOG_ERROR("type mismatch, value type is null, get type=%{public}d", type); + return RDB_E_DATA_TYPE_NULL; + } + if (valueType != type) { + LOG_ERROR("type mismatch, value type=%{public}d, get type=%{public}d", valueType, type); + return RDB_E_TYPE_MISMATCH; + } + return RDB_OK; +} + +OH_Data_Value *OH_Value_Create() +{ + OH_Data_Value *value = new (std::nothrow) OH_Data_Value; + if (value == nullptr) { + return nullptr; + } + return value; +} + +int OH_Value_Destroy(OH_Data_Value *value) +{ + if (value == nullptr || !value->IsValid()) { + return RDB_E_INVALID_ARGS; + } + delete value; + return RDB_OK; +} + +int OH_Value_PutNull(OH_Data_Value *value) +{ + if (value == nullptr || !value->IsValid()) { + return RDB_E_INVALID_ARGS; + } + value->value_.value = ValueObject::Nil{}; + return RDB_OK; +} + +int OH_Value_PutInt(OH_Data_Value *value, int64_t val) +{ + if (value == nullptr || !value->IsValid()) { + return RDB_E_INVALID_ARGS; + } + value->value_.value = val; + return RDB_OK; +} + +int OH_Value_PutReal(OH_Data_Value *value, double val) +{ + if (value == nullptr || !value->IsValid()) { + return RDB_E_INVALID_ARGS; + } + value->value_.value = val; + return RDB_OK; +} + +int OH_Value_PutText(OH_Data_Value *value, const char *val) +{ + if (value == nullptr || !value->IsValid()) { + return RDB_E_INVALID_ARGS; + } + value->value_.value = std::string(val); + return RDB_OK; +} + +int OH_Value_PutBlob(OH_Data_Value *value, const unsigned char *val, size_t length) +{ + if (value == nullptr || !value->IsValid() || val == nullptr) { + return RDB_E_INVALID_ARGS; + } + value->value_.value = std::vector{ val, val + length }; + return RDB_OK; +} + +int OH_Value_PutAsset(OH_Data_Value *value, const Data_Asset *val) +{ + if (value == nullptr || !value->IsValid() || val == nullptr) { + return RDB_E_INVALID_ARGS; + } + value->value_.value = val->asset_; + return RDB_OK; +} + +int OH_Value_PutAssets(OH_Data_Value *value, const Data_Asset * const * val, size_t length) +{ + if (value == nullptr || !value->IsValid() || val == nullptr || length == 0) { + return RDB_E_INVALID_ARGS; + } + ValueObject::Assets assets; + for (size_t i = 0; i < length; i++) { + if (val[i] != nullptr) { + assets.push_back(val[i]->asset_); + } + } + value->value_.value = assets; + return RDB_OK; +} + +int OH_Value_PutFloatVector(OH_Data_Value *value, const float *val, size_t length) +{ + if (value == nullptr || !value->IsValid() || val == nullptr) { + return RDB_E_INVALID_ARGS; + } + std::vector valVec = std::vector{ val, val + length }; + value->value_.value = valVec; + return RDB_OK; +} + +int OH_Value_PutUnlimitedInt(OH_Data_Value *value, int sign, const uint64_t *trueForm, size_t length) +{ + if (value == nullptr || !value->IsValid() || (sign != 0 && sign != 1) || trueForm == nullptr) { + return RDB_E_INVALID_ARGS; + } + ValueObject::BigInt bigNumber(sign, {trueForm, trueForm + length}); + value->value_.value = bigNumber; + return RDB_OK; +} + +int OH_Value_GetType(OH_Data_Value *value, OH_ColumnType *type) +{ + if (value == nullptr || !value->IsValid() || type == nullptr) { + return RDB_E_INVALID_ARGS; + } + auto valueType = value->value_.GetType(); + if (valueType < TO_OH_TYPE_SIZE) { + *type = static_cast(TO_OH_TYPE[valueType]); + return RDB_OK; + } + return RDB_E_INVALID_ARGS; +} + +int OH_Value_IsNull(OH_Data_Value *value, bool *val) +{ + if (value == nullptr || !value->IsValid() || val == nullptr) { + return RDB_E_INVALID_ARGS; + } + *val = (value->value_.GetType() == ValueObject::TYPE_NULL); + return RDB_OK; +} + +int OH_Value_GetInt(OH_Data_Value *value, int64_t *val) +{ + if (val == nullptr) { + return RDB_E_INVALID_ARGS; + } + int checkRet = CheckValueType(value, ValueObject::TYPE_INT); + if (checkRet != RDB_OK) { + return checkRet; + } + *val = value->value_; + return RDB_OK; +} + +int OH_Value_GetReal(OH_Data_Value *value, double *val) +{ + if (val == nullptr) { + return RDB_E_INVALID_ARGS; + } + int checkRet = CheckValueType(value, ValueObject::TYPE_DOUBLE); + if (checkRet != RDB_OK) { + return checkRet; + } + *val = value->value_; + return RDB_OK; +} + +int OH_Value_GetText(OH_Data_Value *value, const char **val) +{ + if (val == nullptr) { + return RDB_E_INVALID_ARGS; + } + int checkRet = CheckValueType(value, ValueObject::TYPE_STRING); + if (checkRet != RDB_OK) { + return checkRet; + } + auto actualValue = std::get_if(&value->value_.value); + if (actualValue == nullptr) { + return RDB_E_TYPE_MISMATCH; + } + *val = actualValue->c_str(); + return RDB_OK; +} + +int OH_Value_GetBlob(OH_Data_Value *value, const uint8_t **val, size_t *length) +{ + if (val == nullptr || length == nullptr) { + return RDB_E_INVALID_ARGS; + } + int checkRet = CheckValueType(value, ValueObject::TYPE_BLOB); + if (checkRet != RDB_OK) { + return checkRet; + } + auto actualValue = std::get_if>(&value->value_.value); + if (actualValue == nullptr) { + return RDB_E_TYPE_MISMATCH; + } + *val = actualValue->data(); + *length = actualValue->size(); + return RDB_OK; +} + +int OH_Value_GetAsset(OH_Data_Value *value, Data_Asset *val) +{ + if (val == nullptr) { + return RDB_E_INVALID_ARGS; + } + int checkRet = CheckValueType(value, ValueObject::TYPE_ASSET); + if (checkRet != RDB_OK) { + return checkRet; + } + val->asset_ = std::get(value->value_.value); + return RDB_OK; +} + +int OH_Value_GetAssetsCount(OH_Data_Value *value, size_t *size) +{ + if (size == nullptr) { + return RDB_E_INVALID_ARGS; + } + int checkRet = CheckValueType(value, ValueObject::TYPE_ASSETS); + if (checkRet != RDB_OK) { + return checkRet; + } + *size = std::get(value->value_.value).size(); + return RDB_OK; +} + +int OH_Value_GetAssets(OH_Data_Value *value, Data_Asset **val, size_t inLen, size_t *outLen) +{ + if (val == nullptr || outLen == nullptr) { + return RDB_E_INVALID_ARGS; + } + int checkRet = CheckValueType(value, ValueObject::TYPE_ASSETS); + if (checkRet != RDB_OK) { + return checkRet; + } + for (size_t i = 0; i < inLen; i++) { + if (val[i] == nullptr || val[i]->cid != DATA_ASSET_V0) { + return RDB_E_INVALID_ARGS; + } + } + + auto asserts = std::get(value->value_.value); + *outLen = 0; + for (size_t i = 0; i < inLen && i < asserts.size(); i++) { + if (val[i] != nullptr) { + val[i]->asset_ = asserts[i]; + (*outLen)++; + } + } + return RDB_OK; +} + +int OH_Value_GetFloatVectorCount(OH_Data_Value *value, size_t *length) +{ + if (length == nullptr) { + return RDB_E_INVALID_ARGS; + } + int checkRet = CheckValueType(value, ValueObject::TYPE_VECS); + if (checkRet != RDB_OK) { + return checkRet; + } + *length = std::get(value->value_.value).size(); + return RDB_OK; +} + +int OH_Value_GetFloatVector(OH_Data_Value *value, float *val, size_t inLen, size_t *outLen) +{ + if (val == nullptr || inLen == 0 || outLen == nullptr) { + return RDB_E_INVALID_ARGS; + } + int checkRet = CheckValueType(value, ValueObject::TYPE_VECS); + if (checkRet != RDB_OK) { + return checkRet; + } + auto floatVec = std::get(value->value_.value); + *outLen = 0; + for (size_t i = 0; i < floatVec.size() && i < inLen; i++) { + val[i] = floatVec[i]; + (*outLen)++; + } + return RDB_OK; +} + +int OH_Value_GetUnlimitedIntBand(OH_Data_Value *value, size_t *length) +{ + if (length == nullptr) { + return RDB_E_INVALID_ARGS; + } + int checkRet = CheckValueType(value, ValueObject::TYPE_BIGINT); + if (checkRet != RDB_OK) { + return checkRet; + } + *length = std::get(value->value_.value).Size(); + return RDB_OK; +} + +int OH_Value_GetUnlimitedInt(OH_Data_Value *value, int *sign, uint64_t *trueForm, size_t inLen, size_t *outLen) +{ + if (sign == nullptr || trueForm == nullptr || inLen == 0 || outLen == nullptr) { + return RDB_E_INVALID_ARGS; + } + int checkRet = CheckValueType(value, ValueObject::TYPE_BIGINT); + if (checkRet != RDB_OK) { + return checkRet; + } + auto bigInt = std::get(value->value_.value); + if (inLen < bigInt.Size()) { + return RDB_E_INVALID_ARGS; + } + auto numVec = bigInt.Value(); + *outLen = 0; + for (size_t i = 0; i < numVec.size(); i++) { + trueForm[i] = numVec[i]; + (*outLen)++; + } + *sign = bigInt.Sign(); + return RDB_OK; +} + +bool OH_Data_Value::IsValid() const +{ + return id == OH_VALUE_ID; +} \ No newline at end of file diff --git a/relational_store/interfaces/ndk/src/oh_data_values.cpp b/relational_store/interfaces/ndk/src/oh_data_values.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e284bb4d05ba2faf055bf423c37e5d57109dca84 --- /dev/null +++ b/relational_store/interfaces/ndk/src/oh_data_values.cpp @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2024 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 "DataValues" + +#include "oh_data_values.h" +#include "oh_data_define.h" +#include "relational_store_error_code.h" +#include "logger.h" + +using namespace OHOS::RdbNdk; + +static bool IsValidValues(const OH_Data_Values *values) +{ + if (values == nullptr) { + LOG_ERROR("values is null."); + return false; + } + bool ret = values->IsValid(); + if (!ret) { + LOG_ERROR("invalid data values object."); + } + return ret; +} + +static bool IsValidValuesElement(OH_Data_Values *values, int index) +{ + if (!IsValidValues(values) || index < 0 || static_cast(index) >= values->values_.size()) { + return false; + } + return true; +} + +OH_Data_Values *OH_Values_Create() +{ + OH_Data_Values *values = new (std::nothrow) OH_Data_Values; + return values; +} + +int OH_Values_Destroy(OH_Data_Values *values) +{ + if (!IsValidValues(values)) { + return RDB_E_INVALID_ARGS; + } + delete values; + return RDB_OK; +} + +int OH_Values_Put(OH_Data_Values *values, const OH_Data_Value *val) +{ + if (!IsValidValues(values) || (val == nullptr) || !val->IsValid()) { + return RDB_E_INVALID_ARGS; + } + values->values_.push_back(*val); + return RDB_OK; +} + +int OH_Values_PutNull(OH_Data_Values *values) +{ + if (!IsValidValues(values)) { + return RDB_E_INVALID_ARGS; + } + OH_Data_Value nullValue; + int ret = OH_Value_PutNull(&nullValue); + if (ret != RDB_OK) { + return ret; + } + values->values_.push_back(nullValue); + return RDB_OK; +} + +int OH_Values_PutInt(OH_Data_Values *values, int64_t val) +{ + if (!IsValidValues(values)) { + return RDB_E_INVALID_ARGS; + } + OH_Data_Value intValue; + int ret = OH_Value_PutInt(&intValue, val); + if (ret != RDB_OK) { + return ret; + } + values->values_.push_back(intValue); + return RDB_OK; +} + +int OH_Values_PutReal(OH_Data_Values *values, double val) +{ + if (!IsValidValues(values)) { + return RDB_E_INVALID_ARGS; + } + OH_Data_Value realValue; + int ret = OH_Value_PutReal(&realValue, val); + if (ret != RDB_OK) { + return ret; + } + values->values_.push_back(realValue); + return RDB_OK; +} + +int OH_Values_PutText(OH_Data_Values *values, const char *val) +{ + if (!IsValidValues(values)) { + return RDB_E_INVALID_ARGS; + } + OH_Data_Value textValue; + int ret = OH_Value_PutText(&textValue, val); + if (ret != RDB_OK) { + return ret; + } + values->values_.push_back(textValue); + return RDB_OK; +} + +int OH_Values_PutBlob(OH_Data_Values *values, const unsigned char *val, size_t length) +{ + if (!IsValidValues(values)) { + return RDB_E_INVALID_ARGS; + } + OH_Data_Value blobValue; + int ret = OH_Value_PutBlob(&blobValue, val, length); + if (ret != RDB_OK) { + return ret; + } + values->values_.push_back(blobValue); + return RDB_OK; +} + +int OH_Values_PutAsset(OH_Data_Values *values, const Data_Asset *val) +{ + if (!IsValidValues(values)) { + return RDB_E_INVALID_ARGS; + } + OH_Data_Value assetValue; + int ret = OH_Value_PutAsset(&assetValue, val); + if (ret != RDB_OK) { + return ret; + } + values->values_.push_back(assetValue); + return RDB_OK; +} + +int OH_Values_PutAssets(OH_Data_Values *values, const Data_Asset * const * val, size_t length) +{ + if (!IsValidValues(values)) { + return RDB_E_INVALID_ARGS; + } + OH_Data_Value assetsValue; + int ret = OH_Value_PutAssets(&assetsValue, val, length); + if (ret != RDB_OK) { + return ret; + } + values->values_.push_back(assetsValue); + return RDB_OK; +} + +int OH_Values_PutFloatVector(OH_Data_Values *values, const float *val, size_t length) +{ + if (!IsValidValues(values)) { + return RDB_E_INVALID_ARGS; + } + OH_Data_Value floatVectorValue; + int ret = OH_Value_PutFloatVector(&floatVectorValue, val, length); + if (ret != RDB_OK) { + return ret; + } + values->values_.push_back(floatVectorValue); + return RDB_OK; +} + +int OH_Values_PutUnlimitedInt(OH_Data_Values *values, int sign, const uint64_t *trueForm, size_t length) +{ + if (!IsValidValues(values)) { + return RDB_E_INVALID_ARGS; + } + OH_Data_Value unlimitedIntValue; + int ret = OH_Value_PutUnlimitedInt(&unlimitedIntValue, sign, trueForm, length); + if (ret != RDB_OK) { + return ret; + } + values->values_.push_back(unlimitedIntValue); + return RDB_OK; +} + +int OH_Values_Count(OH_Data_Values *values, size_t *count) +{ + if (!IsValidValues(values) || count == nullptr) { + return RDB_E_INVALID_ARGS; + } + *count = values->values_.size(); + return RDB_OK; +} + +int OH_Values_GetType(OH_Data_Values *values, int index, OH_ColumnType *type) +{ + if (!IsValidValuesElement(values, index)) { + return RDB_E_INVALID_ARGS; + } + return OH_Value_GetType(&values->values_[index], type); +} + +int OH_Values_Get(OH_Data_Values *values, int index, OH_Data_Value **val) +{ + if (!IsValidValuesElement(values, index) || val == nullptr) { + return RDB_E_INVALID_ARGS; + } + *val = &values->values_[index]; + return RDB_OK; +} + +int OH_Values_IsNull(OH_Data_Values *values, int index, bool *val) +{ + if (!IsValidValuesElement(values, index)) { + return RDB_E_INVALID_ARGS; + } + return OH_Value_IsNull(&values->values_[index], val); +} + +int OH_Values_GetInt(OH_Data_Values *values, int index, int64_t *val) +{ + if (!IsValidValuesElement(values, index)) { + return RDB_E_INVALID_ARGS; + } + return OH_Value_GetInt(&values->values_[index], val); +} + +int OH_Values_GetReal(OH_Data_Values *values, int index, double *val) +{ + if (!IsValidValuesElement(values, index)) { + return RDB_E_INVALID_ARGS; + } + return OH_Value_GetReal(&values->values_[index], val); +} + +int OH_Values_GetText(OH_Data_Values *values, int index, const char **val) +{ + if (!IsValidValuesElement(values, index)) { + return RDB_E_INVALID_ARGS; + } + return OH_Value_GetText(&values->values_[index], val); +} + +int OH_Values_GetBlob(OH_Data_Values *values, int index, const uint8_t **val, size_t *length) +{ + if (!IsValidValuesElement(values, index)) { + return RDB_E_INVALID_ARGS; + } + return OH_Value_GetBlob(&values->values_[index], val, length); +} + +int OH_Values_GetAsset(OH_Data_Values *values, int index, Data_Asset *val) +{ + if (!IsValidValuesElement(values, index)) { + return RDB_E_INVALID_ARGS; + } + return OH_Value_GetAsset(&values->values_[index], val); +} + +int OH_Values_GetAssetsCount(OH_Data_Values *values, int index, size_t *length) +{ + if (!IsValidValuesElement(values, index)) { + return RDB_E_INVALID_ARGS; + } + return OH_Value_GetAssetsCount(&values->values_[index], length); +} + +int OH_Values_GetAssets(OH_Data_Values *values, int index, Data_Asset **val, size_t inLen, size_t *outLen) +{ + if (!IsValidValuesElement(values, index)) { + return RDB_E_INVALID_ARGS; + } + return OH_Value_GetAssets(&values->values_[index], val, inLen, outLen); +} + +int OH_Values_GetFloatVectorCount(OH_Data_Values *values, int index, size_t *length) +{ + if (!IsValidValuesElement(values, index)) { + return RDB_E_INVALID_ARGS; + } + return OH_Value_GetFloatVectorCount(&values->values_[index], length); +} + +int OH_Values_GetFloatVector(OH_Data_Values *values, int index, float *val, size_t inLen, size_t *outLen) +{ + if (!IsValidValuesElement(values, index)) { + return RDB_E_INVALID_ARGS; + } + return OH_Value_GetFloatVector(&values->values_[index], val, inLen, outLen); +} + +int OH_Values_GetUnlimitedIntBand(OH_Data_Values *values, int index, size_t *length) +{ + if (!IsValidValuesElement(values, index)) { + return RDB_E_INVALID_ARGS; + } + return OH_Value_GetUnlimitedIntBand(&values->values_[index], length); +} + +int OH_Values_GetUnlimitedInt(OH_Data_Values *values, int index, int *sign, uint64_t *trueForm, size_t inLen, + size_t *outLen) +{ + if (!IsValidValuesElement(values, index)) { + return RDB_E_INVALID_ARGS; + } + return OH_Value_GetUnlimitedInt(&values->values_[index], sign, trueForm, inLen, outLen); +} + +bool OH_Data_Values::IsValid() const +{ + return id == OH_VALUES_ID; +} \ No newline at end of file diff --git a/relational_store/interfaces/ndk/src/oh_data_values_buckets.cpp b/relational_store/interfaces/ndk/src/oh_data_values_buckets.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1bdf1fc86fb207291f71b6fb8264cadc740d8b9 --- /dev/null +++ b/relational_store/interfaces/ndk/src/oh_data_values_buckets.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2024 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 "DataVBuckets" +#include "oh_data_values_buckets.h" +#include "relational_store_error_code.h" +#include "relational_values_bucket.h" +#include "oh_data_define.h" +#include "logger.h" + +using namespace OHOS::RdbNdk; + +static bool IsValidVBuckets(const OH_Data_VBuckets *vbuckets) +{ + if (vbuckets == nullptr) { + LOG_ERROR("vbuckets is null."); + return false; + } + bool ret = vbuckets->IsValid(); + if (!ret) { + LOG_ERROR("invalid data value buckets object."); + } + return ret; +} + +OH_Data_VBuckets *OH_VBuckets_Create() +{ + OH_Data_VBuckets *vbuckets = new (std::nothrow) OH_Data_VBuckets; + if (vbuckets == nullptr) { + LOG_ERROR("create vbuckets fail."); + } + return vbuckets; +} + +int OH_VBuckets_Destroy(OH_Data_VBuckets *buckets) +{ + if (!IsValidVBuckets(buckets)) { + return RDB_E_INVALID_ARGS; + } + delete buckets; + return RDB_OK; +} + +int OH_VBuckets_PutRow(OH_Data_VBuckets *buckets, const OH_VBucket *row) +{ + if (!IsValidVBuckets(buckets) || RelationalValuesBucket::GetSelf(const_cast(row)) == nullptr) { + return RDB_E_INVALID_ARGS; + } + buckets->rows_.push_back(const_cast(row)); + return RDB_OK; +} + +int OH_VBuckets_PutRows(OH_Data_VBuckets *buckets, const OH_Data_VBuckets *rows) +{ + if (!IsValidVBuckets(buckets) || !IsValidVBuckets(rows)) { + return RDB_E_INVALID_ARGS; + } + buckets->rows_.insert(buckets->rows_.end(), rows->rows_.begin(), rows->rows_.end()); + return RDB_OK; +} + +int OH_VBuckets_RowCount(OH_Data_VBuckets *buckets, size_t *count) +{ + if (!IsValidVBuckets(buckets) || count == nullptr) { + return RDB_E_INVALID_ARGS; + } + *count = buckets->rows_.size(); + return RDB_OK; +} + +bool OH_Data_VBuckets::IsValid() const +{ + return id == OH_VBUCKETS_ID; +} \ No newline at end of file diff --git a/relational_store/interfaces/ndk/src/oh_rdb_transaction.cpp b/relational_store/interfaces/ndk/src/oh_rdb_transaction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9e383763d1c60d0b98031d89d81b94fbfa125a99 --- /dev/null +++ b/relational_store/interfaces/ndk/src/oh_rdb_transaction.cpp @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2024 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 "RdbTransaction" + +#include "oh_rdb_transaction.h" +#include "oh_data_define.h" +#include "oh_data_utils.h" +#include "relational_values_bucket.h" +#include "relational_store_error_code.h" +#include "convertor_error_code.h" +#include "relational_predicates.h" +#include "relational_cursor.h" +#include "logger.h" + +using namespace OHOS::RdbNdk; +using namespace OHOS::NativeRdb; + +static bool IsValidRdbTransOptions(const OH_RDB_TransOptions *options) +{ + if (options == nullptr) { + LOG_ERROR("options is null"); + return false; + } + bool ret = options->IsValid(); + if (!ret) { + LOG_ERROR("invalid transaction options object."); + } + return ret; +} + +OH_RDB_TransOptions *OH_RdbTrans_CreateOptions() +{ + OH_RDB_TransOptions *value = new (std::nothrow) OH_RDB_TransOptions; + if (value == nullptr) { + LOG_ERROR("new OH_RDB_TransOptions failed."); + return nullptr; + } + value->type_ = RDB_TRANS_DEFERRED; + return value; +} + +int OH_RdbTrans_DestroyOptions(OH_RDB_TransOptions *opitons) +{ + if (!IsValidRdbTransOptions(opitons)) { + return RDB_E_INVALID_ARGS; + } + delete opitons; + return RDB_OK; +} + +int OH_RdbTransOption_SetType(OH_RDB_TransOptions *opitons, OH_RDB_TransType type) +{ + if (!IsValidRdbTransOptions(opitons) || type < RDB_TRANS_DEFERRED || type >= RDB_TRANS_BUTT) { + LOG_ERROR("invalid options, type=%{public}d.", type); + return RDB_E_INVALID_ARGS; + } + opitons->type_ = type; + return RDB_OK; +} + +static bool IsValidRdbTrans(const OH_Rdb_Transaction *trans) +{ + if (trans == nullptr || trans->trans_ == nullptr) { + LOG_ERROR("trans param has null data"); + return false; + } + bool ret = trans->IsValid(); + if (!ret) { + LOG_ERROR("invalid transaction object."); + } + return ret; +} + +int OH_RdbTrans_Commit(OH_Rdb_Transaction *trans) +{ + if (!IsValidRdbTrans(trans)) { + return RDB_E_INVALID_ARGS; + } + auto errCode = trans->trans_->Commit(); + if (errCode != E_OK) { + LOG_ERROR("commit fail, errCode=%{public}d", errCode); + } + return ConvertorErrorCode::GetInterfaceCode(errCode); +} + +int OH_RdbTrans_Rollback(OH_Rdb_Transaction *trans) +{ + if (!IsValidRdbTrans(trans)) { + return RDB_E_INVALID_ARGS; + } + auto errCode = trans->trans_->Rollback(); + if (errCode != E_OK) { + LOG_ERROR("commit fail, errCode=%{public}d", errCode); + } + return ConvertorErrorCode::GetInterfaceCode(errCode); +} + +int OH_RdbTrans_Insert(OH_Rdb_Transaction *trans, const char *table, const OH_VBucket *row, int64_t *rowId) +{ + auto valuesBucket = RelationalValuesBucket::GetSelf(const_cast(row)); + if (!IsValidRdbTrans(trans) || table == nullptr || valuesBucket == nullptr || rowId == nullptr) { + return RDB_E_INVALID_ARGS; + } + + auto [errCode, id] = trans->trans_->Insert(table, valuesBucket->Get()); + *rowId = id; + if (errCode != E_OK) { + LOG_ERROR("insert fail, errCode=%{public}d id=%{public}" PRId64 "" PRId64, errCode, id); + } + return ConvertorErrorCode::GetInterfaceCode(errCode); +} + +int OH_RdbTrans_BatchInsert(OH_Rdb_Transaction *trans, const char *table, const OH_Data_VBuckets *rows, + Rdb_ConflictResolution resolution, int64_t *changes) +{ + if (!IsValidRdbTrans(trans) || table == nullptr || rows == nullptr || !rows->IsValid() || changes == nullptr || + resolution < RDB_CONFLICT_NONE || resolution > RDB_CONFLICT_REPLACE) { + return RDB_E_INVALID_ARGS; + } + ValuesBuckets datas; + for (size_t i = 0; i < rows->rows_.size(); i++) { + auto valuesBucket = RelationalValuesBucket::GetSelf(const_cast(rows->rows_[i])); + if (valuesBucket == nullptr) { + continue; + } + datas.Put(valuesBucket->Get()); + } + auto [errCode, count] = + trans->trans_->BatchInsertWithConflictResolution(table, datas, Utils::ConvertConflictResolution(resolution)); + *changes = count; + if (errCode != E_OK) { + LOG_ERROR("batch insert fail, errCode=%{public}d count=%{public}" PRId64 "" PRId64, errCode, count); + } + return ConvertorErrorCode::GetInterfaceCode(errCode); +} + +int OH_RdbTrans_Update(OH_Rdb_Transaction *trans, const OH_VBucket *row, const OH_Predicates *predicates, + int64_t *changes) +{ + auto rdbPredicate = RelationalPredicate::GetSelf(const_cast(predicates)); + auto rdbValuesBucket = RelationalValuesBucket::GetSelf(const_cast(row)); + if (!IsValidRdbTrans(trans) || rdbValuesBucket == nullptr || rdbPredicate == nullptr || changes == nullptr) { + return RDB_E_INVALID_ARGS; + } + auto [errCode, count] = trans->trans_->Update(rdbValuesBucket->Get(), rdbPredicate->Get()); + *changes = count; + if (errCode != E_OK) { + LOG_ERROR("update fail, errCode=%{public}d count=%{public}d", errCode, count); + } + return ConvertorErrorCode::GetInterfaceCode(errCode); +} + +int OH_RdbTrans_Delete(OH_Rdb_Transaction *trans, const OH_Predicates *predicates, int64_t *changes) +{ + auto rdbPredicate = RelationalPredicate::GetSelf(const_cast(predicates)); + if (!IsValidRdbTrans(trans) || rdbPredicate == nullptr || changes == nullptr) { + return RDB_E_INVALID_ARGS; + } + + auto [errCode, count] = trans->trans_->Delete(rdbPredicate->Get()); + *changes = count; + if (errCode != E_OK) { + LOG_ERROR("delete fail, errCode=%{public}d count=%{public}d", errCode, count); + } + return ConvertorErrorCode::GetInterfaceCode(errCode); +} + +OH_Cursor *OH_RdbTrans_Query(OH_Rdb_Transaction *trans, const OH_Predicates *predicates, const char *columns[], int len) +{ + auto rdbPredicate = RelationalPredicate::GetSelf(const_cast(predicates)); + if (!IsValidRdbTrans(trans) || rdbPredicate == nullptr) { + return nullptr; + } + std::vector fields; + if (columns != nullptr && len > 0) { + for (int i = 0; i < len; i++) { + fields.emplace_back(columns[i]); + } + } + auto resultSet = trans->trans_->QueryByStep(rdbPredicate->Get(), fields); + if (resultSet == nullptr) { + LOG_ERROR("resultSet is null."); + return nullptr; + } + return new (std::nothrow) RelationalCursor(std::move(resultSet)); +} + +OH_Cursor *OH_RdbTrans_QuerySql(OH_Rdb_Transaction *trans, const char *sql, const OH_Data_Values *args) +{ + if (!IsValidRdbTrans(trans) || sql == nullptr || (args != nullptr && !args->IsValid())) { + return nullptr; + } + std::vector datas; + if (args != nullptr) { + for (auto arg : args->values_) { + if (!arg.IsValid()) { + continue; + } + datas.push_back(arg.value_); + } + } + auto resultSet = trans->trans_->QueryByStep(sql, datas); + if (resultSet == nullptr) { + LOG_ERROR("resultSet is null."); + return nullptr; + } + return new (std::nothrow) RelationalCursor(std::move(resultSet)); +} + +int OH_RdbTrans_Execute(OH_Rdb_Transaction *trans, const char *sql, const OH_Data_Values *args, OH_Data_Value **result) +{ + if (!IsValidRdbTrans(trans) || sql == nullptr || (args != nullptr && !args->IsValid())) { + return RDB_E_INVALID_ARGS; + } + std::vector datas; + if (args != nullptr) { + for (auto arg : args->values_) { + if (!arg.IsValid()) { + continue; + } + datas.push_back(arg.value_); + } + } + auto [errCode, valueObj] = trans->trans_->Execute(sql, datas); + if (errCode != OHOS::NativeRdb::E_OK) { + LOG_ERROR("execute fail, errCode=%{public}d", errCode); + return ConvertorErrorCode::GetInterfaceCode(errCode); + } + if (result != nullptr) { + OH_Data_Value *value = OH_Value_Create(); + if (value == nullptr) { + return RDB_E_ERROR; + } + value->value_ = valueObj; + *result = value; + } + return RDB_OK; +} + +int OH_RdbTrans_Destroy(OH_Rdb_Transaction *trans) +{ + if (!IsValidRdbTrans(trans)) { + LOG_ERROR("invalid trans"); + return RDB_E_INVALID_ARGS; + } + trans->trans_ = nullptr; + delete trans; + return RDB_OK; +} + +bool OH_Rdb_Transaction::IsValid() const +{ + if (trans_ == nullptr) { + return false; + } + return id == OH_RDB_TRANS_ID; +} + +bool OH_RDB_TransOptions::IsValid() const +{ + if (type_ < RDB_TRANS_DEFERRED || type_ >= RDB_TRANS_BUTT) { + LOG_ERROR("invalid type=%{public}d", type_); + return false; + } + return id == OH_TRANS_OPTION_ID; +} \ No newline at end of file diff --git a/relational_store/interfaces/ndk/src/relational_cursor.cpp b/relational_store/interfaces/ndk/src/relational_cursor.cpp index 252b1600a5882954ac31c747e2a6d843783012f2..6925edb469b516544808fdbebed0121f55549d40 100644 --- a/relational_store/interfaces/ndk/src/relational_cursor.cpp +++ b/relational_store/interfaces/ndk/src/relational_cursor.cpp @@ -403,5 +403,62 @@ int RelationalCursor::GetAssetsCount(int32_t columnIndex, uint32_t *count) return OH_Rdb_ErrCode::RDB_OK; } +int RelationalCursor::GetFloatVectorCount(int32_t columnIndex, size_t *length) +{ + if (length == nullptr || resultSet_ == nullptr) { + return OH_Rdb_ErrCode::RDB_E_INVALID_ARGS; + } + std::vector result = {}; + auto errCode = resultSet_->GetFloat32Array(columnIndex, result); + if (errCode != NativeRdb::E_OK) { + return ConvertorErrorCode::GetInterfaceCode(errCode); + } + *length = result.size(); + return OH_Rdb_ErrCode::RDB_OK; +} + +int RelationalCursor::GetFloatVector(int32_t columnIndex, float *val, size_t inLen, size_t *outLen) +{ + if (val == nullptr || inLen == 0 || outLen == nullptr || resultSet_ == nullptr) { + return OH_Rdb_ErrCode::RDB_E_INVALID_ARGS; + } + std::vector result = {}; + auto errCode = resultSet_->GetFloat32Array(columnIndex, result); + if (errCode != NativeRdb::E_OK) { + return ConvertorErrorCode::GetInterfaceCode(errCode); + } + if (inLen < result.size()) { + return OH_Rdb_ErrCode::RDB_E_INVALID_ARGS; + } + *outLen = result.size(); + errCode = memcpy_s(val, inLen * sizeof(float), result.data(), (*outLen) * sizeof(float)); + if (errCode != EOK) { + LOG_ERROR("memcpy_s failed, errCode is %{public}d", errCode); + *outLen = 0; + return OH_Rdb_ErrCode::RDB_E_ERROR; + } + return OH_Rdb_ErrCode::RDB_OK; +} + } // namespace RdbNdk } // namespace OHOS + +using namespace OHOS::RdbNdk; +using namespace OHOS::NativeRdb; +int OH_Cursor_GetFloatVectorCount(OH_Cursor *cursor, int32_t columnIndex, size_t *length) +{ + auto self = RelationalCursor::GetSelf(cursor); + if (self == nullptr) { + return OH_Rdb_ErrCode::RDB_E_INVALID_ARGS; + } + return self->GetFloatVectorCount(columnIndex, length); +} + +int OH_Cursor_GetFloatVector(OH_Cursor *cursor, int32_t columnIndex, float *val, size_t inLen, size_t *outLen) +{ + auto self = RelationalCursor::GetSelf(cursor); + if (self == nullptr) { + return OH_Rdb_ErrCode::RDB_E_INVALID_ARGS; + } + return self->GetFloatVector(columnIndex, val, inLen, outLen); +} diff --git a/relational_store/interfaces/ndk/src/relational_cursor.h b/relational_store/interfaces/ndk/src/relational_cursor.h index 0d765e543b52d7923700b24a1bf9cac719fe4491..025e201d752aceb6e939489c1b54e5eb0abd29c7 100644 --- a/relational_store/interfaces/ndk/src/relational_cursor.h +++ b/relational_store/interfaces/ndk/src/relational_cursor.h @@ -29,6 +29,10 @@ public: explicit RelationalCursor(std::shared_ptr resultSet); virtual ~RelationalCursor() = default; + virtual int GetFloatVectorCount(int32_t columnIndex, size_t *length); + virtual int GetFloatVector(int32_t columnIndex, float *val, size_t inLen, size_t *outLen); + static RelationalCursor *GetSelf(OH_Cursor *cursor); + protected: virtual int GetColumnCount(int *count); virtual int GetColumnType(int32_t columnIndex, OH_ColumnType *columnType); @@ -64,7 +68,6 @@ private: static int IsNull(OH_Cursor *cursor, int32_t columnIndex, bool *isNull); static int GetAssetsCount(OH_Cursor *cursor, int32_t columnIndex, uint32_t *count); static int Destroy(OH_Cursor *cursor); - static RelationalCursor *GetSelf(OH_Cursor *cursor); std::shared_ptr resultSet_; }; } // namespace RdbNdk diff --git a/relational_store/interfaces/ndk/src/relational_predicates.cpp b/relational_store/interfaces/ndk/src/relational_predicates.cpp index 044c9a2cf330596f2585b9ab201237667ca8947d..5ae556650f7ab7e58b270786f0fd40955d0c1e70 100644 --- a/relational_store/interfaces/ndk/src/relational_predicates.cpp +++ b/relational_store/interfaces/ndk/src/relational_predicates.cpp @@ -376,4 +376,4 @@ RelationalPredicate *RelationalPredicate::GetSelf(OH_Predicates *predicates) return static_cast(predicates); } } // namespace RdbNdk -} // namespace OHOS \ No newline at end of file +} // namespace OHOS diff --git a/relational_store/interfaces/ndk/src/relational_store.cpp b/relational_store/interfaces/ndk/src/relational_store.cpp index f09882f0ce2dd9b753ff6b865418c07e24c3841c..ae02e1ca4023f4537bc2450dcc451adeb668c2b6 100644 --- a/relational_store/interfaces/ndk/src/relational_store.cpp +++ b/relational_store/interfaces/ndk/src/relational_store.cpp @@ -34,6 +34,9 @@ #include "relational_values_bucket.h" #include "securec.h" #include "sqlite_global_config.h" +#include "oh_data_define.h" +#include "oh_data_utils.h" +#include "values_buckets.h" using namespace OHOS::RdbNdk; using namespace OHOS::DistributedRdb; @@ -54,6 +57,7 @@ struct OH_Rdb_ConfigV2 { int securityLevel = 0; int area = 0; int dbType = RDB_SQLITE; + int token = RDB_NONE_TOKENIZER; }; OH_Rdb_ConfigV2 *OH_Rdb_CreateConfig() @@ -175,6 +179,35 @@ int OH_Rdb_SetDbType(OH_Rdb_ConfigV2 *config, int dbType) return OH_Rdb_ErrCode::RDB_OK; } +int OH_Rdb_IsTokenizerSupported(Rdb_Tokenizer tokenizer, bool *isSupported) +{ + if (tokenizer < RDB_NONE_TOKENIZER || tokenizer > RDB_CUSTOM_TOKENIZER) { + LOG_ERROR("token is out of range %{public}d", tokenizer); + return OH_Rdb_ErrCode::RDB_E_INVALID_ARGS; + } + if (isSupported == nullptr) { + return OH_Rdb_ErrCode::RDB_E_INVALID_ARGS; + } + *isSupported = OHOS::NativeRdb::RdbHelper::IsSupportedTokenizer(static_cast(tokenizer)); + return OH_Rdb_ErrCode::RDB_OK; +} + +int OH_Rdb_SetTokenizer(OH_Rdb_ConfigV2 *config, Rdb_Tokenizer tokenizer) +{ + if (config == nullptr || (config->magicNum != RDB_CONFIG_V2_MAGIC_CODE) || + (tokenizer < RDB_NONE_TOKENIZER || tokenizer > RDB_CUSTOM_TOKENIZER)) { + LOG_ERROR("config is null %{public}d or magicNum not valid %{public}d or token is out of range %{public}d", + (config == nullptr), (config == nullptr ? 0 : config->magicNum), tokenizer); + return OH_Rdb_ErrCode::RDB_E_INVALID_ARGS; + } + if (config->dbType != Rdb_DBType::RDB_SQLITE) { + LOG_ERROR("ICU Tokenizer only support sqlite db type."); + return OH_Rdb_ErrCode::RDB_E_NOT_SUPPORTED; + } + config->token = tokenizer; + return OH_Rdb_ErrCode::RDB_OK; +} + const int *OH_Rdb_GetSupportedDbType(int *numType) { if (numType == nullptr) { @@ -310,17 +343,33 @@ RelationalStore *GetRelationalStore(OH_Rdb_Store *store) return static_cast(store); } +// caller must ensure token is valid +static OHOS::NativeRdb::Tokenizer ConvertTokenizer2Native(Rdb_Tokenizer token) +{ + if (token == Rdb_Tokenizer::RDB_NONE_TOKENIZER) { + return OHOS::NativeRdb::Tokenizer::NONE_TOKENIZER; + } + if (token == Rdb_Tokenizer::RDB_ICU_TOKENIZER) { + return OHOS::NativeRdb::Tokenizer::ICU_TOKENIZER; + } + if (token == Rdb_Tokenizer::RDB_CUSTOM_TOKENIZER) { + return OHOS::NativeRdb::Tokenizer::CUSTOM_TOKENIZER; + } + return OHOS::NativeRdb::Tokenizer::TOKENIZER_END; +} + static OHOS::NativeRdb::RdbStoreConfig GetRdbStoreConfig(const OH_Rdb_ConfigV2 *config, int *errCode) { if (config->magicNum != RDB_CONFIG_V2_MAGIC_CODE || (OHOS::NativeRdb::SecurityLevel(config->securityLevel) < OHOS::NativeRdb::SecurityLevel::S1 || OHOS::NativeRdb::SecurityLevel(config->securityLevel) >= OHOS::NativeRdb::SecurityLevel::LAST) || (config->area < RDB_SECURITY_AREA_EL1 || config->area > RDB_SECURITY_AREA_EL5) || - (config->dbType < RDB_SQLITE || config->dbType > RDB_CAYLEY)) { + (config->dbType < RDB_SQLITE || config->dbType > RDB_CAYLEY) || + (config->token < RDB_NONE_TOKENIZER || config->token > RDB_CUSTOM_TOKENIZER)) { *errCode = OH_Rdb_ErrCode::RDB_E_INVALID_ARGS; LOG_ERROR("Config magic number is not valid %{public}x or securityLevel %{public}d area %{public}d" - "dbType %{public}d ret %{public}d", - config->magicNum, config->securityLevel, config->area, config->dbType, *errCode); + "dbType %{public}d token %{public}d ret %{public}d", + config->magicNum, config->securityLevel, config->area, config->dbType, config->token, *errCode); return OHOS::NativeRdb::RdbStoreConfig(""); } std::string realPath = @@ -337,6 +386,7 @@ static OHOS::NativeRdb::RdbStoreConfig GetRdbStoreConfig(const OH_Rdb_ConfigV2 * rdbStoreConfig.SetIsVector(config->dbType == RDB_CAYLEY); rdbStoreConfig.SetBundleName(config->bundleName); rdbStoreConfig.SetName(config->storeName); + rdbStoreConfig.SetTokenizer(ConvertTokenizer2Native(static_cast(config->token))); return rdbStoreConfig; } @@ -454,6 +504,31 @@ int OH_Rdb_Insert(OH_Rdb_Store *store, const char *table, OH_VBucket *valuesBuck return rowId >= 0 ? rowId : OH_Rdb_ErrCode::RDB_ERR; } +int OH_Rdb_BatchInsert(OH_Rdb_Store *store, const char *table, + const OH_Data_VBuckets *rows, Rdb_ConflictResolution resolution, int64_t *changes) +{ + auto rdbStore = GetRelationalStore(store); + if (rdbStore == nullptr || table == nullptr || rows == nullptr || changes == nullptr || + resolution < RDB_CONFLICT_NONE || resolution > RDB_CONFLICT_REPLACE) { + return OH_Rdb_ErrCode::RDB_E_INVALID_ARGS; + } + OHOS::NativeRdb::ValuesBuckets datas; + for (size_t i = 0; i < rows->rows_.size(); i++) { + auto valuesBucket = RelationalValuesBucket::GetSelf(const_cast(rows->rows_[i])); + if (valuesBucket == nullptr) { + continue; + } + datas.Put(valuesBucket->Get()); + } + auto [errCode, count] = rdbStore->GetStore()->BatchInsertWithConflictResolution(table, + datas, Utils::ConvertConflictResolution(resolution)); + *changes = count; + if (errCode != OHOS::NativeRdb::E_OK) { + LOG_ERROR("batch insert fail, errCode=%{public}d count=%{public}" PRId64 "" PRId64, errCode, count); + } + return ConvertorErrorCode::GetInterfaceCode(errCode); +} + int OH_Rdb_Update(OH_Rdb_Store *store, OH_VBucket *valueBucket, OH_Predicates *predicates) { auto rdbStore = GetRelationalStore(store); @@ -968,6 +1043,88 @@ OH_Cursor *OH_Rdb_QueryLockedRow( return new OHOS::RdbNdk::RelationalCursor(std::move(resultSet)); } +int OH_Rdb_CreateTransaction(OH_Rdb_Store *store, const OH_RDB_TransOptions *options, OH_Rdb_Transaction **trans) +{ + auto rdbStore = GetRelationalStore(store); + if (rdbStore == nullptr || trans == nullptr || options == nullptr || !options->IsValid()) { + LOG_ERROR("params exist nullptr or invalid options."); + return RDB_E_INVALID_ARGS; + } + OH_Rdb_Transaction *transaction = new (std::nothrow) OH_Rdb_Transaction(); + if (transaction == nullptr) { + LOG_ERROR("new OH_Rdb_Transaction failed."); + return RDB_E_ERROR; + } + auto [ret, tmpTrans] = rdbStore->GetStore()->CreateTransaction(static_cast(options->type_)); + transaction->trans_ = tmpTrans; + *trans = transaction; + return ConvertorErrorCode::NativeToNdk(ret); +} + +int OH_Rdb_ExecuteV2(OH_Rdb_Store *store, const char *sql, const OH_Data_Values *args, OH_Data_Value **result) +{ + auto rdbStore = GetRelationalStore(store); + if (rdbStore == nullptr || sql == nullptr || (args != nullptr && !args->IsValid())) { + return OH_Rdb_ErrCode::RDB_E_INVALID_ARGS; + } + std::vector datas; + if (args != nullptr) { + for (auto arg : args->values_) { + if (!arg.IsValid()) { + return OH_Rdb_ErrCode::RDB_E_INVALID_ARGS; + } + datas.push_back(arg.value_); + } + } + auto innerStore = rdbStore->GetStore(); + if (innerStore == nullptr) { + LOG_ERROR("store is nullptr"); + return OH_Rdb_ErrCode::RDB_E_ALREADY_CLOSED; + } + auto [errCode, valueObj] = innerStore->Execute(sql, datas); + if (errCode != OHOS::NativeRdb::E_OK) { + LOG_ERROR("execute fail, errCode=%{public}d", errCode); + return ConvertorErrorCode::GetInterfaceCode(errCode); + } + if (result != nullptr) { + OH_Data_Value *value = OH_Value_Create(); + if (value == nullptr) { + return RDB_E_ERROR; + } + value->value_ = valueObj; + *result = value; + } + return OH_Rdb_ErrCode::RDB_OK; +} + +OH_Cursor *OH_Rdb_ExecuteQueryV2(OH_Rdb_Store *store, const char *sql, const OH_Data_Values *args) +{ + auto rdbStore = GetRelationalStore(store); + if (rdbStore == nullptr || sql == nullptr || (args != nullptr && !args->IsValid())) { + return nullptr; + } + std::vector datas; + if (args != nullptr) { + for (auto arg : args->values_) { + if (!arg.IsValid()) { + LOG_ERROR("args is invalid"); + return nullptr; + } + datas.push_back(arg.value_); + } + } + auto innerStore = rdbStore->GetStore(); + if (innerStore == nullptr) { + LOG_ERROR("store is nullptr"); + return nullptr; + } + auto resultSet = innerStore->QueryByStep(sql, datas); + if (resultSet == nullptr) { + return nullptr; + } + return new (std::nothrow) RelationalCursor(std::move(resultSet)); +} + NDKDetailProgressObserver::NDKDetailProgressObserver(const Rdb_ProgressObserver *callback) : callback_(callback) { } diff --git a/relational_store/interfaces/ndk/src/relational_values_bucket.cpp b/relational_store/interfaces/ndk/src/relational_values_bucket.cpp index 84901198636a5bc01600ff641898f70f5aa556ab..83bcb280b1a27c519c86cc6450fbac0980fd8b85 100644 --- a/relational_store/interfaces/ndk/src/relational_values_bucket.cpp +++ b/relational_store/interfaces/ndk/src/relational_values_bucket.cpp @@ -153,3 +153,27 @@ int OH_VBucket_PutAssets(OH_VBucket *bucket, const char *field, Data_Asset **val return OH_Rdb_ErrCode::RDB_OK; } + +int OH_VBucket_PutFloatVector(OH_VBucket *bucket, const char *field, const float *vec, size_t len) +{ + auto self = RelationalValuesBucket::GetSelf(bucket); + if (self == nullptr || field == nullptr || vec == nullptr) { + return OH_Rdb_ErrCode::RDB_E_INVALID_ARGS; + } + ValueObject::FloatVector floatVec(vec, vec + len); + self->Get().Put(field, floatVec); + self->capability++; + return OH_Rdb_ErrCode::RDB_OK; +} + +int OH_VBucket_PutUnlimitedInt(OH_VBucket *bucket, const char *field, int sign, const uint64_t *trueForm, size_t len) +{ + auto self = RelationalValuesBucket::GetSelf(bucket); + if (self == nullptr || field == nullptr || trueForm == nullptr) { + return OH_Rdb_ErrCode::RDB_E_INVALID_ARGS; + } + ValueObject::BigInt bigInt(sign, {trueForm, trueForm + len}); + self->Get().Put(field, bigInt); + self->capability++; + return OH_Rdb_ErrCode::RDB_OK; +} diff --git a/relational_store/rdbmock/frameworks/native/win32/dlfcn.cpp b/relational_store/rdbmock/frameworks/native/win32/dlfcn.cpp new file mode 100644 index 0000000000000000000000000000000000000000..62abb46b1dd896d72aa565562da4c14ac0b088a0 --- /dev/null +++ b/relational_store/rdbmock/frameworks/native/win32/dlfcn.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 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 "dlfcn.h" + +void *dlopen(const char *pathName, int mode) +{ + return nullptr; +}; + +void *dlsym(void *handle, const char *funcName) +{ + return nullptr; +}; \ No newline at end of file diff --git a/relational_store/rdbmock/frameworks/native/win32/dlfcn.h b/relational_store/rdbmock/frameworks/native/win32/dlfcn.h new file mode 100644 index 0000000000000000000000000000000000000000..f0fc3b50d0f071e4ef13a95748dfe0aab0f21b35 --- /dev/null +++ b/relational_store/rdbmock/frameworks/native/win32/dlfcn.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 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 MOCK_DLFCN_H +#define MOCK_DLFCN_H + +#ifdef __cplusplus +extern "C" { +#endif +#define RTLD_LAZY 1 +#define RTLD_NOW 2 +#define RTLD_NOLOAD 4 +#define RTLD_NODELETE 4096 +#define RTLD_GLOBAL 256 +#define RTLD_LOCAL 0 + +void *dlopen(const char *pathName, int mode); +void *dlsym(void *handle, const char *funcName); +#ifdef __cplusplus +} +#endif +#endif //MOCK_DLFCN_H diff --git a/relational_store/relational_store.gni b/relational_store/relational_store.gni index 69a033507634ae8585d8c8630100266dbb0dedcc..d5c7eb3e65c12905e3af2bcbd73e547e335221d8 100644 --- a/relational_store/relational_store.gni +++ b/relational_store/relational_store.gni @@ -13,6 +13,12 @@ declare_args() { relational_store_rdb_support_icu = true + if (!defined(global_parts_info) || + defined(global_parts_info.distributeddatamgr_arkdata_database_core)) { + arkdata_db_core_is_exists = true + } else { + arkdata_db_core_is_exists = false + } } common_tool_path = "//foundation/distributeddatamgr/kv_store/frameworks/common" @@ -54,6 +60,10 @@ sdk_c_path = "//interface/sdk_c/distributeddatamgr" plugins_path = "//plugins" +relational_store_frameworks_path = "${relational_store_base_path}/frameworks" + +plugins_path = "//plugins" + foundation_systemabilitymgr_path = "//foundation/systemabilitymgr/" base_security_dataclassification_path = "//base/security/dataclassification" diff --git a/relational_store/test/js/clouddata/unittest/config.json b/relational_store/test/js/clouddata/unittest/config.json index a14bac40f3003bb31eb3b2d59aa6c77f29f99ae1..8f0286adeec00a6515d3f6e0d537e739ea431e17 100644 --- a/relational_store/test/js/clouddata/unittest/config.json +++ b/relational_store/test/js/clouddata/unittest/config.json @@ -19,7 +19,8 @@ "tablet", "2in1", "default", - "phone" + "phone", + "wearable" ], "distro": { "deliveryWithInstall": true, @@ -65,4 +66,4 @@ } ] } -} +} \ No newline at end of file diff --git a/relational_store/test/js/dataability/unittest/config.json b/relational_store/test/js/dataability/unittest/config.json index 865615d255b08fd479e18891941ef167326e4561..8179c0c356df0e89d6db5181910f21a28d96bc60 100644 --- a/relational_store/test/js/dataability/unittest/config.json +++ b/relational_store/test/js/dataability/unittest/config.json @@ -19,7 +19,8 @@ "tablet", "2in1", "default", - "phone" + "phone", + "wearable" ], "distro": { "deliveryWithInstall": true, @@ -60,4 +61,4 @@ } ] } -} +} \ No newline at end of file diff --git a/relational_store/test/js/gdb/BUILD.gn b/relational_store/test/js/gdb/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..903b0e9ffc53f5be249ab2a867bd4cfb77676304 --- /dev/null +++ b/relational_store/test/js/gdb/BUILD.gn @@ -0,0 +1,35 @@ +# Copyright (c) 2024 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. + +import("//build/test.gni") +import("//foundation/distributeddatamgr/relational_store/relational_store.gni") + +#################################group######################################### +group("unittest") { + testonly = true + deps = [] + + if (arkdata_db_core_is_exists) { + deps += [ "unittest/src:unittest" ] + } +} + +group("performancetest") { + testonly = true + deps = [] + + if (arkdata_db_core_is_exists) { + deps += [ "performance/src:GdbPerfJsTest" ] + } +} +############################################################################### diff --git a/relational_store/test/js/gdb/performance/config.json b/relational_store/test/js/gdb/performance/config.json new file mode 100644 index 0000000000000000000000000000000000000000..2f09d1d4672a27ca6a23a2398a27cccebc1612ed --- /dev/null +++ b/relational_store/test/js/gdb/performance/config.json @@ -0,0 +1,63 @@ +{ + "app": { + "bundleName": "com.example.myapplication", + "vendor": "example", + "version": { + "code": 1, + "name": "1.0" + }, + "apiVersion": { + "compatible": 4, + "target": 5 + } + }, + "deviceConfig": {}, + "module": { + "package": "com.example.myapplication", + "name": ".MyApplication", + "deviceType": [ + "tablet", + "2in1", + "default", + "phone" + ], + "distro": { + "deliveryWithInstall": true, + "moduleName": "entry", + "moduleType": "entry" + }, + "abilities": [ + { + "visible": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ], + "name": "com.example.myapplication.MainAbility", + "icon": "$media:icon", + "description": "$string:mainability_description", + "label": "MyApplication", + "type": "page", + "launchType": "standard" + } + ], + "js": [ + { + "pages": [ + "pages/index/index" + ], + "name": "default", + "window": { + "designWidth": 720, + "autoDesignWidth": false + } + } + ] + } +} \ No newline at end of file diff --git a/relational_store/test/js/gdb/performance/openharmony_sx.p7b b/relational_store/test/js/gdb/performance/openharmony_sx.p7b new file mode 100644 index 0000000000000000000000000000000000000000..9be1e98fa4c0c28ca997ed660112fa16b194f0f5 Binary files /dev/null and b/relational_store/test/js/gdb/performance/openharmony_sx.p7b differ diff --git a/relational_store/test/js/gdb/performance/src/BUILD.gn b/relational_store/test/js/gdb/performance/src/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..2baf59addec2980e137b3957e67ef6e456d9a3b4 --- /dev/null +++ b/relational_store/test/js/gdb/performance/src/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright (C) 2024 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. + +import("//build/test.gni") + +module_output_path = "relational_store/gdb_perf" + +ohos_js_unittest("GdbPerfJsTest") { + module_out_path = module_output_path + + hap_profile = "../config.json" + + certificate_profile = "../openharmony_sx.p7b" +} diff --git a/relational_store/test/js/gdb/performance/src/GdbHelperPromisePerf.js b/relational_store/test/js/gdb/performance/src/GdbHelperPromisePerf.js new file mode 100644 index 0000000000000000000000000000000000000000..7bba8fc6266d532b84543f3dcef5ec089224ed3f --- /dev/null +++ b/relational_store/test/js/gdb/performance/src/GdbHelperPromisePerf.js @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2024 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. + */ + +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert } from 'deccjsunit/index'; +import graphStore from '@ohos.data.graphStore'; +import featureAbility from '@ohos.ability.featureAbility'; +import deviceInfo from '@ohos.deviceInfo'; + +const TAG = "[GDBHELPER_PROMISE]"; +const DB_NAME = "gdbPromise"; +const STORE_CONFIG = { + name: DB_NAME, + securityLevel: graphStore.SecurityLevel.S1 +} +let context = featureAbility.getContext(); +let store; +const BASE_COUNT = 2000; // loop times +const BASE_LINE_TABLE = 2500; // callback tablet base line +const BASE_LINE_PHONE = 3000; // callback phone base line +const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_LINE_PHONE; + +describe('gdbHelperPromisePerf', () => { + beforeAll(async () => { + console.info(TAG + 'beforeAll'); + }) + beforeEach(async () => { + console.info(TAG + 'beforeEach'); + }) + afterEach(async () => { + console.info(TAG + 'afterEach'); + }) + afterAll(async () => { + console.info(TAG + 'afterAll'); + await store.close(); + await graphStore.deleteStore(context, STORE_CONFIG); + }) + + console.log(TAG + "*************Unit Test Begin*************"); + + it('Perf_Gdb_GetStore_Promise_001', 0, async () => { + let averageTime = 0; + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + await graphStore.getStore(context, STORE_CONFIG); + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the getStore_Promise average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + }) + + it('Perf_Gdb_DeleteStore_Promise_001', 0, async () => { + let averageTime = 0; + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + await graphStore.deleteStore(context, STORE_CONFIG); + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the deleteStore_Promise average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + console.info(TAG + "*************Unit Test End*************") + }) +}) \ No newline at end of file diff --git a/relational_store/test/js/gdb/performance/src/GdbStorePromisePerf.js b/relational_store/test/js/gdb/performance/src/GdbStorePromisePerf.js new file mode 100644 index 0000000000000000000000000000000000000000..e77064e74d620d5ce48df0b7a9e548efd1a89a3a --- /dev/null +++ b/relational_store/test/js/gdb/performance/src/GdbStorePromisePerf.js @@ -0,0 +1,130 @@ +/* +* Copyright (C) 2024 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. +*/ + +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert } from 'deccjsunit/index'; +import graphStore from '@ohos.data.graphStore'; +import featureAbility from '@ohos.ability.featureAbility'; +import deviceInfo from '@ohos.deviceInfo'; + +const TAG = "[GDBSTORE_PROMISE]"; +const CREATE_GRAPH_TEST = + "CREATE GRAPH test {(person:Person {name STRING, age INT}), (person) -[:FRIEND]-> (person)};"; +const DB_NAME = "gdbStorePromise"; +const STORE_CONFIG = { + name: DB_NAME, + securityLevel: graphStore.SecurityLevel.S1 +} +let context = featureAbility.getContext(); +let store; +const BASE_COUNT = 1000; // loop times +const BASE_LINE_TABLE = 2500; // callback tablet base line +const BASE_LINE_PHONE = 3000; // callback phone base line +const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_LINE_PHONE; + +describe('gdbStorePromisePerf', () => { + beforeAll(async () => { + console.info(TAG + 'beforeAll'); + await graphStore.deleteStore(context, STORE_CONFIG); + store = await graphStore.getStore(context, STORE_CONFIG); + }) + beforeEach(async () => { + console.info(TAG + 'beforeEach'); + await store.write(CREATE_GRAPH_TEST); + }) + afterEach(async () => { + console.info(TAG + 'afterEach'); + await store.write("DROP GRAPH test"); + }) + afterAll(async () => { + console.info(TAG + 'afterAll'); + await store.close(); + await graphStore.deleteStore(context, STORE_CONFIG); + }) + + console.log(TAG + "*************Unit Test Begin*************"); + + it('Perf_Gdb_Write_Promise_001', 0, async () => { + console.info(TAG + "************* testPerfGdbWritePromise001 start *************"); + let averageTime = 0; + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + let INSERT = "INSERT (:Person {name: 'name_" + (i + 1) + "', age:" + (i + 1) + "});"; + await store.write(INSERT); + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the write_INSERT_Promise average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + console.info(TAG + "************* testPerfGdbWritePromise001 end *************"); + }) + + it('Perf_Gdb_Write_Promise_002', 0, async () => { + console.info(TAG + "************* testPerfGdbWritePromise002 start *************"); + for (let i = 0; i < BASE_COUNT; i++) { + let INSERT = "INSERT (:Person {name: 'name_" + (i + 1) + "', age:" + (i + 1) + "});"; + await store.write(INSERT); + } + let averageTime = 0; + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + let UPDATE = "MATCH (n:Person {name: 'name_" + (i + 1) + "' }) SET n.age = " + (i + 2) + ";"; + await store.write(UPDATE); + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the write_UPDATE_Promise average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + console.info(TAG + "************* testPerfGdbWritePromise002 end *************"); + }) + + it('Perf_Gdb_Write_Promise_003', 0, async () => { + console.info(TAG + "************* testPerfGdbWritePromise003 start *************"); + for (let i = 0; i < BASE_COUNT; i++) { + let INSERT = "INSERT (:Person {name: 'name_" + (i + 1) + "', age:" + (i + 1) + "});"; + await store.write(INSERT); + } + let averageTime = 0; + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + let DELETE = "MATCH (n:Person {name: 'name_" + (i + 1) + "' }) DETACH DELETE n;"; + await store.write(DELETE); + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the write_DELETE_Promise average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + console.info(TAG + "************* testPerfGdbWritePromise003 end *************"); + }) + + it('Perf_Gdb_Read_Promise_001', 0, async () => { + console.info(TAG + "************* testPerfGdbReadPromise001 start *************"); + for (let i = 0; i < BASE_COUNT; i++) { + let INSERT = "INSERT (:Person {name: 'name_" + (i + 1) + "', age:" + (i + 1) + "});"; + await store.write(INSERT); + } + let averageTime = 0; + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + let QUERY = "MATCH (n:Person {name: 'name_" + (i + 1) + "' }) RETURN n;"; + await store.read(QUERY); + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the read_Query_Vertex_Promise average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + console.info(TAG + "************* testPerfGdbReadPromise001 end *************"); + }) + console.info(TAG + "*************Unit Test End*************") +}) \ No newline at end of file diff --git a/relational_store/test/js/gdb/unittest/config.json b/relational_store/test/js/gdb/unittest/config.json new file mode 100644 index 0000000000000000000000000000000000000000..ea58402783388eac606d7347d88ebc401476a50d --- /dev/null +++ b/relational_store/test/js/gdb/unittest/config.json @@ -0,0 +1,64 @@ +{ + "app": { + "bundleName": "com.example.myapplication", + "vendor": "example", + "version": { + "code": 1, + "name": "1.0" + }, + "apiVersion": { + "compatible": 4, + "target": 5 + } + }, + "deviceConfig": {}, + "module": { + "package": "com.example.myapplication", + "name": ".MyApplication", + "deviceType": [ + "tablet", + "2in1", + "default", + "phone" + ], + "distro": { + "deliveryWithInstall": true, + "moduleName": "entry", + "moduleType": "entry" + }, + "abilities": [ + { + "visible": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ], + "name": "com.example.myapplication.MainAbility", + "icon": "$media:icon", + "description": "$string:mainability_description", + "label": "MyApplication", + "type": "page", + "launchType": "standard" + } + ], + "js": [ + { + "pages": [ + "pages/index/index" + ], + "name": "default", + "window": { + "designWidth": 720, + "autoDesignWidth": false + } + } + ] + } + } + \ No newline at end of file diff --git a/relational_store/test/js/gdb/unittest/openharmony_sx.p7b b/relational_store/test/js/gdb/unittest/openharmony_sx.p7b new file mode 100644 index 0000000000000000000000000000000000000000..9be1e98fa4c0c28ca997ed660112fa16b194f0f5 Binary files /dev/null and b/relational_store/test/js/gdb/unittest/openharmony_sx.p7b differ diff --git a/relational_store/test/js/gdb/unittest/src/BUILD.gn b/relational_store/test/js/gdb/unittest/src/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..04e1cf5c67a9063b4e720dee43d382203e8d0847 --- /dev/null +++ b/relational_store/test/js/gdb/unittest/src/BUILD.gn @@ -0,0 +1,29 @@ +# Copyright (C) 2024 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. + +import("//build/test.gni") + +module_output_path = "relational_store/gdb" + +ohos_js_unittest("GdbJsTest") { + module_out_path = module_output_path + + hap_profile = "../config.json" + + certificate_profile = "../openharmony_sx.p7b" +} + +group("unittest") { + testonly = true + deps = [ ":GdbJsTest" ] +} diff --git a/relational_store/test/js/gdb/unittest/src/GdbStoreGdbStoreJsunit.test.js b/relational_store/test/js/gdb/unittest/src/GdbStoreGdbStoreJsunit.test.js new file mode 100644 index 0000000000000000000000000000000000000000..f6ea11ba9705f08cbed21d7ee51a9884f3286bbb --- /dev/null +++ b/relational_store/test/js/gdb/unittest/src/GdbStoreGdbStoreJsunit.test.js @@ -0,0 +1,422 @@ +/* + * Copyright (C) 2024 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. + */ + +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from 'deccjsunit/index' +import graphStore from '@ohos.data.graphStore' +import ability_featureAbility from '@ohos.ability.featureAbility' + +const TAG = "[GRAPH_STORE_JSKITS_TEST]"; +const context = ability_featureAbility.getContext(); +const CREATE_GRAPH_TEST = "CREATE GRAPH test {(person:Person {name STRING, age INT}), (person) -[:Friend]-> (person)};" +const STORE_CONFIG = { + name: "graphstore", + securityLevel: graphStore.SecurityLevel.S1, +}; + +describe('graphStoreTest', () => { + beforeAll(async () => { + console.info(TAG + 'beforeAll'); + }) + + beforeEach(async () => { + console.info(TAG + 'beforeEach'); + }) + + afterEach(async () => { + console.info(TAG + 'afterEach'); + await graphStore.deleteStore(context, STORE_CONFIG); + }) + + afterAll(async () => { + console.info(TAG + 'afterAll'); + }) + + console.info(TAG + "*************Unit Test Begin*************"); + + /** + * @tc.name graph store getStore test + * @tc.number GdbStoreGdbStoreJsunitTest0001 + * @tc.desc graph store getStore test + */ + it('testGraphStore0001', 0, async () => { + console.info(TAG + "************* testGraphStore0001 start *************"); + try { + let store = await graphStore.getStore(context, STORE_CONFIG); + await store.close(); + await graphStore.deleteStore(context, STORE_CONFIG); + } catch (e) { + console.error(TAG + "graphStore test_1 failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStore0001 end *************"); + }) + + /** + * @tc.name graph store getStore test + * @tc.number GdbStoreGdbStoreJsunitTest0002 + * @tc.desc graph store getStore and write + */ + it('testGraphStore0002', 0, async () => { + console.info(TAG + "************* testGraphStore0002 start *************"); + try { + let store = await graphStore.getStore(context, STORE_CONFIG); + await store.write(CREATE_GRAPH_TEST); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("DROP GRAPH test"); + await store.close(); + await graphStore.deleteStore(context, STORE_CONFIG); + } catch (e) { + console.error(TAG + "graphStore test_2 failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStore0002 end *************"); + }) + + /** + * @tc.name graph store getStore test + * @tc.number GdbStoreGdbStoreJsunitTest0003 + * @tc.desc graph store getStore with wrong storeConfig name + */ + it('testGraphStore0003', 0, async () => { + console.info(TAG + "************* testGraphStore0003 start *************"); + let storeConfig = { + name: "/wrong/graphstore", + securityLevel: graphStore.SecurityLevel.S1, + }; + try { + let store = await graphStore.getStore(context, storeConfig); + await store.write(CREATE_GRAPH_TEST); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("DROP GRAPH test"); + await store.close(); + await graphStore.deleteStore(context, storeConfig); + expect().assertFail(); + } catch (e) { + expect('401').assertEqual(e.code); + } + console.info(TAG + "************* testGraphStore0003 end *************"); + }) + + /** + * @tc.name graph store getStore test + * @tc.number GdbStoreGdbStoreJsunitTest0004 + * @tc.desc graph store getStore with securityLevel + */ + it('testGraphStore0004', 0, async () => { + console.info(TAG + "************* testGraphStore0004 start *************"); + let storeConfig = { + name: "secure", + securityLevel: graphStore.SecurityLevel.S3, + }; + try { + let store = await graphStore.getStore(context, storeConfig); + await store.write(CREATE_GRAPH_TEST); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("DROP GRAPH test"); + await store.close(); + await graphStore.deleteStore(context, storeConfig); + } catch (e) { + console.error(TAG + "graphStore test_4 failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStore0004 end *************"); + }) + + /** + * @tc.name graph store getStore test + * @tc.number GdbStoreGdbStoreJsunitTest0005 + * @tc.desc graph store getStore with invalid securityLevel + */ + it('testGraphStore0005', 0, async () => { + console.info(TAG + "************* testGraphStore0005 start *************"); + let storeConfig = { + name: "secure", + securityLevel: 0, + }; + try { + //expect getStore failed + let store = await graphStore.getStore(context, storeConfig); + await store.write(CREATE_GRAPH_TEST); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("DROP GRAPH test"); + await store.close(); + await graphStore.deleteStore(context, storeConfig); + expect().assertFail(); + } catch (e) { + expect(401).assertEqual(e.code); + } + console.info(TAG + "************* testGraphStore0005 end *************"); + }) + + /** + * @tc.name graph store getStore test + * @tc.number GdbStoreGdbStoreJsunitTest0006 + * @tc.desc graph store getStore with 1 param + */ + it('testGraphStore0006', 0, async () => { + console.info(TAG + "************* testGraphStore0006 start *************"); + try { + //expect getStore failed + let store = await graphStore.getStore(STORE_CONFIG); + expect().assertFail(); + } catch (e) { + expect('401').assertEqual(e.code); + } + console.info(TAG + "************* testGraphStore0006 end *************"); + }) + + /** + * @tc.name graph store getStore test + * @tc.number GdbStoreGdbStoreJsunitTest0007 + * @tc.desc graph store getStore name has db Suffix + */ + it('testGraphStore0007', 0, async () => { + console.info(TAG + "************* testGraphStore0007 start *************"); + let storeConfig = { + name: "suffix.db", + securityLevel: graphStore.SecurityLevel.S1, + } + try { + // expect get store failed + let store = await graphStore.getStore(context, storeConfig); + await store.write(CREATE_GRAPH_TEST); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("DROP GRAPH test"); + await store.close(); + await graphStore.deleteStore(context, storeConfig); + expect().assertFail(); + } catch (e) { + expect(31300000).assertEqual(e.code); + } + console.info(TAG + "************* testGraphStore0007 end *************"); + }) + + /** + * @tc.name graph store getStore test + * @tc.number GdbStoreGdbStoreJsunitTest0008 + * @tc.desc graph store getStore with null storeConfig name + */ + it('testGraphStore0008', 0, async () => { + console.info(TAG + "************* testGraphStore0008 start *************"); + let storeConfig = { + securityLevel: graphStore.SecurityLevel.S1, + } + try { + // expect get store failed + let store = await graphStore.getStore(context, storeConfig); + await store.write(CREATE_GRAPH_TEST); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("DROP GRAPH test"); + await store.close(); + await graphStore.deleteStore(context, storeConfig); + expect().assertFail(); + } catch (e) { + expect('401').assertEqual(e.code); + } + console.info(TAG + "************* testGraphStore0008 end *************"); + }) + + /** + * @tc.name graph store getStore test + * @tc.number GdbStoreGdbStoreJsunitTest0009 + * @tc.desc graph store getStore name has special characters + */ + it('testGraphStore0009', 0, async () => { + console.info(TAG + "************* testGraphStore0009 start *************"); + let storeConfig = { + name: "char*@#!(.&", + securityLevel: graphStore.SecurityLevel.S1, + } + try { + // expect get store failed + let store = await graphStore.getStore(context, storeConfig); + await store.write(CREATE_GRAPH_TEST); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("DROP GRAPH test"); + await store.close(); + await graphStore.deleteStore(context, storeConfig); + expect().assertFail(); + } catch (e) { + expect(31300000).assertEqual(e.code); + } + console.info(TAG + "************* testGraphStore0009 end *************"); + }) + + /** + * @tc.name graph store getStore test + * @tc.number GdbStoreGdbStoreJsunitTest0010 + * @tc.desc graph store getStore SecurityLevel S2->S1 + */ + it('testGraphStore0010', 0, async () => { + console.info(TAG + "************* testGraphStore0010 start *************"); + let storeConfig = { + name: "graphstore", + securityLevel: graphStore.SecurityLevel.S2, + } + try { + let store = await graphStore.getStore(context, storeConfig); + await store.close(); + store = await graphStore.getStore(context, STORE_CONFIG); + expect().assertFail(); + } catch (e) { + expect(401).assertEqual(e.code); + } + await graphStore.deleteStore(context, storeConfig); + console.info(TAG + "************* testGraphStore0010 end *************"); + }) + + /** + * @tc.name graph store getStore test + * @tc.number GdbStoreGdbStoreJsunitTest0011 + * @tc.desc graph store getStore SecurityLevel S1->S2 + */ + it('testGraphStore0011', 0, async () => { + console.info(TAG + "************* testGraphStore0011 start *************"); + let storeConfig = { + name: "graphstore", + securityLevel: graphStore.SecurityLevel.S2, + } + try { + let store = await graphStore.getStore(context, STORE_CONFIG); + await store.close(); + store = await graphStore.getStore(context, storeConfig); + await store.close(); + await graphStore.deleteStore(context, storeConfig); + } catch (e) { + console.error(TAG + "graphStore test_11 failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStore0011 end *************"); + }) + + /** + * @tc.name graph store deleteStore test + * @tc.number GdbStoreGdbStoreJsunitTest0012 + * @tc.desc graph store deleteStore test + */ + it('testGraphStore0012', 0, async () => { + console.info(TAG + "************* testGraphStore0012 start *************"); + let store = await graphStore.getStore(context, STORE_CONFIG); + await store.write(CREATE_GRAPH_TEST); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("DROP GRAPH test"); + await store.close(); + try { + await graphStore.deleteStore(context, STORE_CONFIG); + } catch (e) { + console.error(TAG + "graphStore test_12 failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStore0012 end *************"); + }) + + /** + * @tc.name graph store deleteStore test + * @tc.number GdbStoreGdbStoreJsunitTest0013 + * @tc.desc graph store deleteStore with wrong store name + */ + it('testGraphStore0013', 0, async () => { + console.info(TAG + "************* testGraphStore0013 start *************"); + let storeConfig = { + name: "/wrong/graphstore", + securityLevel: graphStore.SecurityLevel.S1, + } + let store = await graphStore.getStore(context, STORE_CONFIG); + await store.write(CREATE_GRAPH_TEST); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("DROP GRAPH test"); + await store.close(); + try { + await graphStore.deleteStore(context, storeConfig); + expect().assertFail(); + } catch (e) { + expect('401').assertEqual(e.code); + } + console.info(TAG + "************* testGraphStore0013 end *************"); + }) + + /** + * @tc.name graph store deleteStore test + * @tc.number GdbStoreGdbStoreJsunitTest0014 + * @tc.desc graph store deleteStore with different store name + */ + it('testGraphStore0014', 0, async () => { + console.info(TAG + "************* testGraphStore0014 start *************"); + let storeConfig = { + name: "teststore", + securityLevel: graphStore.SecurityLevel.S1, + } + let store = await graphStore.getStore(context, STORE_CONFIG); + await store.write(CREATE_GRAPH_TEST); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("DROP GRAPH test"); + await store.close(); + try { + // delete success + await graphStore.deleteStore(context, storeConfig); + } catch (e) { + expect().assertFail(); + } + console.info(TAG + "************* testGraphStore0014 end *************"); + }) + + /** + * @tc.name graph store deleteStore test + * @tc.number GdbStoreGdbStoreJsunitTest0015 + * @tc.desc graph store deleteStore with different securityLevel + */ + it('testGraphStore0015', 0, async () => { + console.info(TAG + "************* testGraphStore0015 start *************"); + let storeConfig = { + name: "graphstore", + securityLevel: graphStore.SecurityLevel.S4, + } + let store = await graphStore.getStore(context, STORE_CONFIG); + await store.write(CREATE_GRAPH_TEST); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("DROP GRAPH test"); + await store.close(); + try { + // delete success + await graphStore.deleteStore(context, storeConfig); + } catch (e) { + expect().assertFail(); + } + console.info(TAG + "************* testGraphStore0015 end *************"); + }) + + /** + * @tc.name graph store deleteStore test + * @tc.number GdbStoreGdbStoreJsunitTest0016 + * @tc.desc graph store deleteStore with 1 param + */ + it('testGraphStore0016', 0, async () => { + console.info(TAG + "************* testGraphStore0016 start *************"); + let store = await graphStore.getStore(context, STORE_CONFIG); + await store.write(CREATE_GRAPH_TEST); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("DROP GRAPH test"); + await store.close(); + try { + await graphStore.deleteStore(context); + expect().assertFail(); + } catch (e) { + expect('401').assertEqual(e.code); + } + console.info(TAG + "************* testGraphStore0016 end *************"); + }) + + console.info(TAG + "*************Unit Test End*************"); +}) diff --git a/relational_store/test/js/gdb/unittest/src/GdbStoreReadWriteJsunit.test.js b/relational_store/test/js/gdb/unittest/src/GdbStoreReadWriteJsunit.test.js new file mode 100644 index 0000000000000000000000000000000000000000..17cb922e14b96194f3d9a58d1525453c6a9ba052 --- /dev/null +++ b/relational_store/test/js/gdb/unittest/src/GdbStoreReadWriteJsunit.test.js @@ -0,0 +1,936 @@ +/* + * Copyright (C) 2024 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. + */ + +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from 'deccjsunit/index' +import graphStore from '@ohos.data.graphStore' +import ability_featureAbility from '@ohos.ability.featureAbility' + +const TAG = "[GRAPH_STORE_JSKITS_TEST]"; +const context = ability_featureAbility.getContext(); +const CREATE_GRAPH_TEST = "CREATE GRAPH test {(person:Person {name STRING, age INT}), (person) -[:Friend]-> (person)};" +const STORE_CONFIG = { + name: "readwritegraph", + securityLevel: graphStore.SecurityLevel.S1, +}; + +describe('graphStoreReadWriteTest', () => { + let store; + beforeAll(async () => { + console.info(TAG + 'beforeAll'); + await graphStore.deleteStore(context, STORE_CONFIG); + store = await graphStore.getStore(context, STORE_CONFIG); + }) + + beforeEach(async () => { + console.info(TAG + 'beforeEach'); + await store.write(CREATE_GRAPH_TEST); + }) + + afterEach(async () => { + console.info(TAG + 'afterEach'); + await store.write("DROP GRAPH test"); + }) + + afterAll(async () => { + console.info(TAG + 'afterAll'); + await store.close(); + await graphStore.deleteStore(context, STORE_CONFIG); + }) + + console.info(TAG + "*************Unit Test Begin*************"); + + /** + * @tc.name graph store close test + * @tc.number GdbStoreCloseTest0001 + * @tc.desc graph store close test + */ + it('testGraphStoreClose0001', 0, async () => { + console.info(TAG + "************* testGraphStoreClose0001 start *************"); + let storeConfig = { + name: "closeStore", + securityLevel: graphStore.SecurityLevel.S1, + }; + let closestore = await graphStore.getStore(context, storeConfig); + await closestore.write(CREATE_GRAPH_TEST); + await closestore.write("INSERT (:Person {name: 'name_1', age: 11});"); + await closestore.write("DROP GRAPH test"); + try { + await closestore.close(); + } catch (e) { + console.error(TAG + "close test failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + await graphStore.deleteStore(context, storeConfig); + console.info(TAG + "************* testGraphStoreClose0001 end *************"); + }) + + /** + * @tc.name graph store write test + * @tc.number GdbStoreWriteTest0001 + * @tc.desc graph store write insert + */ + it('testGraphStoreWrite0001', 0, async () => { + console.info(TAG + "************* testGraphStoreWrite0001 start *************"); + try { + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + await store.write( + "MATCH (p1:Person {name: 'name_1'}), (p2:Person {name: 'name_2'}) INSERT (p1) -[:Friend]-> (p2);" + ); + let result = await store.read("MATCH (p:Person) where p.age < 30 RETURN p") + if (result.records) { + expect(2).assertEqual(result.records.length); + } else { + console.error(TAG + "write test1 INSERT vertex failed."); + expect().assertFail(); + } + let path = await store.read( + "MATCH path = (p1:Person {name: 'name_1'})-[]-(p2:Person {name: 'name_2'}) RETURN path;" + ); + if (path.records) { + expect(1).assertEqual(path.records.length); + } else { + console.error(TAG + "write test1 INSERT edge failed."); + expect().assertFail(); + } + } catch (e) { + console.error(TAG + "write test1 failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStoreWrite0001 end *************"); + }) + + /** + * @tc.name graph store write test + * @tc.number GdbStoreWriteTest0002 + * @tc.desc graph store write update + */ + it('testGraphStoreWrite0002', 0, async () => { + console.info(TAG + "************* testGraphStoreWrite0002 start *************"); + try { + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + await store.write( + "MATCH (p1:Person {name: 'name_1'}), (p2:Person {name: 'name_2'}) INSERT (p1) -[:Friend]-> (p2);" + ); + await store.write("MATCH (p1:Person {name: 'name_1'}) SET p1.age = 21;"); + await store.write("MATCH (p2:Person {name: 'name_2'}) SET p2.name = 'Aname';"); + await store.write("MATCH (n:Person {name: 'name_1'})-[r:Friend]->(m:Person) SET m.age = 32"); + + let p1 = await store.read("MATCH (p1:Person) where p1.name = 'name_1' RETURN p1;"); + if (p1.records) { + expect(1).assertEqual(p1.records.length); + let temp = p1.records[0]; + let vertex = temp["p1"]; + expect('1').assertEqual(vertex.vid); + let proper = vertex.properties; + expect(21).assertEqual(proper["AGE"]); + expect('name_1').assertEqual(proper["NAME"]); + } else { + console.error(TAG + "write test2 read data1 failed."); + expect().assertFail(); + } + + let p2 = await store.read("MATCH (p2:Person) where p2.name = 'name_2' RETURN p2;"); + if (p2.records) { + expect(0).assertEqual(p2.records.length); + } else { + console.error(TAG + "write test2 read data2 failed."); + expect().assertFail(); + } + + let p3 = await store.read("MATCH (p3:Person) where p3.name = 'Aname' RETURN p3;"); + if (p3.records) { + expect(1).assertEqual(p3.records.length); + let temp = p3.records[0]; + let vertex = temp["p3"]; + expect('2').assertEqual(vertex.vid); + let proper = vertex.properties; + expect(32).assertEqual(proper["AGE"]); + expect('Aname').assertEqual(proper["NAME"]); + } else { + console.error(TAG + "write test2 read data3 failed."); + expect().assertFail(); + } + } catch (e) { + console.error(TAG + "write test2 failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStoreWrite0002 end *************"); + }) + + /** + * @tc.name graph store write test + * @tc.number GdbStoreWriteTest0003 + * @tc.desc graph store write delete + */ + it('testGraphStoreWrite0003', 0, async () => { + console.info(TAG + "************* testGraphStoreWrite0003 start *************"); + try { + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + await store.write( + "MATCH (p1:Person {name: 'name_1'}), (p2:Person {name: 'name_2'}) INSERT (p1) -[:Friend]-> (p2);" + ); + await store.write("MATCH (p:Person {name: 'name_1'}) DETACH DELETE p;"); + // read + let p = await store.read("MATCH (p:Person) where p.age < 30 RETURN p"); + if (p.records) { + expect(1).assertEqual(p.records.length); + } else { + console.error(TAG + "write test3 read data1 failed."); + expect().assertFail(); + } + + let path = await store.read( + "MATCH path = (p1:Person {name: 'name_1'})-[]-(p2:Person {name: 'name_2'}) RETURN path;" + ) + if (path.records) { + expect(0).assertEqual(path.records.length); + } else { + console.error(TAG + "write test3 read data2 failed."); + expect().assertFail(); + } + } catch (e) { + console.error(TAG + "write test3 failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStoreWrite0003 end *************"); + }) + + /** + * @tc.name graph store write test + * @tc.number GdbStoreWriteTest0004 + * @tc.desc graph store write with 2 params + */ + it('testGraphStoreWrite0004', 0, async () => { + console.info(TAG + "************* testGraphStoreWrite0004 start *************"); + try { + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + let INSERT1 = "INSERT (:Person {name: 'name_3', age: 33});" + let INSERT2 = "INSERT (:Person {name: 'name_4', age: 44});" + await store.write(INSERT1, INSERT2); + expect().assertFail(); + } catch (e) { + expect('401').assertEqual(e.code); + // read + let p = await store.read("MATCH (p:Person) where p.age < 50 RETURN p"); + if (p.records) { + expect(2).assertEqual(p.records.length); + } else { + console.error(TAG + "write test4 read data failed."); + expect().assertFail(); + } + } + console.info(TAG + "************* testGraphStoreWrite0004 end *************"); + }) + + /** + * @tc.name graph store write test + * @tc.number GdbStoreWriteTest0005 + * @tc.desc graph store close before write + */ + it('testGraphStoreWrite0005', 0, async () => { + console.info(TAG + "************* testGraphStoreWrite0005 start *************"); + let storeConfig = { + name: "closeStore", + securityLevel: graphStore.SecurityLevel.S1, + }; + let closestore = await graphStore.getStore(context, storeConfig); + await closestore.write(CREATE_GRAPH_TEST); + try { + await closestore.write("INSERT (:Person {name: 'name_1', age: 11});"); + let p = await closestore.read("MATCH (p:Person) where p.age < 30 RETURN p"); + if (p.records) { + expect(1).assertEqual(p.records.length); + } else { + console.error(TAG + "write test5 read data failed."); + expect().assertFail(); + } + await closestore.close(); + await closestore.write("INSERT (:Person {name: 'name_2', age: 22});"); + expect().assertFail(); + } catch (e) { + expect('31300002').assertEqual(e.code); + } + await graphStore.deleteStore(context, storeConfig); + console.info(TAG + "************* testGraphStoreWrite0005 end *************"); + }) + + /** + * @tc.name graph store write test + * @tc.number GdbStoreWriteTest0006 + * @tc.desc graph store write with duplicate type + */ + it('testGraphStoreWrite0006', 0, async () => { + console.info(TAG + "************* testGraphStoreWrite0006 start *************") + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + let INSERT = "INSERT (:Person {name: 'name_3', name: 'name_4', age: 33});" + try { + //insert failed but no error + await store.write(INSERT); + let result = await store.write("MATCH (p:Person) where p.age = 33 RETURN p;"); + if (result.records) { + expect(0).assertEqual(result.records.length); + } + } catch (e) { + console.error(TAG + "write test6 failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStoreWrite0006 end *************"); + }) + + /** + * @tc.name graph store write test + * @tc.number GdbStoreWriteTest0007 + * @tc.desc graph store write with undefined type + */ + it('testGraphStoreWrite0007', 0, async () => { + console.info(TAG + "************* testGraphStoreWrite0007 start *************"); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + let UPDATE = "MATCH (p:Person {name: 'name_1'}) DETACH DELETE p_error" + try { + await store.write(UPDATE); + expect().assertFail(); + } catch (e) { + expect(31300007).assertEqual(e.code); + // read + let p = await store.read("MATCH (p:Person) where p.age < 50 RETURN p"); + if (p.records) { + expect(2).assertEqual(p.records.length); + } else { + console.error(TAG + "write test7 read data failed."); + expect().assertFail(); + } + } + console.info(TAG + "************* testGraphStoreWrite0007 end *************"); + }) + + /** + * @tc.name graph store write test + * @tc.number GdbStoreWriteTest0008 + * @tc.desc graph store write with GQL statement syntax error + */ + it('testGraphStoreWrite0008', 0, async () => { + console.info(TAG + "************* testGraphStoreWrite0008 start *************"); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + let INSERT = "INSERT (:ZOO {name: 'name_3', age: 33);" + try { + await store.write(INSERT); + expect().assertFail(); + } catch (e) { + expect(31300009).assertEqual(e.code); + // read + let p = await store.read("MATCH (p:Person) where p.age < 50 RETURN p"); + if (p.records) { + expect(2).assertEqual(p.records.length); + } else { + console.error(TAG + "write test8 read data failed."); + expect().assertFail(); + } + } + console.info(TAG + "************* testGraphStoreWrite0008 end *************"); + }) + + /** + * @tc.name graph store write test + * @tc.number GdbStoreWriteTest0009 + * @tc.desc graph store write with GQL statement semantic error + */ + it('testGraphStoreWrite0009', 0, async () => { + console.info(TAG + "************* testGraphStoreWrite0009 start *************"); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + let UPDATE = "MATCH (p1:Person {name: 'name_1'}) SET p1.age = 'six';" + try { + await store.write(UPDATE); + expect().assertFail(); + } catch (e) { + expect(31300010).assertEqual(e.code); + // read + let p = await store.read("MATCH (p:Person) where p.age < 50 RETURN p"); + if (p.records) { + expect(2).assertEqual(p.records.length); + let temp = p.records[0]; + let vertex = temp["p"]; + expect('1').assertEqual(vertex.vid); + let proper = vertex.properties; + expect('name_1').assertEqual(proper["NAME"]); + expect(11).assertEqual(proper["AGE"]); + } else { + console.error(TAG + "write test9 read data failed."); + expect().assertFail(); + } + } + console.info(TAG + "************* testGraphStoreWrite0009 end *************"); + }) + + /** + * @tc.name graph store write test + * @tc.number GdbStoreWriteTest0010 + * @tc.desc graph store write and update null data + */ + it('testGraphStoreWrite0010', 0, async () => { + console.info(TAG + "************* testGraphStoreWrite0010 start *************"); + await store.write("INSERT (:Person {name: 'name_1'});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + let data = await store.read("MATCH (p:Person) where p.age < 50 RETURN p"); + if (data.records) { + expect(1).assertEqual(data.records.length); + let temp = data.records[0]; + let vertex = temp["p"]; + expect('2').assertEqual(vertex.vid); + let proper = vertex.properties; + expect(22).assertEqual(proper["AGE"]); + } else { + console.error(TAG + "write test10 INSERT data failed."); + expect().assertFail(); + } + let UPDATE1 = "MATCH (p1:Person {name: 'name_1'}) SET p1.age = 16;" + let UPDATE2 = "MATCH (p2:Person {name: 'name_2'}) SET p2.age = 16, p2.name = null;" + try { + await store.write(UPDATE1); + await store.write(UPDATE2); + data = await store.read("MATCH (p:Person) where p.age < 50 RETURN p"); + if (data.records) { + expect(2).assertEqual(data.records.length); + let temp = data.records[0]; + let vertex = temp["p"]; + expect('1').assertEqual(vertex.vid); + let proper = vertex.properties; + expect('name_1').assertEqual(proper["NAME"]); + expect(16).assertEqual(proper["AGE"]); + + temp = data.records[1]; + vertex = temp["p"]; + expect('2').assertEqual(vertex.vid); + proper = vertex.properties; + // name undefined + expect(16).assertEqual(proper["AGE"]); + } else { + console.error(TAG + "write test10 read data failed."); + expect().assertFail(); + } + } catch (e) { + console.error(TAG + "write test10 update null data failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStoreWrite0010 end *************"); + }) + + /** + * @tc.name graph store write test + * @tc.number GdbStoreWriteTest0011 + * @tc.desc graph store write create too many graphs + */ + it('testGraphStoreWrite0011', 0, async () => { + console.info(TAG + "************* testGraphStoreWrite0011 start *************"); + try { + await store.write("CREATE GRAPH test1 {(company:Company {rowid INT, name STRING}) };"); + expect().assertFail(); + } catch (e) { + expect(31300012).assertEqual(e.code); + } + console.info(TAG + "************* testGraphStoreWrite0011 end *************"); + }) + + /** + * @tc.name graph store write test + * @tc.number GdbStoreWriteTest0012 + * @tc.desc graph store write delete the vertexs of a relation + */ + it('testGraphStoreWrite0012', 0, async () => { + console.info(TAG + "************* testGraphStoreWrite0012 start *************"); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + await store.write("INSERT (:Person {name: 'name_3', age: 33});"); + await store.write( + "MATCH (p1:Person {name: 'name_1'}), (p3:Person {name: 'name_3'}) INSERT (p1) -[:Friend]-> (p3);" + ); + let data = await store.read("MATCH (p:Person) where p.age < 50 RETURN p"); + if (data.records) { + expect(3).assertEqual(data.records.length); + } else { + console.error(TAG + "write test12 INSERT data failed."); + expect().assertFail(); + } + let DELETE = "MATCH (p:Person)-[:Friend]->(relatedP:Person) DETACH DELETE p, relatedP;" + try { + await store.write(DELETE); + data = await store.read("MATCH (p:Person) where p.age < 50 RETURN p"); + // read data + if (data.records) { + expect(1).assertEqual(data.records.length); + let temp = data.records[0]; + let vertex = temp["p"]; + expect('2').assertEqual(vertex.vid); + let proper = vertex.properties; + expect('name_2').assertEqual(proper["NAME"]); + expect(22).assertEqual(proper["AGE"]); + } else { + console.error(TAG + "write test12 read data failed."); + expect().assertFail(); + } + } catch (e) { + console.error(TAG + "write test12 delete failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStoreWrite0012 end *************"); + }) + + /** + * @tc.name graph store read test + * @tc.number GdbStoreReadTest0001 + * @tc.desc graph store read query vertex test + */ + it('testGraphStoreRead0001', 0, async () => { + console.info(TAG + "************* testGraphStoreRead0001 start *************"); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + await store.write("INSERT (:Person {name: 'name_3', age: 22});"); + try { + let p = await store.read("MATCH (p:Person {age: 22}) RETURN p;"); + if (p.records) { + expect(2).assertEqual(p.records.length); + let temp = p.records[0]; + let vertex = temp["p"]; + expect('2').assertEqual(vertex.vid); + let proper = vertex.properties; + expect('name_2').assertEqual(proper["NAME"]); + expect(22).assertEqual(proper["AGE"]); + + temp = p.records[1]; + vertex = temp["p"]; + expect('3').assertEqual(vertex.vid); + proper = vertex.properties; + expect('name_3').assertEqual(proper["NAME"]); + expect(22).assertEqual(proper["AGE"]); + } else { + console.error(TAG + "read test1 query failed."); + expect().assertFail(); + } + } catch (e) { + console.error(TAG + "read test1 failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStoreRead0001 end *************"); + }) + + /** + * @tc.name graph store read test + * @tc.number GdbStoreReadTest0002 + * @tc.desc graph store read query null data test + */ + it('testGraphStoreRead0002', 0, async () => { + console.info(TAG + "************* testGraphStoreRead0002 start *************"); + await store.write("INSERT (:Person {age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + await store.write("INSERT (:Person {name: 'name_3', age: 22});"); + try { + let p = await store.read("MATCH (p:Person {age: 11}) RETURN p;"); + if (p.records) { + expect(1).assertEqual(p.records.length); + let temp = p.records[0]; + let vertex = temp["p"]; + expect('1').assertEqual(vertex.vid); + let proper = vertex.properties; + // name undefined + expect(11).assertEqual(proper["AGE"]); + } else { + console.error(TAG + "read test2 query null data failed."); + expect().assertFail(); + } + + p = await store.read("MATCH (p:Person {age: 22}) RETURN p;"); + if (p.records) { + expect(2).assertEqual(p.records.length); + let temp = p.records[0]; + let vertex = temp["p"]; + expect('2').assertEqual(vertex.vid); + let proper = vertex.properties; + expect('name_2').assertEqual(proper["NAME"]); + expect(22).assertEqual(proper["AGE"]); + + temp = p.records[1]; + vertex = temp["p"]; + proper = vertex.properties; + expect('name_3').assertEqual(proper["NAME"]); + } else { + console.error(TAG + "read test2 query null data failed."); + expect().assertFail(); + } + } catch (e) { + console.error(TAG + "read test2 failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStoreRead0002 end *************"); + }) + + /** + * @tc.name graph store read test + * @tc.number GdbStoreReadTest0003 + * @tc.desc graph store read by relation + */ + it('testGraphStoreRead0003', 0, async () => { + console.info(TAG + "************* testGraphStoreRead0003 start *************"); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + await store.write("INSERT (:Person {name: 'name_3', age: 22});"); + await store.write( + "MATCH (p1:Person {name: 'name_1'}), (p2:Person {name: 'name_2'}) INSERT (p1)-[:Friend]->(p2);" + ) + try { + let data = await store.read( + "MATCH (p1:Person {age: 11})-[r:Friend]->(p2:Person {name :'name_2'}) RETURN p1, r, p2;" + ); + if (data.records) { + expect(1).assertEqual(data.records.length); + let temp = data.records[0]; + let vertex = temp["p1"]; + expect('1').assertEqual(vertex.vid); + let proper = vertex.properties; + expect('name_1').assertEqual(proper["NAME"]); + expect(11).assertEqual(proper["AGE"]); + + let edge = temp["r"]; + expect('4').assertEqual(edge.eid); + expect('1').assertEqual(edge.startVid); + expect('2').assertEqual(edge.endVid); + + vertex = temp["p2"]; + expect('2').assertEqual(vertex.vid); + proper = vertex.properties; + expect(22).assertEqual(proper["AGE"]); + } else { + console.error(TAG + "read test3 query relation failed."); + expect().assertFail(); + } + } catch (e) { + console.error(TAG + "read test3 failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStoreRead0003 end *************"); + }) + + /** + * @tc.name graph store read test + * @tc.number GdbStoreReadTest0004 + * @tc.desc graph store read by where statement + */ + it('testGraphStoreRead0004', 0, async () => { + console.info(TAG + "************* testGraphStoreRead0004 start *************"); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + await store.write("INSERT (:Person {name: 'name_3', age: 22});"); + try { + let data = await store.read("MATCH (p:Person) where p.age >= 22 RETURN p;"); + if (data.records) { + expect(2).assertEqual(data.records.length); + let temp = data.records[0]; + let vertex = temp["p"]; + expect('2').assertEqual(vertex.vid); + let proper = vertex.properties; + expect('name_2').assertEqual(proper["NAME"]); + expect(22).assertEqual(proper["AGE"]); + + temp = data.records[1]; + vertex = temp["p"]; + expect('3').assertEqual(vertex.vid); + proper = vertex.properties; + expect('name_3').assertEqual(proper["NAME"]); + } else { + console.error(TAG + "read test4 query by where failed."); + expect().assertFail(); + } + } catch (e) { + console.error(TAG + "read test4 failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStoreRead0004 end *************"); + }) + + /** + * @tc.name graph store read test + * @tc.number GdbStoreReadTest0005 + * @tc.desc graph store read by where statement + */ + it('testGraphStoreRead0005', 0, async () => { + console.info(TAG + "************* testGraphStoreRead0005 start *************"); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + await store.write("INSERT (:Person {name: 'name_3', age: 22});"); + try { + let data = await store.read("MATCH (p:Person) where p.age < 22 RETURN p;"); + if (data.records) { + expect(1).assertEqual(data.records.length); + let temp = data.records[0]; + let vertex = temp["p"]; + expect('1').assertEqual(vertex.vid); + let proper = vertex.properties; + expect('name_1').assertEqual(proper["NAME"]); + expect(11).assertEqual(proper["AGE"]); + } else { + console.error(TAG + "read test5 query by where failed."); + expect().assertFail(); + } + } catch (e) { + console.error(TAG + "read test5 failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStoreRead0005 end *************"); + }) + + /** + * @tc.name graph store read test + * @tc.number GdbStoreReadTest0006 + * @tc.desc graph store read by where statement + */ + it('testGraphStoreRead0006', 0, async () => { + console.info(TAG + "************* testGraphStoreRead0006 start *************"); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + await store.write("INSERT (:Person {name: 'name_3', age: 33});"); + try { + let data = await store.read("MATCH (p:Person) where p.age <> 22 RETURN p;"); + if (data.records) { + expect(2).assertEqual(data.records.length); + let temp = data.records[0]; + let vertex = temp["p"]; + expect('1').assertEqual(vertex.vid); + let proper = vertex.properties; + expect('name_1').assertEqual(proper["NAME"]); + expect(11).assertEqual(proper["AGE"]); + + temp = data.records[1]; + vertex = temp["p"]; + expect('3').assertEqual(vertex.vid); + proper = vertex.properties; + expect('name_3').assertEqual(proper["NAME"]); + expect(33).assertEqual(proper["AGE"]); + } else { + console.error(TAG + "read test6 query by where failed."); + expect().assertFail(); + } + } catch (e) { + console.error(TAG + "read test6 failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStoreRead0006 end *************"); + }) + + /** + * @tc.name graph store read test + * @tc.number GdbStoreReadTest0007 + * @tc.desc graph store read by like statement + */ + it('testGraphStoreRead0007', 0, async () => { + console.info(TAG + "************* testGraphStoreRead0007 start *************"); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + await store.write("INSERT (:Person {name: 'name_3', age: 33});"); + try { + let data = await store.read("MATCH (p:Person) where p.name like 'name_%' RETURN p;"); + if (data.records) { + expect(3).assertEqual(data.records.length); + let temp = data.records[0]; + let vertex = temp["p"]; + expect('1').assertEqual(vertex.vid); + let proper = vertex.properties; + expect('name_1').assertEqual(proper["NAME"]); + expect(11).assertEqual(proper["AGE"]); + + temp = data.records[1]; + vertex = temp["p"]; + expect('2').assertEqual(vertex.vid); + proper = vertex.properties; + expect('name_2').assertEqual(proper["NAME"]); + expect(22).assertEqual(proper["AGE"]); + + temp = data.records[2]; + vertex = temp["p"]; + expect('3').assertEqual(vertex.vid); + proper = vertex.properties; + expect('name_3').assertEqual(proper["NAME"]); + expect(33).assertEqual(proper["AGE"]); + } else { + console.error(TAG + "read test7 query by like failed."); + expect().assertFail(); + } + } catch (e) { + console.error(TAG + "read test7 failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStoreRead0007 end *************"); + }) + + /** + * @tc.name graph store read test + * @tc.number GdbStoreReadTest0008 + * @tc.desc graph store read path + */ + it('testGraphStoreRead0008', 0, async () => { + console.info(TAG + "************* testGraphStoreRead0008 start *************"); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + await store.write("INSERT (:Person {name: 'name_3', age: 33});"); + await store.write( + "MATCH (p1:Person {name: 'name_1'}), (p2:Person {name: 'name_2'}) INSERT (p1) -[:Friend]-> (p2);" + ); + await store.write( + "MATCH (p2:Person {name: 'name_2'}), (p3:Person {name: 'name_3'}) INSERT (p2) -[:Friend]-> (p3);" + ); + try { + let data = await store.read( + "MATCH path = (a:Person {name: 'name_1'})-[]->{2,2}(b:Person {name: 'name_3'}) RETURN a, b, path;" + ); + if (data.records) { + expect(1).assertEqual(data.records.length); + let temp = data.records[0]; + + let vertex1 = temp["a"]; + expect('1').assertEqual(vertex1.vid); + let proper = vertex1.properties; + expect('name_1').assertEqual(proper["NAME"]); + expect(11).assertEqual(proper["AGE"]); + + let vertex2 = temp["b"]; + expect('3').assertEqual(vertex2.vid); + proper = vertex2.properties; + expect('name_3').assertEqual(proper["NAME"]); + expect(33).assertEqual(proper["AGE"]); + + let path = temp["path"]; + expect(2).assertEqual(path.length); + let segments = path.segments; + expect(JSON.stringify(vertex1)).assertEqual(JSON.stringify(segments[0].start)); + expect(JSON.stringify(vertex2)).assertEqual(JSON.stringify(segments[1].end)); + + let edge = segments[1].edge; + expect('5').assertEqual(edge.eid); + expect('2').assertEqual(edge.startVid); + expect('3').assertEqual(edge.endVid); + } else { + console.error(TAG + "read test8 query path failed."); + expect().assertFail(); + } + } catch (e) { + console.error(TAG + "read test8 failed, error:" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* testGraphStoreRead0008 end *************"); + }) + + /** + * @tc.name graph store read test + * @tc.number GdbStoreReadTest0009 + * @tc.desc graph store read with 2 params + */ + it('testGraphStoreRead0009', 0, async () => { + console.info(TAG + "************* testGraphStoreRead0009 start *************"); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + await store.write( + "MATCH (p1:Person {name: 'name_1'}), (p2:Person {name: 'name_2'}) INSERT (p1) -[:Friend]-> (p2);" + ); + + let MATCH1 = "MATCH (p1:Person {name: 'name_1'}) RETURN p1;" + let MATCH2 = "MATCH (p2:Person {name: 'name_2'}) RETURN p2;" + try { + let result = await store.read(MATCH1, MATCH2); + expect().assertFail(); + } catch (e) { + expect('401').assertEqual(e.code); + } + console.info(TAG + "************* testGraphStoreRead0009 end *************"); + }) + + /** + * @tc.name graph store read test + * @tc.number GdbStoreReadTest0010 + * @tc.desc graph store close before read + */ + it('testGraphStoreRead0010', 0, async () => { + console.info(TAG + "************* testGraphStoreRead0010 start *************"); + let storeConfig = { + name: "closeStore", + securityLevel: graphStore.SecurityLevel.S1, + }; + let closestore = await graphStore.getStore(context, storeConfig); + await closestore.write(CREATE_GRAPH_TEST); + await closestore.write("INSERT (:Person {name: 'name_1', age: 11});"); + await closestore.write("INSERT (:Person {name: 'name_2', age: 22});"); + await closestore.write( + "MATCH (p1:Person {name: 'name_1'}), (p2:Person {name: 'name_2'}) INSERT (p1) -[:Friend]-> (p2);" + ); + await closestore.close(); + let MATCH = "MATCH (p1:Person {name: 'name_1'}) RETURN p1;" + try { + let result = await closestore.read(MATCH); + expect().assertFail(); + } catch (e) { + expect('31300002').assertEqual(e.code); + } + await graphStore.deleteStore(context, storeConfig); + console.info(TAG + "************* testGraphStoreRead0010 end *************"); + }) + + /** + * @tc.name graph store read test + * @tc.number GdbStoreReadTest0011 + * @tc.desc graph store read with undefined type + */ + it('testGraphStoreRead0011', 0, async () => { + console.info(TAG + "************* testGraphStoreRead0011 start *************"); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + await store.write( + "MATCH (p1:Person {name: 'name_1'}), (p2:Person {name: 'name_2'}) INSERT (p1) -[:Friend]-> (p2);" + ); + let MATCH = "MATCH path = (p1:ZOO {name: 'name_1'})-[]-(p2:Person {name: 'name_2'}) RETURN path;" + try { + let result = await store.read(MATCH); + expect().assertFail(); + } catch (e) { + expect(31300007).assertEqual(e.code); + } + console.info(TAG + "************* testGraphStoreRead0011 end *************"); + }) + + /** + * @tc.name graph store read test + * @tc.number GdbStoreReadTest0012 + * @tc.desc graph store read with GQL statement syntax error + */ + it('testGraphStoreRead0012', 0, async () => { + console.info(TAG + "************* testGraphStoreRead0012 start *************"); + await store.write("INSERT (:Person {name: 'name_1', age: 11});"); + await store.write("INSERT (:Person {name: 'name_2', age: 22});"); + await store.write( + "MATCH (p1:Person {name: 'name_1'}), (p2:Person {name: 'name_2'}) INSERT (p1) -[:Friend]-> (p2);" + ); + try { + let result = await store.read("MATCH (p:Person {name: 'name_1}) RETURN p"); + expect().assertFail(); + } catch (e) { + expect(31300009).assertEqual(e.code); + } + console.info(TAG + "************* testGraphStoreRead0012 end *************"); + }) + console.info(TAG + "*************Unit Test End*************"); +}) \ No newline at end of file diff --git a/relational_store/test/js/rdb/performance/config.json b/relational_store/test/js/rdb/performance/config.json index 865615d255b08fd479e18891941ef167326e4561..8179c0c356df0e89d6db5181910f21a28d96bc60 100644 --- a/relational_store/test/js/rdb/performance/config.json +++ b/relational_store/test/js/rdb/performance/config.json @@ -19,7 +19,8 @@ "tablet", "2in1", "default", - "phone" + "phone", + "wearable" ], "distro": { "deliveryWithInstall": true, @@ -60,4 +61,4 @@ } ] } -} +} \ No newline at end of file diff --git a/relational_store/test/js/rdb/unittest/config.json b/relational_store/test/js/rdb/unittest/config.json index 865615d255b08fd479e18891941ef167326e4561..92c71ecea3597e6a31df7dfea3f9f69a4a18569b 100644 --- a/relational_store/test/js/rdb/unittest/config.json +++ b/relational_store/test/js/rdb/unittest/config.json @@ -7,8 +7,8 @@ "name": "1.0" }, "apiVersion": { - "compatible": 4, - "target": 5 + "compatible": 9, + "target": 14 } }, "deviceConfig": {}, @@ -19,7 +19,8 @@ "tablet", "2in1", "default", - "phone" + "phone", + "wearable" ], "distro": { "deliveryWithInstall": true, @@ -60,4 +61,4 @@ } ] } -} +} \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/performance/config.json b/relational_store/test/js/relationalstore/performance/config.json index 865615d255b08fd479e18891941ef167326e4561..8179c0c356df0e89d6db5181910f21a28d96bc60 100644 --- a/relational_store/test/js/relationalstore/performance/config.json +++ b/relational_store/test/js/relationalstore/performance/config.json @@ -19,7 +19,8 @@ "tablet", "2in1", "default", - "phone" + "phone", + "wearable" ], "distro": { "deliveryWithInstall": true, @@ -60,4 +61,4 @@ } ] } -} +} \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/unittest/config.json b/relational_store/test/js/relationalstore/unittest/config.json index 865615d255b08fd479e18891941ef167326e4561..92c71ecea3597e6a31df7dfea3f9f69a4a18569b 100644 --- a/relational_store/test/js/relationalstore/unittest/config.json +++ b/relational_store/test/js/relationalstore/unittest/config.json @@ -7,8 +7,8 @@ "name": "1.0" }, "apiVersion": { - "compatible": 4, - "target": 5 + "compatible": 9, + "target": 14 } }, "deviceConfig": {}, @@ -19,7 +19,8 @@ "tablet", "2in1", "default", - "phone" + "phone", + "wearable" ], "distro": { "deliveryWithInstall": true, @@ -60,4 +61,4 @@ } ] } -} +} \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbStoreCloud.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbStoreCloud.test.js index 1aa3f190f53b0185cbdc640f8ef72a828df9ce4d..1a9ebb64e1dc7f87b64fc9f53c28a0778793d501 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbStoreCloud.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbStoreCloud.test.js @@ -402,6 +402,97 @@ describe('rdbStoreCloud', function () { } }) + /** + * @tc.name set distributeded table cloud with promise + * @tc.number SUB_DDM_AppDataFWK_JSRDB_CLOUD_0014 + * @tc.desc set distributed table cloud with 'asyncDownloadAsset' is true + */ + it('testRdbStoreCloud0014', 0, async function (done) { + console.log(TAG + "************* testRdbStoreCloud0014 start *************"); + try { + let config = { + autoSync: false, + asyncDownloadAsset: true + } + await rdbStore.setDistributedTables(['employee'], + relationalStore.DistributedType.DISTRIBUTED_CLOUD, config).then(() => { + console.log(TAG + "set employee to be distributed cloud table success"); + expect(true).assertTrue(); + console.log(TAG + "************* testRdbStoreCloud0014 end *************"); + done(); + }).catch((err) => { + console.log(TAG + `set employee to be distributed table failed, errcode:${JSON.stringify(err)}.`); + expect().assertFail(); + done() + }); + } catch (err) { + console.log(TAG + `set employee to be distributed table failed, errcode:${JSON.stringify(err)}.`); + expect().assertFail(); + done() + } + }) + + /** + * @tc.name set distributeded table cloud with promise + * @tc.number SUB_DDM_AppDataFWK_JSRDB_CLOUD_0015 + * @tc.desc set distributed table cloud with 'asyncDownloadAsset' is true + */ + it('testRdbStoreCloud0015', 0, async function (done) { + console.log(TAG + "************* testRdbStoreCloud0015 start *************"); + try { + let config = { + autoSync: false, + asyncDownloadAsset: false + } + await rdbStore.setDistributedTables(['employee'], + relationalStore.DistributedType.DISTRIBUTED_CLOUD, config).then(()=>{ + console.log(TAG + "set employee to be distributed cloud table success"); + expect(true).assertTrue(); + console.log(TAG + "************* testRdbStoreCloud0015 end *************"); + done(); + }).catch((err)=>{ + console.log(TAG + `set employee to be distributed table failed, errcode:${JSON.stringify(err)}.`); + expect().assertFail(); + done() + }); + } catch (err) { + console.log(TAG + `set employee to be distributed table failed, errcode:${JSON.stringify(err)}.`); + expect().assertFail(); + done() + } + }) + + /** + * @tc.name set distributeded table cloud with promise + * @tc.number SUB_DDM_AppDataFWK_JSRDB_CLOUD_0016 + * @tc.desc set distributed table cloud with 'asyncDownloadAsset' is true + */ + it('testRdbStoreCloud0016', 0, async function (done) { + console.log(TAG + "************* testRdbStoreCloud0016 start *************"); + try { + let config = { + autoSync: false, + asyncDownloadAsset: 20 + } + await rdbStore.setDistributedTables(['employee'], + relationalStore.DistributedType.DISTRIBUTED_CLOUD, config).then(() => { + console.log(TAG + "set employee to be distributed cloud table success"); + expect().assertFail(); + console.log(TAG + "************* testRdbStoreCloud0016 end *************"); + done(); + }).catch((err) => { + console.log(TAG + `set employee to be distributed table failed, errcode:${JSON.stringify(err)}.`); + expect().assertFail(); + done() + }); + } catch (err) { + console.log(TAG + `set employee to be distributed table failed, errcode:${JSON.stringify(err)}.`); + expect(err.code == 401).assertTrue(); + expect(true).assertTrue(); // Parameter error must be catched here. + done() + } + }) + /** * @tc.name test field enum value * @tc.number SUB_DDM_AppDataFWK_JSRDB_CLOUD_0014 diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbStoreRdExecuteJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbStoreRdExecuteJsunit.test.js new file mode 100644 index 0000000000000000000000000000000000000000..b4c4570fd1da7c3bb3a9af02b1c16b46e528c13a --- /dev/null +++ b/relational_store/test/js/relationalstore/unittest/src/RdbStoreRdExecuteJsunit.test.js @@ -0,0 +1,817 @@ +/* + * Copyright (C) 2025 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. + */ + +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect} from 'deccjsunit/index' +import relationalStore from '@ohos.data.relationalStore'; +import ability_featureAbility from '@ohos.ability.featureAbility' + + +const TAG = "[RELATIONAL_STORE_JSKITS_TEST]" +const SELECT_VEC = + "'[0.0034683854319155216,0.03641285002231598,-0.07023966312408447,0.044056713581085205,0.0012323030969128013," + + "0.0668216347694397,-0.051434680819511414,-0.08662710338830948,-0.05796094238758087,0.0445525236427784," + + "0.06823701411485672,0.15785539150238037,0.008310764096677303,0.0031550948042422533,0.059119582176208496," + + "0.16296637058258057,-0.16677643358707428,0.028591593727469444,-0.0774831622838974,0.13105066120624542," + + "-0.06658935546875,-0.17502543330192566,0.0004895461024716496,-0.039065588265657425,-0.021489106118679047," + + "0.08095866441726685,0.1294800341129303,0.0903729498386383,0.03329519182443619,0.047984130680561066," + + "-0.0037370261270552874,-0.038509905338287354,0.0800866112112999,-0.027948979288339615,0.04174582660198212," + + "0.13182558119297028,-0.059934262186288834,-0.08387927711009979,0.113731250166893,-0.026094511151313782," + + "-0.1130823865532875,0.039138030260801315,0.007647618185728788,-0.0945548489689827,0.12383178621530533," + + "0.09071730822324753,-0.023663459345698357,-0.05253434553742409,-0.040944185107946396,0.10114503651857376," + + "-0.051067765802145004,0.034750234335660934,0.10236344486474991,-0.08334743976593018,-0.05340084061026573," + + "-0.12497875094413757,-0.004996792413294315,0.025939637795090675,0.056392405182123184,-0.09303992241621017," + + "0.04230094328522682,-0.033300627022981644,0.06190573796629906,-0.10170590877532959,0.033479053527116776," + + "0.11075326800346375,0.02244972623884678,-0.14792247116565704,-0.14567142724990845,-0.018098996952176094," + + "0.05258564278483391,0.0011908907908946276,0.1809721440076828,-0.022740621119737625,0.10480812191963196," + + "-0.10338152199983597,-0.030866824090480804,0.04990679770708084,-0.005369830410927534,0.025820014998316765," + + "0.08079411834478378,-0.18422630429267883,0.07818714529275894,0.09904448688030243,0.19703106582164764," + + "-0.11577515304088593,0.1655191332101822,-0.25517070293426514,0.20069096982479095,0.0844234824180603," + + "-0.12411679327487946,-0.019857294857501984,0.09271357953548431,-0.0442894883453846,0.059886328876018524," + + "0.002025386318564415,0.022315988317131996,-0.019258759915828705,-0.03424579277634621,-0.07038101553916931," + + "-0.02083408646285534,0.11584726721048355,0.04192301630973816,0.12722893059253693,-0.1408625841140747," + + "-0.02967262640595436,-0.014546873979270458,0.06512382626533508,-0.04907092824578285,-0.05675692856311798," + + "-0.026348542422056198,0.07538445293903351,0.08171205967664719,-0.06878633797168732,-0.130681112408638," + + "0.005745945032685995,-0.10949227958917618,0.13608132302761078,0.04036335274577141,-0.09908778220415115," + + "-0.025767125189304352,-0.05611008033156395,-0.06343607604503632,-0.03752011060714722,0.15635617077350616," + + "0.0960443913936615,0.03842826932668686,-0.12800946831703186]'"; +const vec1 = '[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,' + + '38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,' + + '75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,' + + '109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128]'; +const vec2 = '[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,' + + '38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,' + + '75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,' + + '109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129]'; +const vec3 = '[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,' + + '38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,' + + '75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,' + + '109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130]'; +const vec4 = '[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,' + + '39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,' + + '76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,' + + '109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131]'; +const vec5 = '[5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,' + + '39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,' + + '75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,' + + '108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132]'; +const vec6 = '[6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,' + + '40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,' + + '76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,' + + '109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133]'; +const vec7 = '[7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,' + + '40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,' + + '75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,' + + '107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134]'; +const vec8 = '[8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,' + + '41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,' + + '77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,' + + '110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135]'; +const vec9 = '[9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,' + + '42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,' + + '78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,' + + '111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136]'; +const vec10 = '[10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,' + + '42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,' + + '78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,' + + '110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137]'; + +let isSupportVector = false; +let store; +let context = ability_featureAbility.getContext() +const STORE_CONFIG = { + name: "vector_database_test.db", + securityLevel: relationalStore.SecurityLevel.S1, + vector: true, +}; +describe('rdbStoreRdExecuteTest', function () { + beforeAll(async function () { + console.info(TAG + 'beforeAll') + isSupportVector = relationalStore.isVectorSupported(); + console.info(TAG + 'isSupportVector: ' + isSupportVector); + }) + + beforeEach(async function () { + console.info(TAG + 'beforeEach') + if (!isSupportVector) { + console.error(TAG + 'not support vector.'); + return; + } + try { + store?.close(); + await relationalStore.deleteRdbStore(context, STORE_CONFIG); + store = await relationalStore.getRdbStore(context, STORE_CONFIG) + await store?.execute("CREATE TABLE IF NOT EXISTS title_vector_20" + + "(docId text primary key, dir text, fileExt text, appSource text, " + + "createdDate bigint, isDeleted bool);"); + await store?.execute("CREATE TABLE IF NOT EXISTS content_vector_20" + + "(uid bigint primary key, docId text, chunkId int, contentRepr floatvector(128) NOT COPY);"); + await store?.execute("CREATE INDEX idx ON content_vector_20 USING GSDISKANN(contentRepr COSINE) " + + "WITH (out_degree=46,enable_lvq=true,lvq_quant_bit=8,reserve_dist=false,accelerate_prune=true);"); + await store?.execute( + "INSERT INTO title_vector_20 VALUES ('1', 'opt/test/app00/', 'pptx', 'app00', 1685421482, true);"); + await store?.execute( + "INSERT INTO title_vector_20 VALUES ('2', 'opt/test/app11/', 'pptx', 'app11', 1685421483, true);"); + await store?.execute( + "INSERT INTO title_vector_20 VALUES ('3', 'opt/test/app22/', 'pptx', 'app22', 1685421484, true);"); + await store?.execute( + "INSERT INTO title_vector_20 VALUES ('4', 'opt/test/app33/', 'docx', 'app33', 1685421485, true);"); + await store?.execute( + "INSERT INTO title_vector_20 VALUES ('5', 'opt/test/app44/', 'docx', 'app44', 1685421486, true);"); + await store?.execute( + "INSERT INTO title_vector_20 VALUES ('6', 'opt/test/app55/', 'json', 'app55', 1685421487, true);"); + await store?.execute( + "INSERT INTO title_vector_20 VALUES ('7', 'opt/test/app66/', 'json', 'app66', 1685421488, true);"); + await store?.execute( + "INSERT INTO title_vector_20 VALUES ('8', 'opt/test/app77/', 'json', 'app77', 1685421489, true);"); + await store?.execute( + "INSERT INTO title_vector_20 VALUES ('9', 'opt/test/app88/', 'json', 'app88', 1685421489, true);"); + await store?.execute( + "INSERT INTO title_vector_20 VALUES ('10', 'opt/test/app99/', 'json', 'app99', 1685421499, true);"); + await store?.execute(`INSERT INTO content_vector_20 VALUES (1, '1', 1, '${vec1}');`); + await store?.execute(`INSERT INTO content_vector_20 VALUES (2, '2', 2, '${vec2}');`); + await store?.execute(`INSERT INTO content_vector_20 VALUES (3, '3', 3, '${vec3}');`); + await store?.execute(`INSERT INTO content_vector_20 VALUES (4, '4', 4, '${vec4}');`); + await store?.execute(`INSERT INTO content_vector_20 VALUES (5, '5', 5, '${vec5}');`); + await store?.execute(`INSERT INTO content_vector_20 VALUES (6, '6', 6, '${vec6}');`); + await store?.execute(`INSERT INTO content_vector_20 VALUES (7, '7', 7, '${vec7}');`); + await store?.execute(`INSERT INTO content_vector_20 VALUES (8, '8', 8, '${vec8}');`); + await store?.execute(`INSERT INTO content_vector_20 VALUES (9, '9', 9, '${vec9}');`); + await store?.execute(`INSERT INTO content_vector_20 VALUES (10, '10', 10, '${vec10}');`); + } catch (e) { + console.error(TAG + `beforeEach init data failed. errcode: ${e.code}`); + } + }) + + afterEach(async function () { + console.info(TAG + 'afterEach') + try { + await store?.close(); + store = null; + await relationalStore.deleteRdbStore(context, STORE_CONFIG); + } catch (e) { + console.error(TAG + `clear data failed. errcode: ${e.code}`); + } + }) + + afterAll(async function () { + console.info(TAG + 'afterAll') + }) + + console.log(TAG + "*************Unit Test Begin*************"); + + /** + * @tc.name testVectorSubSelectSuccess0001 + * @tc.number SUB_DISTRIBUTEDDATAMGR_RDB_JSVectorStore_SubSelect_success_0001 + * @tc.desc sub select in select where success + */ + it('testVectorSubSelectSuccess0001', 0, async function () { + console.log(TAG + "************* testVectorSubSelectSuccess0001 start *************"); + if (!isSupportVector) { + expect(isSupportVector).assertFalse(); + return; + } + try { + const selectSql = `SELECT docId, chunkId, contentRepr, contentRepr <=> ${SELECT_VEC} as vc + FROM content_vector_20 + WHERE contentRepr <=> ${SELECT_VEC} + < 1 + AND docId IN ( + SELECT docId from title_vector_20 WHERE (createdDate + > 1685421481 + and createdDate + < 1685507881) + AND (dir = 'opt/test/app00/' + or dir = 'opt/test/app22/' + or dir = 'opt/test/app44/') + AND isDeleted = true + ) + ORDER BY contentRepr <=> ${SELECT_VEC} LIMIT 20;`; + const result = await store?.querySql(selectSql); + expect(result?.rowCount).assertEqual(3); + result?.close(); + } catch (e) { + console.error(TAG + `testVectorSubSelectSuccess0001 failed. err: ${JSON.stringify(e)}`); + expect().assertFail(); + } + console.log(TAG + "************* testVectorSubSelectSuccess0001 end *************"); + }); + + /** + * @tc.name testVectorSubSelectFailed0001 + * @tc.number SUB_DISTRIBUTEDDATAMGR_RDB_JSVectorStore_SubSelect_failed_0001 + * @tc.desc sub select in select where failed, syntax error + */ + it('testVectorSubSelectFailed0001', 0, async function () { + console.log(TAG + "************* testVectorSubSelectFailed0001 start *************"); + if (!isSupportVector) { + expect(isSupportVector).assertFalse(); + return; + } + try { + const selectSql = `SELECT docId, chunkId, contentRepr, contentRepr <=> ${SELECT_VEC} as vc + FROM content_vector_20 + WHERE contentRepr <=> ${SELECT_VEC} + < 1 + AND docId IN ( + SELECT docId from title_vector_201 WHERE (createdDate + > 1685421481 + and createdDate + < 1685507881) + AND (dir = 'opt/test/app00/' + or dir = 'opt/test/app22/' + or dir = 'opt/test/app44/') + AND isDeleted = true + ) + ORDER BY contentRepr <=> ${SELECT_VEC} LIMIT 20;`; + const result = await store?.querySql(selectSql); + expect(result?.rowCount).assertEqual(-1); + expect(result?.goToNextRow()).assertFalse(); + result?.close(); + } catch (e) { + console.error(TAG + `testVectorSubSelectFailed0001 failed. err: ${JSON.stringify(e)}`); + expect().assertFail(); + } + console.log(TAG + "************* testVectorSubSelectFailed0001 end *************"); + }); + + /** + * @tc.name testVectorSubSelectFailed0002 + * @tc.number SUB_DISTRIBUTEDDATAMGR_RDB_JSVectorStore_SubSelect_failed_0002 + * @tc.desc sub select in select where failed, result empty + */ + it('testVectorSubSelectFailed0002', 0, async function () { + console.log(TAG + "************* testVectorSubSelectFailed0002 start *************"); + if (!isSupportVector) { + expect(isSupportVector).assertFalse(); + return; + } + try { + const selectSql = `SELECT docId, chunkId, contentRepr, contentRepr <=> ${SELECT_VEC} as vc + FROM content_vector_20 + WHERE contentRepr <=> ${SELECT_VEC} + < 1 + AND docId IN ( + SELECT docId from title_vector_20 WHERE (createdDate + > 1685421481 + and createdDate + < 1685507881) + AND (dir = 'opt/test/app00/1' + or dir = 'opt/test/app22/1' + or dir = 'opt/test/app44/1') + AND isDeleted = true + ) + ORDER BY contentRepr <=> ${SELECT_VEC} LIMIT 20;`; + const result = await store?.querySql(selectSql); + expect(result?.rowCount).assertEqual(0); + expect(result?.goToNextRow()).assertFalse(); + result?.close(); + } catch (e) { + console.error(TAG + `testVectorSubSelectFailed0002 failed. err: ${JSON.stringify(e)}`); + expect().assertFail(); + } + console.log(TAG + "************* testVectorSubSelectFailed0002 end *************"); + }); + + /** + * @tc.name testVectorSubSelectSuccess0002 + * @tc.number SUB_DISTRIBUTEDDATAMGR_RDB_JSVectorStore_SubSelect_success_0002 + * @tc.desc sub select in select from success + */ + it('testVectorSubSelectSuccess0002', 0, async function () { + console.log(TAG + "************* testVectorSubSelectSuccess0002 start *************"); + if (!isSupportVector) { + expect(isSupportVector).assertFalse(); + return; + } + try { + const selectSql = `select * + from (SELECT docId + from title_vector_20 + WHERE (createdDate > 1685421481 and createdDate < 1685507881) + AND (dir = 'opt/test/app00/' or dir = 'opt/test/app22/' or + dir = 'opt/test/app44/') + AND isDeleted = true) as docId;`; + const result = await store?.querySql(selectSql); + expect(result?.rowCount).assertEqual(3); + result?.close(); + } catch (e) { + console.error(TAG + `testVectorSubSelectSuccess0002 failed. err: ${JSON.stringify(e)}`); + expect().assertFail(); + } + console.log(TAG + "************* testVectorSubSelectSuccess0002 end *************"); + }); + + /** + * @tc.name testVectorSubSelectSuccess0003 + * @tc.number SUB_DISTRIBUTEDDATAMGR_RDB_JSVectorStore_SubSelect_success_0003 + * @tc.desc sub select in select target success + */ + it('testVectorSubSelectSuccess0003', 0, async function () { + console.log(TAG + "************* testVectorSubSelectSuccess0003 start *************"); + if (!isSupportVector) { + expect(isSupportVector).assertFalse(); + return; + } + try { + const selectSql = `select (SELECT contentRepr <=> ${SELECT_VEC} as vc + FROM content_vector_20 + WHERE contentRepr <=> ${SELECT_VEC} < 1) as myVc + from title_vector_20`; + const result = await store?.querySql(selectSql); + expect(result?.rowCount).assertEqual(10); + result?.close(); + } catch (e) { + console.error(TAG + `testVectorSubSelectSuccess0004 failed. err: ${JSON.stringify(e)}`); + expect().assertFail(); + } + console.log(TAG + "************* testVectorSubSelectSuccess0003 end *************"); + }); + + /** + * @tc.name testVectorSubSelectSuccess0004 + * @tc.number SUB_DISTRIBUTEDDATAMGR_RDB_JSVectorStore_SubSelect_success_0004 + * @tc.desc sub select in insert success + */ + it('testVectorSubSelectSuccess0004', 0, async function () { + console.log(TAG + "************* testVectorSubSelectSuccess0004 start *************"); + if (!isSupportVector) { + expect(isSupportVector).assertFalse(); + return; + } + try { + const createTable2 = `CREATE TABLE IF NOT EXISTS title_vector_21 + ( + docId text primary key, + dir text, + fileExt text, + appSource text, + createdDate bigint, + isDeleted bool + );`; + await store?.execute(createTable2); + + const insert = `insert into title_vector_21 select * from title_vector_20;`; + await store?.execute(insert); + + const result = await store?.querySql(`select * from title_vector_21`); + expect(result?.rowCount).assertEqual(10); + result?.close(); + } catch (e) { + console.error(TAG + `testVectorSubSelectSuccess0004 failed. err: ${JSON.stringify(e)}`); + expect().assertFail(); + } + console.log(TAG + "************* testVectorSubSelectSuccess0004 end *************"); + }); + + /** + * @tc.name testVectorSubSelectFailed0003 + * @tc.number SUB_DISTRIBUTEDDATAMGR_RDB_JSVectorStore_SubSelect_failed_0003 + * @tc.desc sub select in insert failed, sub select empty + */ + it('testVectorSubSelectFailed0003', 0, async function () { + console.log(TAG + "************* testVectorSubSelectFailed0003 start *************"); + if (!isSupportVector) { + expect(isSupportVector).assertFalse(); + return; + } + const createTable2 = `CREATE TABLE IF NOT EXISTS title_vector_21 + ( + docId text primary key, + dir text, + fileExt text, + appSource text, + createdDate bigint, + isDeleted bool + );`; + await store?.execute(createTable2); + try { + const insert = `insert into title_vector_20 select * from title_vector_21;`; + await store?.execute(insert); + + const result = await store?.querySql(`select * from title_vector_20`); + expect(result?.rowCount).assertEqual(10); + result?.close(); + } catch (e) { + console.error(TAG + `testVectorSubSelectFailed0003 failed. err: ${JSON.stringify(e)}`); + expect().assertFail(); + } + console.log(TAG + "************* testVectorSubSelectFailed0003 end *************"); + }); + + /** + * @tc.name testVectorSubSelectFailed0004 + * @tc.number SUB_DISTRIBUTEDDATAMGR_RDB_JSVectorStore_SubSelect_failed_0004 + * @tc.desc sub select in insert failed, syntax error + */ + it('testVectorSubSelectFailed0004', 0, async function () { + console.log(TAG + "************* testVectorSubSelectFailed0004 start *************"); + if (!isSupportVector) { + expect(isSupportVector).assertFalse(); + return; + } + const createTable2 = `CREATE TABLE IF NOT EXISTS title_vector_21 + ( + docId text primary key, + dir text, + fileExt text, + appSource text, + createdDate bigint, + isDeleted bool + );`; + await store?.execute(createTable2); + try { + const insert = `insert into title_vector_21 select * from title_vector_22;`; + await store?.execute(insert); + } catch (e) { + console.error(TAG + `testVectorSubSelectFailed0004 failed. err: ${JSON.stringify(e)}`); + expect(e.code).assertEqual(14800000); + } + console.log(TAG + "************* testVectorSubSelectFailed0004 end *************"); + }); + + /** + * @tc.name testVectorSubSelectSuccess0005 + * @tc.number SUB_DISTRIBUTEDDATAMGR_RDB_JSVectorStore_SubSelect_success_0005 + * @tc.desc sub select in delete success + */ + it('testVectorSubSelectSuccess0005', 0, async function () { + console.log(TAG + "************* testVectorSubSelectSuccess0005 start *************"); + if (!isSupportVector) { + expect(isSupportVector).assertFalse(); + return; + } + try { + const deleteSql = `delete + from content_vector_20 + where docId IN (SELECT docId + from title_vector_20 + WHERE (createdDate > 1685421481 and createdDate < 1685507881) + AND (dir = 'opt/test/app00/' or dir = 'opt/test/app22/' or + dir = 'opt/test/app44/') + AND isDeleted = true);`; + await store?.execute(deleteSql); + + const result = await store?.querySql(`select * from content_vector_20`); + expect(result?.rowCount).assertEqual(7); + result?.close(); + } catch (e) { + console.error(TAG + `testVectorSubSelectSuccess0005 failed. err: ${JSON.stringify(e)}`); + expect().assertFail(); + } + console.log(TAG + "************* testVectorSubSelectSuccess0005 end *************"); + }); + + /** + * @tc.name testVectorSubSelectFailed0005 + * @tc.number SUB_DISTRIBUTEDDATAMGR_RDB_JSVectorStore_SubSelect_failed_0005 + * @tc.desc sub select in delete failed, syntax error + */ + it('testVectorSubSelectFailed0005', 0, async function () { + console.log(TAG + "************* testVectorSubSelectSuccess0005 start *************"); + if (!isSupportVector) { + expect(isSupportVector).assertFalse(); + return; + } + try { + const deleteSql = `delete + from content_vector_20 + where docId IN (SELECT docIds + from title_vector_20 + WHERE (createdDate > 1685421481 and createdDate < 1685507881) + AND (dir = 'opt/test/app00/' or dir = 'opt/test/app22/' or + dir = 'opt/test/app44/') + AND isDeleted = true);`; + await store?.execute(deleteSql); + } catch (e) { + console.error(TAG + `testVectorSubSelectFailed0005 failed. err: ${JSON.stringify(e)}`); + expect(e.code).assertEqual(14800000); + } + console.log(TAG + "************* testVectorSubSelectFailed0005 end *************"); + }); + + /** + * @tc.name testVectorSubSelectFailed0006 + * @tc.number SUB_DISTRIBUTEDDATAMGR_RDB_JSVectorStore_SubSelect_failed_0006 + * @tc.desc sub select in delete failed, sub select empty + */ + it('testVectorSubSelectFailed0006', 0, async function () { + console.log(TAG + "************* testVectorSubSelectFailed0006 start *************"); + if (!isSupportVector) { + expect(isSupportVector).assertFalse(); + return; + } + try { + const deleteSql = `delete + from content_vector_20 + where docId IN (SELECT docId + from title_vector_20 + WHERE (createdDate > 1685421481 and createdDate < 1685507881) + AND (dir = 'opt/test/app00/111' or dir = 'opt/test/app22/111' or + dir = 'opt/test/app44/111') + AND isDeleted = true);`; + await store?.execute(deleteSql); + + const result = await store?.querySql(`select * from content_vector_20`); + expect(result?.rowCount).assertEqual(10); + result?.close(); + } catch (e) { + console.error(TAG + `testVectorSubSelectFailed0006 failed. err: ${JSON.stringify(e)}`); + expect().assertFail(); + } + console.log(TAG + "************* testVectorSubSelectFailed0006 end *************"); + }); + + /** + * @tc.name testVectorSubSelectSuccess0006 + * @tc.number SUB_DISTRIBUTEDDATAMGR_RDB_JSVectorStore_SubSelect_success_0006 + * @tc.desc sub select in update where success + */ + it('testVectorSubSelectSuccess0006', 0, async function () { + console.log(TAG + "************* testVectorSubSelectSuccess0006 start *************"); + if (!isSupportVector) { + expect(isSupportVector).assertFalse(); + return; + } + const where = `WHERE contentRepr <=> ${SELECT_VEC} < 1 AND docId IN ( + SELECT docId from title_vector_20 WHERE (createdDate > 1685421481 and createdDate < 1685507881) + AND (dir = 'opt/test/app00/' or dir = 'opt/test/app22/' or dir = 'opt/test/app44/') + AND isDeleted = true + );`; + const selectSql = `select docId, chunkId from content_vector_20 ${where}`; + + try { + const result = await store?.querySql(selectSql); + while (result?.goToNextRow()) { + let value1 = result?.getValue(0); + let value2 = result?.getValue(1); + console.log(TAG + "before docId: " + value1?.toString() + ", chunkId: " + value2?.toString()); + } + expect(result?.rowCount).assertEqual(3); + result?.close(); + const expectChunkId = 111; + const updateSql = `update content_vector_20 set chunkId = ${expectChunkId} ${where}`; + await store?.execute(updateSql); + + const result2 = await store?.querySql(selectSql); + while (result2?.goToNextRow()) { + let value1 = result2?.getValue(0); + let value2 = result2?.getValue(1); + expect(expectChunkId == value2).assertTrue(); + console.log(TAG + "after docId: " + value1?.toString() + ", chunkId: " + value2?.toString()); + } + expect(result2?.rowCount).assertEqual(3); + result2?.close(); + } catch (e) { + console.error(TAG + `testVectorSubSelectSuccess0006 failed. err: ${JSON.stringify(e)}`); + expect().assertFail(); + } + console.log(TAG + "************* testVectorSubSelectSuccess0006 end *************"); + }); + + /** + * @tc.name testVectorSubSelectFailed0007 + * @tc.number SUB_DISTRIBUTEDDATAMGR_RDB_JSVectorStore_SubSelect_failed_0007 + * @tc.desc sub select in update where, sub select empty + */ + it('testVectorSubSelectFailed0007', 0, async function () { + console.log(TAG + "************* testVectorSubSelectFailed0007 start *************"); + if (!isSupportVector) { + expect(isSupportVector).assertFalse(); + return; + } + const selectSql = `select chunkId + from content_vector_20 + WHERE contentRepr <=> ${SELECT_VEC} + < 1 + AND docId IN ( + SELECT docId from title_vector_20 WHERE (createdDate + > 1685421481 + and createdDate + < 1685507881) + AND (dir = 'opt/test/app00/' + or dir = 'opt/test/app22/' + or dir = 'opt/test/app44/') + AND isDeleted = true + );`; + + try { + const result = await store?.querySql(selectSql); + while (result?.goToNextRow()) { + let value = result?.getValue(0); + console.log(TAG + "value: " + value?.toString()); + } + expect(result?.rowCount).assertEqual(3); + result?.close(); + + const updateSql = `update content_vector_20 + set chunkId = 111 + WHERE contentRepr <=> ${SELECT_VEC} + < 1 + AND docId IN ( + SELECT docId from title_vector_20 WHERE (createdDate + > 1685421481 + and createdDate + < 1685507881) + AND (dir = 'opt/test/app00/111' + or dir = 'opt/test/app22/111' + or dir = 'opt/test/app44/111') + AND isDeleted = true + );`; + await store?.execute(updateSql); + + const result2 = await store?.querySql(selectSql); + while (result2?.goToNextRow()) { + let value = result2?.getValue(0); + console.log(TAG + "value: " + value?.toString()); + } + expect(result2?.rowCount).assertEqual(3); + result2?.close(); + } catch (e) { + console.error(TAG + `testVectorSubSelectFailed0007 failed. err: ${JSON.stringify(e)}`); + expect().assertFail(); + } + console.log(TAG + "************* testVectorSubSelectFailed0007 end *************"); + }); + + /** + * @tc.name testVectorSubSelectSuccess0007 + * @tc.number SUB_DISTRIBUTEDDATAMGR_RDB_JSVectorStore_SubSelect_success_0007 + * @tc.desc sub select in update set success + */ + it('testVectorSubSelectSuccess0007', 0, async function () { + console.log(TAG + "************* testVectorSubSelectSuccess0007 start *************"); + if (!isSupportVector) { + expect(isSupportVector).assertFalse(); + return; + } + const selectSql = `select chunkId + from content_vector_20 + WHERE contentRepr <=> ${SELECT_VEC} + < 1 + AND docId IN ( + SELECT docId from title_vector_20 WHERE (createdDate + > 1685421481 + and createdDate + < 1685507881) + AND (dir = 'opt/test/app00/' + or dir = 'opt/test/app22/' + or dir = 'opt/test/app44/') + AND isDeleted = true + );`; + + try { + const result = await store?.querySql(selectSql); + while (result?.goToNextRow()) { + let value = result?.getValue(0); + console.log(TAG + "value: " + value?.toString()); + } + expect(result?.rowCount).assertEqual(3); + result?.close(); + + const updateSql = `update content_vector_20 + set chunkId = (select sum(chunkId) from content_vector_20) + WHERE contentRepr <=> ${SELECT_VEC} + < 1 + AND docId IN ( + SELECT docId from title_vector_20 WHERE (createdDate + > 1685421481 + and createdDate + < 1685507881) + AND (dir = 'opt/test/app00/' + or dir = 'opt/test/app22/' + or dir = 'opt/test/app44/') + AND isDeleted = true + );`; + await store?.execute(updateSql); + + const result2 = await store?.querySql(selectSql); + const expectChunkId = 55; + while (result2?.goToNextRow()) { + let value = result2?.getValue(0); + expect(expectChunkId == value).assertTrue(); + console.log(TAG + "value: " + value?.toString()); + } + expect(result2?.rowCount).assertEqual(3); + result2?.close(); + } catch (e) { + console.error(TAG + `testVectorSubSelectSuccess0007 failed. err: ${JSON.stringify(e)}`); + expect().assertFail(); + } + console.log(TAG + "************* testVectorSubSelectSuccess0007 end *************"); + }); + + /** + * @tc.name testVectorSubSelectFailed0008 + * @tc.number SUB_DISTRIBUTEDDATAMGR_RDB_JSVectorStore_SubSelect_failed_0008 + * @tc.desc sub select in update set, sub select empty + */ + it('testVectorSubSelectFailed0008', 0, async function () { + console.log(TAG + "************* testVectorSubSelectFailed0008 start *************"); + if (!isSupportVector) { + expect(isSupportVector).assertFalse(); + return; + } + const selectSql = `select chunkId + from content_vector_20 + WHERE contentRepr <=> ${SELECT_VEC} + < 1 + AND docId IN ( + SELECT docId from title_vector_20 WHERE (createdDate + > 1685421481 + and createdDate + < 1685507881) + AND (dir = 'opt/test/app00/' + or dir = 'opt/test/app22/' + or dir = 'opt/test/app44/') + AND isDeleted = true + );`; + + try { + const result = await store?.querySql(selectSql); + while (result?.goToNextRow()) { + let value = result?.getValue(0); + console.log(TAG + "value: " + value?.toString()); + } + expect(result?.rowCount).assertEqual(3); + result?.close(); + + const updateSql = `update content_vector_20 + set chunkId = (select sum(chunkId) from content_vector_20 where chunkId = 111) + WHERE contentRepr <=> ${SELECT_VEC} + < 1 + AND docId IN ( + SELECT docId from title_vector_20 WHERE (createdDate + > 1685421481 + and createdDate + < 1685507881) + AND (dir = 'opt/test/app00/' + or dir = 'opt/test/app22/' + or dir = 'opt/test/app44/') + AND isDeleted = true + );`; + await store?.execute(updateSql); + + const result2 = await store?.querySql(selectSql); + while (result2?.goToNextRow()) { + let value = result2?.getValue(0); + console.log(TAG + "value: " + value?.toString()); + } + expect(result2?.rowCount).assertEqual(3); + result2?.close(); + } catch (e) { + console.error(TAG + `testVectorSubSelectFailed0008 failed. err: ${JSON.stringify(e)}`); + expect().assertFail(); + } + console.log(TAG + "************* testVectorSubSelectFailed0008 end *************"); + }); + + /** + * @tc.name testVectorSubSelectFailed0009 + * @tc.number SUB_DISTRIBUTEDDATAMGR_RDB_JSVectorStore_SubSelect_failed_0009 + * @tc.desc sub select in update set, sub select result out of range. + */ + it('testVectorSubSelectFailed0009', 0, async function () { + console.log(TAG + "************* testVectorSubSelectFailed0009 start *************"); + if (!isSupportVector) { + expect(isSupportVector).assertFalse(); + return; + } + const selectSql = `select chunkId from content_vector_20 + WHERE contentRepr <=> ${SELECT_VEC} < 1 AND docId IN ( + SELECT docId from title_vector_20 WHERE (createdDate > 1685421481 and createdDate < 1685507881) + AND (dir = 'opt/test/app00/' or dir = 'opt/test/app22/' or dir = 'opt/test/app44/') + AND isDeleted = true group by docId + );`; + + const result = await store?.querySql(selectSql); + + try { + while (result?.goToNextRow()) { + let value = result.getValue(0); + console.log(TAG + "value: " + value?.toString()); + } + result?.getValue(10); + expect().assertFail(); + result?.close(); + } catch (e) { + console.error(TAG + `testVectorSubSelectFailed0009 failed. err: ${JSON.stringify(e)}`); + result?.close(); + expect(14800012 == e.code).assertTrue(); + } + console.log(TAG + "************* testVectorSubSelectFailed0009 end *************"); + }); + + console.log(TAG + "*************Unit Test End*************"); +}) \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbStoreReadOnlyJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbStoreReadOnlyJsunit.test.js index 49f31906fb8dbfe645839bd8c24de4cbb05f58e1..ede3df40d1cd526566b33aa9c2f2d7ed53d0da7d 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbStoreReadOnlyJsunit.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbStoreReadOnlyJsunit.test.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from 'deccjsunit/index'; import relationalStore from '@ohos.data.relationalStore'; import featureAbility from '@ohos.ability.featureAbility' @@ -51,7 +51,6 @@ describe('rdbStoreReadOnlyTest', function () { try { await relationalStore.deleteRdbStore(context, STORE_CONFIG); let rdbStore = await relationalStore.getRdbStore(context, STORE_CONFIG); - expect(rdbStore === null).assertFalse(); const CREATE_TABLE_SQL = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, " + "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; @@ -60,9 +59,8 @@ describe('rdbStoreReadOnlyTest', function () { await rdbStore.insert('test', valueBucket); await rdbStore.insert('test', valueBucket); - rdbStore.backup(STORE_CONFIG2.name) + await rdbStore.backup(STORE_CONFIG2.name) await relationalStore.deleteRdbStore(context, STORE_CONFIG); - } catch (err) { console.error(TAG, `init database failed, errCode:${err.code}, message:${err.message}`); expect().assertFail(); @@ -71,7 +69,6 @@ describe('rdbStoreReadOnlyTest', function () { beforeEach(async function () { store = await relationalStore.getRdbStore(context, STORE_CONFIG2); - expect(store === null).assertFalse(); console.info(TAG + 'beforeEach'); }) @@ -297,6 +294,70 @@ describe('rdbStoreReadOnlyTest', function () { console.info(TAG + "************* readOnlyTest0010 end *************"); }) + /** + * @tc.name batch insert with conflict resolution to read-only database + * @tc.number readOnlyTest011 + * @tc.desc batch insert with conflict resolution by store + * @tc.size MediumTest + * @tc.type Function + * @tc.level Level 2 + */ + it('readOnlyTest011', 0, async function () { + console.info(TAG + "************* readOnlyTest011 start *************"); + const row = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + } + let valueBucketArray = new Array(); + for (let i = 0; i < 2; i++) { + valueBucketArray.push(row); + } + try { + store.batchInsertWithConflictResolutionSync('test', valueBucketArray, relationalStore.ConflictResolution.ON_CONFLICT_NONE); + expect().assertFail(); + } catch (err) { + console.error(TAG, `readOnlyTest011 ON_CONFLICT_NONE failed, errCode:${err.code}, message:${err.message}`); + expect(err.code == 801).assertTrue(); + } + try { + await store.batchInsertWithConflictResolution('test', valueBucketArray, relationalStore.ConflictResolution.ON_CONFLICT_ROLLBACK); + expect().assertFail(); + } catch (err) { + console.error(TAG, `readOnlyTest011 ON_CONFLICT_ROLLBACK failed, errCode:${err.code}, message:${err.message}`); + expect(err.code == 801).assertTrue(); + } + try { + store.batchInsertWithConflictResolutionSync('test', valueBucketArray, relationalStore.ConflictResolution.ON_CONFLICT_ABORT); + expect().assertFail(); + } catch (err) { + console.error(TAG, `readOnlyTest011 ON_CONFLICT_ABORT failed, errCode:${err.code}, message:${err.message}`); + expect(err.code == 801).assertTrue(); + } + try { + await store.batchInsertWithConflictResolution('test', valueBucketArray, relationalStore.ConflictResolution.ON_CONFLICT_FAIL); + expect().assertFail(); + } catch (err) { + console.error(TAG, `readOnlyTest011 ON_CONFLICT_FAIL failed, errCode:${err.code}, message:${err.message}`); + expect(err.code == 801).assertTrue(); + } + try { + store.batchInsertWithConflictResolutionSync('test', valueBucketArray, relationalStore.ConflictResolution.ON_CONFLICT_IGNORE); + expect().assertFail(); + } catch (err) { + console.error(TAG, `readOnlyTest011 ON_CONFLICT_IGNORE failed, errCode:${err.code}, message:${err.message}`); + expect(err.code == 801).assertTrue(); + } + try { + await store.batchInsertWithConflictResolution('test', valueBucketArray, relationalStore.ConflictResolution.ON_CONFLICT_REPLACE); + expect().assertFail(); + } catch (err) { + console.error(TAG, `readOnlyTest011 ON_CONFLICT_REPLACE failed, errCode:${err.code}, message:${err.message}`); + expect(err.code == 801).assertTrue(); + } + console.info(TAG + "************* readOnlyTest011 end *************"); + }) + console.info(TAG + "*************Unit Test End*************"); }) diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetGetRow.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetGetRow.test.js index 0f27c785829d2b9b9106f1f972b11904330fbf87..ccba5086621e11c03cf40e7970efe69b28c8c71a 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetGetRow.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetGetRow.test.js @@ -285,5 +285,1011 @@ describe('rdbStoreResultSetGetRowTest', function () { expect(1).assertEqual(valueBucket_ret["1"]); console.log(TAG + "************* rdbStoreResultSetGetRowTest0009 end *************"); }) + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRowTest0010 + * @tc.desc Insert a string greater than number.MAX_SAFE_INTEGER is also obtained as a string by getRow + */ + it('rdbStoreResultSetGetRowTest0010', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowTest0010 start *************"); + let rowId = 0; + let valueNum = Number.MAX_SAFE_INTEGER.toString() + 0; + let valueBucket = { + data2: valueNum + }; + rowId = await rdbStore.insert("test", valueBucket); + expect(1).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + resultSet.goToFirstRow(); + let res = resultSet.getRow(); + resultSet.close(); + console.info(TAG + 'valueNum ' + valueNum + ' getRow data2:' + res.data2 + ' type:' + typeof res.data2); + expect(valueNum).assertEqual(res.data2); + console.info(TAG + "************* rdbStoreResultSetGetRowTest0010 end *************"); + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRowTest0011 + * @tc.desc Insert as a string equal to number.MAX_SAFE_INTEGER, getRow obtains the number + */ + it('rdbStoreResultSetGetRowTest0011', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowTest0011 start *************"); + let rowId = 0; + let valueNum = Number.MAX_SAFE_INTEGER.toString(); + let valueBucket = { + data2: valueNum + }; + rowId = await rdbStore.insert("test", valueBucket); + expect(1).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + resultSet.goToFirstRow(); + let res = resultSet.getRow(); + resultSet.close(); + console.info(TAG + 'valueNum ' + valueNum + ' getRow data2:' + res.data2 + ' type:' + typeof res.data2); + expect(Number.MAX_SAFE_INTEGER).assertEqual(res.data2); + console.info(TAG + "************* rdbStoreResultSetGetRowTest0011 end *************"); + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0001 + * @tc.desc resultSet getRows(maxCount) test: 100 rows of data, with empty arg + */ + it('rdbStoreResultSetGetRowsTest0001', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0001 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let rows; + let cnt = 0; + while ((rows = await resultSet.getRows()).length != 0) { + cnt++; + console.info(JSON.stringify(rows[0])); + } + expect(0).assertEqual(cnt); + resultSet.close(); + expect().assertFail(); + } catch (e) { + resultSet.close(); + expect('401').assertEqual(e.code); + } + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0001 end *************"); + }); + + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0002 + * @tc.desc resultSet getRows(maxCount) test: 100 rows of data, with maxCount set to 100 + */ + it('rdbStoreResultSetGetRowsTest0002', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0002 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let rows; + let cnt = 0; + while ((rows = await resultSet.getRows(100)).length != 0) { + expect(100).assertEqual(rows.length); + for (let i = 0; i < rows.length; i++) { + expect('test' + (i + 1)).assertEqual(rows[i].data1); + expect(i + 1).assertEqual(rows[i].data6); + } + cnt++; + } + expect(1).assertEqual(cnt); + resultSet.close(); + } catch (e) { + resultSet.close(); + console.error(TAG + "rdbStoreResultSetGetRowsTest0002 failed, error" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0002 end *************"); + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0003 + * @tc.desc resultSet getRows(maxCount) test: 100 rows of data, with maxCount set to 50 + */ + it('rdbStoreResultSetGetRowsTest0003', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0003 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let rows; + let cnt = 0; + while ((rows = await resultSet.getRows(50)).length != 0) { + expect(50).assertEqual(rows.length); + for (let i = 0; i < rows.length; i++) { + expect('test' + (i + 1 + 50 * cnt)).assertEqual(rows[i].data1); + expect(i + 1 + 50 * cnt).assertEqual(rows[i].data6); + } + cnt++; + } + expect(2).assertEqual(cnt); + resultSet.close(); + } catch (e) { + resultSet.close(); + console.error(TAG + "rdbStoreResultSetGetRowsTest0003 failed, error" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0003 end *************"); + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0004 + * @tc.desc resultSet getRows(maxCount) test: 100 rows of data, with maxCount set to 60 + */ + it('rdbStoreResultSetGetRowsTest0004', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0004 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let rows; + let cnt = 0; + while ((rows = await resultSet.getRows(60)).length != 0) { + if (cnt == 0) { + expect(60).assertEqual(rows.length); + } else { + expect(40).assertEqual(rows.length); + } + for (let i = 0; i < rows.length; i++) { + expect('test' + (i + 1 + 60 * cnt)).assertEqual(rows[i].data1); + expect(i + 1 + 60 * cnt).assertEqual(rows[i].data6); + } + cnt++; + } + expect(2).assertEqual(cnt); + resultSet.close(); + } catch (e) { + resultSet.close(); + console.error(TAG + "rdbStoreResultSetGetRowsTest0004 failed, error" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0004 end *************"); + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0005 + * @tc.desc resultSet getRows(maxCount) test: 100 rows of data, with maxCount set to 200 + */ + it('rdbStoreResultSetGetRowsTest0005', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0005 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let rows; + let cnt = 0; + while ((rows = await resultSet.getRows(200)).length != 0) { + expect(100).assertEqual(rows.length); + for (let i = 0; i < rows.length; i++) { + expect('test' + (i + 1)).assertEqual(rows[i].data1); + expect(i + 1).assertEqual(rows[i].data6); + } + cnt++; + } + expect(1).assertEqual(cnt); + resultSet.close(); + } catch (e) { + resultSet.close(); + console.error(TAG + "rdbStoreResultSetGetRowsTest0005 failed, error" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0005 end *************"); + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0006 + * @tc.desc resultSet getRows(maxCount) test: 100 rows of data, with invalid maxCount 0 + */ + it('rdbStoreResultSetGetRowsTest0006', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0006 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let rows; + let cnt = 0; + while ((rows = await resultSet.getRows(0)).length != 0) { + console.info(JSON.stringify(rows[0])) + cnt++; + } + expect(0).assertEqual(cnt); + resultSet.close(); + expect().assertFail(); + } catch (e) { + expect('401').assertEqual(e.code); + resultSet.close(); + } + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0006 end *************"); + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0007 + * @tc.desc resultSet getRows(maxCount) test: 100 rows of data, with invalid maxCount -1 + */ + it('rdbStoreResultSetGetRowsTest0007', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0007 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let rows; + let cnt = 0; + while ((rows = await resultSet.getRows(-1)).length != 0) { + cnt++; + } + expect(0).assertEqual(cnt); + resultSet.close(); + expect().assertFail(); + } catch (e) { + expect('401').assertEqual(e.code); + resultSet.close(); + } + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0007 end *************"); + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0008 + * @tc.desc resultSet getRows(maxCount, position) test: 100 rows of data, with (maxCount, position) set to (50, 0) + */ + it('rdbStoreResultSetGetRowsTest0008', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0008 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let rows; + let position = 0; + let cnt = 0; + while ((rows = await resultSet.getRows(50, position)).length != 0) { + expect(50).assertEqual(rows.length); + for (let i = 0; i < rows.length; i++) { + expect('test' + (i + 1 + 50 * cnt)).assertEqual(rows[i].data1); + expect(i + 1 + 50 * cnt).assertEqual(rows[i].data6); + } + position += rows.length; + cnt++; + } + expect(100).assertEqual(position); + expect(2).assertEqual(cnt); + resultSet.close(); + } catch (e) { + resultSet.close(); + console.error(TAG + "rdbStoreResultSetGetRowsTest0008 failed, error" + JSON.stringify(e)); + expect().assertFail(); + } + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0008 end *************"); + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0009 + * @tc.desc resultSet getRows(maxCount, position) test: 100 rows of data, with (maxCount, position) set to (50, 70) + */ + it('rdbStoreResultSetGetRowsTest0009', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0009 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let rows; + let position = 70; + let cnt = 0; + while ((rows = await resultSet.getRows(50, position)).length != 0) { + expect(30).assertEqual(rows.length); + for (let i = 0; i < rows.length; i++) { + expect('test' + (i + 71)).assertEqual(rows[i].data1); + expect(i + 71).assertEqual(rows[i].data6); + } + position += rows.length; + cnt++; + } + expect(100).assertEqual(position); + expect(1).assertEqual(cnt); + resultSet.close(); + } catch (e) { + console.error(TAG + "rdbStoreResultSetGetRowsTest0009 failed, error" + JSON.stringify(e)); + resultSet.close(); + expect().assertFail(); + } + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0009 end *************"); + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0010 + * @tc.desc resultSet getRows(maxCount, position) test: 100 rows of data, with (maxCount, position) set to (50, 50) + */ + it('rdbStoreResultSetGetRowsTest0010', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0010 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let rows; + let position = 50; + let cnt = 0; + while ((rows = await resultSet.getRows(50, position)).length != 0) { + expect(50).assertEqual(rows.length); + for (let i = 0; i < rows.length; i++) { + expect('test' + (i + 51)).assertEqual(rows[i].data1); + expect(i + 51).assertEqual(rows[i].data6); + } + position += rows.length; + cnt++; + } + expect(100).assertEqual(position); + expect(1).assertEqual(cnt); + resultSet.close(); + } catch (e) { + console.error(TAG + "rdbStoreResultSetGetRowsTest0010 failed, error" + JSON.stringify(e)); + resultSet.close(); + expect().assertFail(); + } + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0010 end *************"); + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0011 + * @tc.desc resultSet getRows(maxCount, position) test: 100 rows of data, with (maxCount, position) set to (20, 50) + */ + it('rdbStoreResultSetGetRowsTest0011', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0011 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let rows; + let position = 50; + let cnt = 0; + while ((rows = await resultSet.getRows(20, position)).length != 0) { + if (cnt != 2) { + expect(20).assertEqual(rows.length); + for (let i = 0; i < rows.length; i++) { + expect('test' + (i + 51 + 20 * cnt)).assertEqual(rows[i].data1); + expect(i + 51 + 20 * cnt).assertEqual(rows[i].data6); + } + } else { + expect(10).assertEqual(rows.length); + for (let i = 0; i < rows.length; ++i) { + expect('test' + (i + 91)).assertEqual(rows[i].data1); + expect(i + 91).assertEqual(rows[i].data6); + } + } + position += rows.length; + cnt++; + } + expect(100).assertEqual(position); + expect(3).assertEqual(cnt); + resultSet.close(); + } catch (e) { + console.error(TAG + "rdbStoreResultSetGetRowsTest0011 failed, error" + JSON.stringify(e)); + resultSet.close(); + expect().assertFail(); + } + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0011 end *************"); + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0012 + * @tc.desc resultSet getRows(maxCount, position) test: 100 rows of data and goToRow(50) before getrows, + * with (maxCount, position) set to (50, 0) + */ + it('rdbStoreResultSetGetRowsTest0012', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0012 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + resultSet.goToRow(50); + try { + let rows; + let position = 0; + let cnt = 0; + while ((rows = await resultSet.getRows(50, position)).length != 0) { + expect(50).assertEqual(rows.length); + for (let i = 0; i < rows.length; i++) { + expect('test' + (i + 1 + 50 * cnt)).assertEqual(rows[i].data1); + expect(i + 1 + 50 * cnt).assertEqual(rows[i].data6); + } + position += rows.length; + cnt++; + } + expect(100).assertEqual(position); + expect(2).assertEqual(cnt); + resultSet.close(); + } catch (e) { + console.error(TAG + "rdbStoreResultSetGetRowsTest0012 failed, error" + JSON.stringify(e)); + resultSet.close(); + expect().assertFail(); + } + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0012 end *************"); + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0013 + * @tc.desc resultSet getRows(maxCount, position) test: 100 rows of data, with (maxCount, position) set to (20, 100) + */ + it('rdbStoreResultSetGetRowsTest0013', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0013 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let rows; + let position = 100; + let cnt = 0; + while ((rows = await resultSet.getRows(20, position)).length != 0) { + position += rows.length; + cnt++; + } + expect(0).assertEqual(position); + expect(0).assertEqual(cnt); + resultSet.close(); + expect().assertFail(); + } catch (e) { + expect(14800012).assertEqual(e.code); + resultSet.close(); + } + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0013 end *************"); + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0014 + * @tc.desc resultSet getRows(maxCount, position) test: 100 rows of data, with invalid position -1 + */ + it('rdbStoreResultSetGetRowsTest0014', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0014 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let rows; + let position = -1; + let cnt = 0; + while ((rows = await resultSet.getRows(20, position)).length != 0) { + position += rows.length; + cnt++; + } + expect(0).assertEqual(position); + expect(0).assertEqual(cnt); + resultSet.close(); + expect().assertFail(); + } catch (e) { + expect('401').assertEqual(e.code); + resultSet.close(); + } + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0014 end *************"); + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0015 + * @tc.desc resultSet getRows(maxCount, position) test: resultSet closed before getRows + */ + it('rdbStoreResultSetGetRowsTest0015', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0015 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let rows; + let position = 50; + let cnt = 0; + resultSet.close(); + while ((rows = await resultSet.getRows(20, position)).length != 0) { + position += rows.length; + cnt++; + } + expect(0).assertEqual(position); + expect(0).assertEqual(cnt); + resultSet.close(); + expect().assertFail(); + } catch (e) { + expect('14800014').assertEqual(e.code); + resultSet.close(); + console.info(TAG + "rdbStoreResultSetGetRowsTest0015 success, err" + JSON.stringify(e)); + } + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0015 end *************"); + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0016 + * @tc.desc resultSet getRows(maxCount, position) test: concurrent getRows and close on resultSet + */ + it('rdbStoreResultSetGetRowsTest0016', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0016 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let position = 20 + const getRowsPromise = resultSet.getRows(100, position); + getRowsPromise.then((rows) => { + expect(80).assertEqual(rows.length); + for (let i = 0; i < rows.length; i++) { + expect('test' + (i + 21)).assertEqual(rows[i].data1); + expect(i + 21).assertEqual(rows[i].data6); + } + console.info(TAG + "rdbStoreResultSetGetRowsTest0016 success"); + }).catch((e) =>{ + expect(14800014).assertEqual(e); + console.info(TAG + "rdbStoreResultSetGetRowsTest0016 success, err" + JSON.stringify(e)); + }).finally(() =>{ + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0016 end *************"); + }) + resultSet.close(); + } catch (error) { + resultSet.close(); + console.error(TAG + "rdbStoreResultSetGetRowsTest0016 failed, error" + JSON.stringify(error)); + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0016 end *************"); + expect().assertFail(); + } + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0017 + * @tc.desc resultSet getRows(maxCount, position) test: concurrent getRows and goTo on resultSet + */ + it('rdbStoreResultSetGetRowsTest0017', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0017 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let position = 20; + const getRowsPromise = resultSet.getRows(100, position); + getRowsPromise.then((rows) => { + console.info(TAG + "rows.length: " + JSON.stringify(rows.length)); + console.info(TAG + "data of rows[0]: " + JSON.stringify(rows[0])); + console.info(TAG + "rdbStoreResultSetGetRowsTest0017 success"); + }).catch((e) =>{ + console.info(TAG + "rdbStoreResultSetGetRowsTest0017 success, err" + JSON.stringify(e)); + }).finally(() =>{ + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0017 end *************"); + resultSet.close(); + }) + resultSet.goTo(10);// goto: rowPos_ + 10 + } catch (error) { + resultSet.close(); + console.error(TAG + "rdbStoreResultSetGetRowsTest0017 failed, error" + JSON.stringify(error)); + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0017 end *************"); + expect().assertFail(); + } + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0018 + * @tc.desc resultSet getRows(maxCount, position) test: concurrent getRows and goToRow on resultSet + */ + it('rdbStoreResultSetGetRowsTest0018', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0018 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let position = 20; + const getRowsPromise = resultSet.getRows(100, position); + getRowsPromise.then((rows) => { + console.info(TAG + "rows.length: " + JSON.stringify(rows.length)); + console.info(TAG + "data of rows[0]: " + JSON.stringify(rows[0])); + console.info(TAG + "rdbStoreResultSetGetRowsTest0018 success"); + }).catch((e) =>{ + console.info(TAG + "rdbStoreResultSetGetRowsTest0018 success, err" + JSON.stringify(e)); + }).finally(() =>{ + resultSet.close(); + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0018 end *************"); + }) + resultSet.goToRow(1); + } catch (error) { + resultSet.close(); + console.error(TAG + "rdbStoreResultSetGetRowsTest0018 failed, error" + JSON.stringify(error)); + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0018 end *************"); + expect().assertFail(); + } + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0019 + * @tc.desc resultSet getRows(maxCount, position) test: concurrent getRows and goToFirstRow on resultSet + */ + it('rdbStoreResultSetGetRowsTest0019', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0019 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let position = 20; + const getRowsPromise = resultSet.getRows(100, position); + getRowsPromise.then((rows) => { + console.info(TAG + "rows.length: " + JSON.stringify(rows.length)); + console.info(TAG + "data of rows[0]: " + JSON.stringify(rows[0])); + console.info(TAG + "rdbStoreResultSetGetRowsTest0019 success"); + }).catch((e) =>{ + console.info(TAG + "rdbStoreResultSetGetRowsTest0019 success, err" + JSON.stringify(e)); + }).finally(() =>{ + resultSet.close(); + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0019 end *************"); + }) + resultSet.goToFirstRow(); + } catch (error) { + resultSet.close(); + console.error(TAG + "rdbStoreResultSetGetRowsTest0019 failed, error" + JSON.stringify(error)); + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0019 end *************"); + expect().assertFail(); + } + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0020 + * @tc.desc resultSet getRows(maxCount, position) test: concurrent getRows and goToLastRow on resultSet + */ + it('rdbStoreResultSetGetRowsTest0020', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0020 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let position = 20; + const getRowsPromise = resultSet.getRows(100, position); + getRowsPromise.then((rows) => { + console.info(TAG + "rows.length: " + JSON.stringify(rows.length)); + console.info(TAG + "data of rows[0]: " + JSON.stringify(rows[0])); + console.info(TAG + "rdbStoreResultSetGetRowsTest0020 success"); + }).catch((e) =>{ + console.info(TAG + "rdbStoreResultSetGetRowsTest0020 success, err" + JSON.stringify(e)); + }).finally(() =>{ + resultSet.close(); + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0020 end *************"); + }) + resultSet.goToLastRow(); + } catch (error) { + resultSet.close(); + console.error(TAG + "rdbStoreResultSetGetRowsTest0020 failed, error" + JSON.stringify(error)); + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0020 end *************"); + expect().assertFail(); + } + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0021 + * @tc.desc resultSet getRows(maxCount, position) test: concurrent getRows and goToNextRow on resultSet + */ + it('rdbStoreResultSetGetRowsTest0021', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0021 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let position = 20; + const getRowsPromise = resultSet.getRows(100, position); + getRowsPromise.then((rows) => { + console.info(TAG + "rows.length: " + JSON.stringify(rows.length)); + console.info(TAG + "data of rows[0]: " + JSON.stringify(rows[0])); + console.info(TAG + "rdbStoreResultSetGetRowsTest0021 success"); + }).catch((e) =>{ + console.info(TAG + "rdbStoreResultSetGetRowsTest0021 success, err" + JSON.stringify(e)); + }).finally(() =>{ + resultSet.close(); + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0021 end *************"); + }) + resultSet.goToNextRow(); + } catch (error) { + resultSet.close(); + console.error(TAG + "rdbStoreResultSetGetRowsTest0021 failed, Err" + JSON.stringify(error)); + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0021 end *************"); + expect().assertFail(); + } + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0022 + * @tc.desc resultSet getRows(maxCount, position) test: concurrent getRows and goToPreviousRow on resultSet + */ + it('rdbStoreResultSetGetRowsTest0022', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0022 start *************"); + let rowId = 0; + for (let i = 1; i <= 100; i++) { + let valueBucket = { + data1: 'test' + i, + data6: i, + }; + rowId = await rdbStore.insert("test", valueBucket); + } + expect(100).assertEqual(rowId); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(100).assertEqual(resultSet.rowCount); + try { + let position = 20; + const getRowsPromise = resultSet.getRows(100, position); + getRowsPromise.then((rows) => { + console.info(TAG + "rows.length: " + JSON.stringify(rows.length)); + console.info(TAG + "data of rows[0]: " + JSON.stringify(rows[0])); + console.info(TAG + "rdbStoreResultSetGetRowsTest0022 success"); + }).catch((e) =>{ + console.info(TAG + "rdbStoreResultSetGetRowsTest0022 success, err" + JSON.stringify(e)); + }).finally(() =>{ + resultSet.close(); + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0022 end *************"); + }) + resultSet.goToPreviousRow(); + } catch (error) { + resultSet.close(); + console.error(TAG + "rdbStoreResultSetGetRowsTest0022 failed, error" + JSON.stringify(error)); + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0022 end *************"); + expect().assertFail(); + } + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0023 + * @tc.desc resultSet getRows(maxCount) test: getRows(50) with empty resultSet + */ + it('rdbStoreResultSetGetRowsTest0023', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0023 start *************"); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(0).assertEqual(resultSet.rowCount); + try { + let rows; + let cnt = 0; + while ((rows = await resultSet.getRows(50)).length != 0) { + console.info(JSON.stringify(rows[0])); + cnt++; + } + expect(0).assertEqual(cnt); + expect(0).assertEqual(rows.length); + resultSet.close(); + } catch (e) { + resultSet.close(); + expect().assertFail(); + } + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0023 end *************"); + }); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRows0024 + * @tc.desc resultSet getRows(maxCount,position) test: getRows(50, 0) with empty resultSet + */ + it('rdbStoreResultSetGetRowsTest0024', 0, async () => { + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0024 start *************"); + let predicates = new data_relationalStore.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + expect(0).assertEqual(resultSet.rowCount); + try { + let rows; + let cnt = 0; + while ((rows = await resultSet.getRows(50, 0)).length != 0) { + console.info(JSON.stringify(rows[0])); + cnt++; + } + expect(0).assertEqual(cnt); + expect(0).assertEqual(rows.length); + resultSet.close(); + expect().assertFail(); + } catch (e) { + resultSet.close(); + expect(14800012).assertEqual(e.code); + } + console.info(TAG + "************* rdbStoreResultSetGetRowsTest0024 end *************"); + }); console.log(TAG + "*************Unit Test End*************"); }) \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetGetValue.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetGetValue.test.js index 5f56638ec5464244465feb6c372045e91047215d..8488553435b5525f18e45d95a6ad49d762dd74a4 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetGetValue.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetGetValue.test.js @@ -350,5 +350,63 @@ describe('rdbStoreResultSetGetValueTest', function () { console.log(TAG + "************* rdbStoreResultSetGetValueTest_0010 end *************"); }) + /** + * @tc.name rdb store resultSet getValue test + * @tc.number rdbStoreResultSetGetValueTest_0011 + * @tc.desc Insert a string greater than number.MAX_SAFE_INTEGER is also obtained as a string by getValue + */ + it('rdbStoreResultSetGetValueTest_0011', 0, async function () { + console.log(TAG + "************* rdbStoreResultSetGetValueTest_0011 start *************"); + let valueNum = Number.MAX_SAFE_INTEGER.toString() + 0; + let valueBucket = { + age: valueNum + }; + try { + let rowId = await rdbStore.insert("test", valueBucket); + expect(1).assertEqual(rowId); + } catch (err) { + console.error(`### insert failed, code:${err.code}, message:${err.message}`) + } + + try { + let resultSet = await rdbStore.querySql('SELECT * FROM test') + expect(true).assertEqual(resultSet.goToFirstRow()); + expect(valueNum).assertEqual(resultSet.getValue(resultSet.getColumnIndex('age'))); + resultSet.close(); + } catch (err) { + console.error(`### query failed, code:${err.code}, message:${err.message}`) + } + console.log(TAG + "************* rdbStoreResultSetGetValueTest_0011 end *************"); + }) + + /** + * @tc.name rdb store resultSet getValue test + * @tc.number rdbStoreResultSetGetValueTest_0012 + * @tc.desc Insert as a string equal to number.MAX_SAFE_INTEGER, getValue obtains the number + */ + it('rdbStoreResultSetGetValueTest_0012', 0, async function () { + console.log(TAG + "************* rdbStoreResultSetGetValueTest_0012 start *************"); + let valueNum = Number.MAX_SAFE_INTEGER.toString(); + let valueBucket = { + age: valueNum + }; + try { + let rowId = await rdbStore.insert("test", valueBucket); + expect(1).assertEqual(rowId); + } catch (err) { + console.error(`### insert failed, code:${err.code}, message:${err.message}`) + } + + try { + let resultSet = await rdbStore.querySql('SELECT * FROM test') + expect(true).assertEqual(resultSet.goToFirstRow()); + expect(Number.MAX_SAFE_INTEGER).assertEqual(resultSet.getValue(resultSet.getColumnIndex('age'))); + resultSet.close(); + } catch (err) { + console.error(`### query failed, code:${err.code}, message:${err.message}`) + } + console.log(TAG + "************* rdbStoreResultSetGetValueTest_0012 end *************"); + }) + console.log(TAG + "*************Unit Test End*************"); }) \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetJsunit.test.js index 45fd2aaa4124da45048faa21f8a652a16140b14f..c6447d7abc0b039a56354f56c38a6ff310435f63 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetJsunit.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetJsunit.test.js @@ -811,6 +811,28 @@ describe('rdbResultSetTest', function () { console.log(TAG + "************* testGoToFirstRow0003 end *************"); }) + /** + * @tc.name resultSet goToFirstRow with no result test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_ResultSet_0103 + * @tc.desc resultSet goToFirstRow with no result test + */ + it('testGoToFirstRow0004', 0, async function (done) { + console.log(TAG + "************* testGoToFirstRow0004 start *************"); + + let predicates = await new data_relationalStore.RdbPredicates("test") + let resultSet = await rdbStore.query(predicates) + resultSet.close() + try { + resultSet.goToFirstRow() + } catch (e) { + expect(e.code).assertFail("14800014"); + } + + resultSet = null + done(); + console.log(TAG + "************* testGoToFirstRow0004 end *************"); + }) + /** * @tc.name resultSet goToLastRow test * @tc.number SUB_DDM_AppDataFWK_JSRDB_ResultSet_0110 @@ -868,6 +890,27 @@ describe('rdbResultSetTest', function () { }) + /** + * @tc.name resultSet goToLastRow with no result test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_ResultSet_0113 + * @tc.desc resultSet goToLastRow with no result test + */ + it('testGoToLastRow0004', 0, async function (done) { + console.log(TAG + "************* testGoToLastRow0004 start *************"); + let predicates = await new data_relationalStore.RdbPredicates("test") + predicates.equalTo("name", "wangwu"); + let resultSet = await rdbStore.query(predicates) + resultSet.close() + try { + resultSet.goToLastRow() + } catch (error) { + expect(error.code).assertEqual("14800014") + } + resultSet = null; + done(); + console.log(TAG + "************* testGoToLastRow0004 end *************"); + }) + /** * @tc.name resultSet goToNextRow test * @tc.number SUB_DDM_AppDataFWK_JSRDB_ResultSet_0120 @@ -953,6 +996,29 @@ describe('rdbResultSetTest', function () { }) + /** + * @tc.name resultSet goToNextRow with no result test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_ResultSet_0124 + * @tc.desc resultSet goToNextRow with no result test + */ + it('testGoToNextRow0005', 0, async function (done) { + console.log(TAG + "************* testGoToNextRow0005 start *************"); + + let predicates = await new data_relationalStore.RdbPredicates("test") + let resultSet = await rdbStore.query(predicates) + resultSet.close() + try { + resultSet.goToNextRow() + } catch (error) { + expect(error.code).assertEqual("14800014") + } + + resultSet = null; + done(); + console.log(TAG + "************* testGoToNextRow0005 end *************"); + + }) + /** * @tc.name resultSet goToPreviousRow test * @tc.number SUB_DDM_AppDataFWK_JSRDB_ResultSet_0130 @@ -1037,6 +1103,28 @@ describe('rdbResultSetTest', function () { }) + /** + * @tc.name resultSet goToPreviousRow with no result test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_ResultSet_0134 + * @tc.desc resultSet goToPreviousRow with no result test + */ + it('testGoToPreviousRow0005', 0, async function (done) { + console.log(TAG + "************* testGoToPreviousRow0005 start *************"); + + let predicates = await new data_relationalStore.RdbPredicates("test") + let resultSet = await rdbStore.query(predicates) + resultSet.close() + try { + resultSet.goToPreviousRow() + } catch (error) { + expect(error).assertEqual("14800014") + } + resultSet = null; + done(); + console.log(TAG + "************* testGoToPreviousRow0005 end *************"); + + }) + /** * @tc.name resultSet goTo test * @tc.number SUB_DDM_AppDataFWK_JSRDB_ResultSet_0140 @@ -1126,6 +1214,31 @@ describe('rdbResultSetTest', function () { }) + /** + * @tc.name resultSet goTo after last row test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_ResultSet_0144 + * @tc.desc resultSet goTo after last row test + */ + it('testGoTo0005', 0, async function (done) { + console.log(TAG + "************* testGoTo0005 start *************"); + + let predicates = await new data_relationalStore.RdbPredicates("test") + predicates.equalTo("name", "wangwu"); + let resultSet = await rdbStore.query(predicates) + resultSet.close() + + try { + resultSet.goTo(1) + } catch (error) { + expect(error.code).assertEqual("14800014") + } + + resultSet = null; + done(); + console.log(TAG + "************* testGoTo0005 end *************"); + + }) + /** * @tc.name resultSet goToRow test * @tc.number SUB_DDM_AppDataFWK_JSRDB_ResultSet_0150 @@ -1194,6 +1307,31 @@ describe('rdbResultSetTest', function () { }) + /** + * @tc.name resultSet goToRow with no result test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_ResultSet_0154 + * @tc.desc resultSet goToRow with no result test + */ + it('testGoToRow0005', 0, async function (done) { + console.log(TAG + "************* testGoToRow0005 start *************"); + + let predicates = await new data_relationalStore.RdbPredicates("test") + predicates.equalTo("name", "wangwu"); + let resultSet = await rdbStore.query(predicates) + + resultSet.close() + try { + resultSet.goToRow(1) + } catch (error) { + expect(error.code).assertEqual("14800014") + } + + resultSet = null; + done(); + console.log(TAG + "************* testGoToRow0005 end *************"); + + }) + /** * @tc.name resultSet goToRow after last row test * @tc.number SUB_DDM_AppDataFWK_JSRDB_ResultSet_0153 @@ -1644,6 +1782,7 @@ describe('rdbResultSetTest', function () { let resultSet = await rdbStore.query(predicates) expect(true).assertEqual(resultSet.goToFirstRow()) expect(1).assertEqual(resultSet.getColumnIndex("data1")) + expect(-1).assertEqual(resultSet.getColumnIndex("data0")) resultSet.close() resultSet = null; @@ -1713,6 +1852,28 @@ describe('rdbResultSetTest', function () { }) + /** + * @tc.name resultSet getColumnIndex test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_ResultSet_0204 + * @tc.desc resultSet getColumnIndex test + */ + it('testGetColumnIndex0005', 0, async function (done) { + console.log(TAG + "************* testGetColumnIndex0005 start *************"); + + let predicates = await new data_relationalStore.RdbPredicates("test") + let resultSet = await rdbStore.query(predicates) + resultSet.close() + try { + resultSet.getColumnIndex("dataX") + } catch (error) { + expect(error.code).assertEqual("14800014") + } + resultSet = null; + done(); + console.log(TAG + "************* testGetColumnIndex0005 end *************"); + + }) + /** * @tc.name resultSet getColumnName test * @tc.number SUB_DDM_AppDataFWK_JSRDB_ResultSet_0210 @@ -1797,6 +1958,28 @@ describe('rdbResultSetTest', function () { }) + /** + * @tc.name resultSet getColumnName test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_ResultSet_0214 + * @tc.desc resultSet getColumnName test + */ + it('testGetColumnName0005', 0, async function (done) { + console.log(TAG + "************* testGetColumnName0005 start *************"); + + let predicates = await new data_relationalStore.RdbPredicates("test") + let resultSet = await rdbStore.query(predicates) + resultSet.close() + try { + resultSet.getColumnName(10) + } catch (error) { + expect(error.code).assertEqual("14800014") + } + resultSet = null; + done(); + console.log(TAG + "************* testGetColumnName0005 end *************"); + + }) + /** * @tc.name resultSet close test * @tc.number SUB_DDM_AppDataFWK_JSRDB_ResultSet_0220 diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbStoreTransaction.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbStoreTransaction.test.js index 269740ff79a21405a3430b6474e8f42844305bfb..a973a7a215478d5dd63461d489d41402243a6d5a 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbStoreTransaction.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbStoreTransaction.test.js @@ -1696,5 +1696,544 @@ describe('rdbStoreTransactionTest', function () { console.log(TAG + "************* testTransactionWithReadOnlyStore0001 end *************"); }) + /** + * @tc.number testbatchInsertWithConflictResolutionInTransaction0001 + * @tc.name batchInsertWithConflictResolutionInTransaction + * @tc.desc normal batch insert with ON_CONFLICT_NONE + */ + it('testbatchInsertWithConflictResolutionInTransaction0001', 0, async function (done) { + console.log(TAG + "************* testbatchInsertWithConflictResolutionInTransaction0001 start *************"); + var u8 = new Uint8Array([1, 2, 3]) + var transaction = await rdbStore.createTransaction() + try { + const valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + let valueBucketArray = new Array(); + for (let i = 0; i < 2; i++) { + valueBucketArray.push(valueBucket); + } + var num = await transaction.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_NONE) + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0001 batch num1 " + num) + expect(2).assertEqual(num); + + num = await transaction.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_ROLLBACK) + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0001 batch num2 " + num) + expect(2).assertEqual(num); + + num = await transaction.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_ABORT) + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0001 batch num3 " + num) + expect(2).assertEqual(num); + + num = await transaction.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_FAIL) + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0001 batch num4 " + num) + expect(2).assertEqual(num); + + num = await transaction.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_IGNORE) + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0001 batch num5 " + num) + expect(2).assertEqual(num); + + num = await transaction.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_REPLACE) + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0001 batch num6 " + num) + expect(2).assertEqual(num); + + let resultSet = await transaction.querySql("select * from test") + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0001 result count " + resultSet.rowCount) + expect(12).assertEqual(resultSet.rowCount) + resultSet.close() + + await transaction.commit() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + await transaction.rollback() + expect(null).assertFail() + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0001 failed"); + } + done() + console.log(TAG + "************* testbatchInsertWithConflictResolutionInTransaction0001 end *************"); + }) + + /** + * @tc.number testbatchInsertWithConflictResolutionInTransaction0011 + * @tc.name batchInsertWithConflictResolutionInTransaction + * @tc.desc conflict batch insert with ON_CONFLICT_NONE + */ + it('testbatchInsertWithConflictResolutionInTransaction0011', 0, async function (done) { + console.log(TAG + "************* testbatchInsertWithConflictResolutionInTransaction0011 start *************"); + var u8 = new Uint8Array([1, 2, 3]) + var transaction = await rdbStore.createTransaction() + try { + const valueBucket = { + "id" : 2, + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await transaction.insert("test", valueBucket); + let valueBucketArray = new Array(); + for (let i = 0; i < 5; i++) { + var vb = {...valueBucket}; + vb.id = i; + valueBucketArray.push(vb); + } + let num = await transaction.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_NONE) + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0011 failed num " + num); + expect(null).assertFail() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(14800032).assertEqual(e.code) + await transaction.rollback() + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0011 success"); + } + done() + console.log(TAG + "************* testbatchInsertWithConflictResolutionInTransaction0011 end *************"); + }) + + /** + * @tc.number testbatchInsertWithConflictResolutionInTransaction0012 + * @tc.name batchInsertWithConflictResolutionInTransaction + * @tc.desc conflict batch insert with ON_CONFLICT_ABORT + */ + it('testbatchInsertWithConflictResolutionInTransaction0012', 0, async function (done) { + console.log(TAG + "************* testbatchInsertWithConflictResolutionInTransaction0012 start *************"); + var u8 = new Uint8Array([1, 2, 3]) + var transaction = await rdbStore.createTransaction() + try { + const valueBucket = { + "id" : 2, + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await transaction.insert("test", valueBucket); + let valueBucketArray = new Array(); + for (let i = 0; i < 5; i++) { + var vb = {...valueBucket}; + vb.id = i; + valueBucketArray.push(vb); + } + let num = await transaction.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_ABORT) + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0012 failed num " + num); + expect(null).assertFail() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(14800032).assertEqual(e.code) + await transaction.rollback() + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0012 success"); + } + done() + console.log(TAG + "************* testbatchInsertWithConflictResolutionInTransaction0012 end *************"); + }) + + /** + * @tc.number testbatchInsertWithConflictResolutionInTransaction0013 + * @tc.name batchInsertWithConflictResolutionInTransaction + * @tc.desc conflict batch insert with ON_CONFLICT_FAIL + */ + it('testbatchInsertWithConflictResolutionInTransaction0013', 0, async function (done) { + console.log(TAG + "************* testbatchInsertWithConflictResolutionInTransaction0013 start *************"); + var u8 = new Uint8Array([1, 2, 3]) + var transaction = await rdbStore.createTransaction() + try { + const valueBucket = { + "id" : 2, + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await transaction.insert("test", valueBucket); + let valueBucketArray = new Array(); + for (let i = 0; i < 5; i++) { + var vb = {...valueBucket}; + vb.id = i; + valueBucketArray.push(vb); + } + let num = await transaction.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_FAIL) + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0013 failed num " + num); + expect(null).assertFail() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(14800032).assertEqual(e.code) + await transaction.rollback() + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0013 success"); + } + done() + console.log(TAG + "************* testbatchInsertWithConflictResolutionInTransaction0013 end *************"); + }) + + /** + * @tc.number testbatchInsertWithConflictResolutionInTransaction0014 + * @tc.name batchInsertWithConflictResolutionInTransaction + * @tc.desc conflict batch insert with ON_CONFLICT_IGNORE + */ + it('testbatchInsertWithConflictResolutionInTransaction0014', 0, async function (done) { + console.log(TAG + "************* testbatchInsertWithConflictResolutionInTransaction0014 start *************"); + var u8 = new Uint8Array([1, 2, 3]) + var transaction = await rdbStore.createTransaction() + try { + const valueBucket = { + "id" : 2, + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await transaction.insert("test", valueBucket); + let valueBucketArray = new Array(); + for (let i = 0; i < 5; i++) { + var vb = {...valueBucket}; + vb.id = i; + valueBucketArray.push(vb); + } + let num = await transaction.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_IGNORE) + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0014 success num " + num); + expect(4).assertEqual(num) + + let resultSet = await transaction.querySql("select * from test") + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0014 result count " + resultSet.rowCount) + expect(5).assertEqual(resultSet.rowCount) + resultSet.close() + + await transaction.commit() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + await transaction.rollback() + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0014 failed"); + expect(null).assertFail() + } + done() + console.log(TAG + "************* testbatchInsertWithConflictResolutionInTransaction0014 end *************"); + }) + + /** + * @tc.number testbatchInsertWithConflictResolutionInTransaction0015 + * @tc.name batchInsertWithConflictResolutionInTransaction + * @tc.desc conflict batch insert with ON_CONFLICT_REPLACE + */ + it('testbatchInsertWithConflictResolutionInTransaction0015', 0, async function (done) { + console.log(TAG + "************* testbatchInsertWithConflictResolutionInTransaction0015 start *************"); + var u8 = new Uint8Array([1, 2, 3]) + var transaction = await rdbStore.createTransaction() + try { + const valueBucket = { + "id" : 2, + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await transaction.insert("test", valueBucket); + let valueBucketArray = new Array(); + for (let i = 0; i < 5; i++) { + var vb = {...valueBucket}; + vb.id = i; + valueBucketArray.push(vb); + } + let num = await transaction.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_REPLACE) + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0015 success num " + num); + expect(5).assertEqual(num) + + let resultSet = await transaction.querySql("select * from test") + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0015 result count " + resultSet.rowCount) + expect(5).assertEqual(resultSet.rowCount) + resultSet.close() + + await transaction.commit() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + await transaction.rollback() + console.log(TAG + "testbatchInsertWithConflictResolutionInTransaction0015 failed"); + expect(null).assertFail() + } + done() + console.log(TAG + "************* testbatchInsertWithConflictResolutionInTransaction0015 end *************"); + }) + + /** + * @tc.number testON_CONFLICT_ROLLBACKInTransaction0021 + * @tc.name InsertWithON_CONFLICT_ROLLBACKInTransaction + * @tc.desc conflict insert with ON_CONFLICT_ROLLBACK + */ + it('testON_CONFLICT_ROLLBACKInTransaction0021', 0, async function (done) { + console.log(TAG + "************* testON_CONFLICT_ROLLBACKInTransaction0021 start *************"); + var u8 = new Uint8Array([1, 2, 3]) + var transaction = await rdbStore.createTransaction() + try { + const valueBucket = { + "name": null, + "age": 18, + "salary": 100.5, + "blobType": u8, + } + var num = await transaction.insert("test", valueBucket, + data_relationalStore.ConflictResolution.ON_CONFLICT_ROLLBACK); + console.log(TAG + "testON_CONFLICT_ROLLBACKInTransaction0021 fail num " + num); + expect(null).assertFail() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(e.code).assertEqual(14800032) + try { + await transaction.rollback() + expect(null).assertFail() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(e.code).assertEqual(14800014); + } + console.log(TAG + "testON_CONFLICT_ROLLBACKInTransaction0021 success"); + } + done() + console.log(TAG + "************* testON_CONFLICT_ROLLBACKInTransaction0021 end *************"); + }) + + /** + * @tc.number testON_CONFLICT_ROLLBACKInTransaction0022 + * @tc.name InsertWithON_CONFLICT_ROLLBACKInTransaction + * @tc.desc conflict insert with ON_CONFLICT_ROLLBACK + */ + it('testON_CONFLICT_ROLLBACKInTransaction0022', 0, async function (done) { + console.log(TAG + "************* testON_CONFLICT_ROLLBACKInTransaction0022 start *************"); + var u8 = new Uint8Array([1, 2, 3]) + var transaction = await rdbStore.createTransaction() + try { + const valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + var num = await transaction.insert("test", valueBucket); + console.log(TAG + "testON_CONFLICT_ROLLBACKInTransaction0022 insert num " + num) + let predicates = new data_relationalStore.RdbPredicates("test"); + predicates.equalTo("name", "zhangsan"); + const updateValueBucket = { + "name": null, + "age": 28, + "salary": 25, + "blobType": u8, + } + await transaction.update(updateValueBucket, predicates, data_relationalStore.ConflictResolution.ON_CONFLICT_ROLLBACK); + expect(null).assertFail() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(e.code).assertEqual(14800032) + try { + await transaction.rollback() + expect(null).assertFail() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(e.code).assertEqual(14800014); + } + console.log(TAG + "testON_CONFLICT_ROLLBACKInTransaction0022 success"); + } + done() + console.log(TAG + "************* testON_CONFLICT_ROLLBACKInTransaction0022 end *************"); + }) + + /** + * @tc.number testON_CONFLICT_ROLLBACKInTransaction0023 + * @tc.name BatchInsertWithON_CONFLICT_ROLLBACKInTransaction + * @tc.desc conflict insert with ON_CONFLICT_ROLLBACK + */ + it('testON_CONFLICT_ROLLBACKInTransaction0023', 0, async function (done) { + console.log(TAG + "************* testON_CONFLICT_ROLLBACKInTransaction0023 start *************"); + var u8 = new Uint8Array([1, 2, 3]) + var transaction = await rdbStore.createTransaction() + try { + const valueBucket = { + "name": null, + "age": 18, + "salary": 100.5, + "blobType": u8, + } + let valueBucketArray = new Array(); + valueBucketArray.push(valueBucket); + var num = transaction.batchInsertWithConflictResolutionSync("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_ROLLBACK); + console.log(TAG + "testON_CONFLICT_ROLLBACKInTransaction0023 insert num " + num) + expect(null).assertFail() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(e.code).assertEqual(14800032) + try { + await transaction.rollback() + expect(null).assertFail() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(e.code).assertEqual(14800014); + } + console.log(TAG + "testON_CONFLICT_ROLLBACKInTransaction0023 success"); + } + done() + console.log(TAG + "************* testON_CONFLICT_ROLLBACKInTransaction0023 end *************"); + }) + + /** + * @tc.number testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0031 + * @tc.name testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs + * @tc.desc batch Insert With ConflictResolution with Invalid Args + */ + it('testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0031', 0, async function (done) { + console.log(TAG + "************* testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0031 start *************"); + var u8 = new Uint8Array([1, 2, 3]) + var transaction = await rdbStore.createTransaction(); + try { + const valueBucket = { + "name": "bbb", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + let valueBucketArray = new Array(); + valueBucketArray.push(valueBucket); + var num = await transaction.batchInsertWithConflictResolution(123, valueBucket, + data_relationalStore.ConflictResolution.ON_CONFLICT_ABORT); + console.log(TAG + "testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0031 insert num " + num) + expect(null).assertFail() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(String(e.code)).assertEqual(String(401)) + console.log(TAG + "testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0031 success"); + } + await transaction.rollback(); + done() + console.log(TAG + "************* testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0031 end *************"); + }) + + /** + * @tc.number testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0032 + * @tc.name testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs + * @tc.desc batch Insert With ConflictResolution with Invalid Args + */ + it('testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0032', 0, async function (done) { + console.log(TAG + "************* testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0032 start *************"); + var transaction = await rdbStore.createTransaction(); + try { + var num = transaction.batchInsertWithConflictResolutionSync("table", undefined, + data_relationalStore.ConflictResolution.ON_CONFLICT_FAIL); + console.log(TAG + "testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0032 insert num " + num) + expect(null).assertFail() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(String(e.code)).assertEqual(String(401)) + console.log(TAG + "testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0032 success"); + } + await transaction.rollback(); + done() + console.log(TAG + "************* testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0032 end *************"); + }) + + /** + * @tc.number testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0033 + * @tc.name testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs + * @tc.desc batch Insert With ConflictResolution with Invalid Args + */ + it('testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0033', 0, async function (done) { + console.log(TAG + "************* testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0033 start *************"); + var u8 = new Uint8Array([1, 2, 3]) + var transaction = await rdbStore.createTransaction() + try { + const valueBucket = { + "name": "aaa", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + let valueBucketArray = new Array(); + valueBucketArray.push(valueBucket); + var num = await transaction.batchInsertWithConflictResolution("test", valueBucketArray, "abc"); + console.log(TAG + "testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0033 insert num " + num) + expect(null).assertFail() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(String(e.code)).assertEqual(String(401)) + console.log(TAG + "testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0033 success"); + } + await transaction.rollback(); + done() + console.log(TAG + "************* testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0033 end *************"); + }) + + /** + * @tc.number testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0034 + * @tc.name testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs + * @tc.desc batch Insert With ConflictResolution with Invalid Args + */ + it('testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0034', 0, async function (done) { + console.log(TAG + "************* testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0034 start *************"); + var u8 = new Uint8Array([1, 2, 3]) + var transaction = await rdbStore.createTransaction() + try { + const valueBucket = { + "name": "aaa", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + let valueBucketArray = new Array(); + valueBucketArray.push(valueBucket); + var num = transaction.batchInsertWithConflictResolutionSync("test", valueBucketArray); + console.log(TAG + "testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0034 insert num " + num) + expect(null).assertFail() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(String(e.code)).assertEqual(String(401)) + console.log(TAG + "testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0034 success"); + } + await transaction.rollback(); + done() + console.log(TAG + "************* testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0034 end *************"); + }) + + /** + * @tc.number testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0035 + * @tc.name testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs + * @tc.desc batch Insert With ConflictResolution with Invalid Args + */ + it('testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0035', 0, async function (done) { + console.log(TAG + "************* testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0035 start *************"); + var u8 = new Uint8Array([1, 2, 3]) + var transaction = await rdbStore.createTransaction() + try { + const valueBucket = { + "name": "aaa", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + let valueBucketArray = new Array(); + let rows = 32768 / 4 + 1; + for (let i = 0; i < rows; i++) { + valueBucketArray.push(valueBucket); + } + var num = await transaction.batchInsertWithConflictResolution("test", valueBucketArray, data_relationalStore.ConflictResolution.ON_CONFLICT_NONE); + console.log(TAG + "testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0035 insert num " + num) + expect(null).assertFail() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(String(e.code)).assertEqual(String(14800000)) + console.log(TAG + "testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0035 success"); + } + await transaction.rollback(); + done() + console.log(TAG + "************* testBatchInsertWithConflictResolutionInTransactionWithInvalidArgs0035 end *************"); + }) + console.log(TAG + "*************Unit Test End*************"); }) \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbstoreAfterCloseJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbstoreAfterCloseJsunit.test.js index af3f4e00fd391d5c6308383f6663f6ea257c9a55..c508c32f86609b8be3e75593e681ba9b3180b2b8 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbstoreAfterCloseJsunit.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbstoreAfterCloseJsunit.test.js @@ -61,7 +61,7 @@ describe('rdbStoreAfterCloseTest', function () { /** * @tc.number testRdbAfterClose0001 * @tc.name RDB Close test - * @tc.desc ececute after RDB closed + * @tc.desc execute after RDB closed */ it('testRdbAfterClose0001', 0, async function () { console.log(TAG + "************* testRdbAfterClose0001 start *************"); diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbstoreBackupRestoreWithFAContextJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbstoreBackupRestoreWithFAContextJsunit.test.js index ea5fcaa53824b096b0d14556abe727b0a250e715..d5d899903c049bd76165bff04a16352707ca3d9c 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbstoreBackupRestoreWithFAContextJsunit.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbstoreBackupRestoreWithFAContextJsunit.test.js @@ -291,6 +291,260 @@ describe('rdbStoreBackupRestoreWithFAContextTest', function () { done(); console.log(TAG + "************* RdbBackupRestoreBackupTest_0060 end *************") }) + /** + * @tc.name RDB BackupRestore by sql test + * @tc.number SUB_DDM_RDB_JS_RdbBackupRestoreTest_0062 + * @tc.desc sql func empty param test + */ + it('RdbBackupRestoreBackupTest_0062', 0, async function (done) { + console.log(TAG + "************* RdbBackupRestoreBackupTest_0062 start *************") + + const DEST_STORE_NAME = "Dest.db"; + const destDb = await data_relationalStore.getRdbStore( + context, + { + name: DEST_STORE_NAME, + securityLevel: data_relationalStore.SecurityLevel.S3 + } + ) + + try { + await destDb.executeSql(`select import_db_from_path()`); + } catch (error) { + console.error("****** RdbBackupRestoreBackupTest_0062 ******" + JSON.stringify(error)); + expect(error.code).assertEqual(14800021); + } + + expect('ok', await destDb.execute("pragma integrity_check")); + await data_relationalStore.deleteRdbStore(context, DEST_STORE_NAME); + done(); + }) + + /** + * @tc.name RDB BackupRestore by sql test + * @tc.number SUB_DDM_RDB_JS_RdbBackupRestoreTest_0063 + * @tc.desc empty path test + */ + it('RdbBackupRestoreBackupTest_0063', 0, async function (done) { + console.log(TAG + "************* RdbBackupRestoreBackupTest_0063 start *************") + + const DEST_STORE_NAME = "Dest.db"; + const destDb = await data_relationalStore.getRdbStore( + context, + { + name: DEST_STORE_NAME, + securityLevel: data_relationalStore.SecurityLevel.S3 + } + ) + + try { + await destDb.executeSql(`select import_db_from_path('')`); + } catch (error) { + console.error("****** RdbBackupRestoreBackupTest_0063 ******" + JSON.stringify(error)); + expect(error.code).assertEqual(14800030); + } + expect('ok', await destDb.execute("pragma integrity_check")); + await data_relationalStore.deleteRdbStore(context, DEST_STORE_NAME); + done(); + }) + + /** + * @tc.name RDB BackupRestore by sql test + * @tc.number SUB_DDM_RDB_JS_RdbBackupRestoreTest_0064 + * @tc.desc souce db not exist test + */ + it('RdbBackupRestoreBackupTest_0064', 0, async function (done) { + console.log(TAG + "************* RdbBackupRestoreBackupTest_0064 start *************") + + const DEST_STORE_NAME = "Dest.db"; + const destDb = await data_relationalStore.getRdbStore( + context, + { + name: DEST_STORE_NAME, + securityLevel: data_relationalStore.SecurityLevel.S3 + } + ) + + try { + await destDb.executeSql(`select import_db_from_path('/path/not_exist.db')`); + } catch (error) { + console.error("****** RdbBackupRestoreBackupTest_0064 ******" + JSON.stringify(error)); + expect(error.code).assertEqual(14800030); + } + expect('ok', await destDb.execute("pragma integrity_check")); + await data_relationalStore.deleteRdbStore(context, DEST_STORE_NAME); + done(); + }) + + /** + * @tc.name RDB BackupRestore by sql test + * @tc.number SUB_DDM_RDB_JS_RdbBackupRestoreTest_0065 + * @tc.desc RDB dest store in transaction + */ + it('RdbBackupRestoreBackupTest_0065', 0, async function (done) { + console.log(TAG + "************* RdbBackupRestoreBackupTest_0065 start *************") + + const SOURCE_STORE_NAME = "Source.db"; + const SOURCE_STORE_PATH = "/data/storage/el2/database/entry/rdb/Source.db"; + + const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "data1 text," + "data2 long, " + "data3 double," + "data4 blob)"; + const sourceDb = await data_relationalStore.getRdbStore( + context, + { + name: SOURCE_STORE_NAME, + securityLevel: data_relationalStore.SecurityLevel.S3 + } + ) + + await sourceDb.executeSql(CREATE_TABLE_TEST, null); + await sourceDb.close(); + + const DEST_STORE_NAME = "Dest.db"; + const destDb = await data_relationalStore.getRdbStore( + context, + { + name: DEST_STORE_NAME, + securityLevel: data_relationalStore.SecurityLevel.S3 + } + ) + + destDb.beginTransaction(); + + try { + await destDb.executeSql(`select import_db_from_path('${SOURCE_STORE_PATH}')`); + } catch (error) { + console.error("****** RdbBackupRestoreBackupTest_0065 ******" + JSON.stringify(error)); + expect(error.code).assertEqual(14800024); + } + expect('ok', await destDb.execute("pragma integrity_check")); + await data_relationalStore.deleteRdbStore(context, SOURCE_STORE_NAME); + await data_relationalStore.deleteRdbStore(context, DEST_STORE_NAME); + done(); + }) + + /** + * @tc.name RDB import_db_from_path sql func test + * @tc.number SUB_DDM_RDB_JS_RdbBackupRestoreTest_0070 + * @tc.desc source store corrupted + */ + it('RdbBackupRestoreBackupTest_0070', 0, async function (done) { + console.log(TAG + "************* RdbBackupRestoreBackupTest_0070 start *************") + + const SOURCE_STORE_NAME = "Source.db"; + const SOURCE_STORE_PATH = "/data/storage/el2/database/entry/rdb/Source.db"; + + const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "data1 text," + "data2 long, " + "data3 double," + "data4 blob)"; + const sourceDb = await data_relationalStore.getRdbStore( + context, + { + name: SOURCE_STORE_NAME, + securityLevel: data_relationalStore.SecurityLevel.S3 + } + ) + + await sourceDb.executeSql(CREATE_TABLE_TEST, null); + await sourceDb.close(); + + const fileStream = await fileio.createStream(SOURCE_STORE_PATH, 'r+'); + const buffer = new ArrayBuffer(32); + const uint8View = new Uint8Array(buffer); + uint8View.forEach((val, index) => { + uint8View[index] = 0xFF; + }); + + await fileStream.write(buffer, { offset: 0x0f40, length: uint8View.length }); + fileStream.closeSync(); + + const DEST_STORE_NAME = "Dest.db"; + const destDb = await data_relationalStore.getRdbStore( + context, + { + name: DEST_STORE_NAME, + securityLevel: data_relationalStore.SecurityLevel.S3 + } + ) + + try { + await destDb.executeSql(`select import_db_from_path('${SOURCE_STORE_PATH}')`); + } catch (error) { + console.error("****** RdbBackupRestoreBackupTest_0070 ******" + JSON.stringify(error)); + expect(error.code).assertEqual(14800011); + } + expect('ok', await destDb.execute("pragma integrity_check")); + await data_relationalStore.deleteRdbStore(context, SOURCE_STORE_NAME); + await data_relationalStore.deleteRdbStore(context, DEST_STORE_NAME); + done(); + }) + + /** + * @tc.name RDB import_db_from_path sql func test + * @tc.number SUB_DDM_RDB_JS_RdbBackupRestoreTest_0080 + * @tc.desc execute import check row count + */ + it('RdbBackupRestoreBackupTest_0080', 0, async function (done) { + console.log(TAG + "************* RdbBackupRestoreBackupTest_0080 start *************") + + const SOURCE_STORE_NAME = "Source.db"; + + const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "data1 text," + "data2 long, " + "data3 double," + "data4 blob)"; + const sourceDb = await data_relationalStore.getRdbStore( + context, + { + name: SOURCE_STORE_NAME, + securityLevel: data_relationalStore.SecurityLevel.S3 + } + ) + + await sourceDb.executeSql(CREATE_TABLE_TEST, null); + let times = 100; + + while (times--) { + const valuesBuckets = new Array(100).fill(0).map((it, index) => { + return { + "data1": "hello" + index, + "data2": 10, + "data3": 1.0, + "data4": new Uint8Array([1, 2, 3]), + } + }); + await sourceDb.batchInsert('test', valuesBuckets); + } + + let predicates = await new data_relationalStore.RdbPredicates("test") + let resultSet = sourceDb.querySync(predicates); + console.log(TAG + "************* RdbBackupRestoreBackupTest_0080 start ************* rowCount: " + resultSet.rowCount); + + await resultSet.close(); + await sourceDb.close(); + + + const DEST_STORE_NAME = "Dest.db"; + const destDb = await data_relationalStore.getRdbStore( + context, + { + name: DEST_STORE_NAME, + securityLevel: data_relationalStore.SecurityLevel.S3 + } + ) + + try { + await destDb.executeSql("select import_db_from_path('/data/storage/el2/database/entry/rdb/Source.db')"); + + let predicates = await new data_relationalStore.RdbPredicates("test") + let resultSet = destDb.querySync(predicates); + expect(resultSet.rowCount).assertEqual(100 * 100); + } catch (error) { + console.error("****** RdbBackupRestoreBackupTest_0080 ******" + JSON.stringify(error)); + expect().assertFail(); + } + expect('ok', await destDb.execute("pragma integrity_check")); + await data_relationalStore.deleteRdbStore(context, SOURCE_STORE_NAME); + await data_relationalStore.deleteRdbStore(context, DEST_STORE_NAME); + done(); + }) console.log(TAG + "*************Unit Test End*************") } diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbstoreEncryptionJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbstoreEncryptionJsunit.test.js index 72519ca8cfa1f7dfb2d69b48062610bf884f1fbe..b743503a56951d10caa9a05e23566cf766d026d8 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbstoreEncryptionJsunit.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbstoreEncryptionJsunit.test.js @@ -16,6 +16,7 @@ import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from import data_relationalStore from '@ohos.data.relationalStore' import ability_featureAbility from '@ohos.ability.featureAbility' import factory from '@ohos.data.distributedKVStore' +import fs from '@ohos.file.fs' const TAG = "[RELATIONAL_STORE_JSKITS_TEST]" const TEST_BUNDLE_NAME = "com.example.myapplication" @@ -734,6 +735,54 @@ describe('rdbEncryptTest', function () { console.log(TAG + "************* RdbDecryptTest_0090 end *************") }) + /** + * @tc.number testConfigChange001 + * @tc.name Abnormal test case of config change, but service not perceived + * @tc.desc 1.Get encrypt rdb1 + * 2.Get decrypt rdb2 + * 3.rename rdb2 to rdb1 + * 4.Get rdb1 use decrypt + */ + it('testConfigChange001', 0, async () => { + console.log(TAG + "************* testConfigChange001 start *************"); + let rdbConfig = { + name: "testConfigChange001.db", + securityLevel: data_relationalStore.SecurityLevel.S1, + encrypt: true, + } + let otherRdbConfig = { + name: "other_testConfigChange001.db", + securityLevel: data_relationalStore.SecurityLevel.S1, + encrypt: false, + } + try { + let rdbStore = await data_relationalStore.getRdbStore(context, rdbConfig); + rdbStore.close(); + rdbStore = await data_relationalStore.getRdbStore(context, otherRdbConfig); + let databaseDir = "/data/storage/el2/database/entry/rdb/"; + console.log(TAG + "testConfigChange001 dataBaseDir:" + databaseDir); + let filenames = fs.listFileSync(databaseDir); + console.log(TAG + "testConfigChange001 filenames:" + filenames); + for (let i = 0; i < filenames.length; i++) { + if (filenames[i].startsWith("testConfigChange001.db")) { + fs.unlinkSync(databaseDir + filenames[i]); + fs.renameSync(databaseDir + "other_" + filenames[i], databaseDir + filenames[i]); + console.info("filename: " + filenames[i]); + } + } + rdbConfig.encrypt = false; + rdbStore = await data_relationalStore.getRdbStore(context, rdbConfig); + expect(true).assertTrue(); + console.log(TAG + "testConfigChange001 success"); + } catch (e) { + console.error(`testConfigChange001 failed, error code: ${e.code}, err message: ${e.message}`); + expect(null).assertFail(); + } + await data_relationalStore.deleteRdbStore(context, rdbConfig); + await data_relationalStore.deleteRdbStore(context, otherRdbConfig); + console.log(TAG + "************* testConfigChange001 end *************"); + }) + /** * @tc.number testEncryptRdbAndKv0001 * @tc.name Normal test case of using encrypt kv, then using rdb attach interface diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbstoreInsertJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbstoreInsertJsunit.test.js index bd388015bf0d9ebff7a424305067aa82b9f711c3..85f8ff3e15dc4daa6e33392e2e8cdcaeb621c4ca 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbstoreInsertJsunit.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbstoreInsertJsunit.test.js @@ -656,7 +656,7 @@ describe('rdbStoreInsertTest', function () { * @tc.desc 1.Insert data with ON_CONFLICT_REPLACE * 2.Query data ("name" is "zhangsan") * 3.Insert data with ON_CONFLICT_REPLACE (conflict "id") - * 4.Query data + * 4.Query data */ it('InsertWithConflictResolution0004', 0, async function (done) { console.log(TAG + "************* InsertWithConflictResolution0004 start *************"); @@ -830,5 +830,452 @@ describe('rdbStoreInsertTest', function () { console.log(TAG + "************* testRdbStoreBatchInsert002 end *************"); }) + /** + * @tc.number testRdbStoreBatchInsertWithConflictResolution001 + * @tc.name batch insert with conflict resolution + * @tc.desc normal batch insert with conflict resolution + */ + it('testRdbStoreBatchInsertWithConflictResolution001', 0, async function (done) { + console.log(TAG + "************* testRdbStoreBatchInsertWithConflictResolution001 start *************"); + var u8 = new Uint8Array([1, 2, 3]) + try { + const valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + let valueBucketArray = new Array(); + for (let i = 0; i < 2; i++) { + valueBucketArray.push(valueBucket); + } + var num = await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_NONE) + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution001 batch num1 " + num) + expect(2).assertEqual(num); + + num = await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_ROLLBACK) + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution001 batch num2 " + num) + expect(2).assertEqual(num); + + num = await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_ABORT) + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution001 batch num3 " + num) + expect(2).assertEqual(num); + + num = await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_FAIL) + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution001 batch num4 " + num) + expect(2).assertEqual(num); + + num = await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_IGNORE) + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution001 batch num5 " + num) + expect(2).assertEqual(num); + + num = await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_REPLACE) + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution001 batch num6 " + num) + expect(2).assertEqual(num); + + let resultSet = await rdbStore.querySql("select * from test") + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution001 result count " + resultSet.rowCount) + expect(12).assertEqual(resultSet.rowCount) + resultSet.close() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(null).assertFail() + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution001 failed"); + } + done() + console.log(TAG + "************* testRdbStoreBatchInsertWithConflictResolution001 end *************"); + }) + + /** + * @tc.number testRdbStoreBatchInsertWithConflictResolution002 + * @tc.name batch insert with conflict resolution + * @tc.desc conflict when batch insert with conflict resolution + */ + it('testRdbStoreBatchInsertWithConflictResolution002', 0, async function (done) { + console.log(TAG + "************* testRdbStoreBatchInsertWithConflictResolution002 start *************"); + var u8 = new Uint8Array([1, 2, 3]) + try { + const valueBucket = { + "id" : 2, + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await rdbStore.insert("test", valueBucket); + let valueBucketArray = new Array(); + for (let i = 0; i < 5; i++) { + let val = { + "id" : i, + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + valueBucketArray.push(val); + } + try { + await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_NONE); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution002 ON_CONFLICT_NONE code: " + e.code); + expect(14800032).assertEqual(e.code) + } + try { + await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_ROLLBACK); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution002 ON_CONFLICT_ROLLBACK code: " + e.code); + expect(14800032).assertEqual(e.code) + } + try { + await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_ABORT); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution002 ON_CONFLICT_ABORT code: " + e.code); + expect(14800032).assertEqual(e.code) + } + try { + await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_FAIL); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution002 ON_CONFLICT_FAIL code: " + e.code); + expect(14800032).assertEqual(e.code) + } + try { + let num = await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_IGNORE); + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution002 ON_CONFLICT_IGNORE num " + num) + expect(2).assertEqual(num) + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution002 ON_CONFLICT_IGNORE code: " + e.code); + expect(null).assertFail(); + } + try { + let num = await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_REPLACE); + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution002 ON_CONFLICT_REPLACE num " + num) + expect(5).assertEqual(num) + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution002 ON_CONFLICT_REPLACE code: " + e.code); + expect(null).assertFail(); + } + let resultSet = await rdbStore.querySql("select * from test") + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution002 result count " + resultSet.rowCount) + expect(5).assertEqual(resultSet.rowCount) + resultSet.close() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(null).assertFail() + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution002 failed"); + } + done() + console.log(TAG + "************* testRdbStoreBatchInsertWithConflictResolution002 end *************"); + }) + + /** + * @tc.number testRdbStoreBatchInsertWithConflictResolution003 + * @tc.name batch insert with conflict resolution + * @tc.desc conflict when batch insert with conflict resolution + */ + it('testRdbStoreBatchInsertWithConflictResolution003', 0, async function (done) { + console.log(TAG + "************* testRdbStoreBatchInsertWithConflictResolution003 start *************"); + var u8 = new Uint8Array([1, 2, 3]) + try { + let valueBucketArray = new Array(); + for (let i = 0; i < 5; i++) { + let val = { + "id": i, + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + if (i == 2) { + val.name = null; + } + valueBucketArray.push(val); + } + try { + await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_NONE); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution003 ON_CONFLICT_NONE code: " + e.code); + expect(14800032).assertEqual(e.code) + } + try { + await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_ROLLBACK); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution003 ON_CONFLICT_ROLLBACK code: " + e.code); + expect(14800032).assertEqual(e.code) + } + try { + await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_ABORT); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution003 ON_CONFLICT_ABORT code: " + e.code); + expect(14800032).assertEqual(e.code) + } + try { + await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_FAIL); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution003 ON_CONFLICT_FAIL code: " + e.code); + expect(14800032).assertEqual(e.code) + } + try { + let num = await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_IGNORE); + expect(2).assertEqual(num) + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution003 ON_CONFLICT_IGNORE code: " + e.code); + expect(null).assertFail(); + } + try { + await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_REPLACE); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution003 ON_CONFLICT_REPLACE code: " + e.code); + expect(14800032).assertEqual(e.code) + } + let resultSet = await rdbStore.querySql("select * from test") + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution003 result count " + resultSet.rowCount) + expect(4).assertEqual(resultSet.rowCount) + resultSet.close() + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(null).assertFail() + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution003 failed"); + } + done() + console.log(TAG + "************* testRdbStoreBatchInsertWithConflictResolution003 end *************"); + }) + + /** + * @tc.number testRdbStoreBatchInsertWithConflictResolution004 + * @tc.name batch insert with conflict resolution + * @tc.desc conflict when batch insert with conflict resolution + */ + it('testRdbStoreBatchInsertWithConflictResolution004', 0, async function (done) { + console.log(TAG + "************* testRdbStoreBatchInsertWithConflictResolution004 start *************"); + let valueBucketArray = new Array(); + for (let i = 0; i < 5; i++) { + let val = { + "id": i, + "name": "zhangsan", + } + valueBucketArray.push(val); + } + try { + await rdbStore.executeSql("DROP TABLE IF EXISTS test004"); + await rdbStore.executeSql("CREATE TABLE test004 (id INTEGER PRIMARY KEY CHECK (id >= 3 OR id <= 1), name TEXT NOT NULL)", null) + try { + await rdbStore.batchInsertWithConflictResolution("test004", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_NONE); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution004 ON_CONFLICT_NONE code: " + e.code); + expect(14800032).assertEqual(e.code) + } + try { + rdbStore.batchInsertWithConflictResolutionSync("test004", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_ROLLBACK); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution004 ON_CONFLICT_ROLLBACK code: " + e.code); + expect(14800032).assertEqual(e.code) + } + try { + await rdbStore.batchInsertWithConflictResolution("test004", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_ABORT); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution004 ON_CONFLICT_ABORT code: " + e.code); + expect(14800032).assertEqual(e.code) + } + try { + rdbStore.batchInsertWithConflictResolutionSync("test004", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_FAIL); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution004 ON_CONFLICT_FAIL code: " + e.code); + expect(14800032).assertEqual(e.code) + } + try { + let num = await rdbStore.batchInsertWithConflictResolution("test004", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_IGNORE); + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution004 ON_CONFLICT_IGNORE num " + num) + expect(2).assertEqual(num) + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution004 ON_CONFLICT_IGNORE code: " + e.code); + expect(null).assertFail(); + } + try { + let num = rdbStore.batchInsertWithConflictResolutionSync("test004", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_REPLACE); + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution004 ON_CONFLICT_REPLACE num " + num) + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution004 ON_CONFLICT_REPLACE code: " + e.code); + expect(14800032).assertEqual(e.code) + } + let resultSet = await rdbStore.querySql("select * from test004") + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution004 result count " + resultSet.rowCount) + expect(4).assertEqual(resultSet.rowCount) + resultSet.close() + await rdbStore.executeSql("DROP TABLE IF EXISTS test004"); + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(null).assertFail() + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution004 failed"); + } + done() + console.log(TAG + "************* testRdbStoreBatchInsertWithConflictResolution004 end *************"); + }) + + /** + * @tc.number testRdbStoreBatchInsertWithConflictResolution005 + * @tc.name batch insert with conflict resolution + * @tc.desc batch insert with conflict resolution with invalid args + */ + it('testRdbStoreBatchInsertWithConflictResolution005', 0, async function (done) { + console.log(TAG + "************* testRdbStoreBatchInsertWithConflictResolution005 start *************"); + try { + try { + rdbStore.batchInsertWithConflictResolutionSync(); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution005 no args: " + e.code); + expect(String(e.code)).assertEqual(String(401)) + } + try { + await rdbStore.batchInsertWithConflictResolution("test"); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution005 with 1 args: " + e.code); + expect(String(e.code)).assertEqual(String(401)) + } + try { + rdbStore.batchInsertWithConflictResolutionSync("test", undefined); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution005 with 2 args: " + e.code); + expect(String(e.code)).assertEqual(String(401)) + } + try { + const valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + } + let valueBucketArray = new Array(); + for (let i = 0; i < 2; i++) { + valueBucketArray.push(valueBucket); + } + await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, undefined); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + "testRdbStoreBatchInsertWithConflictResolution005 with 3 args: " + e.code); + expect(String(e.code)).assertEqual(String(401)) + } + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(null).assertFail() + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution005 failed"); + } + done() + console.log(TAG + "************* testRdbStoreBatchInsertWithConflictResolution005 end *************"); + }) + + /** + * @tc.number testRdbStoreBatchInsertWithConflictResolution006 + * @tc.name batch insert with conflict resolution + * @tc.desc batch insert with conflict resolution with over limit rows + */ + it('testRdbStoreBatchInsertWithConflictResolution006', 0, async function (done) { + console.log(TAG + "************* testRdbStoreBatchInsertWithConflictResolution006 start *************"); + + var u8 = new Uint8Array([1, 2, 3]) + try { + const valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + let valueBucketArray = new Array(); + let rows = 32768 / 4 + 1; + for (let i = 0; i < rows; i++) { + valueBucketArray.push(valueBucket); + } + let num = await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_NONE); + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution006 failed num " + num); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(14800000).assertEqual(e.code) + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution006 success"); + } + done() + console.log(TAG + "************* testRdbStoreBatchInsertWithConflictResolution006 end *************"); + }) + + /** + * @tc.number testRdbStoreBatchInsertWithConflictResolution007 + * @tc.name batch insert with conflict resolution + * @tc.desc batch insert with conflict resolution with busy + */ + it('testRdbStoreBatchInsertWithConflictResolution007', 0, async function (done) { + console.log(TAG + "************* testRdbStoreBatchInsertWithConflictResolution007 start *************"); + + let transaction = await rdbStore.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + try { + const valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + } + let valueBucketArray = new Array(); + for (let i = 0; i < 2; i++) { + valueBucketArray.push(valueBucket); + } + await rdbStore.batchInsertWithConflictResolution("test", valueBucketArray, + data_relationalStore.ConflictResolution.ON_CONFLICT_NONE); + await transaction.rollback(); + expect(null).assertFail(); + } catch (e) { + console.log(TAG + e + " code: " + e.code); + expect(14800024).assertEqual(e.code) + console.log(TAG + "testRdbStoreBatchInsertWithConflictResolution007 failed"); + try { + await transaction.rollback(); + }catch (e) { + console.log(TAG + e + " rollback code: " + e.code); + expect(null).assertFail(); + } + } + done() + console.log(TAG + "************* testRdbStoreBatchInsertWithConflictResolution007 end *************"); + }) + console.log(TAG + "*************Unit Test End*************"); }) \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbstoreRdbstoreJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbstoreRdbstoreJsunit.test.js index 3de78fe46a2cbca6067626748c298fe2210a1bab..04599cd29bae9ea34f970e73349907e92f7ecfaa 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbstoreRdbstoreJsunit.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbstoreRdbstoreJsunit.test.js @@ -26,6 +26,10 @@ const STORE_CONFIG = { name: "rdbstore.db", securityLevel: data_relationalStore.SecurityLevel.S1, } +const STORE_CONFIG1 = { + name: "rdbstore1.db", + securityLevel: data_relationalStore.SecurityLevel.S1, +} describe('rdbStoreTest', function () { beforeAll(async function () { console.info(TAG + 'beforeAll') @@ -245,7 +249,7 @@ describe('rdbStoreTest', function () { /** * @tc.name rdb store getRdbStore with different securityLevel - * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0010 + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0100 * @tc.desc rdb store getRdbStore with different securityLevel * @tc.require: I5PIL6 */ @@ -277,7 +281,7 @@ describe('rdbStoreTest', function () { /** * @tc.name rdb store getRdbStore with invalid securityLevel - * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0011 + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0110 * @tc.desc rdb store getRdbStore with invalid securityLevel */ it('testRdbStore0011', 0, async function () { @@ -300,7 +304,7 @@ describe('rdbStoreTest', function () { /** * @tc.name rdb store wal file overlimit test - * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0012 + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0120 * @tc.desc Checkpoint failure delayed retry */ it('testRdbStore0012', 0, async function (done) { @@ -318,7 +322,6 @@ describe('rdbStoreTest', function () { + "blobType BLOB)"; rdbStore.executeSync(CREATE_TABLE_TEST); - const valueBuckets = Array(rowCount).fill(0).map(() => { return { blobType: new Uint8Array(Array(1024 * 1024).fill(1)), @@ -331,23 +334,22 @@ describe('rdbStoreTest', function () { const resultSet = rdbStore.querySync(predicates); expect(resultSet.rowCount).assertEqual(rowCount); resultSet.goToFirstRow() - + const value = new Uint8Array(Array(1024 * 1024).fill(1)); const startTime = new Date().getTime(); rdbStore.insertSync('test', { blobType: new Uint8Array(Array(1024 * 1024).fill(1)), }) const middleTime = new Date().getTime(); - console.log(TAG + "testRdbStore0012, startTime:" + startTime + " middleTime:" + middleTime); - + console.log(TAG + "testRdbStore0012, startTime:" + startTime + " middleTime:" + middleTime + " costTime" + (middleTime-startTime)); expect((middleTime - startTime) > 500).assertTrue(); - + rdbStore.insertSync('test', { - blobType: new Uint8Array(Array(1024 * 1024).fill(1)), + blobType: value, }) const endTime = new Date().getTime(); - console.log(TAG + "testRdbStore0012, endTime:" + endTime + " middleTime:" + middleTime); - + console.log(TAG + "testRdbStore0012, endTime:" + endTime + " middleTime:" + middleTime + " costTime" + (endTime-middleTime)); expect((endTime - middleTime) < 500).assertTrue(); + console.log(TAG + "************* testRdbStore0012 end *************"); done(); } catch (e) { @@ -356,5 +358,1103 @@ describe('rdbStoreTest', function () { expect().assertFail(); } }) + + /** + * @tc.name rdb store update after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0130 + * @tc.desc rdb store update after deleteRdbStore + */ + it('testRdbStore0013', 0, async function () { + console.log(TAG + "************* testRdbStore0013 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await store.executeSql(CREATE_TABLE_TEST); + + var u8 = new Uint8Array([1, 2, 3]) + const valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await store.insert("test", valueBucket) + + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + const valueBucket1 = { + "name": "zhangsan", + "age": 19, + "salary": 200.5, + "blobType": u8, + } + let predicates = new data_relationalStore.RdbPredicates("test"); + predicates.equalTo("NAME", "zhangsan"); + await store.update(valueBucket1, predicates) + } catch (err) { + expect().assertFail(); + } + store = null + console.log(TAG + "************* testRdbStore0013 end *************"); + }) + + /** + * @tc.name rdb store insert after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0140 + * @tc.desc rdb store insert after deleteRdbStore + */ + it('testRdbStore0014', 0, async function () { + console.log(TAG + "************* testRdbStore0014 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await store.executeSql(CREATE_TABLE_TEST); + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + var u8 = new Uint8Array([1, 2, 3]) + { + const valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await store.insert("test", valueBucket) + } + } catch (err) { + expect().assertFail(); + } + store = null + console.log(TAG + "************* testRdbStore0014 end *************"); + }) + + /** + * @tc.name rdb store batchInsert after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0150 + * @tc.desc rdb store batchInsert after deleteRdbStore + */ + it('testRdbStore0015', 0, async function () { + console.log(TAG + "************* testRdbStore0015 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await store.executeSql(CREATE_TABLE_TEST); + + var u8 = new Uint8Array([1, 2, 3]) + const valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + let valueBucketArray = new Array(); + for (let i = 0; i < 10; i++) { + valueBucketArray.push(valueBucket); + } + + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + await store.batchInsert("test", valueBucketArray) + } catch (err) { + expect().assertFail(); + } + store = null + console.log(TAG + "************* testRdbStore0015 end *************"); + }) + + /** + * @tc.name rdb store delete after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0160 + * @tc.desc rdb store delete after deleteRdbStore + */ + it('testRdbStore0016', 0, async function () { + console.log(TAG + "************* testRdbStore0016 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await store.executeSql(CREATE_TABLE_TEST); + var u8 = new Uint8Array([1, 2, 3]) + { + const valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await store.insert("test", valueBucket) + } + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + let predicates = await new data_relationalStore.RdbPredicates("test") + await store.delete(predicates) + } catch (err) { + expect().assertFail(); + } + store = null + console.log(TAG + "************* testRdbStore0016 end *************"); + }) + + /** + * @tc.name rdb store query after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0170 + * @tc.desc rdb store query after deleteRdbStore + */ + it('testRdbStore0017', 0, async function () { + console.log(TAG + "************* testRdbStore0017 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await store.executeSql(CREATE_TABLE_TEST); + var u8 = new Uint8Array([1, 2, 3]) + { + const valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await store.insert("test", valueBucket) + } + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + let predicates = await new data_relationalStore.RdbPredicates("test") + await store.query(predicates) + } catch (err) { + expect().assertFail(); + } + store = null + console.log(TAG + "************* testRdbStore0017 end *************"); + }) + + /** + * @tc.name rdb store querySql after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0180 + * @tc.desc rdb store querySql after deleteRdbStore + */ + it('testRdbStore0018', 0, async function () { + console.log(TAG + "************* testRdbStore0018 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await store.executeSql(CREATE_TABLE_TEST); + var u8 = new Uint8Array([1, 2, 3]) + { + const valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await store.insert("test", valueBucket) + } + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + await store.querySql("SELECT * FROM test") + } catch (err) { + expect().assertFail(); + } + store = null + console.log(TAG + "************* testRdbStore0018 end *************"); + }) + + /** + * @tc.name rdb store backup after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0190 + * @tc.desc rdb store backup after deleteRdbStore + */ + it('testRdbStore0019', 0, async function () { + console.log(TAG + "************* testRdbStore0019 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + await store.backup("backup.db"); + } catch (err) { + expect().assertFail(); + } + store = null + console.log(TAG + "************* testRdbStore0019 end *************"); + }) + + /** + * @tc.name rdb store restore after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0200 + * @tc.desc rdb store restore after deleteRdbStore + */ + it('testRdbStore0020', 0, async function () { + console.log(TAG + "************* testRdbStore0020 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await store.backup("backup.db"); + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + await store.restore("backup.db"); + } catch (err) { + expect().assertFail(); + } + store = null + console.log(TAG + "************* testRdbStore0020 end *************"); + }) + + /** + * @tc.name rdb store cleanDirtyData after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0210 + * @tc.desc rdb store cleanDirtyData after deleteRdbStore + */ + it('testRdbStore0021', 0, async function () { + console.log(TAG + "************* testRdbStore0021 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + await store.cleanDirtyData('test') + expect().assertFail(); + } catch (err) { + expect(14800000).assertEqual(err.code) + } + store = null + console.log(TAG + "************* testRdbStore0021 end *************"); + }) + + /** + * @tc.name rdb store executeSql after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0220 + * @tc.desc rdb store executeSql after deleteRdbStore + */ + it('testRdbStore0022', 0, async function () { + console.log(TAG + "************* testRdbStore0022 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + await store.executeSql(CREATE_TABLE_TEST) + } catch (err) { + expect().assertFail(); + } + store = null + console.log(TAG + "************* testRdbStore0022 end *************"); + }) + + /** + * @tc.name rdb store execute after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0230 + * @tc.desc rdb store execute after deleteRdbStore + */ + it('testRdbStore0023', 0, async function () { + console.log(TAG + "************* testRdbStore0023 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + await store.execute(CREATE_TABLE_TEST) + } catch (err) { + expect().assertFail(); + } + store = null + console.log(TAG + "************* testRdbStore0023 end *************"); + }) + + /** + * @tc.name rdb store beginTransaction after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0240 + * @tc.desc rdb store beginTransaction after deleteRdbStore + */ + it('testRdbStore0024', 0, async function () { + console.log(TAG + "************* testRdbStore0024 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + store.beginTransaction(); + } catch (err) { + expect().assertFail(); + } + store = null + console.log(TAG + "************* testRdbStore0024 end *************"); + }) + + /** + * @tc.name rdb store setDistributedTables after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0250 + * @tc.desc rdb store setDistributedTables after deleteRdbStore + */ + it('testRdbStore0025', 0, async function () { + console.log(TAG + "************* testRdbStore0025 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await store.executeSql(CREATE_TABLE_TEST); + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + await store.setDistributedTables(['test']) + expect().assertFail(); + } catch (err) { + expect(14800000).assertEqual(err.code); + } + store = null + console.log(TAG + "************* testRdbStore0025 end *************"); + }) + + /** + * @tc.name rdb store attach after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0260 + * @tc.desc rdb store attach after deleteRdbStore + */ + it('testRdbStore0026', 0, async function () { + console.log(TAG + "************* testRdbStore0026 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await store.executeSql(CREATE_TABLE_TEST); + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + await store.attach(context, STORE_CONFIG1, "attachDB"); + expect().assertFail(); + } catch (err) { + expect(14800010).assertEqual(err.code); + } + store = null + console.log(TAG + "************* testRdbStore0026 end *************"); + }) + + /** + * @tc.name rdb store detach after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0270 + * @tc.desc rdb store detach after deleteRdbStore + */ + it('testRdbStore0027', 0, async function () { + console.log(TAG + "************* testRdbStore0027 start *************"); + + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await data_relationalStore.getRdbStore(context, STORE_CONFIG1); + await store.executeSql(CREATE_TABLE_TEST); + + await store.attach(context, STORE_CONFIG1, "attachDB"); + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + await store.detach("attachDB") + } catch (err) { + expect().assertFail(); + } + store = null + console.log(TAG + "************* testRdbStore0027 end *************"); + }) + + /** + * @tc.name rdb store createTransaction after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0280 + * @tc.desc rdb store createTransaction after deleteRdbStore + */ + it('testRdbStore0028', 0, async function () { + console.log(TAG + "************* testRdbStore0028 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await store.executeSql(CREATE_TABLE_TEST); + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + + try { + await store?.createTransaction({ + transactionType: data_relationalStore.TransactionType.IMMEDIATE + }); + } catch (err) { + expect().assertFail(); + } + store = null + console.log(TAG + "************* testRdbStore0028 end *************"); + }) + + /** + * @tc.name rdb store beginTrans after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0290 + * @tc.desc rdb store beginTrans after deleteRdbStore + */ + it('testRdbStore0029', 0, async function () { + console.log(TAG + "************* testRdbStore0029 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + await store.beginTrans(); + expect().assertFail(); + } catch (err) { + expect(801).assertEqual(err.code); + } + store = null + console.log(TAG + "************* testRdbStore0029 end *************"); + }) + + /** + * @tc.name rdb store commit after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0300 + * @tc.desc rdb store commit after deleteRdbStore + */ + it('testRdbStore0030', 0, async function () { + console.log(TAG + "************* testRdbStore0030 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await store.executeSql(CREATE_TABLE_TEST); + + store.beginTransaction(); + var u8 = new Uint8Array([1, 2, 3]) + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await store.insert("test", valueBucket) + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + store.commit(); + } catch (err) { + expect().assertFail(); + } + store = null + console.log(TAG + "************* testRdbStore0030 end *************"); + }) + + /** + * @tc.name rdb store getModifyTime after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0310 + * @tc.desc rdb store getModifyTime after deleteRdbStore + */ + it('testRdbStore0031', 0, async function () { + console.log(TAG + "************* testRdbStore0031 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await store.executeSql(CREATE_TABLE_TEST); + var u8 = new Uint8Array([1, 2, 3]) + { + const valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await store.insert("test", valueBucket) + } + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + await store.getModifyTime('test', 'name', [1]); + expect().assertFail(); + } catch (err) { + expect(14800000).assertEqual(err.code); + } + store = null + console.log(TAG + "************* testRdbStore0031 end *************"); + }) + + /** + * @tc.name rdb store rollBack after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0320 + * @tc.desc rdb store rollBack after deleteRdbStore + */ + it('testRdbStore0032', 0, async function () { + console.log(TAG + "************* testRdbStore0032 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await store.executeSql(CREATE_TABLE_TEST); + + store.beginTransaction(); + var u8 = new Uint8Array([1, 2, 3]) + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await store.insert("test", valueBucket) + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + try { + store.rollBack(); + } catch (err) { + expect().assertFail(); + } + store = null + console.log(TAG + "************* testRdbStore0032 end *************"); + }) + + /** + * @tc.name rdb store queryLockedRow after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0330 + * @tc.desc rdb store queryLockedRow after deleteRdbStore + */ + it('testRdbStore0033', 0, async function () { + console.log(TAG + "************* testRdbStore0033 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await store.executeSql(CREATE_TABLE_TEST); + + var u8 = new Uint8Array([1, 2, 3]) + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await store.insert("test", valueBucket) + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + + try { + let predicates = new data_relationalStore.RdbPredicates("test"); + predicates.equalTo('age', 18); + await store.queryLockedRow(predicates); + } catch (err) { + expect().assertFail(); + } + store = null + console.log(TAG + "************* testRdbStore0033 end *************"); + }) + + /** + * @tc.name rdb store lockRow after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0340 + * @tc.desc rdb store lockRow after deleteRdbStore + */ + it('testRdbStore0034', 0, async function () { + console.log(TAG + "************* testRdbStore0034 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await store.executeSql(CREATE_TABLE_TEST); + + var u8 = new Uint8Array([1, 2, 3]) + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await store.insert("test", valueBucket) + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + + try { + let predicates = new data_relationalStore.RdbPredicates("test"); + predicates.equalTo('age', 18); + await store.lockRow(predicates); + expect().assertFail(); + } catch (err) { + expect(14800018).assertEqual(err.code); + } + store = null + console.log(TAG + "************* testRdbStore0034 end *************"); + }) + + /** + * @tc.name rdb store unlockRow after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0350 + * @tc.desc rdb store unlockRow after deleteRdbStore + */ + it('testRdbStore0035', 0, async function () { + console.log(TAG + "************* testRdbStore0035 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await store.executeSql(CREATE_TABLE_TEST); + + var u8 = new Uint8Array([1, 2, 3]) + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await store.insert("test", valueBucket) + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + + try { + let predicates = new data_relationalStore.RdbPredicates("test"); + predicates.equalTo('age', 18); + await store.unlockRow(predicates); + expect().assertFail(); + } catch (err) { + expect(14800018).assertEqual(err.code); + } + store = null + console.log(TAG + "************* testRdbStore0035 end *************"); + }) + + /** + * @tc.name rdb store transaction insert after deleteRdbStore + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0360 + * @tc.desc rdb store transaction insert after deleteRdbStore + */ + it('testRdbStore0036', 0, async function () { + console.log(TAG + "************* testRdbStore0036 start *************"); + let store = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + await store.executeSql(CREATE_TABLE_TEST); + var transaction = await store?.createTransaction({ + transactionType: data_relationalStore.TransactionType.DEFERRED + }); + await data_relationalStore.deleteRdbStore(context, "rdbstore.db"); + + try { + var u8 = new Uint8Array([1, 2, 3]) + const valueBucket = { + "name": "lisi", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await transaction.insert("test", valueBucket) + } catch (err) { + expect().assertFail(); + } + store = null + console.log(TAG + "************* testRdbStore0036 end *************"); + }) + + /** + * @tc.name rootDir support test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0037 + * @tc.desc invalid rootDir path async + */ + it('testRdbStore0037', 0, async function (done) { + console.log(TAG + "************* testRdbStore0037 start *************"); + try { + await data_relationalStore.getRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + rootDir: "invalidPath", + customDir: "entry/rdb" + }); + expect().assertFail(); + } catch (e) { + expect("14800010").assertEqual(e.code); + } + console.log(TAG + "************* testRdbStore0037 end *************"); + done(); + }) + + /** + * @tc.name rootDir support test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0038 + * @tc.desc invalid rootDir path callback + */ + it('testRdbStore0038', 0, async (done) => { + console.log(TAG + "************* testRdbStore0038 start *************"); + try { + data_relationalStore.getRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + rootDir: "invalidPath", + customDir: "entry/rdb" + }, () => { + expect().assertFail(); + }) + } catch (e) { + expect("14800010").assertEqual(e.code); + console.log(TAG + "************* testRdbStore0038 end *************"); + done(); + }; + }) + + /** + * @tc.name rootDir support test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0039 + * @tc.desc db not exist test async + */ + it('testRdbStore0039', 0, async function (done) { + console.log(TAG + "************* testRdbStore0039 start *************"); + try { + await data_relationalStore.getRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + rootDir: "/data/storage/el2/database", + customDir: "entry/rdb" + }); + expect().assertFail(); + } catch (e) { + expect("14800010").assertEqual(e.code); + } + console.log(TAG + "************* testRdbStore0039 end *************"); + done(); + }) + + /** + * @tc.name rootDir support test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0040 + * @tc.desc db not exist test callback + */ + it('testRdbStore0040', 0, async function (done) { + console.log(TAG + "************* testRdbStore0040 start *************"); + try { + data_relationalStore.getRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + rootDir: "/data/storage/el2/database", + customDir: "entry/rdb" + }, () => { + expect().assertFail(); + }) + } catch (e) { + expect("14800010").assertEqual(e.code); + console.log(TAG + "************* testRdbStore0040 end *************"); + done(); + } + }) + + /** + * @tc.name rootDir support test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0041 + * @tc.desc query test async + */ + it('testRdbStore0041', 0, async function (done) { + console.log(TAG + "************* testRdbStore0041 start *************"); + try { + const rowCount = 18; + const rdbStore = await data_relationalStore.getRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + }) + + rdbStore.executeSync(CREATE_TABLE_TEST); + + const valueBuckets = Array(rowCount).fill(0).map(() => { + return { + "name": "lisi", + "age": 15, + "salary": 153.3, + "blobType": new Uint8Array([1, 2, 3]), + }; + }) + rdbStore.batchInsertSync('test', valueBuckets); + rdbStore.close(); + + const rdbStore1 = await data_relationalStore.getRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + rootDir: "/data/storage/el2/database", + customDir: "entry/rdb" + }) + + const predicates = new data_relationalStore.RdbPredicates('test'); + const resultSet = rdbStore1.querySync(predicates); + expect(resultSet.rowCount).assertEqual(rowCount); + } catch (e) { + console.log("catch err: failed, err: code=" + e.code + " message=" + e.message) + expect().assertFail(); + } + await data_relationalStore.deleteRdbStore(context, "rootDirTest"); + console.log(TAG + "************* testRdbStore0041 end *************"); + done(); + }) + + /** + * @tc.name rootDir support test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0042 + * @tc.desc query test callback + */ + it('testRdbStore0042', 0, async function (done) { + console.log(TAG + "************* testRdbStore0042 start *************"); + const rowCount = 18; + const rdbStore = await data_relationalStore.getRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + }) + + rdbStore.executeSync(CREATE_TABLE_TEST); + + const valueBuckets = Array(rowCount).fill(0).map(() => { + return { + "name": "lisi", + "age": 15, + "salary": 153.3, + "blobType": new Uint8Array([1, 2, 3]), + }; + }) + rdbStore.batchInsertSync('test', valueBuckets); + rdbStore.close(); + + data_relationalStore.getRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + rootDir: "/data/storage/el2/database", + customDir: "entry/rdb" + }, (e, rdbStore) => { + if (e) { + console.log("catch err: failed, err: code=" + e.code + " message=" + e.message); + expect().assertFail(); + } else { + const predicates = new data_relationalStore.RdbPredicates('test'); + const resultSet = rdbStore.querySync(predicates); + expect(resultSet.rowCount).assertEqual(rowCount); + data_relationalStore.deleteRdbStore(context, "rootDirTest"); + console.log(TAG + "************* testRdbStore0042 end *************"); + done(); + } + }) + }) + + /** + * @tc.name rootDir support test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0043 + * @tc.desc write test async + */ + it('testRdbStore0043', 0, async function (done) { + console.log(TAG + "************* testRdbStore0043 start *************"); + try { + const rdbStore = await data_relationalStore.getRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + }) + + rdbStore.executeSync(CREATE_TABLE_TEST); + rdbStore.close(); + + const rdbStore1 = await data_relationalStore.getRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + rootDir: "/data/storage/el2/database", + customDir: "entry/rdb" + }) + + rdbStore1.insertSync('test', { + "name": "lisi", + "age": 15, + "salary": 153.3, + "blobType": new Uint8Array([1, 2, 3]), + }); + expect().assertFail(); + } catch (e) { + console.log("catch err: failed, err: code=" + e.code + " message=" + e.message) + expect(801).assertEqual(e.code); + } + await data_relationalStore.deleteRdbStore(context, "rootDirTest"); + console.log(TAG + "************* testRdbStore0043 end *************"); + done(); + }) + + /** + * @tc.name rootDir support test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0044 + * @tc.desc write test callback + */ + it('testRdbStore0044', 0, async function (done) { + console.log(TAG + "************* testRdbStore0044 start *************"); + const rdbStore = await data_relationalStore.getRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + }) + + rdbStore.executeSync(CREATE_TABLE_TEST); + rdbStore.close(); + + data_relationalStore.getRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + rootDir: "/data/storage/el2/database", + customDir: "entry/rdb" + }, (e, rdbStore) => { + try { + rdbStore.insertSync('test', { + "name": "lisi", + "age": 15, + "salary": 153.3, + "blobType": new Uint8Array([1, 2, 3]), + }); + expect().assertFail(); + } catch (e) { + console.log("catch err: failed, err: code=" + e.code + " message=" + e.message) + expect(801).assertEqual(e.code); + } + data_relationalStore.deleteRdbStore(context, "rootDirTest"); + console.log(TAG + "************* testRdbStore0044 end *************"); + done(); + }) + }) + + /** + * @tc.name rootDir support deleteRdb test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0045 + * @tc.desc deleteRdb test async + */ + it('testRdbStore0045', 0, async (done) => { + console.log(TAG + "************* testRdbStore0045 start *************"); + try { + const rdbStore = await data_relationalStore.getRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + }) + + rdbStore.executeSync(CREATE_TABLE_TEST); + rdbStore.close(); + + await data_relationalStore.deleteRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + rootDir: "/data/storage/el2/database", + customDir: "entry/rdb" + }) + } catch (e) { + console.log("catch err: failed, err: code=" + e.code + " message=" + e.message) + expect().assertFail(); + } + console.log(TAG + "************* testRdbStore0045 end *************"); + done(); + }) + + /** + * @tc.name rootDir support deleteRdb test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0046 + * @tc.desc deleteRdb test callback + */ + it('testRdbStore0046', 0, async (done) => { + console.log(TAG + "************* testRdbStore0046 start *************"); + const rdbStore = await data_relationalStore.getRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + }) + + rdbStore.executeSync(CREATE_TABLE_TEST); + rdbStore.close(); + + data_relationalStore.deleteRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + rootDir: "/data/storage/el2/database", + customDir: "entry/rdb" + }, (e) => { + if (e) { + console.log("catch err: failed, err: code=" + e.code + " message=" + e.message) + expect().assertFail(); + } else { + console.log(TAG + "************* testRdbStore0046 end *************"); + done(); + } + }) + }) + + /** + * @tc.name rootDir support deleteRdb test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0047 + * @tc.desc invalid rootDir test async + */ + it('testRdbStore0047', 0, async (done) => { + console.log(TAG + "************* testRdbStore0047 start *************"); + try { + await data_relationalStore.deleteRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + rootDir: "invalidPath", + customDir: "entry/rdb" + }) + expect().assertFail(); + } catch (e) { + console.log("catch err: failed, err: code=" + e.code + " message=" + e.message); + expect("14800010").assertEqual(e.code); + } + console.log(TAG + "************* testRdbStore0047 end *************"); + done(); + }) + + /** + * @tc.name rootDir support deleteRdb test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0048 + * @tc.desc invalid rootDir test callback + */ + it('testRdbStore0048', 0, (done) => { + console.log(TAG + "************* testRdbStore0048 start *************"); + try { + data_relationalStore.deleteRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + rootDir: "invalidPath", + customDir: "entry/rdb" + }, (e) => { + expect().assertFail(); + }) + } catch (e) { + console.log("catch err: failed, err: code=" + e.code + " message=" + e.message); + expect("14800010").assertEqual(e.code); + console.log(TAG + "************* testRdbStore0048 end *************"); + done(); + } + }) + + /** + * @tc.name rootDir support deleteRdb test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0049 + * @tc.desc db not exist test async + */ + it('testRdbStore0049', 0, async (done) => { + console.log(TAG + "************* testRdbStore0049 start *************"); + try { + await data_relationalStore.deleteRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + rootDir: "/data/storage/el2/database/entry/rdb", + }) + expect().assertFail(); + } catch (e) { + console.log("catch err: failed, err: code=" + e.code + " message=" + e.message); + expect("14800010").assertEqual(e.code); + } + console.log(TAG + "************* testRdbStore0049 end *************"); + done(); + }) + + /** + * @tc.name rootDir support deleteRdb test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0050 + * @tc.desc db not exist test async + */ + it('testRdbStore0050', 0, (done) => { + console.log(TAG + "************* testRdbStore0050 start *************"); + try { + data_relationalStore.deleteRdbStore(context, { + name: "rootDirTest", + securityLevel: data_relationalStore.SecurityLevel.S3, + rootDir: "/data/storage/el2/database/entry/rdb", + }, () => { + expect().assertFail(); + }) + } catch (e) { + console.log("catch err: failed, err: code=" + e.code + " message=" + e.message); + expect("14800010").assertEqual(e.code); + console.log(TAG + "************* testRdbStore0050 end *************"); + done(); + } + }) + + /** + * @tc.name tokenizer supported test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0051 + * @tc.desc invalid tokenizer test callback + */ + it('testRdbStore0051', 0, (done) => { + console.log(TAG + "************* testRdbStore0051 start *************"); + try { + data_relationalStore.isTokenizerSupported(112321); + expect().assertFail(); + } catch (e) { + console.log("catch err: failed, err: code=" + e.code + " message=" + e.message); + expect("401").assertEqual(e.code); + console.log(TAG + "************* testRdbStore0051 end *************"); + done(); + } + }) + + /** + * @tc.name tokenizer supported test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0052 + * @tc.desc invalid tokenizer test callback + */ + it('testRdbStore0052', 0, (done) => { + console.log(TAG + "************* testRdbStore0052 start *************"); + try { + data_relationalStore.isTokenizerSupported("abc"); + expect().assertFail(); + } catch (e) { + console.log("catch err: failed, err: code=" + e.code + " message=" + e.message); + expect("401").assertEqual(e.code); + console.log(TAG + "************* testRdbStore0052 end *************"); + done(); + } + }) + + /** + * @tc.name tokenizer supported test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0053 + * @tc.desc invalid tokenizer test callback + */ + it('testRdbStore0053', 0, (done) => { + console.log(TAG + "************* testRdbStore0053 start *************"); + try { + data_relationalStore.isTokenizerSupported(undefined); + expect().assertFail(); + } catch (e) { + console.log("catch err: failed, err: code=" + e.code + " message=" + e.message); + expect("401").assertEqual(e.code); + console.log(TAG + "************* testRdbStore0053 end *************"); + done(); + } + }) + + /** + * @tc.name tokenizer supported test + * @tc.number SUB_DDM_AppDataFWK_JSRDB_RdbStore_0054 + * @tc.desc invalid tokenizer test callback + */ + it('testRdbStore0054', 0, (done) => { + console.log(TAG + "************* testRdbStore0054 start *************"); + try { + data_relationalStore.isTokenizerSupported(); + expect().assertFail(); + } catch (e) { + console.log("catch err: failed, err: code=" + e.code + " message=" + e.message); + expect("401").assertEqual(e.code); + console.log(TAG + "************* testRdbStore0054 end *************"); + done(); + } + }) console.log(TAG + "*************Unit Test End*************"); }) \ No newline at end of file diff --git a/relational_store/test/native/gdb/BUILD.gn b/relational_store/test/native/gdb/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..3162965ef8e1d10cca8d5e95176d4b6443f934ae --- /dev/null +++ b/relational_store/test/native/gdb/BUILD.gn @@ -0,0 +1,95 @@ +# Copyright (c) 2025 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. +import("//build/test.gni") +import("//foundation/distributeddatamgr/relational_store/relational_store.gni") + +module_output_path = "relational_store/native_gdb" + +############################################################################### + +ohos_unittest("NativeGdbTest") { + module_out_path = module_output_path + + include_dirs = [ + "${relational_store_common_path}/include", + "${relational_store_innerapi_path}/gdb/include", + "${relational_store_innerapi_path}/rdb/include", + "${relational_store_native_path}/gdb/include", + "${relational_store_native_path}/gdb/adapter/include", + "${relational_store_native_path}/rdb/include", + ] + + sources = [ + "unittest/gdb_encrypt_test.cpp", + "unittest/gdb_execute_test.cpp", + "unittest/gdb_function_test.cpp", + "unittest/gdb_grdapi_test.cpp", + "unittest/gdb_multi_thread_test.cpp", + "unittest/gdb_query_test.cpp", + "unittest/gdb_transaction_test.cpp", + ] + + external_deps = [ + "c_utils:utils", + "googletest:gtest_main", + "hilog:libhilog", + "json:nlohmann_json_static", + "kv_store:distributeddata_inner", + ] + + deps = [ "${relational_store_innerapi_path}/gdb:framework_graphstore" ] +} + +ohos_unittest("NativeGdbAdaptTest") { + module_out_path = module_output_path + + include_dirs = [ + "${relational_store_common_path}/include", + "${relational_store_innerapi_path}/gdb/include", + "${relational_store_innerapi_path}/rdb/include", + "${relational_store_native_path}/gdb/include", + "${relational_store_native_path}/gdb/adapter/include", + "${relational_store_native_path}/rdb/include", + ] + + sources = [ "unittest/gdb_adapt_test.cpp" ] + + external_deps = [ + "c_utils:utils", + "googletest:gmock", + "googletest:gtest_main", + "hilog:libhilog", + "json:nlohmann_json_static", + ] + + deps = [ "${relational_store_innerapi_path}/gdb:framework_graphstore" ] +} + +############################################################################### +group("unittest") { + testonly = true + + deps = [ + ":NativeGdbAdaptTest", + ":NativeGdbTest", + ] +} + +############################################################################### + +group("fuzztest") { + testonly = true + deps = [] + deps += [ "fuzztest/gdbstore_fuzzer:fuzztest" ] +} +############################################################################### diff --git a/relational_store/test/native/gdb/fuzztest/gdbstore_fuzzer/BUILD.gn b/relational_store/test/native/gdb/fuzztest/gdbstore_fuzzer/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..464b24ec5035d2dd0eabeece4b39e6b9bbd6f17b --- /dev/null +++ b/relational_store/test/native/gdb/fuzztest/gdbstore_fuzzer/BUILD.gn @@ -0,0 +1,59 @@ +# Copyright (c) 2022 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. + +#####################hydra-fuzz################### +import("//build/config/features.gni") +import("//build/test.gni") +import("//foundation/distributeddatamgr/relational_store/relational_store.gni") + +##############################fuzztest########################################## +ohos_fuzztest("GdbStoreFuzzTest") { + module_out_path = "relational_store/relational_store" + + include_dirs = [ + "${relational_store_innerapi_path}/gdb/include", + "${relational_store_innerapi_path}/rdb/include", + "${relational_store_native_path}/gdb/adapter/include", + "${relational_store_native_path}/gdb/include", + ] + + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + + fuzz_config_file = + "${relational_store_base_path}/test/native/gdb/fuzztest/gdbstore_fuzzer" + + sources = [ "gdbstore_fuzzer.cpp" ] + + deps = [ "${relational_store_innerapi_path}/gdb:framework_graphstore" ] + + external_deps = [ + "hilog:libhilog", + "json:nlohmann_json_static", + ] +} + +############################################################################### +group("fuzztest") { + testonly = true + deps = [] + deps += [ + # deps file + ":GdbStoreFuzzTest", + ] +} +############################################################################### diff --git a/relational_store/test/native/gdb/fuzztest/gdbstore_fuzzer/corpus/init b/relational_store/test/native/gdb/fuzztest/gdbstore_fuzzer/corpus/init new file mode 100644 index 0000000000000000000000000000000000000000..e7c3fecd8d4d4816e40088113a2316bb9eb2e13f --- /dev/null +++ b/relational_store/test/native/gdb/fuzztest/gdbstore_fuzzer/corpus/init @@ -0,0 +1,14 @@ +# Copyright (c) 2024 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. + +FUZZ \ No newline at end of file diff --git a/relational_store/test/native/gdb/fuzztest/gdbstore_fuzzer/gdbstore_fuzzer.cpp b/relational_store/test/native/gdb/fuzztest/gdbstore_fuzzer/gdbstore_fuzzer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..880eca299b20c75446c040574ad927f687063646 --- /dev/null +++ b/relational_store/test/native/gdb/fuzztest/gdbstore_fuzzer/gdbstore_fuzzer.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024 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 "gdbstore_fuzzer.h" + +#include "gdb_helper.h" + +using namespace OHOS; +using namespace OHOS::DistributedDataAip; + +namespace OHOS { +const std::string DATABASE_NAME = "gdbStoreFuzz"; +const std::string DATABASE_PATH = "/data/test"; +StoreConfig config_(DATABASE_NAME, DATABASE_PATH); + +std::shared_ptr GetStore() +{ + int errCode = 0; + auto store = GDBHelper::GetDBStore(config_, errCode); + return store; +} + +void GdbQueryFuzz(const uint8_t *data, size_t size) +{ + std::string gql(data, data + size); + auto store = GetStore(); + if (store == nullptr) { + return; + } + store->QueryGql(gql); + GDBHelper::DeleteDBStore(config_); +} + +void GdbExecuteFuzz(const uint8_t *data, size_t size) +{ + std::string gql(data, data + size); + auto store = GetStore(); + if (store == nullptr) { + return; + } + store->ExecuteGql(gql); + GDBHelper::DeleteDBStore(config_); +} +} // namespace OHOS + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + /* Run your code on data */ + if (data == nullptr) { + return 0; + } + OHOS::GdbQueryFuzz(data, size); + OHOS::GdbExecuteFuzz(data, size); + return 0; +} \ No newline at end of file diff --git a/relational_store/test/native/gdb/fuzztest/gdbstore_fuzzer/gdbstore_fuzzer.h b/relational_store/test/native/gdb/fuzztest/gdbstore_fuzzer/gdbstore_fuzzer.h new file mode 100644 index 0000000000000000000000000000000000000000..05581d1a77661046a98d3ea69f4c3a08e07ec893 --- /dev/null +++ b/relational_store/test/native/gdb/fuzztest/gdbstore_fuzzer/gdbstore_fuzzer.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 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 GDBSTORE_FUZZER_H +#define GDBSTORE_FUZZER_H + +#define FUZZ_PROJECT_NAME "gdbstore_fuzzer" + +#endif // GDBSTORE_FUZZER_H \ No newline at end of file diff --git a/relational_store/test/native/gdb/fuzztest/gdbstore_fuzzer/project.xml b/relational_store/test/native/gdb/fuzztest/gdbstore_fuzzer/project.xml new file mode 100644 index 0000000000000000000000000000000000000000..6d3e765c7dc1097ac2fb92d825dfad6b0b08636d --- /dev/null +++ b/relational_store/test/native/gdb/fuzztest/gdbstore_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + \ No newline at end of file diff --git a/relational_store/test/native/gdb/unittest/gdb_adapt_test.cpp b/relational_store/test/native/gdb/unittest/gdb_adapt_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d480ad837eca67cd43c8d66f5448900c05b0e8fd --- /dev/null +++ b/relational_store/test/native/gdb/unittest/gdb_adapt_test.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2025 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 + +#include "gmock/gmock.h" +#include "grd_adapter_manager.h" +#include "grd_adapter.h" +#include "gdb_store.h" + +using namespace testing::ext; +using namespace OHOS::DistributedDataAip; +using ::testing::Return; +using ::testing::NiceMock; +class MockDlsym { +public: + MOCK_METHOD(void *, dlopen, (const char *fileName, int flag)); + MOCK_METHOD(void *, dlsym, (void *handle, const char *symbol)); +}; + +NiceMock *mockDlsym; + +extern "C" { + // mock dlopen + void *dlopen(const char *fileName, int flag) + { + if (mockDlsym == nullptr) { + mockDlsym = new NiceMock(); + } + return mockDlsym->dlopen(fileName, flag); + } + + // mock dlsym + void *dlsym(void *handle, const char *symbol) + { + if (mockDlsym == nullptr) { + mockDlsym = new NiceMock(); + } + return mockDlsym->dlsym(handle, symbol); + } +} + +class GdbAdaptTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + void MockAllSymbols(); + static const std::string databaseName; + static const std::string databasePath; + const std::vector> mockSymbols = { + {"GRD_DBOpen", reinterpret_cast(0x1111)}, + {"GRD_DBClose", reinterpret_cast(0x2222)}, + {"GRD_DBRepair", reinterpret_cast(0x3333)}, + {"GRD_GqlPrepare", reinterpret_cast(0x4444)}, + {"GRD_GqlReset", reinterpret_cast(0x5555)}, + {"GRD_GqlFinalize", reinterpret_cast(0x6666)}, + {"GRD_GqlStep", reinterpret_cast(0x7777)}, + {"GRD_GqlColumnCount", reinterpret_cast(0x8888)}, + {"GRD_GqlColumnType", reinterpret_cast(0x9999)}, + {"GRD_GqlColumnBytes", reinterpret_cast(0xaaaa)}, + {"GRD_GqlColumnName", reinterpret_cast(0xbbbb)}, + {"GRD_GqlColumnValue", reinterpret_cast(0xcccc)}, + {"GRD_GqlColumnInt64", reinterpret_cast(0xdddd)}, + {"GRD_GqlColumnInt", reinterpret_cast(0xeeee)}, + {"GRD_GqlColumnDouble", reinterpret_cast(0xffff)}, + {"GRD_GqlColumnText", reinterpret_cast(0x1112)}, + {"GRD_DBBackup", reinterpret_cast(0x1222)}, + {"GRD_DBRestore", reinterpret_cast(0x1333)}, + {"GRD_DBRekey", reinterpret_cast(0x1444)}, + }; +}; + +const std::string GdbAdaptTest::databaseName = "execute_test"; +const std::string GdbAdaptTest::databasePath = "/data"; + +void GdbAdaptTest::SetUpTestCase(void) +{ + if (!IsSupportArkDataDb()) { + GTEST_SKIP() << "Current testcase is not compatible from current gdb"; + return; + } + mockDlsym = new NiceMock(); +} + +void GdbAdaptTest::TearDownTestCase(void) +{ + delete mockDlsym; + mockDlsym = nullptr; +} + +void GdbAdaptTest::SetUp() +{ + if (!IsSupportArkDataDb()) { + GTEST_SKIP() << "Current testcase is not compatible from current gdb"; + return; + } +} + +void GdbAdaptTest::TearDown() +{ +} + +void GdbAdaptTest::MockAllSymbols() +{ + EXPECT_CALL(*mockDlsym, dlopen(::testing::_, RTLD_LAZY)) + .WillRepeatedly(Return(reinterpret_cast(0x1234))); + + for (const auto &symbol : mockSymbols) { + EXPECT_CALL(*mockDlsym, dlsym(::testing::_, ::testing::StrEq(symbol.first.c_str()))) + .WillRepeatedly(Return(symbol.second)); + } +} + +/** + * @tc.name: GdbAdaptTest_Dlopen01 + * @tc.desc: No Mock All Symbols + * @tc.type: FUNC + */ +HWTEST_F(GdbAdaptTest, GdbAdaptTest_Dlopen01, TestSize.Level2) +{ + GetAdapterHolder(); + EXPECT_CALL(*mockDlsym, dlopen(::testing::_, RTLD_LAZY)) + .WillRepeatedly(Return(reinterpret_cast(0x1234))); + GrdAdapterHolder holder = GetAdapterHolder(); + EXPECT_EQ(holder.Open, nullptr); + EXPECT_EQ(holder.Close, nullptr); + EXPECT_EQ(holder.Repair, nullptr); + EXPECT_EQ(holder.Prepare, nullptr); + EXPECT_EQ(holder.Reset, nullptr); + EXPECT_EQ(holder.Finalize, nullptr); + EXPECT_EQ(holder.Step, nullptr); + EXPECT_EQ(holder.ColumnCount, nullptr); + EXPECT_EQ(holder.GetColumnType, nullptr); + EXPECT_EQ(holder.ColumnBytes, nullptr); + EXPECT_EQ(holder.ColumnName, nullptr); + EXPECT_EQ(holder.ColumnValue, nullptr); + EXPECT_EQ(holder.ColumnInt64, nullptr); + EXPECT_EQ(holder.ColumnInt, nullptr); + EXPECT_EQ(holder.ColumnDouble, nullptr); + EXPECT_EQ(holder.ColumnText, nullptr); + EXPECT_EQ(holder.Backup, nullptr); + EXPECT_EQ(holder.Restore, nullptr); + EXPECT_EQ(holder.Rekey, nullptr); + GrdAdapter::Open(databaseName.c_str(), databasePath.c_str(), 1, nullptr); + GrdAdapter::Close(nullptr, 1); + GrdAdapter::Repair(databasePath.c_str(), {}); + GrdAdapter::Prepare(nullptr, databaseName.c_str(), 1, nullptr, nullptr); + GrdAdapter::Reset(nullptr); + GrdAdapter::Finalize(nullptr); + GrdAdapter::Step(nullptr); + GrdAdapter::ColumnCount(nullptr); + GrdAdapter::ColumnType(nullptr, 1); + GrdAdapter::ColumnBytes(nullptr, 1); + GrdAdapter::ColumnName(nullptr, 1); + GrdAdapter::ColumnValue(nullptr, 1); + GrdAdapter::ColumnInt64(nullptr, 1); + GrdAdapter::ColumnInt(nullptr, 1); + GrdAdapter::ColumnDouble(nullptr, 1); + GrdAdapter::ColumnText(nullptr, 1); + GrdAdapter::Backup(nullptr, databaseName.c_str(), {}); + GrdAdapter::Restore(nullptr, databaseName.c_str(), {}); + GrdAdapter::Rekey(nullptr, databaseName.c_str(), {}); +} + +/** + * @tc.name: GdbAdaptTest_Dlopen02 + * @tc.desc: Mock All Symbols test. + * @tc.type: FUNC + */ +HWTEST_F(GdbAdaptTest, GdbAdaptTest_Dlopen02, TestSize.Level2) +{ + EXPECT_CALL(*mockDlsym, dlopen(::testing::_, RTLD_LAZY)) + .WillRepeatedly(Return(reinterpret_cast(0x1234))); + MockAllSymbols(); + GrdAdapterHolder holder = GetAdapterHolder(); + EXPECT_NE(holder.Open, nullptr); + EXPECT_NE(holder.Close, nullptr); + EXPECT_NE(holder.Repair, nullptr); + EXPECT_NE(holder.Prepare, nullptr); + EXPECT_NE(holder.Reset, nullptr); + EXPECT_NE(holder.Finalize, nullptr); + EXPECT_NE(holder.Step, nullptr); + EXPECT_NE(holder.ColumnCount, nullptr); + EXPECT_NE(holder.GetColumnType, nullptr); + EXPECT_NE(holder.ColumnBytes, nullptr); + EXPECT_NE(holder.ColumnName, nullptr); + EXPECT_NE(holder.ColumnValue, nullptr); + EXPECT_NE(holder.ColumnInt64, nullptr); + EXPECT_NE(holder.ColumnInt, nullptr); + EXPECT_NE(holder.ColumnDouble, nullptr); + EXPECT_NE(holder.ColumnText, nullptr); + EXPECT_NE(holder.Backup, nullptr); + EXPECT_NE(holder.Restore, nullptr); + EXPECT_NE(holder.Rekey, nullptr); +} \ No newline at end of file diff --git a/relational_store/test/native/gdb/unittest/gdb_encrypt_test.cpp b/relational_store/test/native/gdb/unittest/gdb_encrypt_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5fbce743657a4ceb305dd58d5b19d60d8cea3d2d --- /dev/null +++ b/relational_store/test/native/gdb/unittest/gdb_encrypt_test.cpp @@ -0,0 +1,460 @@ +/* + * Copyright (c) 2025 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 +#include +#include +#include + +#include "aip_errors.h" +#include "db_store_impl.h" +#include "db_store_manager.h" +#include "edge.h" +#include "grd_adapter.h" +#include "grd_adapter_manager.h" +#include "gdb_helper.h" +#include "gdb_store.h" +#include "gdb_utils.h" +#include "graph_statement.h" +#include "graph_connection.h" +#include "path.h" +#include "result.h" +#include "vertex.h" + +using namespace testing::ext; +using namespace OHOS::DistributedDataAip; +class GdbEncryptTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + void VerifyPersonInfo(const GraphValue &person, const std::string &name, const int32_t &age); + static const std::string createGraphGql; + static const std::string databasePath; +}; +const std::string GdbEncryptTest::databasePath = "/data"; +const std::string GdbEncryptTest::createGraphGql = "CREATE GRAPH test { " + "(person:Person {name STRING, age INT, sex BOOL DEFAULT false})," + "(dog:Dog {name STRING, age INT}), " + "(person) -[:Friend]-> (person) " + "};"; + +void GdbEncryptTest::SetUpTestCase() +{ + if (!IsSupportArkDataDb()) { + GTEST_SKIP() << "Current testcase is not compatible from current gdb"; + return; + } +} + +void GdbEncryptTest::TearDownTestCase() +{ +} + +void GdbEncryptTest::SetUp() +{ + if (!IsSupportArkDataDb()) { + GTEST_SKIP() << "Current testcase is not compatible from current gdb"; + return; + } +} + +void GdbEncryptTest::TearDown() +{ +} + +HWTEST_F(GdbEncryptTest, GdbEncrypt_DeaultIsUnencrypt, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "DeaultIsUnencrypt"; + std::string dbPath = databasePath; + // DeaultIsUnencrypt + auto config = StoreConfig(dbName, dbPath, DBType::DB_GRAPH); + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + auto result = store->ExecuteGql(createGraphGql); + EXPECT_NE(result.second, nullptr); + EXPECT_EQ(result.first, E_OK); + result = store->ExecuteGql("INSERT (:Person {name: 'name_1', age: 11});"); + EXPECT_EQ(result.first, E_OK); + result = store->QueryGql("MATCH (person:Person {age: 11}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + VerifyPersonInfo(person, "name_1", 11); + store->Close(); + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbEncryptTest, GdbEncrypt_Unencrypt, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "Unencrypt"; + std::string dbPath = databasePath; + // Unencryptdb + auto config = StoreConfig(dbName, dbPath, DBType::DB_GRAPH, false); + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + auto result = store->ExecuteGql(createGraphGql); + EXPECT_NE(result.second, nullptr); + EXPECT_EQ(result.first, E_OK); + result = store->ExecuteGql("INSERT (:Person {name: 'name_1', age: 11});"); + EXPECT_EQ(result.first, E_OK); + result = store->QueryGql("MATCH (person:Person {age: 11}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + VerifyPersonInfo(person, "name_1", 11); + store->Close(); + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbEncryptTest, GdbEncrypt_Encrypt, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "Encrypt"; + std::string dbPath = databasePath; + // Unencryptdb + auto config = StoreConfig(dbName, dbPath, DBType::DB_GRAPH, true); + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + auto result = store->ExecuteGql(createGraphGql); + EXPECT_NE(result.second, nullptr); + EXPECT_EQ(result.first, E_OK); + result = store->ExecuteGql("INSERT (:Person {name: 'name_1', age: 11});"); + EXPECT_EQ(result.first, E_OK); + result = store->QueryGql("MATCH (person:Person {age: 11}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + VerifyPersonInfo(person, "name_1", 11); + store->Close(); + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbEncryptTest, GdbEncrypt_UnencryptToEncrypt, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "UnencryptToEncrypt"; + std::string dbPath = databasePath; + // Unencryptdb + auto config = StoreConfig(dbName, dbPath, DBType::DB_GRAPH, false); + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + auto result = store->ExecuteGql(createGraphGql); + EXPECT_NE(result.second, nullptr); + EXPECT_EQ(result.first, E_OK); + result = store->ExecuteGql("INSERT (:Person {name: 'name_1', age: 11});"); + EXPECT_EQ(result.first, E_OK); + result = store->QueryGql("MATCH (person:Person {age: 11}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + VerifyPersonInfo(person, "name_1", 11); + result.second = nullptr; + store->Close(); + StoreManager::GetInstance().Clear(); + // Unencryptdb to encryptdb + config.SetEncryptStatus(true); + store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + if (store != nullptr) { + result = store->ExecuteGql("INSERT (:Person {name: 'name_2', age: 22});"); + EXPECT_EQ(result.first, E_OK); + result = store->QueryGql("MATCH (person:Person {age: 22}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + VerifyPersonInfo(person, "name_2", 22); + store->Close(); + } + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbEncryptTest, GdbEncrypt_EncryptToUnencrypt, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "EncryptToUnencrypt"; + std::string dbPath = databasePath; + // encryptdb + auto config = StoreConfig(dbName, dbPath, DBType::DB_GRAPH, true); + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + auto result = store->ExecuteGql(createGraphGql); + EXPECT_NE(result.second, nullptr); + EXPECT_EQ(result.first, E_OK); + result = store->ExecuteGql("INSERT (:Person {name: 'name_1', age: 11});"); + EXPECT_EQ(result.first, E_OK); + result = store->QueryGql("MATCH (person:Person {age: 11}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + VerifyPersonInfo(person, "name_1", 11); + store->Close(); + StoreManager::GetInstance().Clear(); + // encryptdb to Unencryptdb + config.SetEncryptStatus(false); + store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_EQ(errCode, E_GRD_INVALID_ARGS); + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbEncryptTest, GdbEncrypt_DefaultToEncrypt, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "DefaultToEncrypt"; + std::string dbPath = databasePath; + // Unencryptdb + auto config = StoreConfig(dbName, dbPath); + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + auto result = store->ExecuteGql(createGraphGql); + EXPECT_NE(result.second, nullptr); + EXPECT_EQ(result.first, E_OK); + result = store->ExecuteGql("INSERT (:Person {name: 'name_1', age: 11});"); + EXPECT_EQ(result.first, E_OK); + result = store->QueryGql("MATCH (person:Person {age: 11}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + VerifyPersonInfo(person, "name_1", 11); + result.second = nullptr; + store->Close(); + StoreManager::GetInstance().Clear(); + // Unencryptdb to encryptdb + config.SetEncryptStatus(true); + store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + if (store != nullptr) { + result = store->ExecuteGql("INSERT (:Person {name: 'name_2', age: 22});"); + EXPECT_EQ(result.first, E_OK); + result = store->QueryGql("MATCH (person:Person {age: 22}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + VerifyPersonInfo(person, "name_2", 22); + store->Close(); + } + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbEncryptTest, GdbEncrypt_EncryptToEncrypt, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "EncryptToUnencrypt"; + std::string dbPath = databasePath; + // encryptdb + auto config = StoreConfig(dbName, dbPath, DBType::DB_GRAPH, true); + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + auto result = store->ExecuteGql(createGraphGql); + EXPECT_NE(result.second, nullptr); + EXPECT_EQ(result.first, E_OK); + result = store->ExecuteGql("INSERT (:Person {name: 'name_1', age: 11});"); + EXPECT_EQ(result.first, E_OK); + result = store->QueryGql("MATCH (person:Person {age: 11}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + VerifyPersonInfo(person, "name_1", 11); + store->Close(); + StoreManager::GetInstance().Clear(); + // encryptdb to encryptdb + config.SetEncryptStatus(true); + store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + result = store->ExecuteGql("INSERT (:Person {name: 'name_2', age: 22});"); + EXPECT_EQ(result.first, E_OK); + result = store->QueryGql("MATCH (person:Person {age: 22}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + person = result.second->GetAllData()[0]["person"]; + VerifyPersonInfo(person, "name_2", 22); + store->Close(); + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbEncryptTest, GdbEncrypt_UnencryptToUnencrypt, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "UnencryptToEncrypt"; + std::string dbPath = databasePath; + // Unencryptdb + auto config = StoreConfig(dbName, dbPath, DBType::DB_GRAPH, false); + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + auto result = store->ExecuteGql(createGraphGql); + EXPECT_NE(result.second, nullptr); + EXPECT_EQ(result.first, E_OK); + result = store->ExecuteGql("INSERT (:Person {name: 'name_1', age: 11});"); + EXPECT_EQ(result.first, E_OK); + result = store->QueryGql("MATCH (person:Person {age: 11}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + VerifyPersonInfo(person, "name_1", 11); + store->Close(); + StoreManager::GetInstance().Clear(); + // Unencryptdb to Unencryptdb + config.SetEncryptStatus(false); + store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + result = store->ExecuteGql("INSERT (:Person {name: 'name_2', age: 22});"); + EXPECT_EQ(result.first, E_OK); + result = store->QueryGql("MATCH (person:Person {age: 22}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + person = result.second->GetAllData()[0]["person"]; + VerifyPersonInfo(person, "name_2", 22); + store->Close(); + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbEncryptTest, GdbEncrypt_DefaultToUnencrypt, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "UnencryptToEncrypt"; + std::string dbPath = databasePath; + // Unencryptdb + auto config = StoreConfig(dbName, dbPath, DBType::DB_GRAPH); + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + auto result = store->ExecuteGql(createGraphGql); + EXPECT_NE(result.second, nullptr); + EXPECT_EQ(result.first, E_OK); + result = store->ExecuteGql("INSERT (:Person {name: 'name_1', age: 11});"); + EXPECT_EQ(result.first, E_OK); + result = store->QueryGql("MATCH (person:Person {age: 11}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + VerifyPersonInfo(person, "name_1", 11); + store->Close(); + StoreManager::GetInstance().Clear(); + // Unencryptdb to Unencryptdb + config.SetEncryptStatus(false); + store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + result = store->ExecuteGql("INSERT (:Person {name: 'name_2', age: 22});"); + EXPECT_EQ(result.first, E_OK); + result = store->QueryGql("MATCH (person:Person {age: 22}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + person = result.second->GetAllData()[0]["person"]; + VerifyPersonInfo(person, "name_2", 22); + store->Close(); + GDBHelper::DeleteDBStore(config); +} + +void GdbEncryptTest::VerifyPersonInfo(const GraphValue &person, const std::string &name, const int32_t &age) +{ + auto expectSize = 3; + ASSERT_TRUE(std::holds_alternative>(person)); + auto personVertex = std::get>(person); + EXPECT_EQ(personVertex->GetLabel(), "Person"); + ASSERT_EQ(personVertex->GetProperties().size(), expectSize); + + auto nameDb = personVertex->GetProperties().find("name"); + ASSERT_NE(nameDb, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(nameDb->second)); + EXPECT_EQ(std::get(nameDb->second), name); + + auto ageDb = personVertex->GetProperties().find("age"); + ASSERT_NE(ageDb, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(ageDb->second)); + EXPECT_EQ(std::get(ageDb->second), age); + + auto sex = personVertex->GetProperties().find("sex"); + ASSERT_NE(sex, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(sex->second)); + EXPECT_EQ(std::get(sex->second), 0); +} + +HWTEST_F(GdbEncryptTest, GdbEncrypt_Config, TestSize.Level1) +{ + std::string dbName = "UnencryptToEncrypt"; + std::string dbPath = databasePath; + auto config = StoreConfig(dbName, dbPath, DBType::DB_GRAPH); + EXPECT_EQ(config.IsEncrypt(), false); + config.GenerateEncryptedKey(); + EXPECT_EQ(config.GetEncryptKey().size(), 0); + EXPECT_EQ(config.GetNewEncryptKey().size(), 0); + + config.SetBundleName(""); + EXPECT_EQ(config.GetBundleName(), ""); + config.SetEncryptStatus(true); + EXPECT_EQ(config.IsEncrypt(), true); + config.SetBundleName("test_name"); + EXPECT_EQ(config.GetBundleName(), "test_name"); + // empty return E_ERROR + EXPECT_EQ(config.SetBundleName(""), E_ERROR); + EXPECT_EQ(config.GetBundleName(), "test_name"); + + config.GenerateEncryptedKey(); + // not exists bundleName, failed + EXPECT_EQ(config.GetEncryptKey().size(), 0); + EXPECT_EQ(config.GetNewEncryptKey().size(), 0); + config.ChangeEncryptKey(); + config.GenerateEncryptedKey(); + config.ChangeEncryptKey(); +} + +HWTEST_F(GdbEncryptTest, GdbEncrypt_Config_Test, TestSize.Level1) +{ + std::string dbName = "ConfigTest"; + std::string dbPath = databasePath; + auto config = StoreConfig(dbName, dbPath, DBType::DB_GRAPH, true); + EXPECT_EQ(config.IsEncrypt(), true); + config.GenerateEncryptedKey(); + ASSERT_TRUE(config.GetEncryptKey().size() > 0); + EXPECT_EQ(config.GetNewEncryptKey().size(), 0); + // newkey is empty, not change key + config.ChangeEncryptKey(); + ASSERT_TRUE(config.GetEncryptKey().size() > 0); + EXPECT_EQ(config.GetNewEncryptKey().size(), 0); +} \ No newline at end of file diff --git a/relational_store/test/native/gdb/unittest/gdb_execute_test.cpp b/relational_store/test/native/gdb/unittest/gdb_execute_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..49d3126321f35ba7e27096d14844a77519e14b21 --- /dev/null +++ b/relational_store/test/native/gdb/unittest/gdb_execute_test.cpp @@ -0,0 +1,2056 @@ +/* + * Copyright (c) 2024 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 +#include +#include +#include + +#include "aip_errors.h" +#include "db_store_impl.h" +#include "edge.h" +#include "grd_adapter.h" +#include "grd_adapter_manager.h" +#include "gdb_helper.h" +#include "gdb_store.h" +#include "gdb_utils.h" +#include "graph_statement.h" +#include "graph_connection.h" +#include "path.h" +#include "result.h" +#include "vertex.h" + +using namespace testing::ext; +using namespace OHOS::DistributedDataAip; +class GdbExecuteTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + void VerifyPersonInfo(const GraphValue &person, const std::string &name, const int32_t &age); + void MatchAndVerifyPerson(const std::string &name, const int32_t &age); + + static const std::string databaseName; + static const std::string databasePath; + static std::shared_ptr store_; + static const std::string createGraphGql; + static const std::shared_ptr databaseConfig; + static const std::string pathJsonString; +}; +std::shared_ptr GdbExecuteTest::store_; +const std::string GdbExecuteTest::databaseName = "execute_test"; +const std::string GdbExecuteTest::databasePath = "/data"; +const std::string GdbExecuteTest::createGraphGql = "CREATE GRAPH test { " + "(person:Person {name STRING, age INT, sex BOOL DEFAULT false})," + "(dog:Dog {name STRING, age INT}), " + "(person) -[:Friend]-> (person) " + "};"; +const std::string GdbExecuteTest::pathJsonString = R"({ + "start": { + "label": "PERSON", + "identity": 1, + "properties": { + "AGE": 32, + "SALARY": 75.35, + "NAME": "Alice", + "GENDER": "Female", + "PHONENUMBERS": false, + "EMAILS": null + } + }, + "end": { + "label": "PERSON", + "identity": 2, + "properties": { + "AGE": 28, + "SALARY": 65000, + "NAME": "Bob", + "GENDER": "Male", + "PHONENUMBERS": "123456789", + "EMAILS": "bob@example.com" + } + }, + "relationship": { + "label": "é©å¯¸éƒ´æµœæ’ç˜", + "identity": 3, + "start": 1, + "end": 2, + "properties": { + "NUM": 4, + "PINYIN": "zhixiqinshu" + } + } + })"; + +void GdbExecuteTest::SetUpTestCase() +{ + if (!IsSupportArkDataDb()) { + GTEST_SKIP() << "Current testcase is not compatible from current gdb"; + return; + } + int errCode = E_OK; + auto config = StoreConfig(databaseName, databasePath); + GDBHelper::DeleteDBStore(config); + + GdbExecuteTest::store_ = GDBHelper::GetDBStore(config, errCode); +} + +void GdbExecuteTest::TearDownTestCase() +{ + GDBHelper::DeleteDBStore(StoreConfig(databaseName, databasePath)); + store_ = nullptr; +} + +void GdbExecuteTest::SetUp() +{ + if (!IsSupportArkDataDb()) { + GTEST_SKIP() << "Current testcase is not compatible from current gdb"; + return; + } + auto result = store_->ExecuteGql(createGraphGql); +} + +void GdbExecuteTest::TearDown() +{ + if (store_ != nullptr) { + auto result = store_->ExecuteGql("DROP GRAPH test"); + } +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "success"; + std::string dbPath = databasePath; + auto config = StoreConfig(dbName, dbPath); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStoreVector, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "success"; + std::string dbPath = databasePath; + auto config = StoreConfig(dbName, dbPath, DBType::DB_VECTOR); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_EQ(errCode, E_NOT_SUPPORT); + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStoreButt, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "success"; + std::string dbPath = databasePath; + auto config = StoreConfig(dbName, dbPath, DBType::DB_BUTT); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_EQ(errCode, E_NOT_SUPPORT); + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStoreReadConSize, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "success"; + std::string dbPath = databasePath; + auto config = StoreConfig(dbName, dbPath); + config.SetReadConSize(0); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStoreReadConSizeMax, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "success"; + std::string dbPath = databasePath; + auto config = StoreConfig(dbName, dbPath); + config.SetReadConSize(500); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_EQ(errCode, E_ARGS_READ_CON_OVERLOAD); + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_NameHasdbSuffix, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "success.db"; + std::string dbPath = databasePath; + auto config = StoreConfig(dbName, dbPath); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_NE(errCode, E_OK); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_NameHasDBSuffix, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "success.DB"; + std::string dbPath = databasePath; + auto config = StoreConfig(dbName, dbPath); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_NE(errCode, E_OK); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_NameHasSpecialChar, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "suc@!#$*(cess."; + std::string dbPath = databasePath; + auto config = StoreConfig(dbName, dbPath); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_NE(errCode, E_OK); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_PathOkEmptyName, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = ""; + std::string dbPath = databasePath; + auto config = StoreConfig(dbName, dbPath); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_NE(errCode, E_OK); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_NotFoundPath, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "success"; + std::string dbPath = "/test/path1/"; + auto config = StoreConfig(dbName, dbPath); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_EQ(errCode, E_GRD_FAILED_FILE_OPERATION); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_PathErrorEmptyName, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = ""; + std::string dbPath = "/test/path2"; + auto config = StoreConfig(dbName, dbPath); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_EQ(errCode, E_GRD_INVAILD_NAME_ERR); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_Empty_Path, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = databaseName; + std::string dbPath = ""; + auto config = StoreConfig(dbName, dbPath); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_EQ(errCode, E_GRD_FAILED_FILE_OPERATION); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_Empty_NameAndPath, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = ""; + std::string dbPath = ""; + auto config = StoreConfig(dbName, dbPath); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_EQ(errCode, E_GRD_INVAILD_NAME_ERR); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_OK, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "execute_test_ok"; + std::string dbPath = "/data"; + auto config = StoreConfig(dbName, dbPath); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_OK_PathRepeat, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "execute_test_ok_2"; + std::string dbPath = "/data"; + auto config = StoreConfig(dbName, dbPath); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_LongName, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = ""; + for (int32_t i = 0; i < 1000000; i++) { + dbName += "A"; + } + std::string dbPath = "/test/path2"; + auto config = StoreConfig(dbName, dbPath); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_EQ(errCode, E_GRD_FAILED_FILE_OPERATION); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_LongNamePathOk, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = ""; + for (int32_t i = 0; i < 1000000; i++) { + dbName += "A"; + } + std::string dbPath = "/data"; + auto config = StoreConfig(dbName, dbPath); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_EQ(errCode, E_GRD_SEMANTIC_ERROR); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_LongPath, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = ""; + for (int32_t i = 0; i < 30; i++) { + dbName += "A"; + } + std::string dbPath = "/test/path2"; + for (int32_t i = 0; i < 3000000; i++) { + dbPath += "A"; + } + auto config = StoreConfig(dbName, dbPath); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_EQ(errCode, E_GRD_SEMANTIC_ERROR); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_InVaildSecurityLevel, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "tttt"; + std::string dbPath = "/data"; + + auto config = StoreConfig(dbName, dbPath); + config.SetSecurityLevel(-3); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_EQ(errCode, E_INVALID_ARGS); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_InVaildSecurityLevel02, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "tttt"; + std::string dbPath = "/data"; + + auto config = StoreConfig(dbName, dbPath); + config.SetSecurityLevel(0); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_EQ(errCode, E_INVALID_ARGS); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_InVaildSecurityLevel03, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "tttt"; + std::string dbPath = "/data"; + + auto config = StoreConfig(dbName, dbPath); + config.SetSecurityLevel(500); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_EQ(errCode, E_INVALID_ARGS); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_SecurityLevel, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "tttt"; + std::string dbPath = "/data"; + + auto config = StoreConfig(dbName, dbPath); + config.SetSecurityLevel(3); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_SecurityLevelLast, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "tttt"; + std::string dbPath = "/data"; + + auto config = StoreConfig(dbName, dbPath); + config.SetSecurityLevel(SecurityLevel::LAST); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(store, nullptr); + EXPECT_EQ(errCode, E_INVALID_ARGS); + store = nullptr; + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_GetSecurityLeve, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "tttt03"; + std::string dbPath = "/data"; + auto config = StoreConfig(dbName, dbPath); + config.SetSecurityLevel(SecurityLevel::S2); + auto level = config.GetSecurityLevel(); + EXPECT_EQ(level, SecurityLevel::S2); + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + + store = nullptr; + GDBHelper::DeleteDBStore(config); + + config.SetSecurityLevel(SecurityLevel::LAST); + level = config.GetSecurityLevel(); + EXPECT_EQ(level, SecurityLevel::LAST); + store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(errCode, E_INVALID_ARGS); + EXPECT_EQ(store, nullptr); + store = nullptr; + GDBHelper::DeleteDBStore(config); +} + +/** + * @tc.name: GdbStore_GetDBStore_SecurityLevel03 + * @tc.desc: test StoreConfig SetSecurityLevel S2->S1 + * @tc.type: FUNC + */ +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_SecurityLevel02, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "tttt02"; + std::string dbPath = "/data"; + auto config = StoreConfig(dbName, dbPath); + config.SetSecurityLevel(SecurityLevel::S2); + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + store = nullptr; + + auto invalidConfig = config; + invalidConfig.SetSecurityLevel(SecurityLevel::S1); + store = GDBHelper::GetDBStore(invalidConfig, errCode); + EXPECT_EQ(errCode, E_CONFIG_INVALID_CHANGE); + EXPECT_EQ(store, nullptr); + store = nullptr; + GDBHelper::DeleteDBStore(config); +} + +/** + * @tc.name: GdbStore_GetDBStore_SecurityLevel03 + * @tc.desc: test StoreConfig SetSecurityLevel S2->S3 + * @tc.type: FUNC + */ +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_SecurityLevel03, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "tttt02"; + std::string dbPath = "/data"; + auto config = StoreConfig(dbName, dbPath); + config.SetSecurityLevel(SecurityLevel::S2); + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + store = nullptr; + + auto invalidConfig = config; + invalidConfig.SetSecurityLevel(SecurityLevel::S3); + store = GDBHelper::GetDBStore(invalidConfig, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + store = nullptr; + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_NoInsertQuery, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->QueryGql("MATCH (person:Person {age: 11}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 0); +} + +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_AfterClose, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + int errCode = E_OK; + std::string dbName = "ttttclose"; + std::string dbPath = "/data"; + + auto config = StoreConfig(dbName, dbPath); + config.SetSecurityLevel(SecurityLevel::S3); + + auto store = GDBHelper::GetDBStore(config, errCode); + ASSERT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + auto ret = store->Close(); + EXPECT_EQ(E_OK, ret); + EXPECT_NE(store, nullptr); + auto result = store_->ExecuteGql("INSERT (:Person {name: 'name_1', age: 11});"); + EXPECT_EQ(result.first, E_OK); + result = store_->QueryGql("MATCH (person:Person {age: 11}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GDBHelper::DeleteDBStore(config); +} + +/** + * @tc.name: GdbStore_GetDBStore_AfterDrop + * @tc.desc: test GdbStore AfterDrop Insert + * @tc.type: FUNC + */ +HWTEST_F(GdbExecuteTest, GdbStore_GetDBStore_AfterDrop, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + int errCode = E_OK; + std::string dbName = "ttttdrop"; + std::string dbPath = "/data"; + + auto config = StoreConfig(dbName, dbPath); + config.SetSecurityLevel(SecurityLevel::S3); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + + auto result = store_->ExecuteGql("DROP GRAPH test;"); + EXPECT_NE(result.second, nullptr); + EXPECT_EQ(result.first, E_OK); + + result = store_->ExecuteGql("INSERT (:Person {name: 'name_1', age: 11});"); + EXPECT_EQ(result.first, E_GRD_UNDEFINED_PARAM); + result = store_->ExecuteGql(createGraphGql); + EXPECT_NE(result.second, nullptr); + EXPECT_EQ(result.first, E_OK); + GDBHelper::DeleteDBStore(config); +} + +/** + * @tc.name: GdbStore_Execute_001 + * @tc.desc: test GdbStore Execute + * @tc.type: FUNC + */ +HWTEST_F(GdbExecuteTest, GdbStore_Execute_LongName, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->ExecuteGql("INSERT (:Person {name: 'name_1', age: 11});"); + EXPECT_EQ(result.first, E_OK); + result = store_->QueryGql("MATCH (person:Person {age: 11}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + std::string name = "name2"; + for (int32_t i = 0; i < 300; i++) { + name += "A"; + } + result = store_->ExecuteGql("INSERT (:Person {name: '" + name + "', age: 11});"); + ASSERT_EQ(result.first, E_OK); + result = store_->QueryGql("MATCH (person:Person {age: 11}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 2); + + std::string name2 = "name2"; + for (int32_t i = 0; i < 3000000; i++) { + name2 += "A"; + } + result = store_->ExecuteGql("INSERT (:Person {name: '" + name2 + "', age: 11});"); + ASSERT_EQ(result.first, E_INVALID_ARGS); + result = store_->QueryGql("MATCH (person:Person {age: 11}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 2); +} + +/** + * @tc.name: GdbStore_Execute_001 + * @tc.desc: test GdbStore Execute + * @tc.type: FUNC + */ +HWTEST_F(GdbExecuteTest, GdbStore_Execute_001, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->ExecuteGql("INSERT (:Person {name: 'name_1', age: 11});"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("name_1", 11); + result = store_->ExecuteGql("INSERT (:Person {name: 'name_2', age: 22});"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("name_2", 22); + result = store_->ExecuteGql("INSERT (:Person {name: 'name_3', age: 33});"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("name_3", 33); + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_1'}), (p2:Person {name: 'name_2'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_2'}), (p2:Person {name: 'name_3'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + + result = store_->QueryGql("MATCH (person:Person)-[relation:Friend]->() RETURN person, relation;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 2); + auto data = result.second->GetAllData(); + GraphValue person = data[0]["person"]; + VerifyPersonInfo(person, "name_1", 11); + + auto result2 = + store_->QueryGql("MATCH path=(a:Person {name: 'name_1'})-[]->{2, 2}(b:Person {name: 'name_3'}) RETURN path;"); + ASSERT_EQ(result2.first, E_OK); + EXPECT_EQ(result2.second->GetAllData().size(), 1); + + GraphValue path = result2.second->GetAllData()[0]["path"]; + ASSERT_TRUE(std::holds_alternative>(path)); + + auto pathPath = std::get>(path); + EXPECT_EQ(pathPath->GetPathLength(), 2); +} + +/** + * @tc.name: GdbStore_Execute_001 + * @tc.desc: test GdbStore Execute + * @tc.type: FUNC + */ +HWTEST_F(GdbExecuteTest, GdbStore_Execute_002, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->ExecuteGql("INSERT (:Person {name: 'name_1', age: 11});"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql("INSERT (:Person {name: 'name_2', age: 22});"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql("INSERT (:Person {name: 'name_3', age: 33});"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_1'}), (p2:Person {name: 'name_2'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_2'}), (p2:Person {name: 'name_3'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_1'}), (p2:Person {name: 'name_3'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + + result = store_->QueryGql( + "MATCH (person:Person {name: 'name_1'})-[relation:Friend]->(d) where d.age > 25 RETURN person, relation;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + VerifyPersonInfo(person, "name_1", 11); + + GraphValue relation = result.second->GetAllData()[0]["relation"]; + ASSERT_TRUE(std::holds_alternative>(relation)); + auto relationGraphEdge = std::get>(relation); + EXPECT_EQ(relationGraphEdge->GetLabel(), "Friend"); +} + +void GdbExecuteTest::MatchAndVerifyPerson(const std::string &name, const int32_t &age) +{ + ASSERT_NE(store_, nullptr); + auto gql = "MATCH (person:Person {name: '" + name + "'}) RETURN person;"; + auto result = store_->QueryGql(gql); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + VerifyPersonInfo(person, name, age); +} + +void GdbExecuteTest::VerifyPersonInfo(const GraphValue &person, const std::string &name, const int32_t &age) +{ + auto expectSize = 3; + ASSERT_TRUE(std::holds_alternative>(person)); + auto personVertex = std::get>(person); + EXPECT_EQ(personVertex->GetLabel(), "Person"); + ASSERT_EQ(personVertex->GetProperties().size(), expectSize); + + auto nameDb = personVertex->GetProperties().find("name"); + ASSERT_NE(nameDb, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(nameDb->second)); + EXPECT_EQ(std::get(nameDb->second), name); + + auto ageDb = personVertex->GetProperties().find("age"); + ASSERT_NE(ageDb, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(ageDb->second)); + EXPECT_EQ(std::get(ageDb->second), age); + + auto sex = personVertex->GetProperties().find("sex"); + ASSERT_NE(sex, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(sex->second)); + EXPECT_EQ(std::get(sex->second), 0); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_Updata, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->ExecuteGql("INSERT (:Person {name: 'name_1', age: 11});"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("name_1", 11); + + result = store_->ExecuteGql("MATCH (p1:Person {name: 'name_1'}) SET p1.name = 'name_1_modify';"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("name_1_modify", 11); + + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_1_modify'}) SET p1.name = 'name_1_modify2', p1.age=100 + 11;"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("name_1_modify2", 111); + + result = store_->ExecuteGql("INSERT (:Person {name: 'name_2', age: 22});"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("name_2", 22); + result = store_->ExecuteGql("MATCH (p2:Person {name: 'name_2'}) SET p2 = {name: 'name_2_modify_all', age: 99};"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("name_2_modify_all", 99); + + result = store_->ExecuteGql("MATCH (p1:Person {name: 'name_1_modify2'}), (p2:Person {name: 'name_2_modify_all'}) " + "INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + result = + store_->ExecuteGql("MATCH (n:Person {name: 'name_1_modify2'})-[r:Friend]->(m:Person ) SET m.name = 'name_3';"); + MatchAndVerifyPerson("name_3", 99); + EXPECT_EQ(result.first, E_OK); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_UpdataNull, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->ExecuteGql("INSERT (:Person {name: 'hahaha', age: 987});"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("hahaha", 987); + // update name = null + result = store_->ExecuteGql("MATCH (p1:Person {name: 'hahaha'}) SET p1 = {age: 666};"); + EXPECT_EQ(result.first, E_OK); + result = store_->QueryGql("MATCH (person:Person {age: 666}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + ASSERT_TRUE(std::holds_alternative>(person)); + auto personVertex = std::get>(person); + EXPECT_EQ(personVertex->GetLabel(), "Person"); + ASSERT_EQ(personVertex->GetProperties().size(), 2); + + auto nameDb = personVertex->GetProperties().find("name"); + ASSERT_EQ(nameDb, personVertex->GetProperties().end()); + + auto ageDb = personVertex->GetProperties().find("age"); + ASSERT_NE(ageDb, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(ageDb->second)); + EXPECT_EQ(std::get(ageDb->second), 666); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_UpdataNull02, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->ExecuteGql("INSERT (:Person {name: 'hahaha', age: 987});"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("hahaha", 987); + // update name = null + result = store_->ExecuteGql("MATCH (p1:Person {name: 'hahaha'}) SET p1.age = 666, p1.name = null;"); + EXPECT_EQ(result.first, E_OK); + result = store_->QueryGql("MATCH (person:Person {age: 666}) RETURN person;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + ASSERT_TRUE(std::holds_alternative>(person)); + auto personVertex = std::get>(person); + EXPECT_EQ(personVertex->GetLabel(), "Person"); + ASSERT_EQ(personVertex->GetProperties().size(), 2); + + auto nameDb = personVertex->GetProperties().find("name"); + ASSERT_EQ(nameDb, personVertex->GetProperties().end()); + + auto ageDb = personVertex->GetProperties().find("age"); + ASSERT_NE(ageDb, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(ageDb->second)); + EXPECT_EQ(std::get(ageDb->second), 666); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_Updata_MatchFail, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->ExecuteGql("INSERT (:Person {name: 'zhangsan001', age: 10});"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("zhangsan001", 10); + + result = store_->ExecuteGql("MATCH (p1:Person {name: 'notFound'}) SET p1.name = 'name_1_modify';"); + EXPECT_EQ(result.first, E_OK); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_Updata_AgeError, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto result = store_->ExecuteGql("INSERT (:Person {name: 'name_4', age: 44});"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("name_4", 44); + + result = store_->ExecuteGql("MATCH (p1:Person {name: 'name_4'}) SET p1.age = 'string_age';"); + EXPECT_EQ(result.first, E_GRD_SEMANTIC_ERROR); + // update failed, no change + MatchAndVerifyPerson("name_4", 44); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_Updata_ColumnError, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto result = store_->ExecuteGql("INSERT (:PersonErr {name: true, age: 44});"); + EXPECT_EQ(result.first, E_GRD_UNDEFINED_PARAM); + + auto gql = "MATCH (person:Person) RETURN person;"; + result = store_->QueryGql(gql); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 0); + + result = store_->ExecuteGql("INSERT (:Person {name: true, age: 44});"); + EXPECT_EQ(result.first, E_GRD_SEMANTIC_ERROR); + gql = "MATCH (person:Person) RETURN person;"; + result = store_->QueryGql(gql); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 0); + + result = store_->ExecuteGql("INSERT (:Person {name: 'zhangsan', age: 'error'});"); + EXPECT_EQ(result.first, E_GRD_SEMANTIC_ERROR); + gql = "MATCH (person:Person) RETURN person;"; + result = store_->QueryGql(gql); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 0); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_Delete, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto result = store_->ExecuteGql("INSERT (:Person {name: 'zhangsan_delete', age: 10});"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("zhangsan_delete", 10); + + result = store_->ExecuteGql("MATCH (p:Person {name: 'zhangsan_delete'}) DETACH DELETE p;"); + EXPECT_EQ(result.first, E_OK); + auto gql = "MATCH (person:Person {name: 'zhangsan_delete'}) RETURN person;"; + result = store_->QueryGql(gql); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 0); + // Double Delete + result = store_->ExecuteGql("MATCH (p:Person {name: 'zhangsan_delete'}) DETACH DELETE p;"); + EXPECT_EQ(result.first, E_OK); + gql = "MATCH (person:Person {name: 'zhangsan_delete'}) RETURN person;"; + result = store_->QueryGql(gql); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 0); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_Delete_NotFound, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->ExecuteGql("INSERT (:Person {name: 'zhangsan_delete', age: 10});"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("zhangsan_delete", 10); + + result = store_->ExecuteGql("MATCH (p:Person {name: 'notFound'}) DETACH DELETE p;"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("zhangsan_delete", 10); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_Delete_PError, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->ExecuteGql("INSERT (:Person {name: 'delete_error', age: 11});"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("delete_error", 11); + + result = store_->ExecuteGql("MATCH (p:Person {name: 'delete_error'}) DETACH DELETE p_error;"); + EXPECT_EQ(result.first, E_GRD_UNDEFINED_PARAM); + MatchAndVerifyPerson("delete_error", 11); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_Delete_Related, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto result = store_->ExecuteGql("INSERT (:Person {name: 'delete_1', age: 11});"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("delete_1", 11); + result = store_->ExecuteGql("INSERT (:Person {name: 'delete_2', age: 22});"); + MatchAndVerifyPerson("delete_2", 22); + EXPECT_EQ(result.first, E_OK); + + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'delete_1'}), (p2:Person {name: 'delete_2'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + result = + store_->QueryGql("MATCH (person:Person {name: 'delete_1'})-[relation:Friend]->() RETURN person, relation;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + ASSERT_TRUE(std::holds_alternative>(person)); + auto personVertex = std::get>(person); + EXPECT_EQ(personVertex->GetLabel(), "Person"); + ASSERT_EQ(personVertex->GetProperties().size(), 3); + auto name = personVertex->GetProperties().find("name"); + ASSERT_NE(name, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(name->second)); + EXPECT_EQ(std::get(name->second), "delete_1"); + + auto age = personVertex->GetProperties().find("age"); + ASSERT_NE(age, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(age->second)); + EXPECT_EQ(std::get(age->second), 11); + + result = store_->ExecuteGql("MATCH (p:Person)-[:Friend]->(relatedPerson:Person) DETACH DELETE p, relatedPerson;"); + EXPECT_EQ(result.first, E_OK); + result = + store_->QueryGql("MATCH (person:Person {name: 'delete_1'})-[relation:Friend]->() RETURN person, relation;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 0); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_Delete_Related_Error, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto result = store_->ExecuteGql("INSERT (:Person {name: 'delete_3', age: 11});"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("delete_3", 11); + result = store_->ExecuteGql("INSERT (:Person {name: 'delete_4', age: 22});"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyPerson("delete_4", 22); + + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'delete_3'}), (p2:Person {name: 'delete_4'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + result = + store_->QueryGql("MATCH (person:Person {name: 'delete_3'})-[relation:Friend]->() RETURN person, relation;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + ASSERT_TRUE(std::holds_alternative>(person)); + auto personVertex = std::get>(person); + EXPECT_EQ(personVertex->GetLabel(), "Person"); + ASSERT_EQ(personVertex->GetProperties().size(), 3); + auto name = personVertex->GetProperties().find("name"); + ASSERT_NE(name, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(name->second)); + EXPECT_EQ(std::get(name->second), "delete_3"); + + // No Friend_Error, delete Eror + result = + store_->ExecuteGql("MATCH (p:Person)-[:Friend_Error]->(relatedPerson:Person) DETACH DELETE p, relatedPerson;"); + EXPECT_EQ(result.first, E_GRD_UNDEFINED_PARAM); + // p:Person, but delete p_error + result = + store_->ExecuteGql("MATCH (p:Person)-[:Friend]->(relatedPerson:Person) DETACH DELETE p_error, relatedPerson;"); + EXPECT_EQ(result.first, E_GRD_UNDEFINED_PARAM); + //relatedPerson:Person, but delete relatedPerson_error + result = + store_->ExecuteGql("MATCH (p:Person)-[:Friend]->(relatedPerson:Person) DETACH DELETE p, relatedPerson_error;"); + EXPECT_EQ(result.first, E_GRD_UNDEFINED_PARAM); + + result = store_->ExecuteGql("MATCH (p:Person)-[:Friend]->(relatedPerson:Person) DETACH DELETE relatedPerson, p;"); + EXPECT_EQ(result.first, E_OK); + // delete success, data.size == 0 + result = + store_->QueryGql("MATCH (person:Person {name: 'delete_3'})-[relation:Friend]->() RETURN person, relation;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 0); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_QueryGql, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->ExecuteGql("INSERT (:Person {name: 'zhangsan_111', age: 11, sex: true});"); + EXPECT_EQ(result.first, E_OK); + + result = store_->QueryGql("MATCH (person:Person {name: 'zhangsan_111'}) RETURN person;"); + EXPECT_EQ(result.first, E_OK); + + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue personErr = result.second->GetAllData()[0]["personErr"]; + // No personErr + ASSERT_TRUE(std::holds_alternative(personErr)); + + GraphValue person = result.second->GetAllData()[0]["person"]; + ASSERT_TRUE(std::holds_alternative>(person)); + auto personVertex = std::get>(person); + ASSERT_NE(personVertex->GetLabel(), "error_label"); + EXPECT_EQ(personVertex->GetLabel(), "Person"); + // size = 4 {name, age, sex, identity} + ASSERT_EQ(personVertex->GetProperties().size(), 3); + + auto name = personVertex->GetProperties().find("name"); + ASSERT_NE(name, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(name->second)); + EXPECT_EQ(std::get(name->second), "zhangsan_111"); + + auto age = personVertex->GetProperties().find("age"); + ASSERT_NE(age, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(age->second)); + EXPECT_EQ(std::get(age->second), 11); + + auto sex = personVertex->GetProperties().find("sex"); + ASSERT_NE(sex, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(sex->second)); + EXPECT_EQ(std::get(sex->second), 1); + // No Propertie is OTHER, equal End + auto other = personVertex->GetProperties().find("OTHER"); + EXPECT_EQ(other, personVertex->GetProperties().end()); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_QueryGql_2, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto result = store_->ExecuteGql("INSERT (:Person {name: 'lisi_1', age: 66});"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql("INSERT (:Person {name: 'lisi_2', age: 66, sex: true});"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql("INSERT (:Dog {name: 'xiaohuang1', age: 66});"); + EXPECT_EQ(result.first, E_OK); + result = store_->QueryGql("MATCH (person:Person{age: 66}) RETURN person;"); + EXPECT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 2); + + GraphValue person = result.second->GetAllData()[0]["person"]; + ASSERT_TRUE(std::holds_alternative>(person)); + auto personVertex = std::get>(person); + EXPECT_EQ(personVertex->GetLabel(), "Person"); + ASSERT_EQ(personVertex->GetProperties().size(), 3); + auto name = personVertex->GetProperties().find("name"); + ASSERT_NE(name, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(name->second)); + EXPECT_EQ(std::get(name->second), "lisi_1"); + auto age = personVertex->GetProperties().find("age"); + ASSERT_NE(age, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(age->second)); + EXPECT_EQ(std::get(age->second), 66); + auto sex = personVertex->GetProperties().find("sex"); + ASSERT_NE(sex, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(age->second)); + EXPECT_EQ(std::get(sex->second), 0); + + person = result.second->GetAllData()[1]["person"]; + ASSERT_TRUE(std::holds_alternative>(person)); + personVertex = std::get>(person); + EXPECT_EQ(personVertex->GetLabel(), "Person"); + ASSERT_EQ(personVertex->GetProperties().size(), 3); + name = personVertex->GetProperties().find("name"); + ASSERT_NE(name, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(name->second)); + EXPECT_EQ(std::get(name->second), "lisi_2"); + age = personVertex->GetProperties().find("age"); + ASSERT_NE(age, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(age->second)); + EXPECT_EQ(std::get(age->second), 66); + sex = personVertex->GetProperties().find("sex"); + ASSERT_NE(sex, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(age->second)); + EXPECT_EQ(std::get(sex->second), 1); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_ParseEdge, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + int errCode = E_ERROR; + // no start, no end + nlohmann::json json = nlohmann::json::parse("{\"name\" : \"zhangsan\"}", nullptr, false); + ASSERT_FALSE(json.is_discarded()); + ASSERT_FALSE(json.is_null()); + Edge::Parse(json, errCode); + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); + // no identity + std::string jsonStr = "{\"start\" : 1, \"end\" : 2}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Edge::Parse(json, errCode); + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); + // ok + jsonStr = "{\"start\" : 1, \"end\" : 2, \"label\":\"COMPANY\",\"identity\":3," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":2011}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Edge::Parse(json, errCode); + EXPECT_EQ(errCode, E_OK); + // start is AA + jsonStr = "{\"start\" : \"AA\", \"end\" : 2, \"label\":\"COMPANY\",\"identity\":3," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":2011}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Edge::Parse(json, errCode); + EXPECT_EQ(errCode, E_OK); + // end is B + jsonStr = "{\"start\" : 1, \"end\" : \"B\", \"label\":\"COMPANY\",\"identity\":3," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":2011}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Edge::Parse(json, errCode); + EXPECT_EQ(errCode, E_OK); + // identity is C + jsonStr = "{\"start\" : 1, \"end\" : 2, \"label\":\"COMPANY\",\"identity\":\"C\"," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":2011}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Edge::Parse(json, errCode); + EXPECT_EQ(errCode, E_OK); + // label is 222 + jsonStr = "{\"start\" : 1, \"end\" : 2, \"label\":222,'identity':3,\"properties\":{\"NAME\":\"myCompany3\"," + "\"FOUNDED\":2011}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Edge::Parse(json, errCode); + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); + // key4 is null + jsonStr = + "{\"start\" : 1, \"end\" : 2, \"label\":\"COMPANY\",\"identity\":2," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":4.5,\"SEX\":true,\"key1\":true,\"key2\":[], \"key3\":{}, " + "\"key4\": null}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Edge::Parse(json, errCode); + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_PathSegment, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + int errCode = E_ERROR; + // NO start and end + nlohmann::json json = nlohmann::json::parse("{\"name\" : \"zhangsan\"}", nullptr, false); + ASSERT_FALSE(json.is_discarded()); + ASSERT_FALSE(json.is_null()); + PathSegment::Parse(json, errCode); + ASSERT_EQ(errCode, E_PARSE_JSON_FAILED); + // no relationship + std::string jsonStr = "{\"start\" : {}, \"end\" : {}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + ASSERT_EQ(errCode, E_PARSE_JSON_FAILED); + + jsonStr = "{\"start\" : {}, \"end\" : {}, \"relationship\":{}, \"label\":\"COMPANY\",\"identity\":3," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":2011}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + ASSERT_EQ(errCode, E_PARSE_JSON_FAILED); + + jsonStr = "{\"start\" : {}, \"end\" : {}, \"relationship\":{}, \"label\":\"COMPANY\",\"identity\":3," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":2011}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + ASSERT_EQ(errCode, E_PARSE_JSON_FAILED); + + jsonStr = "{\"start\" : {}, \"end\" : {}, \"relationship\":{}, \"label\":\"COMPANY\",\"identity\":\"C\"," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":2011}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + ASSERT_EQ(errCode, E_PARSE_JSON_FAILED); + + jsonStr = "{\"start\" : {}, \"end\" : {}, \"relationship\":{}, \"label\":222,\"identity\":2," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":2011}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + ASSERT_EQ(errCode, E_PARSE_JSON_FAILED); + + jsonStr = "{\"start\" : {}, \"end\" : {}, \"relationship\":{}, \"label\":\"COMPANY\",\"identity\":2," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":4.5,\"SEX\":true,\"key1\":true,\"key2\":[], " + "\"key3\":{}, \"key4\": null}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + ASSERT_EQ(errCode, E_PARSE_JSON_FAILED); + + json = nlohmann::json::parse(pathJsonString, nullptr, false); + PathSegment::Parse(json, errCode); + ASSERT_EQ(errCode, E_OK); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_PathSegment02, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + int errCode = E_ERROR; + nlohmann::json json = nlohmann::json::parse(pathJsonString, nullptr, false); + PathSegment::Parse(json, errCode); + EXPECT_EQ(errCode, E_OK); + // identity:A, E_OK + std::string jsonStr = + "{\"start\":{\"label\":\"PERSON\",\"identity\":\"A\",\"properties\":{\"AGE\":32,\"SALARY\":75.35," + "\"NAME\":\"Alice\",\"GENDER\":\"Female\",\"PHONENUMBERS\":false,\"EMAILS\":null}}," + "\"end\":{\"label\":\"PERSON\",\"identity\":2,\"properties\":{\"AGE\":28,\"SALARY\":65000," + "\"NAME\":\"Bob\",\"GENDER\":\"Male\",\"PHONENUMBERS\":\"123456789\",\"EMAILS\":\" bob@example.com\"}}," + "\"relationship\":{\"label\":\"tttt\",\"identity\":3,\"start\":1,\"end\":2,\"properties\":{\"NUM\":4," + "\"PINYIN\":\"zhixiqinshu\"}}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + EXPECT_EQ(errCode, E_OK); + + // label:2, E_PARSE_JSON_FAILED + jsonStr = + "{\"start\":{\"label\":2,\"identity\":1,\"properties\":{\"AGE\":32,\"SALARY\":75.35," + "\"NAME\":\"Alice\",\"GENDER\":\"Female\",\"PHONENUMBERS\":false,\"EMAILS\":null}}," + "\"end\":{\"label\":\"PERSON\",\"identity\":2,\"properties\":{\"AGE\":28,\"SALARY\":65000," + "\"NAME\":\"Bob\",\"GENDER\":\"Male\",\"PHONENUMBERS\":\"123456789\",\"EMAILS\":\" bob@example.com\"}}," + "\"relationship\":{\"label\":\"tttt\",\"identity\":3,\"start\":1,\"end\":2,\"properties\":{\"NUM\":4," + "\"PINYIN\":\"zhixiqinshu\"}}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); + + // relationship->start:B, E_OK + jsonStr = + "{\"start\":{\"label\":\"PERSON\",\"identity\":1,\"properties\":{\"AGE\":32,\"SALARY\":75.35," + "\"NAME\":\"Alice\",\"GENDER\":\"Female\",\"PHONENUMBERS\":false,\"EMAILS\":null}}," + "\"end\":{\"label\":\"PERSON\",\"identity\":2,\"properties\":{\"AGE\":28,\"SALARY\":65000," + "\"NAME\":\"Bob\",\"GENDER\":\"Male\",\"PHONENUMBERS\":\"123456789\",\"EMAILS\":\" bob@example.com\"}}," + "\"relationship\":{\"label\":\"tttt\",\"identity\":3,\"start\":\"B\",\"end\":2,\"properties\":{\"NUM\":4," + "\"PINYIN\":\"zhixiqinshu\"}}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + EXPECT_EQ(errCode, E_OK); + + // relationship->end:C, E_OK + jsonStr = + "{\"start\":{\"label\":\"PERSON\",\"identity\":1,\"properties\":{\"AGE\":32,\"SALARY\":75.35," + "\"NAME\":\"Alice\",\"GENDER\":\"Female\",\"PHONENUMBERS\":false,\"EMAILS\":null}}," + "\"end\":{\"label\":\"PERSON\",\"identity\":2,\"properties\":{\"AGE\":28,\"SALARY\":65000," + "\"NAME\":\"Bob\",\"GENDER\":\"Male\",\"PHONENUMBERS\":\"123456789\",\"EMAILS\":\" bob@example.com\"}}," + "\"relationship\":{\"label\":\"tttt\",\"identity\":3,\"start\":1,\"end\":\"C\",\"properties\":{\"NUM\":4," + "\"PINYIN\":\"zhixiqinshu\"}}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + ASSERT_EQ(errCode, E_OK); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_PathSegment03, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + int errCode = E_ERROR; + nlohmann::json json = nlohmann::json::parse(pathJsonString, nullptr, false); + PathSegment::Parse(json, errCode); + ASSERT_EQ(errCode, E_OK); + // end no label:PERSON and identity: A + std::string jsonStr = + "{\"start\":{\"label\":\"PERSON\",\"identity\":1,\"properties\":{\"AGE\":32,\"SALARY\":75.35," + "\"NAME\":\"Alice\",\"GENDER\":\"Female\",\"PHONENUMBERS\":false,\"EMAILS\":null}}," + "\"end\":{\"identity\":\"A\",\"properties\":{\"AGE\":28,\"SALARY\":65000," + "\"NAME\":\"Bob\",\"GENDER\":\"Male\",\"PHONENUMBERS\":\"123456789\",\"EMAILS\":\" bob@example.com\"}}," + "\"relationship\":{\"label\":\"tttt\",\"identity\":3,\"start\":1,\"end\":2,\"properties\":{\"NUM\":4," + "\"PINYIN\":\"zhixiqinshu\"}}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + ASSERT_EQ(errCode, E_PARSE_JSON_FAILED); + + jsonStr = "{\"start\" : 1, \"end\" : {}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + ASSERT_EQ(errCode, E_PARSE_JSON_FAILED); + + jsonStr = "{\"start\" : {}, \"relationship\" : 1}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + ASSERT_EQ(errCode, E_PARSE_JSON_FAILED); + + jsonStr = "{\"start\" : {}, \"relationship\" : {}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + ASSERT_EQ(errCode, E_PARSE_JSON_FAILED); + + jsonStr = "{\"start\" : {}, \"relationship\" : {}, \"end\" : 1}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + ASSERT_EQ(errCode, E_PARSE_JSON_FAILED); + + jsonStr = "{\"start\" : {}, \"relationship\" : {}, \"end\" : {}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + ASSERT_EQ(errCode, E_PARSE_JSON_FAILED); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_PathSegment04, TestSize.Level1) +{ + int errCode = E_ERROR; + nlohmann::json json = nlohmann::json::parse(pathJsonString, nullptr, false); + PathSegment::Parse(json, errCode); + EXPECT_EQ(errCode, E_OK); + // identity:A, E_OK + std::string jsonStr = + "{\"start\":{\"label\":\"PERSON\",\"identity\":{},\"properties\":{\"AGE\":32,\"SALARY\":75.35," + "\"NAME\":\"Alice\",\"GENDER\":\"Female\",\"PHONENUMBERS\":false,\"EMAILS\":null}}," + "\"end\":{\"label\":\"PERSON\",\"identity\":2,\"properties\":{\"AGE\":28,\"SALARY\":65000," + "\"NAME\":\"Bob\",\"GENDER\":\"Male\",\"PHONENUMBERS\":\"123456789\",\"EMAILS\":\" bob@example.com\"}}," + "\"relationship\":{\"label\":\"tttt\",\"identity\":3,\"start\":1,\"end\":2,\"properties\":{\"NUM\":4," + "\"PINYIN\":\"zhixiqinshu\"}}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); + std::shared_ptr sourceVertex; + std::shared_ptr targetVertex; + std::shared_ptr edge; + auto paths = std::make_shared(sourceVertex, targetVertex, edge); + EXPECT_NE(paths, nullptr); + EXPECT_EQ(sourceVertex, paths->GetSourceVertex()); + EXPECT_EQ(edge, paths->GetEdge()); + EXPECT_EQ(targetVertex, paths->GetTargetVertex()); + jsonStr = + "{\"start\":{\"label\":\"PERSON\",\"identity\":1,\"properties\":{\"AGE\":32,\"SALARY\":75.35," + "\"NAME\":\"Alice\",\"GENDER\":\"Female\",\"PHONENUMBERS\":false,\"EMAILS\":null}}," + "\"end\":{\"label\":\"PERSON\",\"identity\":2,\"properties\":{\"AGE\":28,\"SALARY\":65000," + "\"NAME\":\"Bob\",\"GENDER\":\"Male\",\"PHONENUMBERS\":\"123456789\",\"EMAILS\":\" bob@example.com\"}}," + "\"relationship\":{}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + PathSegment::Parse(json, errCode); + ASSERT_EQ(errCode, E_PARSE_JSON_FAILED); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_Path01, TestSize.Level1) +{ + std::shared_ptr start = std::make_shared(); + std::shared_ptr end = std::make_shared(); + auto path = std::make_shared(); + path = std::make_shared(start, end); + EXPECT_NE(path, nullptr); + path->SetPathLength(1); + EXPECT_EQ(1, path->GetPathLength()); + path->SetStart(std::make_shared("1", "HAHA")); + EXPECT_EQ("1", path->GetStart()->GetId()); + EXPECT_EQ("HAHA", path->GetStart()->GetLabel()); + auto labels = path->GetStart()->GetLabels(); + EXPECT_EQ(1, labels.size()); + + path->SetEnd(std::make_shared("2", "HAHA2")); + EXPECT_EQ("2", path->GetEnd()->GetId()); + EXPECT_EQ("HAHA2", path->GetEnd()->GetLabel()); + auto segment = path->GetSegments(); + EXPECT_EQ(segment.size(), 0); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_Path02, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + int errCode = E_ERROR; + nlohmann::json json = nlohmann::json::parse(pathJsonString, nullptr, false); + Path::Parse(json, errCode); + // no length + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); + // identity:A, E_OK + std::string jsonStr = + "{\"length\": 1,\"start\":{\"label\":\"PERSON\",\"identity\":3,\"properties\":{\"AGE\":32,\"SALARY\":75.35," + "\"NAME\":\"Alice\",\"GENDER\":\"Female\"}}," + "\"end\":{\"label\":\"PERSON\",\"identity\":2,\"properties\":{\"AGE\":28,\"SALARY\":65000," + "\"NAME\":\"Bob\",\"GENDER\":\"Male\",\"PHONENUMBERS\":\"123456789\",\"EMAILS\":\" bob@example.com\"}}," + "\"relationship\":{\"label\":\"tttt\",\"identity\":3,\"start\":1,\"end\":2,\"properties\":{\"NUM\":4," + "\"PINYIN\":\"zhixiqinshu\"}},\"segments\":[{\"start\":{\"label\":\"PERSON\"," + "\"identity\":1,\"properties\":{\"AGE\":32,\"SALARY\":75.35," + "\"NAME\":\"Alice\",\"GENDER\":\"Female\",\"PHONENUMBERS\":false,\"EMAILS\":null}}," + "\"end\":{\"label\":\"PERSON\",\"identity\":2,\"properties\":{\"AGE\":28,\"SALARY\":65000," + "\"NAME\":\"Bob\",\"GENDER\":\"Male\",\"PHONENUMBERS\":\"123456789\",\"EMAILS\":\" bob@example.com\"}}," + "\"relationship\":{\"label\":\"tttt\",\"identity\":3,\"start\":1,\"end\":\"C\",\"properties\":{\"NUM\":4," + "\"PINYIN\":\"zhixiqinshu\"}}}]}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Path::Parse(json, errCode); + EXPECT_EQ(errCode, E_OK); + + // label:2, E_PARSE_JSON_FAILED + jsonStr = + "{\"length\": 1,\"start\":{\"label\":2,\"identity\":1,\"properties\":{\"AGE\":32,\"SALARY\":75.35," + "\"NAME\":\"Alice\",\"GENDER\":\"Female\",\"PHONENUMBERS\":false,\"EMAILS\":null}}," + "\"end\":{\"label\":\"PERSON\",\"identity\":2,\"properties\":{\"AGE\":28,\"SALARY\":65000," + "\"NAME\":\"Bob\",\"GENDER\":\"Male\",\"PHONENUMBERS\":\"123456789\",\"EMAILS\":\" bob@example.com\"}}," + "\"relationship\":{\"label\":\"tttt\",\"identity\":3,\"start\":1,\"end\":2,\"properties\":{\"NUM\":4," + "\"PINYIN\":\"zhixiqinshu\"}},\"segments\":[{}]}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Path::Parse(json, errCode); + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_Path03, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + int errCode = E_ERROR; + nlohmann::json json = nlohmann::json::parse(pathJsonString, nullptr, false); + Path::Parse(json, errCode); + // no length + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); + // relationship->start:B, E_OK + auto jsonStr = + "{\"length\": 1,\"start\":{\"label\":\"PERSON\",\"identity\":1,\"properties\":{\"AGE\":32,\"SALARY\":75.35," + "\"NAME\":\"Alice\",\"GENDER\":\"Female\",\"PHONENUMBERS\":false,\"EMAILS\":null}}," + "\"end\":{\"label\":\"PERSON\",\"identity\":2,\"properties\":{\"AGE\":28,\"SALARY\":65000," + "\"NAME\":\"Bob\",\"GENDER\":\"Male\",\"PHONENUMBERS\":\"123456789\",\"EMAILS\":\" bob@example.com\"}}," + "\"relationship\":{\"label\":\"tttt\",\"identity\":3,\"start\":\"B\",\"end\":2,\"properties\":{\"NUM\":4," + "\"PINYIN\":\"zhixiqinshu\"}},\"segments\":[{}]}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Path::Parse(json, errCode); + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); + + // relationship->end:C, E_OK + jsonStr = + "{\"length\": 1,\"start\":{\"label\":\"PERSON\",\"identity\":1,\"properties\":{\"AGE\":32,\"SALARY\":75.35," + "\"NAME\":\"Alice\",\"GENDER\":\"Female\",\"PHONENUMBERS\":false,\"EMAILS\":null}}," + "\"end\":{\"label\":\"PERSON\",\"identity\":2,\"properties\":{\"AGE\":28,\"SALARY\":65000," + "\"NAME\":\"Bob\",\"GENDER\":\"Male\",\"PHONENUMBERS\":\"123456789\",\"EMAILS\":\" bob@example.com\"}}," + "\"relationship\":{\"label\":\"tttt\",\"identity\":3,\"start\":1,\"end\":\"C\",\"properties\":{\"NUM\":4," + "\"PINYIN\":\"zhixiqinshu\"}},\"segments\":[{\"start\":{\"label\":\"PERSON\",\"identity\":1," + "\"properties\":{\"AGE\":32,\"SALARY\":75.35," + "\"NAME\":\"Alice\",\"GENDER\":\"Female\",\"PHONENUMBERS\":false,\"EMAILS\":null}}," + "\"end\":{\"label\":\"PERSON\",\"identity\":2,\"properties\":{\"AGE\":28,\"SALARY\":65000," + "\"NAME\":\"Bob\",\"GENDER\":\"Male\",\"PHONENUMBERS\":\"123456789\",\"EMAILS\":\" bob@example.com\"}}," + "\"relationship\":{\"label\":\"tttt\",\"identity\":3,\"start\":1,\"end\":\"C\",\"properties\":{\"NUM\":4," + "\"PINYIN\":\"zhixiqinshu\"}}}]}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Path::Parse(json, errCode); + ASSERT_EQ(errCode, E_OK); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_Vertex, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + int errCode = E_ERROR; + // no start, no end + nlohmann::json json = nlohmann::json::parse("{\"name\" : \"zhangsan\"}", nullptr, false); + ASSERT_FALSE(json.is_discarded()); + ASSERT_FALSE(json.is_null()); + Vertex::Parse(json, errCode); + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); + // no identity + std::string jsonStr = "{\"start\" : 1, \"end\" : 2}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Vertex::Parse(json, errCode); + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); + // ok + jsonStr = "{\"start\" : 1, \"end\" : 2, \"label\":\"COMPANY\",\"identity\":3," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":2011}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Vertex::Parse(json, errCode); + EXPECT_EQ(errCode, E_OK); + // start is AA + jsonStr = "{\"start\" : \"AA\", \"end\" : 2, \"label\":\"COMPANY\",\"identity\":3," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":2011}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Vertex::Parse(json, errCode); + EXPECT_EQ(errCode, E_OK); + // end is B + jsonStr = "{\"start\" : 1, \"end\" : \"B\", \"label\":\"COMPANY\",\"identity\":3," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":2011}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Vertex::Parse(json, errCode); + EXPECT_EQ(errCode, E_OK); + // identity is C + jsonStr = "{\"start\" : 1, \"end\" : 2, \"label\":\"COMPANY\",\"identity\":\"C\"," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":2011}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Vertex::Parse(json, errCode); + EXPECT_EQ(errCode, E_OK); + // label is 222 + jsonStr = "{\"start\" : 1, \"end\" : 2, \"label\":222,'identity':3,\"properties\":{\"NAME\":\"myCompany3\"," + "\"FOUNDED\":2011}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Vertex::Parse(json, errCode); + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); + // key4 is null + jsonStr = + "{\"start\" : 1, \"end\" : 2, \"label\":\"COMPANY\",\"identity\":2," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":4.5,\"SEX\":true,\"key1\":true,\"key2\":[], \"key3\":{}, " + "\"key4\": null}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Vertex::Parse(json, errCode); + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_Vertex02, TestSize.Level1) +{ + Vertex vertex; + Vertex vertex2("1", "PERSON"); + ASSERT_EQ(vertex2.GetLabel(), "PERSON"); + vertex2.SetLabel("PERSON1"); + ASSERT_EQ(vertex2.GetLabel(), "PERSON1"); + std::unordered_map properties; + Vertex vertex3("1", "PERSON2", properties); + ASSERT_EQ(vertex3.GetLabel(), "PERSON2"); + vertex3.SetLabel("PERSON3"); + ASSERT_EQ(vertex3.GetLabel(), "PERSON3"); +} + +/** + * @tc.name: GdbStore_Execute_PathChange + * @tc.desc: test Path Change + * @tc.type: FUNC + */ +HWTEST_F(GdbExecuteTest, GdbStore_Execute_PathChange, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->ExecuteGql("INSERT (:Person {name: 'name_1', age: 11});"); + MatchAndVerifyPerson("name_1", 11); + result = store_->ExecuteGql("INSERT (:Person {name: 'name_2', age: 22});"); + MatchAndVerifyPerson("name_2", 22); + result = store_->ExecuteGql("INSERT (:Person {name: 'name_3', age: 33});"); + MatchAndVerifyPerson("name_3", 33); + result = store_->ExecuteGql("INSERT (:Person {name: 'name_4', age: 44});"); + MatchAndVerifyPerson("name_4", 44); + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_1'}), (p2:Person {name: 'name_2'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_1'}), (p2:Person {name: 'name_3'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_1'}), (p2:Person {name: 'name_4'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_2'}), (p2:Person {name: 'name_3'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_2'}), (p2:Person {name: 'name_4'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_3'}), (p2:Person {name: 'name_4'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + + result = + store_->QueryGql("MATCH path=(a:Person {name: 'name_1'})-[]->{0, 3}(b:Person) RETURN path;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 8); + + GraphValue path = result.second->GetAllData()[0]["path"]; + ASSERT_TRUE(std::holds_alternative>(path)); +} + +/** + * @tc.name: GdbStore_Execute_PathChangeRing + * @tc.desc: Querying a Trail with a Ring + * @tc.type: FUNC + */ +HWTEST_F(GdbExecuteTest, GdbStore_Execute_PathChangeRing, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->ExecuteGql("INSERT (:Person {name: 'name_1', age: 11});"); + MatchAndVerifyPerson("name_1", 11); + result = store_->ExecuteGql("INSERT (:Person {name: 'name_2', age: 22});"); + MatchAndVerifyPerson("name_2", 22); + result = store_->ExecuteGql("INSERT (:Person {name: 'name_3', age: 33});"); + MatchAndVerifyPerson("name_3", 33); + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_1'}), (p2:Person {name: 'name_2'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_2'}), (p2:Person {name: 'name_3'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_3'}), (p2:Person {name: 'name_1'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + + result = + store_->QueryGql("MATCH path=(a:Person {name: 'name_1'})-[]->{0, 3}(b:Person) RETURN path;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 4); + + GraphValue path = result.second->GetAllData()[0]["path"]; + ASSERT_TRUE(std::holds_alternative>(path)); +} + +/** + * @tc.name: GdbStore_Execute_AllGraph + * @tc.desc: test All Graph + * @tc.type: FUNC + */ +HWTEST_F(GdbExecuteTest, GdbStore_Execute_AllGraph, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + std::string name = "zhangsanfeng"; + for (int32_t i = 0; i < 50; i++) { + auto nameInner = name + "_" + std::to_string(i); + auto result = store_->ExecuteGql("INSERT (:Person {name: '" + nameInner + "', age: 11});"); + MatchAndVerifyPerson(nameInner, 11); + for (int32_t j = 0; j < 100; j++) { + auto nameOut = nameInner + "_" + std::to_string(j); + result = store_->ExecuteGql("INSERT (:Person {name: '" + nameOut + "', age: 22});"); + MatchAndVerifyPerson(nameOut, 22); + result = store_->ExecuteGql( + "MATCH (p1:Person {name: '" + nameInner + "'}), (p2:Person {name: '" + nameOut + "'}) " + "INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + } + } + auto result = + store_->QueryGql("MATCH path=(a:Person)-[]->{0, 3}(b:Person) RETURN path;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 10050); + GraphValue path = result.second->GetAllData()[0]["path"]; + ASSERT_TRUE(std::holds_alternative>(path)); + + auto gql = "MATCH (person:Person) RETURN person;"; + result = store_->QueryGql(gql); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 5050); +} + +/** + * @tc.name: GdbStore_Execute_SelfPath + * @tc.desc: test Self Path + * @tc.type: FUNC + */ +HWTEST_F(GdbExecuteTest, GdbStore_Execute_SelfPath, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->ExecuteGql("INSERT (:Person {name: 'name_111', age: 11});"); + MatchAndVerifyPerson("name_111", 11); + + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_111'}), (p2:Person {name: 'name_111'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + + result = store_->QueryGql("MATCH path=(a:Person {name: 'name_111'})-[]->{0, 3}(b:Person) RETURN path;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 2); + + GraphValue path = result.second->GetAllData()[0]["path"]; + ASSERT_TRUE(std::holds_alternative>(path)); +} + +/** + * @tc.name: GdbStore_Execute_SelfPath + * @tc.desc: test Self Path + * @tc.type: FUNC + */ +HWTEST_F(GdbExecuteTest, GdbStore_Execute_SelfPath02, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->ExecuteGql("INSERT (:Person {name: 'name_test_001', age: 11});"); + MatchAndVerifyPerson("name_test_001", 11); + + result = store_->ExecuteGql("INSERT (:Person {name: 'name_test_001', age: 11});"); + + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_test_001'}), (p2:Person {name: 'name_test_001'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + + result = store_->ExecuteGql( + "MATCH (p1:Person {name: 'name_test_001'}), (p2:Person {name: 'name_test_001'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + + result = + store_->QueryGql("MATCH path=(a:Person {name: 'name_test_001'})-[]->{0, 3}(b:Person) RETURN path;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 126); + + GraphValue path = result.second->GetAllData()[0]["path"]; + ASSERT_TRUE(std::holds_alternative>(path)); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_StoreConfigSetName, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "success01"; + std::string dbPath = databasePath; + auto config = StoreConfig(dbName, dbPath); + config.SetName("success01_update"); + EXPECT_EQ("success01_update", config.GetName()); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + GDBHelper::DeleteDBStore(StoreConfig("success01_update", databasePath)); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_StoreConfigSetPath, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "success01"; + std::string dbPath = "/test/test"; + auto config = StoreConfig(dbName, dbPath); + config.SetPath(databasePath); + EXPECT_EQ(databasePath, config.GetPath()); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + GDBHelper::DeleteDBStore(StoreConfig(dbName, databasePath)); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_StoreConfigSetDbType, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "success01"; + std::string dbPath = databasePath; + auto config = StoreConfig(dbName, dbPath); + config.SetDbType(DBType::DB_GRAPH); + EXPECT_EQ(config.GetDbType(), DBType::DB_GRAPH); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + GDBHelper::DeleteDBStore(StoreConfig(dbName, databasePath)); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_StoreConfigSetEncryptStatus, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "success01"; + std::string dbPath = databasePath; + auto config = StoreConfig(dbName, dbPath); + config.SetEncryptStatus(true); + ASSERT_TRUE(config.IsEncrypt()); + config.SetEncryptStatus(false); + ASSERT_TRUE(!config.IsEncrypt()); + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + GDBHelper::DeleteDBStore(StoreConfig(dbName, databasePath)); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_StoreConfigSetReadTime, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "success01"; + std::string dbPath = databasePath; + std::vector encryptKey = std::vector(); + auto config = StoreConfig(dbName, dbPath, DBType::DB_GRAPH, true, encryptKey); + config = StoreConfig(dbName, dbPath, DBType::DB_GRAPH, false, encryptKey); + config.SetReadTime(3); + EXPECT_EQ(config.GetReadTime(), 3); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + GDBHelper::DeleteDBStore(StoreConfig(dbName, databasePath)); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_UtilsTest, TestSize.Level1) +{ + int errCode = E_OK; + errCode = GdbUtils::CreateDirectory(""); + EXPECT_EQ(errCode, E_OK); + errCode = GdbUtils::CreateDirectory("dir1"); + EXPECT_EQ(errCode, E_CREATE_FOLDER_FAIT); + GdbUtils::CreateDirectory("dir1/dir2"); + EXPECT_EQ(errCode, E_CREATE_FOLDER_FAIT); + GdbUtils::CreateDirectory("dir1/dir2/dir3"); + EXPECT_EQ(errCode, E_CREATE_FOLDER_FAIT); + GdbUtils::CreateDirectory("/dir1/dir2/dir3"); + EXPECT_EQ(errCode, E_CREATE_FOLDER_FAIT); + GdbUtils::CreateDirectory("/data/"); + EXPECT_EQ(errCode, E_CREATE_FOLDER_FAIT); + GdbUtils::CreateDirectory("/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2" + "/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2" + "/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2" + "/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2" + "/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2" + "/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2" + "/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2/data/dir1/dir2"); + EXPECT_EQ(errCode, E_CREATE_FOLDER_FAIT); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_UtilsAnonymousTest, TestSize.Level1) +{ + auto ret = GdbUtils::Anonymous("fileName"); + EXPECT_EQ(ret, "fileName"); + ret = GdbUtils::Anonymous("dir1/shortPath"); + EXPECT_EQ(ret, "dir1/shortPa"); + ret = GdbUtils::Anonymous("dir1/el1/longPath"); + EXPECT_EQ(ret, "dir1/el1/longPa"); + ret = GdbUtils::Anonymous("el1/l"); + EXPECT_EQ(ret, "el1"); + ret = GdbUtils::Anonymous( + "dir1/el1/longPath/longPath/longPath/longPath/longPath/longPath/longPath/longPath/longPath/longPath/longPath"); + EXPECT_EQ(ret, "dir1/***/el1/***/longPa"); + ret = GdbUtils::Anonymous("/data/dir1/dir2/dir3"); + EXPECT_EQ(ret, "/***/dir3"); + ret = GdbUtils::Anonymous("/data/el1/dir2"); + EXPECT_EQ(ret, "/***/el1/dir2"); + ret = GdbUtils::Anonymous("/data/app/el1/0/base/com.my.hmos.arkwebcore"); + EXPECT_EQ(ret, "/***/el1/***/com.my.hmos.arkwebcore"); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_UtilsErrorTest, TestSize.Level1) +{ + auto errCode = GrdAdapter::TransErrno(100); + EXPECT_EQ(errCode, 100); + errCode = GrdAdapter::TransErrno(E_PARSE_JSON_FAILED); + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); + + errCode = GrdAdapter::TransErrno(E_PARSE_JSON_FAILED); + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); + + errCode = GrdAdapter::TransErrno(E_OK); + EXPECT_EQ(errCode, E_OK); + + errCode = GrdAdapter::TransErrno(-100); + EXPECT_EQ(errCode, E_GRD_INNER_ERR); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_StatementTest, TestSize.Level1) +{ + auto errCode = E_OK; + std::string gql = "INSERT (:Person {name: 'name_test_001', age: 11});"; + GraphStatement statement(nullptr, "", nullptr, errCode); + EXPECT_EQ(errCode, E_PREPARE_CHECK_FAILED); + + GRD_DB *dbHandle; + auto ret = std::make_shared(dbHandle, gql, nullptr, errCode); + EXPECT_NE(ret, nullptr); + errCode = ret->Prepare(); + EXPECT_EQ(errCode, E_PREPARE_CHECK_FAILED); + + errCode = ret->Step(); + EXPECT_EQ(errCode, E_STEP_CHECK_FAILED); + + errCode = ret->Finalize(); + EXPECT_EQ(errCode, E_OK); + + errCode = ret->GetColumnCount(); + EXPECT_EQ(errCode, E_STATEMENT_EMPTY); + + auto pair = ret->GetColumnName(0); + EXPECT_EQ(pair.first, E_STATEMENT_EMPTY); + pair = ret->GetColumnName(0); + EXPECT_EQ(pair.first, E_STATEMENT_EMPTY); + pair = ret->GetColumnName(3); + EXPECT_EQ(pair.first, E_STATEMENT_EMPTY); + pair = ret->GetColumnName(9); + EXPECT_EQ(pair.first, E_STATEMENT_EMPTY); + + auto pair1 = ret->GetColumnValue(0); + EXPECT_EQ(pair1.first, E_STATEMENT_EMPTY); + pair1 = ret->GetColumnValue(3); + EXPECT_EQ(pair1.first, E_STATEMENT_EMPTY); + pair1 = ret->GetColumnValue(100); + EXPECT_EQ(pair1.first, E_STATEMENT_EMPTY); + + errCode = ret->IsReady(); + EXPECT_EQ(errCode, E_OK); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_StatementTest02, TestSize.Level1) +{ + auto errCode = E_OK; + std::string gql = "INSERT (:Person {name: 'name_test_001', age: 11});"; + + auto ret = std::make_shared(nullptr, gql, nullptr, errCode); + EXPECT_NE(ret, nullptr); + errCode = ret->Prepare(); + EXPECT_EQ(errCode, E_PREPARE_CHECK_FAILED); + + errCode = ret->Step(); + EXPECT_EQ(errCode, E_STEP_CHECK_FAILED); + + errCode = ret->Finalize(); + EXPECT_EQ(errCode, E_OK); + + errCode = ret->GetColumnCount(); + EXPECT_EQ(errCode, E_STATEMENT_EMPTY); + + auto pair = ret->GetColumnName(0); + EXPECT_EQ(pair.first, E_STATEMENT_EMPTY); + + auto pair1 = ret->GetColumnValue(0); + EXPECT_EQ(pair1.first, E_STATEMENT_EMPTY); + + errCode = ret->IsReady(); + EXPECT_EQ(errCode, E_OK); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_FullResult, TestSize.Level1) +{ + auto fullResult = std::make_shared(); + EXPECT_NE(fullResult, nullptr); + auto errCode = fullResult->InitData(nullptr); + EXPECT_EQ(errCode, E_STATEMENT_EMPTY); + fullResult = std::make_shared(); + EXPECT_NE(fullResult, nullptr); + auto statement = std::make_shared(nullptr, "", nullptr, errCode); + errCode = fullResult->InitData(statement); + EXPECT_EQ(errCode, E_STEP_CHECK_FAILED); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_EdgeTest, TestSize.Level1) +{ + auto errCode = E_ERROR; + auto edge = std::make_shared(); + EXPECT_NE(edge, nullptr); + edge = std::make_shared(std::make_shared(), "2", "3"); + EXPECT_NE(edge, nullptr); + edge = std::make_shared(nullptr, "2", "3"); + EXPECT_NE(edge, nullptr); + edge = std::make_shared("1", "PERSON", "2", "3"); + EXPECT_NE(edge, nullptr); + edge->SetSourceId("22"); + EXPECT_EQ("22", edge->GetSourceId()); + edge->SetTargetId("33"); + EXPECT_EQ("33", edge->GetTargetId()); + + auto jsonStr = "{\"start\" : 1, \"end\" : 2, \"label\":\"COMPANY\",\"identity\":3," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":2011}}"; + nlohmann::json json = nlohmann::json::parse(jsonStr, nullptr, false); + Edge::Parse(json, errCode); + EXPECT_EQ(errCode, E_OK); + + jsonStr = "{\"start\" : {}, \"end\" : 2, \"label\":\"COMPANY\",\"identity\":3," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":2011}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Edge::Parse(json, errCode); + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); + + jsonStr = "{\"start\" : 1, \"end\" : {}, \"label\":\"COMPANY\",\"identity\":3," + "\"properties\":{\"NAME\":\"myCompany3\",\"FOUNDED\":2011}}"; + json = nlohmann::json::parse(jsonStr, nullptr, false); + Edge::Parse(json, errCode); + EXPECT_EQ(errCode, E_PARSE_JSON_FAILED); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_Connect, TestSize.Level1) +{ + auto errCode = E_ERROR; + errCode = Connection::RegisterCreator(DBType::DB_BUTT, nullptr); + EXPECT_EQ(errCode, E_NOT_SUPPORT); + errCode = Connection::RegisterCreator(static_cast(-1), nullptr); + EXPECT_EQ(errCode, E_NOT_SUPPORT); + auto func = [](const StoreConfig& config, bool isWriter) { + std::pair> ret = std::make_pair( + static_cast(DBType::DB_GRAPH), nullptr); + return ret; + }; + errCode = Connection::RegisterCreator(DBType::DB_GRAPH, func); + EXPECT_EQ(errCode, E_OK); +} + +HWTEST_F(GdbExecuteTest, GdbStore_DBStore01, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "execute_test_ok_2"; + std::string dbPath = "/data"; + auto config = StoreConfig(dbName, dbPath); + + auto store = std::make_shared(config); + EXPECT_NE(store, nullptr); + errCode = store->InitConn(); + EXPECT_EQ(errCode, E_OK); + errCode = store->InitConn(); + EXPECT_EQ(errCode, E_OK); + const std::string gql = "INSERT (:Person {name: 'name_1', age: 11});"; + auto [err, result] = store->QueryGql(gql); + EXPECT_EQ(err, E_GRD_UNDEFINED_PARAM); + auto [err1, result1] = store->ExecuteGql(gql); + EXPECT_EQ(err1, E_GRD_UNDEFINED_PARAM); + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbExecuteTest, GdbStore_NameErre01, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->ExecuteGql("DROP GRAPH test"); + EXPECT_EQ(result.first, E_OK); + + std::string createGql = "CREATE GRAPH test {(person:"; + for (int i = 0; i < 129; ++i) { + createGql += "i"; + } + createGql += " {name STRING, age INT}), (person) -[:FRIEND]-> (person)};"; + result = store_->ExecuteGql(createGql); + EXPECT_EQ(result.first, E_GRD_INVALID_NAME); +} + +HWTEST_F(GdbExecuteTest, GdbStore_NameErre02, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->ExecuteGql("DROP GRAPH test"); + EXPECT_EQ(result.first, E_OK); + + std::string createGql = + "CREATE GRAPH test {(anon_person: Person {name STRING, age INT}), (person) -[:Friend]-> (person)};"; + result = store_->ExecuteGql(createGql); + EXPECT_EQ(result.first, E_GRD_SEMANTIC_ERROR); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Conflict01, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto result = store_->ExecuteGql("DROP GRAPH test"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql( + "CREATE GRAPH test {(person: Person {id INT, name STRING}),(person) -[:Friend]-> (person)};"); + EXPECT_EQ(result.first, E_OK); + + result = store_->ExecuteGql("CREATE UNIQUE INDEX index_person_id ON person(id);"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql("INSERT (:Person {id: 1, name: 'name_1'});"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql("INSERT (:Person {id: 1, name: 'name_2'});"); + EXPECT_EQ(result.first, E_GRD_DATA_CONFLICT); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_UtilsStringTest, TestSize.Level1) +{ + std::string str = "abcd"; + GdbUtils::ClearAndZeroString(str); + EXPECT_EQ(str, ""); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_UtilsConfigTest, TestSize.Level1) +{ + std::vector keys = {1, 2, 3, 4, 5, 6, 7, 8}; + auto ret = GdbUtils::GetConfigStr(keys, false); + EXPECT_EQ(ret, "{\"pageSize\":4, \"crcCheckEnable\":0}"); + ret = GdbUtils::GetConfigStr(keys, true); + EXPECT_EQ(ret, "{\"isEncrypted\":1,\"hexPassword\":\"0102030405060708\",\"pageSize\":4, \"crcCheckEnable\":0}"); +} + +HWTEST_F(GdbExecuteTest, GdbStore_Execute_UtilsKeyTest, TestSize.Level1) +{ + std::vector keys = {1, 2, 3, 4, 5, 6, 7, 8}; + const size_t keyBuffSize = keys.size() * 2 + 1; // 2 hex number can represent a uint8_t, 1 is for '\0' + std::vector keyBuff(keyBuffSize); + auto ret = GdbUtils::GetEncryptKey(keys, keyBuff.data(), keyBuffSize); + std::string hexString(ret, ret + keyBuffSize - 1); + EXPECT_EQ(hexString, "0102030405060708"); +} \ No newline at end of file diff --git a/relational_store/test/native/gdb/unittest/gdb_function_test.cpp b/relational_store/test/native/gdb/unittest/gdb_function_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..289571a2f3aeb748e537b8e3a9e22907445f9ebb --- /dev/null +++ b/relational_store/test/native/gdb/unittest/gdb_function_test.cpp @@ -0,0 +1,204 @@ +/* +* Copyright (c) 2024 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 "GdbFuncTest" +#include + +#include + +#include "aip_errors.h" +#include "connection_pool.h" +#include "gdb_helper.h" +#include "grd_adapter_manager.h" +#include "logger.h" + +using namespace testing::ext; +using namespace OHOS::DistributedDataAip; +class GdbFuncTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void GdbFuncTest::SetUpTestCase() +{ + LOG_INFO("SetUpTestCase"); +} + +void GdbFuncTest::TearDownTestCase() +{ + LOG_INFO("TearDownTestCase"); +} + +void GdbFuncTest::SetUp() +{ + LOG_INFO("SetUp"); + if (!IsSupportArkDataDb()) { + GTEST_SKIP() << "Current testcase is not compatible from current gdb"; + } +} + +void GdbFuncTest::TearDown() +{ + LOG_INFO("TearDown"); +} + +HWTEST_F(GdbFuncTest, GdbStore_Func_OpenClose01, TestSize.Level1) +{ + int errCode = E_OK; + std::string dbName = "testReopendb"; + std::string dbPath = "/data"; + auto config = StoreConfig(dbName, dbPath); + + auto store = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + + auto result = store->QueryGql(""); + EXPECT_NE(result.first, E_OK); + + store->Close(); + result = store->QueryGql("abc"); + EXPECT_NE(result.first, E_OK); + + store = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(errCode, E_OK); + + GDBHelper::DeleteDBStore(config); + + auto store1 = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(store, nullptr); + EXPECT_EQ(errCode, E_OK); + result = store1->ExecuteGql( + "CREATE GRAPH test {(person: Person {name STRING, age INT, sex BOOL DEFAULT false})}"); + EXPECT_EQ(result.first, E_OK); + GDBHelper::DeleteDBStore(config); +} + +HWTEST_F(GdbFuncTest, GdbStore_Func_CreateConnPool01, TestSize.Level1) +{ + int32_t errCode = E_OK; + auto config = StoreConfig("test", "/data", DBType::DB_VECTOR); + auto connectionPool = ConnectionPool::Create(config, errCode); + EXPECT_EQ(errCode, E_NOT_SUPPORT); +} + +HWTEST_F(GdbFuncTest, GdbStore_Func_CreateConnPool02, TestSize.Level1) +{ + int32_t errCode = E_OK; + auto config = StoreConfig("test", "/data", DBType::DB_GRAPH); + config.SetIter(0); + EXPECT_EQ(config.GetIter(), 0); + auto connectionPool = ConnectionPool::Create(config, errCode); + EXPECT_EQ(errCode, E_OK); +} + +HWTEST_F(GdbFuncTest, GdbStore_Func_CreateConnPool03, TestSize.Level1) +{ + int32_t errCode = E_OK; + auto config = StoreConfig("test", "/data", DBType::DB_GRAPH); + config.SetReadConSize(0); + auto connectionPool = ConnectionPool::Create(config, errCode); + EXPECT_EQ(errCode, E_OK); + + auto connRead1 = connectionPool->AcquireRef(true); + EXPECT_NE(connRead1, nullptr); + EXPECT_EQ(connRead1->GetDBType(), DBType::DB_GRAPH); + auto connRead2 = connectionPool->AcquireRef(true); + EXPECT_NE(connRead2, nullptr); + auto connRead3 = connectionPool->AcquireRef(true); + EXPECT_NE(connRead3, nullptr); + + auto connWrite1 = connectionPool->AcquireRef(false); + EXPECT_NE(connWrite1, nullptr); + auto connWrite2 = connectionPool->AcquireRef(false); + EXPECT_NE(connWrite2, nullptr); + auto connWrite3 = connectionPool->AcquireRef(false); + EXPECT_NE(connWrite3, nullptr); + + connWrite1 = nullptr; + connWrite2 = nullptr; + connWrite3 = nullptr; + auto connWrite4 = connectionPool->AcquireRef(false); + EXPECT_NE(connWrite4, nullptr); + + connectionPool->CloseAllConnections(); + + connRead1 = connectionPool->AcquireRef(true); + EXPECT_EQ(connRead1, nullptr); + + connWrite1 = connectionPool->AcquireRef(false); + EXPECT_EQ(connWrite1, nullptr); +} + +HWTEST_F(GdbFuncTest, GdbStore_Func_CreateConnPool04, TestSize.Level1) +{ + int32_t errCode = E_OK; + auto config = StoreConfig("test", "/data", DBType::DB_GRAPH); + config.SetReadConSize(65); + auto connectionPool = ConnectionPool::Create(config, errCode); + EXPECT_EQ(errCode, E_ARGS_READ_CON_OVERLOAD); +} + +HWTEST_F(GdbFuncTest, GdbStore_Func_CreateConnPool05, TestSize.Level1) +{ + int32_t errCode = E_OK; + auto config = StoreConfig("test", "/data", DBType::DB_GRAPH); + auto connectionPool = ConnectionPool::Create(config, errCode); + EXPECT_EQ(errCode, E_OK); + + errCode = connectionPool->Dump(true, "header"); + EXPECT_EQ(errCode, E_OK); + + errCode = connectionPool->RestartReaders(); + EXPECT_EQ(errCode, E_OK); + + auto connRead1 = connectionPool->AcquireRef(true); + EXPECT_NE(connRead1, nullptr); + EXPECT_NE(connRead1->GetId(), -1); + auto connRead2 = connectionPool->AcquireRef(true); + EXPECT_NE(connRead2, nullptr); + auto connRead3 = connectionPool->AcquireRef(true); + EXPECT_NE(connRead3, nullptr); + auto connRead4 = connectionPool->AcquireRef(true); + EXPECT_NE(connRead4, nullptr); + auto connRead5 = connectionPool->AcquireRef(true); + EXPECT_NE(connRead5, nullptr); + auto connRead6 = connectionPool->AcquireRef(true); + EXPECT_NE(connRead6, nullptr); + + auto connWrite1 = connectionPool->AcquireRef(false); + EXPECT_NE(connWrite1, nullptr); + auto connWrite2 = connectionPool->AcquireRef(false); + EXPECT_EQ(connWrite2, nullptr); + auto connWrite3 = connectionPool->AcquireRef(false); + EXPECT_EQ(connWrite3, nullptr); + + connWrite1 = nullptr; + connWrite2 = nullptr; + connWrite3 = nullptr; + auto connWrite4 = connectionPool->AcquireRef(false); + EXPECT_NE(connWrite4, nullptr); + + connectionPool->CloseAllConnections(); + + connRead1 = connectionPool->AcquireRef(true); + EXPECT_EQ(connRead1, nullptr); + + connWrite1 = connectionPool->AcquireRef(false); + EXPECT_EQ(connWrite1, nullptr); +} \ No newline at end of file diff --git a/relational_store/test/native/gdb/unittest/gdb_grdapi_test.cpp b/relational_store/test/native/gdb/unittest/gdb_grdapi_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31fda199c7da17310b767d913baf2131702dbe25 --- /dev/null +++ b/relational_store/test/native/gdb/unittest/gdb_grdapi_test.cpp @@ -0,0 +1,187 @@ +/* +* Copyright (c) 2024 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 "GdbGrdApiTest" +#include +#include + +#include +#include +#include + +#include "aip_errors.h" +#include "db_store_manager.h" +#include "gdb_helper.h" +#include "grd_adapter.h" +#include "grd_adapter_manager.h" +#include "grd_error.h" +#include "logger.h" + +using namespace testing::ext; +using namespace OHOS::DistributedDataAip; +class GdbGrdApiTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void GdbGrdApiTest::SetUpTestCase() +{ + LOG_INFO("SetUpTestCase"); +} + +void GdbGrdApiTest::TearDownTestCase() +{ + LOG_INFO("TearDownTestCase"); +} + +void GdbGrdApiTest::SetUp() +{ + LOG_INFO("SetUp"); + if (!IsSupportArkDataDb()) { + GTEST_SKIP() << "Current testcase is not compatible from current gdb"; + } +} + +void GdbGrdApiTest::TearDown() +{ + LOG_INFO("TearDown"); +} + +HWTEST_F(GdbGrdApiTest, GdbStore_GrdApi_TransType01, TestSize.Level1) +{ + auto type = GrdAdapter::TransColType(GRD_DB_DATATYPE_INTEGER); + EXPECT_EQ(type, ColumnType::TYPE_INTEGER); + type = GrdAdapter::TransColType(GRD_DB_DATATYPE_FLOAT); + EXPECT_EQ(type, ColumnType::TYPE_FLOAT); + type = GrdAdapter::TransColType(GRD_DB_DATATYPE_TEXT); + EXPECT_EQ(type, ColumnType::TYPE_TEXT); + type = GrdAdapter::TransColType(GRD_DB_DATATYPE_BLOB); + EXPECT_EQ(type, ColumnType::TYPE_BLOB); + type = GrdAdapter::TransColType(GRD_DB_DATATYPE_FLOATVECTOR); + EXPECT_EQ(type, ColumnType::TYPE_FLOATVECTOR); + type = GrdAdapter::TransColType(GRD_DB_DATATYPE_JSONSTR); + EXPECT_EQ(type, ColumnType::TYPE_JSONSTR); + type = GrdAdapter::TransColType(GRD_DB_DATATYPE_NULL); + EXPECT_EQ(type, ColumnType::TYPE_NULL); + type = GrdAdapter::TransColType(-1); + EXPECT_EQ(type, ColumnType::TYPE_NULL); + type = GrdAdapter::TransColType(7); + EXPECT_EQ(type, ColumnType::TYPE_NULL); +} + +HWTEST_F(GdbGrdApiTest, GdbStore_GrdApi_NotUsed01, TestSize.Level1) +{ + std::string createGql = "CREATE GRAPH test {(person:Person {name STRING} )};"; + std::string dbPath = "/data/test.db"; + std::string backupPath = "/data/testBackup.db"; + GDBHelper::DeleteDBStore({"test", "/data"}); + if (g_library != nullptr) { + dlclose(g_library); + } + GRD_DB *db = nullptr; + auto ret = GrdAdapter::Open(dbPath.c_str(), "", GRD_DB_OPEN_CREATE, &db); + EXPECT_EQ(ret, E_OK); + + if (g_library != nullptr) { + dlclose(g_library); + } + std::vector entryKey = { 't', 'e', 's', 't' }; + ret = GrdAdapter::Backup(db, backupPath.c_str(), entryKey); + EXPECT_EQ(ret, E_NOT_SUPPORT); + + if (g_library != nullptr) { + dlclose(g_library); + } + ret = GrdAdapter::Close(db, 0); + EXPECT_EQ(ret, E_OK); + + if (g_library != nullptr) { + dlclose(g_library); + } + ret = GrdAdapter::Restore(dbPath.c_str(), backupPath.c_str(), entryKey); + EXPECT_EQ(ret, E_NOT_SUPPORT); + + if (g_library != nullptr) { + dlclose(g_library); + } + ret = GrdAdapter::Repair(dbPath.c_str(), ""); + EXPECT_EQ(ret, E_NOT_SUPPORT); + + if (g_library != nullptr) { + dlclose(g_library); + } + ret = GrdAdapter::Rekey(dbPath.c_str(), "", std::vector()); + EXPECT_EQ(ret, E_GRD_INVALID_ARGS); + GDBHelper::DeleteDBStore({"test", "/data"}); +} + +HWTEST_F(GdbGrdApiTest, GdbStore_GrdApi_NotUsed02, TestSize.Level1) +{ + std::string createGql = "CREATE GRAPH test {(person:Person {name STRING} )};"; + std::string dbPath = "/data/test.db"; + std::string backupPath = "/data/testBackup.db"; + GDBHelper::DeleteDBStore({"test", "/data"}); + GRD_DB *db = nullptr; + if (g_library != nullptr) { + dlclose(g_library); + } + auto ret = GrdAdapter::Open(dbPath.c_str(), "", GRD_DB_OPEN_CREATE, &db); + EXPECT_EQ(ret, E_OK); + + if (g_library != nullptr) { + dlclose(g_library); + } + GRD_Stmt *stmt = nullptr; + ret = GrdAdapter::Prepare(db, createGql.c_str(), createGql.size(), &stmt, nullptr); + EXPECT_EQ(ret, E_OK); + + if (g_library != nullptr) { + dlclose(g_library); + } + ret = GrdAdapter::Reset(stmt); + EXPECT_EQ(ret, E_OK); + + if (g_library != nullptr) { + dlclose(g_library); + } + auto result = GrdAdapter::ColumnBytes(stmt, 0); + EXPECT_EQ(result, 0); + + if (g_library != nullptr) { + dlclose(g_library); + } + auto result2 = GrdAdapter::ColumnInt64(stmt, 0); + EXPECT_EQ(result2, 0); + + result2 = GrdAdapter::ColumnInt(stmt, 0); + EXPECT_EQ(result2, 0); + + auto result3 = GrdAdapter::ColumnDouble(stmt, 0); + EXPECT_EQ(result3, 0.0); + + if (g_library != nullptr) { + dlclose(g_library); + } + auto value = GrdAdapter::ColumnValue(stmt, 0); + EXPECT_EQ(value.type, GRD_DB_DATATYPE_NULL); + ret = StoreManager::GetInstance().Delete(dbPath); + EXPECT_EQ(ret, 1); + ret = StoreManager::GetInstance().Delete(backupPath); + EXPECT_EQ(ret, 1); + GDBHelper::DeleteDBStore({"test", "/data"}); +} \ No newline at end of file diff --git a/relational_store/test/native/gdb/unittest/gdb_multi_thread_test.cpp b/relational_store/test/native/gdb/unittest/gdb_multi_thread_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..85188595cceace2591c5321fbf25ba24a61a2530 --- /dev/null +++ b/relational_store/test/native/gdb/unittest/gdb_multi_thread_test.cpp @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2025 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 +#include +#include +#include + +#include "aip_errors.h" +#include "executor_pool.h" +#include "grd_adapter_manager.h" +#include "gdb_helper.h" +#include "gdb_store.h" +#include "path.h" + +using namespace testing::ext; +using namespace OHOS::DistributedDataAip; +class GdbMultiThreadTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + void VerifyPersonInfo(const GraphValue &person, const std::string &name, const int32_t &age); + void MatchAndVerifyPerson(const std::string &name, const int32_t &age, std::shared_ptr store); + void MultiThreadExecuteInsert(std::shared_ptr store); + void MultiThreadExecuteDBStore(); + void MultiThreadInsertRelation(std::shared_ptr store); + void MultiThreadQueryRelation(std::shared_ptr store); + std::string RandomString(size_t length); + +protected: + std::atomic counter; + static const std::string databaseName; + static const std::string databasePath; + static const std::string createGraphGql; + std::shared_ptr executors_; +}; +const std::string GdbMultiThreadTest::databaseName = "execute_test"; +const std::string GdbMultiThreadTest::databasePath = "/data"; +const std::string GdbMultiThreadTest::createGraphGql = "CREATE GRAPH test { " + "(person:Person {name STRING, age INT, sex BOOL DEFAULT false})," + "(dog:Dog {name STRING, age INT}), " + "(person) -[:Friend]-> (person) " + "};"; + +void GdbMultiThreadTest::SetUpTestCase(void) +{ + if (!IsSupportArkDataDb()) { + GTEST_SKIP() << "Current testcase is not compatible from current gdb"; + return; + } +} + +void GdbMultiThreadTest::TearDownTestCase(void) +{ +} + +void GdbMultiThreadTest::SetUp() +{ + if (!IsSupportArkDataDb()) { + GTEST_SKIP() << "Current testcase is not compatible from current gdb"; + return; + } + int32_t maxThread = 5; + int32_t minThread = 0; + executors_ = std::make_shared(maxThread, minThread); +} + +void GdbMultiThreadTest::TearDown() +{ + executors_ = nullptr; +} + +/** + * @tc.name: MultiThread_GetDBStore_0001 + * @tc.desc: Start two threads to open the database. + * @tc.type: FUNC + */ +HWTEST_F(GdbMultiThreadTest, MultiThread_GetDBStore_0001, TestSize.Level2) +{ + counter.store(0); + MultiThreadExecuteDBStore(); + MultiThreadExecuteDBStore(); + while (true) { + if (counter.load() == 100) { + break; + } + } +} + +/** + * @tc.name: MultiThreadExecuteDBStore + * @tc.desc: Start the database in the current thread for 50 times. + * @tc.type: FUNC + */ +void GdbMultiThreadTest::MultiThreadExecuteDBStore() +{ + executors_->Execute([this]() { + int errCode = E_OK; + std::string dbName = RandomString(10) + RandomString(10); + constexpr int32_t COUNT = 50; + for (uint32_t j = 0; j < COUNT; j++) { + auto config = StoreConfig(dbName + std::to_string(j), databasePath); + GDBHelper::DeleteDBStore(config); + auto store = GDBHelper::GetDBStore(config, errCode); + auto result = store->ExecuteGql(createGraphGql); + EXPECT_NE(store, nullptr); + EXPECT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + + result = store->ExecuteGql("DROP GRAPH test"); + EXPECT_NE(store, nullptr); + EXPECT_EQ(result.first, E_OK); + GDBHelper::DeleteDBStore(config); + counter.fetch_add(1, std::memory_order_relaxed); + } + }); +} + +/** + * @tc.name: MultiThread_GetDBStore_0002 + * @tc.desc: Start two threads to test the insertion Vertex and Edge. + * @tc.type: FUNC + */ +HWTEST_F(GdbMultiThreadTest, MultiThread_GetDBStore_0002, TestSize.Level2) +{ + int errCode = E_OK; + auto config = StoreConfig(databaseName + "test22", databasePath); + auto store = GDBHelper::GetDBStore(config, errCode); + auto result = store->ExecuteGql(createGraphGql); + EXPECT_NE(store, nullptr); + EXPECT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + counter.store(0); + MultiThreadExecuteInsert(store); + sleep(1); + MultiThreadExecuteInsert(store); + while (true) { + // counter ++ 200 + if (counter.load() == 200) { + break; + } + } + sleep(1); + result = store->ExecuteGql("DROP GRAPH test"); + EXPECT_NE(store, nullptr); + EXPECT_EQ(result.first, E_OK); + GDBHelper::DeleteDBStore(config); +} + +/** + * @tc.name: MultiThreadExecuteInsert + * @tc.desc: Start threads to test the insertion Vertex and Edge. + * @tc.type: FUNC + */ +void GdbMultiThreadTest::MultiThreadExecuteInsert(std::shared_ptr store) +{ + executors_->Execute([this, &store]() { + std::string nameStr = RandomString(10) + RandomString(10); + constexpr int32_t MAX_COUNT = 100; + for (uint32_t j = 0; j < MAX_COUNT; j++) { + std::string name = nameStr + std::to_string(j); + auto result = store->ExecuteGql("INSERT (:Person {name: '" + name + "', age: 11});"); + EXPECT_EQ(result.first, E_OK); + constexpr int32_t AGE_11 = 11; + MatchAndVerifyPerson(name, AGE_11, store); + + std::string name2 = name + std::to_string(j); + result = store->ExecuteGql("INSERT (:Person {name: '" + name2 + "', age: 22});"); + EXPECT_EQ(result.first, E_OK); + constexpr int32_t AGE = 22; + MatchAndVerifyPerson(name2, AGE, store); + + std::string name3 = name2 + std::to_string(j); + result = store->ExecuteGql("INSERT (:Person {name: '" + name3 + "', age: 33});"); + EXPECT_EQ(result.first, E_OK); + constexpr int32_t AGE_33 = 33; + MatchAndVerifyPerson(name3, AGE_33, store); + + result = store->ExecuteGql("MATCH (p1:Person {name: '" + name + "'}), (p2:Person {name: '" + name2 + + "'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + result = store->ExecuteGql("MATCH (p1:Person {name: '" + name2 + "'}), (p2:Person {name: '" + name3 + + "'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + + result = store->QueryGql( + "MATCH (person:Person {name: '" + name + "'})-[relation:Friend]->() RETURN person, relation;"); + ASSERT_EQ(result.first, E_OK); + + auto result2 = store->QueryGql("MATCH path=(a:Person {name: '" + name + + "'})-[]->{2, 2}(b:Person {name: '" + name3 + "'}) RETURN path;"); + ASSERT_EQ(result2.first, E_OK); + counter.fetch_add(1, std::memory_order_relaxed); + } + }); +} + +/** + * @tc.name: MultiThread_GetDBStore_0003 + * @tc.desc: Start two threads to insert edges of the same Vertex, and start another thread to query edges. + * @tc.type: FUNC + */ +HWTEST_F(GdbMultiThreadTest, MultiThread_GetDBStore_0003, TestSize.Level2) +{ + int errCode = E_OK; + auto config = StoreConfig(databaseName + "test33", databasePath); + auto store = GDBHelper::GetDBStore(config, errCode); + auto result = store->ExecuteGql(createGraphGql); + EXPECT_NE(store, nullptr); + EXPECT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + counter.store(0); + + std::string name = "zhangsan"; + result = store->ExecuteGql("INSERT (:Person {name: '" + name + "', age: 11});"); + EXPECT_EQ(result.first, E_OK); + constexpr int32_t AGE_11 = 11; + MatchAndVerifyPerson(name, AGE_11, store); + //insert Vertex and edge + MultiThreadInsertRelation(store); + MultiThreadInsertRelation(store); + sleep(1); + //query Vertex and edge + MultiThreadExecuteInsert(store); + while (true) { + if (counter.load() == 300) { + break; + } + } + // query match count is 200 + result = + store->QueryGql("MATCH (person:Person {name: '" + name + "'})-[relation:Friend]->() RETURN person, relation;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 200); + + result = store->ExecuteGql("DROP GRAPH test"); + EXPECT_NE(store, nullptr); + EXPECT_EQ(result.first, E_OK); + GDBHelper::DeleteDBStore(config); +} + +void GdbMultiThreadTest::MultiThreadInsertRelation(std::shared_ptr store) +{ + executors_->Execute([this, &store]() { + std::string nameStr = RandomString(10) + RandomString(10); + std::string name = "zhangsan"; + constexpr int32_t MAX_COUNT = 100; + for (uint32_t j = 0; j < MAX_COUNT; j++) { + std::string name2 = nameStr + std::to_string(j); + auto result = store->ExecuteGql("INSERT (:Person {name: '" + name2 + "', age: 22});"); + EXPECT_EQ(result.first, E_OK); + constexpr int32_t AGE = 22; + MatchAndVerifyPerson(name2, AGE, store); + + result = store->ExecuteGql("MATCH (p1:Person {name: '" + name + "'}), (p2:Person {name: '" + name2 + + "'}) INSERT (p1)-[:Friend]->(p2);"); + EXPECT_EQ(result.first, E_OK); + counter.fetch_add(1, std::memory_order_relaxed); + } + }); +} + +void GdbMultiThreadTest::MultiThreadQueryRelation(std::shared_ptr store) +{ + executors_->Execute([this, &store]() { + std::string name = "zhangsan"; + constexpr int32_t MAX_COUNT = 100; + for (uint32_t j = 0; j < MAX_COUNT; j++) { + auto result = store->QueryGql( + "MATCH (person:Person {name: '" + name + "'})-[relation:Friend]->() RETURN person, relation;"); + ASSERT_EQ(result.first, E_OK); + counter.fetch_add(1, std::memory_order_relaxed); + } + }); +} + +std::string GdbMultiThreadTest::RandomString(size_t length) +{ + const std::string letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> dis(0, letters.size() - 1); + + std::string randomStr; + for (size_t i = 0; i < length; ++i) { + randomStr.push_back(letters[dis(gen)]); + } + return randomStr; +} + +void GdbMultiThreadTest::MatchAndVerifyPerson( + const std::string &name, const int32_t &age, std::shared_ptr store) +{ + EXPECT_NE(store, nullptr); + auto gql = "MATCH (person:Person {name: '" + name + "', age: " + std::to_string(age) + "}) RETURN person;"; + auto result = store->QueryGql(gql); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + ASSERT_EQ(result.second->GetAllData().size(), 1); + GraphValue person = result.second->GetAllData()[0]["person"]; + VerifyPersonInfo(person, name, age); +} + +void GdbMultiThreadTest::VerifyPersonInfo(const GraphValue &person, const std::string &name, const int32_t &age) +{ + auto expectSize = 3; + ASSERT_TRUE(std::holds_alternative>(person)); + auto personVertex = std::get>(person); + EXPECT_EQ(personVertex->GetLabel(), "Person"); + ASSERT_EQ(personVertex->GetProperties().size(), expectSize); + + auto nameDb = personVertex->GetProperties().find("name"); + ASSERT_NE(nameDb, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(nameDb->second)); + EXPECT_EQ(std::get(nameDb->second), name); + + auto ageDb = personVertex->GetProperties().find("age"); + ASSERT_NE(ageDb, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(ageDb->second)); + EXPECT_EQ(std::get(ageDb->second), age); + + auto sex = personVertex->GetProperties().find("sex"); + ASSERT_NE(sex, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(sex->second)); + EXPECT_EQ(std::get(sex->second), 0); +} \ No newline at end of file diff --git a/relational_store/test/native/gdb/unittest/gdb_query_test.cpp b/relational_store/test/native/gdb/unittest/gdb_query_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e1698eac68741683e9479315026043c0fd398ed9 --- /dev/null +++ b/relational_store/test/native/gdb/unittest/gdb_query_test.cpp @@ -0,0 +1,646 @@ +/* +* Copyright (c) 2024 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 +#include +#include +#include + +#include "aip_errors.h" +#include "gdb_helper.h" +#include "gdb_store.h" +#include "grd_adapter_manager.h" + +using namespace testing::ext; +using namespace OHOS::DistributedDataAip; +class GdbQueryTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + void InsertCompany(const std::string &name, const int32_t &founded); + void MatchAndVerifyCompany(const std::string &name, const int32_t &founded); + void VerifyCompanyInfo(const GraphValue &company, const std::string &name, const int32_t &founded); + + static const std::string databaseName; + static const std::string databasePath; + static std::shared_ptr store_; + static const std::string createGraphGql; + static const std::string createGraphGql2; + static const std::shared_ptr databaseConfig; +}; +std::shared_ptr GdbQueryTest::store_; +const std::string GdbQueryTest::databaseName = "test_gdb"; +const std::string GdbQueryTest::databasePath = "/data"; +const std::string GdbQueryTest::createGraphGql = "CREATE GRAPH companyGraph { " + "(company:Company {name STRING, founded INT}), " + "(department:Department {name STRING}), " + "(employee:Employee {name STRING, position STRING}), " + "(project:Project {name STRING, budget INT}), " + "(company) -[:HAS_DEPARTMENT]-> (department), " + "(department) -[:HAS_EMPLOYEE]-> (employee), " + "(employee) -[:WORKS_ON]-> (project), " + "(department) -[:HAS_PROJECT]-> (project) " + "};"; +const std::string GdbQueryTest::createGraphGql2 = "CREATE GRAPH companyGraph2 {" + "(company:Company {name STRING, founded INT}) };"; +void GdbQueryTest::SetUpTestCase() +{ + if (!IsSupportArkDataDb()) { + GTEST_SKIP() << "Current testcase is not compatible from current gdb"; + } + int errCode = E_OK; + auto config = StoreConfig(databaseName, databasePath); + GDBHelper::DeleteDBStore(config); + + GdbQueryTest::store_ = GDBHelper::GetDBStore(config, errCode); + EXPECT_NE(GdbQueryTest::store_, nullptr); + EXPECT_EQ(errCode, E_OK); +} + +void GdbQueryTest::TearDownTestCase() +{ + GDBHelper::DeleteDBStore(StoreConfig(databaseName, databasePath)); + store_ = nullptr; +} + +void GdbQueryTest::SetUp() +{ + if (!IsSupportArkDataDb()) { + GTEST_SKIP() << "Current testcase is not compatible from current gdb"; + } + auto result = store_->ExecuteGql(createGraphGql); + EXPECT_EQ(result.first, E_OK); +} + +void GdbQueryTest::TearDown() +{ + if (store_ != nullptr) { + auto result = store_->ExecuteGql("DROP GRAPH companyGraph"); + } +} + +HWTEST_F(GdbQueryTest, GdbStore_Test_CreateHaveRowId, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + auto createGql = "CREATE GRAPH companyGraph3 {" + "(company:Company {rowid INT, name STRING, founded INT}) };"; + auto result = store_->ExecuteGql(createGql); + EXPECT_EQ(result.first, E_GRD_OVER_LIMIT); +} + +/** + * @tc.name: GdbStore_Test_CreateLimitDb + * @tc.desc: Too many graphs can be created for only one graph in a library. Failed to create too many graphs. + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_Test_CreateLimitDb, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + // Too many graphs can be created for only one graph in a library. Failed to create too many graphs. + auto result = store_->ExecuteGql(createGraphGql2); + EXPECT_EQ(result.first, E_GRD_OVER_LIMIT); +} + +/** + * @tc.name: GdbStore_QuertTest_001 + * @tc.desc: To test the function of querying an employee. + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_001, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + // Insert Employee + const std::string insertEmployeeQuery = "INSERT (:Employee {name: 'John Doe11', position: 'Software Engineer'});"; + auto result = store_->ExecuteGql(insertEmployeeQuery); + EXPECT_EQ(result.first, E_OK); + + // Verifying the Employee Vertex + result = store_->QueryGql("MATCH (e:Employee {name: 'John Doe11'}) RETURN e;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 1); + + GraphValue employee = result.second->GetAllData()[0]["e"]; + ASSERT_TRUE(std::holds_alternative>(employee)); + auto employeeVertex = std::get>(employee); + EXPECT_EQ(employeeVertex->GetLabel(), "Employee"); + + auto name = employeeVertex->GetProperties().find("name"); + ASSERT_NE(name, employeeVertex->GetProperties().end()); + EXPECT_EQ(std::get(name->second), "John Doe11"); + + auto position = employeeVertex->GetProperties().find("position"); + ASSERT_NE(position, employeeVertex->GetProperties().end()); + EXPECT_EQ(std::get(position->second), "Software Engineer"); +} + +/** + * @tc.name: GdbStore_QuertTest_002 + * @tc.desc: To test the function of querying an Employee and Project and Relation. + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_002, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + // insert Employee + auto result = store_->ExecuteGql("INSERT (:Employee {name: 'John Doe', position: 'Software Engineer'});"); + EXPECT_EQ(result.first, E_OK); + // insert Project + result = store_->ExecuteGql("INSERT (:Project {name: 'Project Alpha'});"); + EXPECT_EQ(result.first, E_OK); + + // Associating an Employee with a Project, WORKS_ON + const std::string insertRelationQuery = + "MATCH (e:Employee {name: 'John Doe'}), (p:Project {name: 'Project Alpha'}) " + "INSERT (e)-[:WORKS_ON]->(p);"; + result = store_->ExecuteGql(insertRelationQuery); + EXPECT_EQ(result.first, E_OK); + + // Querying and Verifying the Relationship Existence + result = store_->QueryGql("MATCH (e:Employee {name: 'John Doe'})-[r:WORKS_ON]->" + "(p:Project {name: 'Project Alpha'}) RETURN e, r, p;"); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + + // Verifying the Employee Vertex + GraphValue employee = result.second->GetAllData()[0]["e"]; + ASSERT_TRUE(std::holds_alternative>(employee)); + auto employeeVertex = std::get>(employee); + EXPECT_EQ(employeeVertex->GetLabel(), "Employee"); + + // Verifying Project Vertex + GraphValue project = result.second->GetAllData()[0]["p"]; + ASSERT_TRUE(std::holds_alternative>(project)); + auto projectVertex = std::get>(project); + EXPECT_EQ(projectVertex->GetLabel(), "Project"); + + // Validate Relationships + GraphValue relation = result.second->GetAllData()[0]["r"]; + ASSERT_TRUE(std::holds_alternative>(relation)); + auto relationship = std::get>(relation); + EXPECT_EQ(relationship->GetSourceId(), "1"); + EXPECT_EQ(relationship->GetTargetId(), "2"); +} + +/** + * @tc.name: MatchAndVerifyCompany + * @tc.desc: Match And Verify that company information meets expectations + * @tc.type: FUNC + */ +void GdbQueryTest::MatchAndVerifyCompany(const std::string &name, const int32_t &founded) +{ + ASSERT_NE(store_, nullptr); + auto gql = "MATCH (company:Company {name: '" + name + "'}) RETURN company;"; + auto result = store_->QueryGql(gql); + ASSERT_EQ(result.first, E_OK); + ASSERT_NE(result.second, nullptr); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue company = result.second->GetAllData()[0]["company"]; + VerifyCompanyInfo(company, name, founded); +} + +/** + * @tc.name: VerifyCompanyInfo + * @tc.desc: Verify that company information meets expectations + * @tc.type: FUNC + */ +void GdbQueryTest::VerifyCompanyInfo(const GraphValue &company, const std::string &name, const int32_t &founded) +{ + auto expectSize = 2; + ASSERT_TRUE(std::holds_alternative>(company)); + auto companyVertex = std::get>(company); + EXPECT_EQ(companyVertex->GetLabel(), "Company"); + ASSERT_EQ(companyVertex->GetProperties().size(), expectSize); + + auto nameDb = companyVertex->GetProperties().find("name"); + ASSERT_NE(nameDb, companyVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(nameDb->second)); + EXPECT_EQ(std::get(nameDb->second), name); + + auto foundedDb = companyVertex->GetProperties().find("founded"); + ASSERT_NE(foundedDb, companyVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(foundedDb->second)); + EXPECT_EQ(std::get(foundedDb->second), founded); +} + +/** + * @tc.name: InsertCompany + * @tc.desc: Insert Company Information + * @tc.type: FUNC + */ +void GdbQueryTest::InsertCompany(const std::string &name, const int32_t &founded) +{ + ASSERT_NE(store_, nullptr); + auto result = + store_->ExecuteGql("INSERT (:Company {name: '" + name + "', founded: " + std::to_string(founded) + "});"); + EXPECT_EQ(result.first, E_OK); + MatchAndVerifyCompany(name, founded); +} + +/** + * @tc.name: GdbStore_QuertTest_WhereInMatch + * @tc.desc: Verify the where condition in match. + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_WhereInMatch, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + InsertCompany("myCompany", 1991); + InsertCompany("myCompany2", 2001); + InsertCompany("myCompany3", 2011); + // where condition in match. + auto result = store_->QueryGql("MATCH (company:Company where company.founded > 2000) RETURN company;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 2); + GraphValue company = result.second->GetAllData()[0]["company"]; + VerifyCompanyInfo(company, "myCompany2", 2001); + + GraphValue company1 = result.second->GetAllData()[1]["company"]; + VerifyCompanyInfo(company1, "myCompany3", 2011); +} + +/** + * @tc.name: GdbStore_QuertTest_WhereOutsideMatch + * @tc.desc: Validate where condition outside match + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_WhereOutsideMatch, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + InsertCompany("myCompany", 1991); + InsertCompany("myCompany2", 2001); + InsertCompany("myCompany3", 2011); + // where condition outside match + auto result = store_->QueryGql("MATCH (company:Company) where company.founded != 2001 RETURN company;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 2); + GraphValue company = result.second->GetAllData()[0]["company"]; + VerifyCompanyInfo(company, "myCompany", 1991); + + GraphValue company1 = result.second->GetAllData()[1]["company"]; + VerifyCompanyInfo(company1, "myCompany3", 2011); +} + +/** + * @tc.name: GdbStore_QuertTest_WhereAppendAnd + * @tc.desc: Verify that the where condition is appended to the AND statement outside the match condition. + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_WhereAppendAnd, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + InsertCompany("myCompany", 1991); + InsertCompany("myCompany2", 2001); + InsertCompany("myCompany3", 2011); + // Verify that the where condition is appended to the AND statement outside the match condition. + auto result = store_->QueryGql("MATCH (company:Company) " + "where company.founded != 2001 and company.name <> 'myCompany3' RETURN company;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue company = result.second->GetAllData()[0]["company"]; + VerifyCompanyInfo(company, "myCompany", 1991); +} + +/** + * @tc.name: GdbStore_QuertTest_WhereOutsideAndInsideMatch + * @tc.desc: Validate where conditions outside and inside match + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_WhereOutsideAndInsideMatch, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + InsertCompany("myCompany", 1991); + InsertCompany("myCompany2", 2001); + InsertCompany("myCompany3", 2011); + // Validate where conditions outside and inside match + auto result = store_->QueryGql("MATCH (company:Company where company.founded != 2001 ) " + " where company.name <> 'myCompany3' RETURN company;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue company = result.second->GetAllData()[0]["company"]; + VerifyCompanyInfo(company, "myCompany", 1991); +} + +/** + * @tc.name: GdbStore_QuertTest_WhereStartAnd + * @tc.desc: The validation condition is outside and inside match, but outside it starts with and, not where. + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_WhereStartAnd, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + InsertCompany("myCompany", 1991); + InsertCompany("myCompany2", 2001); + InsertCompany("myCompany3", 2011); + // The validation condition is outside and inside match, but outside it starts with and, not where. + auto result = store_->QueryGql("MATCH (company:Company where company.founded != 2001 ) " + " AND company.name <> 'myCompany3' RETURN company;"); + ASSERT_EQ(result.first, E_GRD_SYNTAX_ERROR); + EXPECT_EQ(result.second->GetAllData().size(), 0); +} + +/** + * @tc.name: GdbStore_QuertTest_WhereByMatch + * @tc.desc: Use {} to transfer query conditions in match. + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_WhereByMatch, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + InsertCompany("myCompany", 1991); + InsertCompany("myCompany2", 2001); + InsertCompany("myCompany3", 2011); + // The validation condition is outside and inside match, but outside it starts with and, not where. + auto result = store_->QueryGql("MATCH (company:Company {founded: 2001} ) " + " where company.name = 'myCompany2' RETURN company;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue company = result.second->GetAllData()[0]["company"]; + VerifyCompanyInfo(company, "myCompany2", 2001); +} + +/** + * @tc.name: GdbStore_QuertTest_WhereOperators + * @tc.desc: Verify that operators are supported in the where condition. + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_WhereOperators, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + InsertCompany("myCompany", 1991); + InsertCompany("myCompany2", 2001); + InsertCompany("myCompany3", 2011); + auto result = store_->QueryGql("MATCH (company:Company) " + "where company.founded >= 2000+1 and company.founded < 2012 -1 RETURN company;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue company = result.second->GetAllData()[0]["company"]; + VerifyCompanyInfo(company, "myCompany2", 2001); + + result = store_->QueryGql("MATCH (company:Company) " + "where company.founded > 2 * 1000 +1 and company.founded < 2 * 1000 +12 RETURN company;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 1); + company = result.second->GetAllData()[0]["company"]; + VerifyCompanyInfo(company, "myCompany3", 2011); +} + +/** + * @tc.name: GdbStore_QuertTest_PostLike + * @tc.desc: Verify that the matching starts with a fixed character and ends with any number of other characters. + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_PostLike, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + InsertCompany("myCompany", 1991); + InsertCompany("myCompany2", 2001); + InsertCompany("aimyCompany", 2011); + auto result = store_->QueryGql("MATCH (company:Company) " + "where company.name like 'myCompany%' RETURN company;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 2); + GraphValue company = result.second->GetAllData()[0]["company"]; + VerifyCompanyInfo(company, "myCompany", 1991); + + company = result.second->GetAllData()[1]["company"]; + VerifyCompanyInfo(company, "myCompany2", 2001); +} + +/** + * @tc.name: GdbStore_QuertTest_WhereLike + * @tc.desc: Matches contain specific characters. + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_Like, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + InsertCompany("myCompany", 1991); + InsertCompany("myCompany2", 2001); + InsertCompany("aimyCompany", 2011); + auto result = store_->QueryGql("MATCH (company:Company) " + "where company.name like '%myCompany%' RETURN company;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 3); + GraphValue company = result.second->GetAllData()[0]["company"]; + VerifyCompanyInfo(company, "myCompany", 1991); + + company = result.second->GetAllData()[1]["company"]; + VerifyCompanyInfo(company, "myCompany2", 2001); + + company = result.second->GetAllData()[2]["company"]; + VerifyCompanyInfo(company, "aimyCompany", 2011); +} + +/** + * @tc.name: GdbStore_QuertTest_BeferLike + * @tc.desc: Matches any number of other characters before the end of a fixed character. + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_BeferLike, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + InsertCompany("myCompany", 1991); + InsertCompany("myCompany2", 2001); + InsertCompany("aimyCompany", 2011); + auto result = store_->QueryGql("MATCH (company:Company) " + "where company.name like '%myCompany' RETURN company;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 2); + GraphValue company = result.second->GetAllData()[0]["company"]; + VerifyCompanyInfo(company, "myCompany", 1991); + + company = result.second->GetAllData()[1]["company"]; + VerifyCompanyInfo(company, "aimyCompany", 2011); +} + +/** + * @tc.name: GdbStore_QuertTest_MatchesCharacter + * @tc.desc: Matches a character + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_MatchesCharacter, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + InsertCompany("myCompany", 1991); + InsertCompany("amyCompany", 2001); + InsertCompany("amyCompanya", 2002); + InsertCompany("abmyCompanyab", 2003); + InsertCompany("abmyCompany", 2004); + auto result = store_->QueryGql("MATCH (company:Company) " + "where company.name like '_myCompany' RETURN company;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue company = result.second->GetAllData()[0]["company"]; + VerifyCompanyInfo(company, "amyCompany", 2001); +} + +/** + * @tc.name: GdbStore_QuertTest_MatchesCharacter02 + * @tc.desc: Matches a character + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_MatchesCharacter02, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + InsertCompany("myCompany", 1991); + InsertCompany("amyCompany", 2001); + InsertCompany("amyCompanya", 2002); + InsertCompany("abmyCompanyab", 2003); + InsertCompany("abmyCompany", 2004); + auto result = store_->QueryGql("MATCH (company:Company) " + "where company.name like '_myCompany_' RETURN company;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue company = result.second->GetAllData()[0]["company"]; + VerifyCompanyInfo(company, "amyCompanya", 2002); +} + +/** + * @tc.name: GdbStore_QuertTest_MatchesCharacter03 + * @tc.desc: Matches a character + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_MatchesCharacter03, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + InsertCompany("myCompany", 1991); + InsertCompany("myCompanya", 2001); + InsertCompany("myCompanyab", 2002); + InsertCompany("amyCompanya", 2003); + auto result = store_->QueryGql("MATCH (company:Company) " + "where company.name like 'myCompany_' RETURN company;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue company = result.second->GetAllData()[0]["company"]; + VerifyCompanyInfo(company, "myCompanya", 2001); +} + +/** + * @tc.name: GdbStore_QuertTest_In + * @tc.desc: Match conditions in + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_In, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + InsertCompany("myCompany", 1991); + InsertCompany("myCompany1", 2001); + InsertCompany("myCompany2", 2002); + auto result = store_->QueryGql("MATCH (company:Company) " + "where company.founded in (2001, 2002, 9999) RETURN company;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 2); + GraphValue company = result.second->GetAllData()[0]["company"]; + VerifyCompanyInfo(company, "myCompany1", 2001); + + company = result.second->GetAllData()[1]["company"]; + VerifyCompanyInfo(company, "myCompany2", 2002); +} + +/** + * @tc.name: GdbStore_QuertTest_In01 + * @tc.desc: Match conditions in + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_NotIn, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + InsertCompany("myCompany", 1991); + InsertCompany("myCompany1", 2001); + InsertCompany("myCompany2", 2002); + auto result = store_->QueryGql("MATCH (company:Company) " + "where company.founded not in (2001, 9999) RETURN company;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 2); + GraphValue company = result.second->GetAllData()[0]["company"]; + VerifyCompanyInfo(company, "myCompany", 1991); + + company = result.second->GetAllData()[1]["company"]; + VerifyCompanyInfo(company, "myCompany2", 2002); +} + +/** + * @tc.name: GdbStore_QuertTest_IsNull + * @tc.desc: Match conditions in + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_IsNull, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto result = store_->ExecuteGql("INSERT (:Employee {name: 'zhangsan', position: 'Software'});"); + EXPECT_EQ(result.first, E_OK); + result = store_->ExecuteGql("INSERT (:Employee {name: 'zhangsan1', position: 'Software1'});"); + EXPECT_EQ(result.first, E_OK); + // 寮簊chemaæ¶“å¬ªå¾æµ æ ¨æ¹­æ¿‰î‚¢ç“§å¨ˆå…¸è´Ÿnull + result = store_->ExecuteGql("MATCH (e:Employee {name: 'zhangsan'}) SET e = {position: 'SoftwareNew'};"); + EXPECT_EQ(result.first, E_OK); + result = store_->QueryGql("MATCH (e:Employee) " + "where e.name IS NULL RETURN e;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 1); + GraphValue company = result.second->GetAllData()[0]["e"]; + ASSERT_TRUE(std::holds_alternative>(company)); + auto companyVertex = std::get>(company); + EXPECT_EQ(companyVertex->GetLabel(), "Employee"); + ASSERT_EQ(companyVertex->GetProperties().size(), 1); + + auto nameDb = companyVertex->GetProperties().find("name"); + EXPECT_EQ(nameDb, companyVertex->GetProperties().end()); + + auto foundedDb = companyVertex->GetProperties().find("position"); + ASSERT_NE(foundedDb, companyVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(foundedDb->second)); + EXPECT_EQ(std::get(foundedDb->second), "SoftwareNew"); +} + +/** + * @tc.name: GdbStore_QuertTest_IsNotNull + * @tc.desc: Match conditions in + * @tc.type: FUNC + */ +HWTEST_F(GdbQueryTest, GdbStore_QuertTest_IsNotNull, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto result = store_->ExecuteGql("INSERT (:Company {founded: 1991});"); + EXPECT_EQ(result.first, E_OK); + InsertCompany("myCompany1", 2001); + InsertCompany("myCompany2", 2002); + result = store_->QueryGql("MATCH (company:Company) " + "where company.name IS NOT NULL RETURN company;"); + ASSERT_EQ(result.first, E_OK); + EXPECT_EQ(result.second->GetAllData().size(), 2); + GraphValue company = result.second->GetAllData()[0]["company"]; + VerifyCompanyInfo(company, "myCompany1", 2001); + + company = result.second->GetAllData()[1]["company"]; + VerifyCompanyInfo(company, "myCompany2", 2002); +} \ No newline at end of file diff --git a/relational_store/test/native/gdb/unittest/gdb_transaction_test.cpp b/relational_store/test/native/gdb/unittest/gdb_transaction_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a964a65f04de8a381eed3ecb6dd3cdbb2b30933 --- /dev/null +++ b/relational_store/test/native/gdb/unittest/gdb_transaction_test.cpp @@ -0,0 +1,603 @@ +/* + * Copyright (c) 2025 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 +#include +#include +#include + +#include "aip_errors.h" +#include "edge.h" +#include "full_result.h" +#include "gdb_helper.h" +#include "gdb_store.h" +#include "grd_adapter_manager.h" +#include "path.h" +#include "result.h" +#include "transaction.h" +#include "vertex.h" + +using namespace testing::ext; +using namespace OHOS::DistributedDataAip; + +using Transaction = OHOS::DistributedDataAip::Transaction; + +class GdbTransactionTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + void InsertPerson(const std::string &name, const int32_t &age, std::shared_ptr trans = nullptr); + void MatchAndVerifyPerson(const std::string &name, const int32_t &age, + std::shared_ptr trans = nullptr, bool hasData = true); + void VerifyPersonInfo(const GraphValue &person, const std::string &name, const int32_t &age); + + static const std::string databaseName; + static const std::string databasePath; + + static const std::string createGraphGql; + + static std::shared_ptr store_; +}; + +const std::string GdbTransactionTest::databaseName = "transaction_test"; +const std::string GdbTransactionTest::databasePath = "/data"; + +const std::string GdbTransactionTest::createGraphGql = "CREATE GRAPH test { " + "(person:Person {name STRING, age INT, sex BOOL DEFAULT false})," + "(dog:Dog {name STRING, age INT}), " + "(person) -[:Friend]-> (person) " + "};"; + +std::shared_ptr GdbTransactionTest::store_; + +static constexpr int32_t MAX_GQL_LEN = 1024 * 1024; + +static constexpr int32_t MAX_CNT = 4; + +void GdbTransactionTest::SetUpTestCase() +{ + if (!IsSupportArkDataDb()) { + GTEST_SKIP() << "Current testcase is not compatible from current gdb"; + return; + } + int errCode = E_OK; + auto config = StoreConfig(databaseName, databasePath); + GDBHelper::DeleteDBStore(config); + + GdbTransactionTest::store_ = GDBHelper::GetDBStore(config, errCode); +} + +void GdbTransactionTest::TearDownTestCase() +{ + GDBHelper::DeleteDBStore(StoreConfig(databaseName, databasePath)); + GdbTransactionTest::store_ = nullptr; +} + +void GdbTransactionTest::SetUp() +{ + if (!IsSupportArkDataDb()) { + GTEST_SKIP() << "Current testcase is not compatible from current gdb"; + return; + } + auto result = store_->ExecuteGql(createGraphGql); +} + +void GdbTransactionTest::TearDown() +{ + if (store_ != nullptr) { + auto result = store_->ExecuteGql("DROP GRAPH test"); + } +} + +void GdbTransactionTest::InsertPerson(const std::string &name, const int32_t &age, std::shared_ptr trans) +{ + ASSERT_NE(store_, nullptr); + int32_t errCode = E_OK; + std::shared_ptr result = std::make_shared(); + std::string gql = "INSERT (:Person {name: '" + name + "', age: " + std::to_string(age) + "});"; + if (trans == nullptr) { + std::tie(errCode, result) = store_->ExecuteGql(gql); + } else { + ASSERT_NE(trans, nullptr); + std::tie(errCode, result) = trans->Execute(gql); + } + EXPECT_EQ(errCode, E_OK); +} + +void GdbTransactionTest::MatchAndVerifyPerson(const std::string &name, const int32_t &age, + std::shared_ptr trans, bool hasData) +{ + ASSERT_NE(store_, nullptr); + int32_t errCode = E_OK; + std::shared_ptr result = std::make_shared(); + std::string gql = "MATCH (person:Person {name: '" + name + "'}) RETURN person;"; + if (trans == nullptr) { + std::tie(errCode, result) = store_->QueryGql(gql); + } else { + ASSERT_NE(trans, nullptr); + std::tie(errCode, result) = trans->Query(gql); + } + ASSERT_EQ(errCode, E_OK); + ASSERT_NE(result, nullptr); + if (!hasData) { + EXPECT_EQ(result->GetAllData().size(), 0); + return; + } + EXPECT_EQ(result->GetAllData().size(), 1); + GraphValue person = result->GetAllData()[0]["person"]; + VerifyPersonInfo(person, name, age); +} + +void GdbTransactionTest::VerifyPersonInfo(const GraphValue &person, const std::string &name, const int32_t &age) +{ + auto expectSize = 3; + ASSERT_TRUE(std::holds_alternative>(person)); + auto personVertex = std::get>(person); + EXPECT_EQ(personVertex->GetLabel(), "Person"); + ASSERT_EQ(personVertex->GetProperties().size(), expectSize); + + auto nameDb = personVertex->GetProperties().find("name"); + ASSERT_NE(nameDb, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(nameDb->second)); + EXPECT_EQ(std::get(nameDb->second), name); + + auto ageDb = personVertex->GetProperties().find("age"); + ASSERT_NE(ageDb, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(ageDb->second)); + EXPECT_EQ(std::get(ageDb->second), age); + + auto sex = personVertex->GetProperties().find("sex"); + ASSERT_NE(sex, personVertex->GetProperties().end()); + ASSERT_TRUE(std::holds_alternative(sex->second)); + EXPECT_EQ(std::get(sex->second), 0); +} + +/** + * @tc.name: GdbTransactionTest001_CreateTransaction_Normal + * @tc.desc: test CreateTransaction + * @tc.type: FUNC + */ +HWTEST_F(GdbTransactionTest, GdbTransactionTest001_CreateTransaction_Normal, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto [err1, trans1] = store_->CreateTransaction(); + EXPECT_EQ(err1, E_OK); + EXPECT_NE(trans1, nullptr); + + auto [err2, trans2] = store_->CreateTransaction(); + EXPECT_EQ(err2, E_OK); + EXPECT_NE(trans2, nullptr); + + auto [err3, trans3] = store_->CreateTransaction(); + EXPECT_EQ(err3, E_OK); + EXPECT_NE(trans3, nullptr); + + auto [err4, trans4] = store_->CreateTransaction(); + EXPECT_EQ(err4, E_OK); + EXPECT_NE(trans4, nullptr); + + err4 = trans4->Commit(); + EXPECT_EQ(err4, E_OK); + + auto [err5, trans5] = store_->CreateTransaction(); + EXPECT_EQ(err5, E_OK); + EXPECT_NE(trans5, nullptr); +} + +/** + * @tc.name: GdbTransactionTest002_CreateTransaction_Abnormal + * @tc.desc: test CreateTransaction upper bound + * @tc.type: FUNC + */ +HWTEST_F(GdbTransactionTest, GdbTransactionTest002_CreateTransaction_Abnormal, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto [err1, trans1] = store_->CreateTransaction(); + EXPECT_EQ(err1, E_OK); + EXPECT_NE(trans1, nullptr); + + auto [err2, trans2] = store_->CreateTransaction(); + EXPECT_EQ(err2, E_OK); + EXPECT_NE(trans2, nullptr); + + auto [err3, trans3] = store_->CreateTransaction(); + EXPECT_EQ(err3, E_OK); + EXPECT_NE(trans3, nullptr); + + auto [err4, trans4] = store_->CreateTransaction(); + EXPECT_EQ(err4, E_OK); + EXPECT_NE(trans4, nullptr); + + auto [err5, trans5] = store_->CreateTransaction(); + EXPECT_EQ(err5, E_DATABASE_BUSY); + EXPECT_EQ(trans5, nullptr); +} + +/** + * @tc.name: GdbTransactionTest003_Query_Execute_Normal + * @tc.desc: test Transaction::Query and Transaction::Execute + * @tc.type: FUNC + */ +HWTEST_F(GdbTransactionTest, GdbTransactionTest003_Query_Execute_Normal, TestSize.Level1) +{ + InsertPerson("name_1", 11); + + auto [err, trans] = store_->CreateTransaction(); + EXPECT_EQ(err, E_OK); + EXPECT_NE(trans, nullptr); + + MatchAndVerifyPerson("name_1", 11, trans); + + InsertPerson("name_2", 22, trans); + + MatchAndVerifyPerson("name_2", 22, trans); +} + +/** + * @tc.name: GdbTransactionTest004_Query_Execute_Abnormal + * @tc.desc: test Transaction::Query and Transaction::Execute with invalid gql + * @tc.type: FUNC + */ +HWTEST_F(GdbTransactionTest, GdbTransactionTest004_Query_Execute_Abnormal, TestSize.Level1) +{ + InsertPerson("name_1", 11); + + auto [err, trans] = store_->CreateTransaction(); + EXPECT_EQ(err, E_OK); + EXPECT_NE(trans, nullptr); + + int32_t errCode = E_OK; + std::shared_ptr result = std::make_shared(); + std::string gql = ""; + std::tie(errCode, result) = trans->Query(gql); + EXPECT_EQ(errCode, E_INVALID_ARGS); + + std::tie(errCode, result) = trans->Execute(gql); + EXPECT_EQ(errCode, E_INVALID_ARGS); + + for (int i = 0; i <= MAX_GQL_LEN; i++) { + gql += "I"; + } + std::tie(errCode, result) = trans->Query(gql); + EXPECT_EQ(errCode, E_INVALID_ARGS); + + std::tie(errCode, result) = trans->Execute(gql); + EXPECT_EQ(errCode, E_INVALID_ARGS); + + gql = "MATCH (person:Person {name: 11}) RETURN person;"; + std::tie(errCode, result) = trans->Query(gql); + EXPECT_EQ(errCode, E_GRD_SEMANTIC_ERROR); + + std::tie(err, trans) = store_->CreateTransaction(); + EXPECT_EQ(err, E_OK); + EXPECT_NE(trans, nullptr); + gql = "INSERT (:Person {name: 11, age: 'name_1'});"; + std::tie(errCode, result) = trans->Execute(gql); + EXPECT_EQ(errCode, E_GRD_SEMANTIC_ERROR); + + std::tie(err, trans) = store_->CreateTransaction(); + EXPECT_EQ(err, E_OK); + EXPECT_NE(trans, nullptr); + gql = "MATCH;"; + std::tie(errCode, result) = trans->Query(gql); + EXPECT_EQ(errCode, E_GRD_SYNTAX_ERROR); + + std::tie(err, trans) = store_->CreateTransaction(); + EXPECT_EQ(err, E_OK); + EXPECT_NE(trans, nullptr); + gql = "INSERT;"; + std::tie(errCode, result) = trans->Execute(gql); + EXPECT_EQ(errCode, E_GRD_SYNTAX_ERROR); +} + +/** + * @tc.name: GdbTransactionTest005_Commit_Normal + * @tc.desc: test Transaction::Commit + * @tc.type: FUNC + */ +HWTEST_F(GdbTransactionTest, GdbTransactionTest005_Commit_Normal, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto [err, trans] = store_->CreateTransaction(); + EXPECT_EQ(err, E_OK); + EXPECT_NE(trans, nullptr); + + InsertPerson("name_1", 11, trans); + + auto gql = "MATCH (person:Person {name: 'name_1'}) RETURN person;"; + auto result = store_->QueryGql(gql); + EXPECT_EQ(result.first, E_DATABASE_BUSY); + + auto errCode = trans->Commit(); + EXPECT_EQ(errCode, E_OK); + + MatchAndVerifyPerson("name_1", 11); +} + +/** + * @tc.name: GdbTransactionTest006_Commit_Abnormal + * @tc.desc: test Transaction::Commit + * @tc.type: FUNC + */ +HWTEST_F(GdbTransactionTest, GdbTransactionTest006_Commit_Abnormal, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto [err, trans] = store_->CreateTransaction(); + EXPECT_EQ(err, E_OK); + ASSERT_NE(trans, nullptr); + + auto errCode = trans->Commit(); + EXPECT_EQ(errCode, E_OK); + + errCode = trans->Commit(); + EXPECT_EQ(errCode, E_GRD_DB_INSTANCE_ABNORMAL); +} + +/** + * @tc.name: GdbTransactionTest007_Rollback_Normal + * @tc.desc: test Transaction::Rollback + * @tc.type: FUNC + */ +HWTEST_F(GdbTransactionTest, GdbTransactionTest007_Rollback_Normal, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto [err, trans] = store_->CreateTransaction(); + EXPECT_EQ(err, E_OK); + EXPECT_NE(trans, nullptr); + + InsertPerson("name_1", 11, trans); + + auto gql = "MATCH (person:Person {name: 'name_1'}) RETURN person;"; + auto result = store_->QueryGql(gql); + EXPECT_EQ(result.first, E_DATABASE_BUSY); + + auto errCode = trans->Rollback(); + EXPECT_EQ(errCode, E_OK); + + MatchAndVerifyPerson("name_1", 11, nullptr, false); +} + +/** + * @tc.name: GdbTransactionTest008_Rollback_Abnormal + * @tc.desc: test Transaction::Rollback + * @tc.type: FUNC + */ +HWTEST_F(GdbTransactionTest, GdbTransactionTest008_Rollback_Abnormal, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto [err, trans] = store_->CreateTransaction(); + EXPECT_EQ(err, E_OK); + ASSERT_NE(trans, nullptr); + + auto errCode = trans->Rollback(); + EXPECT_EQ(errCode, E_OK); + + errCode = trans->Rollback(); + EXPECT_EQ(errCode, E_GRD_DB_INSTANCE_ABNORMAL); +} + +/** + * @tc.name: GdbTransactionTest009_Isolation001 + * @tc.desc: test Transaction + * @tc.type: FUNC + */ +HWTEST_F(GdbTransactionTest, GdbTransactionTest009_Isolation001, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto [err1, trans1] = store_->CreateTransaction(); + EXPECT_EQ(err1, E_OK); + EXPECT_NE(trans1, nullptr); + + auto [err2, trans2] = store_->CreateTransaction(); + EXPECT_EQ(err2, E_OK); + EXPECT_NE(trans2, nullptr); + + InsertPerson("name_1", 11, trans1); + + auto gql = "MATCH (person:Person {name: 'name_1'}) RETURN person;"; + auto [errCode, result] = trans2->Query(gql); + EXPECT_EQ(errCode, E_DATABASE_BUSY); +} + +/** + * @tc.name: GdbTransactionTest010_Isolation002 + * @tc.desc: test Transaction + * @tc.type: FUNC + */ +HWTEST_F(GdbTransactionTest, GdbTransactionTest010_Isolation002, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto [err1, trans1] = store_->CreateTransaction(); + EXPECT_EQ(err1, E_OK); + EXPECT_NE(trans1, nullptr); + + auto [err2, trans2] = store_->CreateTransaction(); + EXPECT_EQ(err2, E_OK); + EXPECT_NE(trans2, nullptr); + + InsertPerson("name_1", 11, trans1); + + ASSERT_NE(trans1, nullptr); + auto errCode = trans1->Commit(); + EXPECT_EQ(errCode, E_OK); + + MatchAndVerifyPerson("name_1", 11, trans2); +} + +/** + * @tc.name: GdbTransactionTest011_Isolation003 + * @tc.desc: test Transaction + * @tc.type: FUNC + */ +HWTEST_F(GdbTransactionTest, GdbTransactionTest011_Isolation003, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto [err1, trans1] = store_->CreateTransaction(); + EXPECT_EQ(err1, E_OK); + EXPECT_NE(trans1, nullptr); + + auto [err2, trans2] = store_->CreateTransaction(); + EXPECT_EQ(err2, E_OK); + EXPECT_NE(trans2, nullptr); + + InsertPerson("name_1", 11, trans1); + + ASSERT_NE(trans1, nullptr); + auto errCode = trans1->Rollback(); + EXPECT_EQ(errCode, E_OK); + + MatchAndVerifyPerson("name_1", 11, trans2, false); +} + +/** + * @tc.name: GdbTransactionTest012_Isolation004 + * @tc.desc: test Transaction + * @tc.type: FUNC + */ +HWTEST_F(GdbTransactionTest, GdbTransactionTest012_Isolation004, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto [err1, trans1] = store_->CreateTransaction(); + EXPECT_EQ(err1, E_OK); + EXPECT_NE(trans1, nullptr); + + auto [err2, trans2] = store_->CreateTransaction(); + EXPECT_EQ(err2, E_OK); + EXPECT_NE(trans2, nullptr); + + InsertPerson("name_1", 11, trans1); + + ASSERT_NE(trans2, nullptr); + int32_t errCode = E_OK; + std::shared_ptr result = std::make_shared(); + std::tie(errCode, result) = trans2->Execute("INSERT (:Person {name: 'name_2', age: 22});"); + EXPECT_EQ(errCode, E_DATABASE_BUSY); + + errCode = trans1->Commit(); + EXPECT_EQ(errCode, E_OK); + + InsertPerson("name_2", 22, trans2); +} + +/** + * @tc.name: GdbTransactionTest013_Close + * @tc.desc: test Close + * @tc.type: FUNC + */ +HWTEST_F(GdbTransactionTest, GdbTransactionTest013_Close, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto [err, trans] = store_->CreateTransaction(); + EXPECT_EQ(err, E_OK); + EXPECT_NE(trans, nullptr); + + InsertPerson("name_1", 11, trans); + + ASSERT_NE(store_, nullptr); + int32_t errCode = store_->Close(); + EXPECT_EQ(errCode, E_OK); + store_ = nullptr; + + auto config = StoreConfig(databaseName, databasePath); + store_ = GDBHelper::GetDBStore(config, errCode); + EXPECT_EQ(errCode, E_OK); + ASSERT_NE(store_, nullptr); + + MatchAndVerifyPerson("name_1", 11, nullptr, false); +} + +/** + * @tc.name: GdbTransactionTest014_StartTransByExecute + * @tc.desc: test Execute("START TRANSACTION;"), Execute("COMMIT") and Execute("ROLLBACK") + * @tc.type: FUNC + */ +HWTEST_F(GdbTransactionTest, GdbTransactionTest014_StartTransByExecute001, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto [err, result] = store_->ExecuteGql("START TRANSACTION;"); + EXPECT_EQ(err, E_INVALID_ARGS); + + std::tie(err, result) = store_->ExecuteGql("COMMIT;"); + EXPECT_EQ(err, E_INVALID_ARGS); + + std::tie(err, result) = store_->ExecuteGql("ROLLBACK;"); + EXPECT_EQ(err, E_INVALID_ARGS); +} + +/** + * @tc.name: GdbTransactionTest015_TransactionNestification + * @tc.desc: test Transaction Nestification + * @tc.type: FUNC + */ +HWTEST_F(GdbTransactionTest, GdbTransactionTest015_TransactionNestification, TestSize.Level1) +{ + ASSERT_NE(store_, nullptr); + + auto [err1, trans1] = store_->CreateTransaction(); + EXPECT_EQ(err1, E_OK); + EXPECT_NE(trans1, nullptr); + + auto result = trans1->Execute("START TRANSACTION;"); + EXPECT_EQ(result.first, E_INVALID_ARGS); +} + +/** + * @tc.name: GdbTransactionTest016_TransactionMultiThread + * @tc.desc: test Transaction MultiThread + * @tc.type: FUNC + */ +HWTEST_F(GdbTransactionTest, GdbTransactionTest016_TransactionMultiThread, TestSize.Level1) +{ + std::thread th[MAX_CNT]; + for (int32_t i = 0; i < MAX_CNT; i++) { + th[i] = std::thread([this, i] () { + ASSERT_NE(store_, nullptr); + + auto [err, trans] = store_->CreateTransaction(); + EXPECT_EQ(err, E_OK); + ASSERT_NE(trans, nullptr); + + InsertPerson("name_" + std::to_string(i), i, trans); + + err = trans->Commit(); + EXPECT_EQ(err, E_OK); + }); + } + + for (int32_t i = 0; i < MAX_CNT; i++) { + th[i].join(); + } + + for (int32_t i = 0; i < MAX_CNT; i++) { + MatchAndVerifyPerson("name_" + std::to_string(i), i); + } +} diff --git a/relational_store/test/native/rdb/BUILD.gn b/relational_store/test/native/rdb/BUILD.gn index 5bf2a26366850e3ddc2887295058b570f96a3c3b..00a203bc4782668988fb30b4e306ea28d8384292 100644 --- a/relational_store/test/native/rdb/BUILD.gn +++ b/relational_store/test/native/rdb/BUILD.gn @@ -32,13 +32,6 @@ config("module_private_config") { ] defines = [ "RELATIONAL_STORE" ] - - if (relational_store_rdb_support_icu) { - include_dirs += [ - "//third_party/icu/icu4c/source/i18n", - "//third_party/icu/icu4c/source/common", - ] - } } ohos_unittest("NativeRdbMultiThreadTest") { @@ -64,15 +57,50 @@ ohos_unittest("NativeRdbMultiThreadTest") { deps = [ "${relational_store_innerapi_path}/rdb:native_rdb", "//third_party/googletest:gtest_main", - "//third_party/icu/icu4c:shared_icui18n", - "//third_party/icu/icu4c:shared_icuuc", "//third_party/sqlite:sqlite", ] } +ohos_unittest("NativeRdbMultiProcessTest") { + module_out_path = module_output_path + + sources = [ + "unittest/common.cpp", + "unittest/multiThread/rdb_store_multiprocess_createDB_test.cpp", + ] + include_dirs = [ + "${relational_store_common_path}/include", + "${relational_store_native_path}/rdb/include", + "${relational_store_innerapi_path}/rdb/include", + "${relational_store_native_path}/dfx/include", + "${relational_store_native_path}/rdb/src", + "${relational_store_innerapi_path}/appdatafwk/include", + ] + + defines = [ "RELATIONAL_STORE" ] + + external_deps = [ + "ability_base:zuri", + "ability_runtime:dataobs_manager", + "c_utils:utils", + "googletest:gtest_main", + "hilog:libhilog", + "huks:libhukssdk", + "ipc:ipc_core", + "kv_store:distributeddb", + "sqlite:sqlite", + ] + + deps = [ "${relational_store_innerapi_path}/rdb:native_rdb" ] +} + ohos_unittest("NativeRdbTest") { module_out_path = module_output_path + cflags = [ + "-fno-access-control", # Ignore Private Member Access Control + ] + sources = [ "unittest/big_integer_test.cpp", "unittest/cache_result_set_test.cpp", @@ -82,6 +110,7 @@ ohos_unittest("NativeRdbTest") { "unittest/rd_utils_test.cpp", "unittest/rdb_attach_test.cpp", "unittest/rdb_bigint_test.cpp", + "unittest/rdb_corrupt_test.cpp", "unittest/rdb_delete_test.cpp", "unittest/rdb_distributed_test.cpp", "unittest/rdb_double_write_test.cpp", @@ -140,6 +169,7 @@ ohos_unittest("NativeRdbTest") { "../../../frameworks/native/rdb/src/share_block.cpp", "../../../frameworks/native/rdb/src/shared_block_serializer_info.cpp", "../../../frameworks/native/rdb/src/sqlite_connection.cpp", + "../../../frameworks/native/rdb/src/sqlite_default_function.cpp", "../../../frameworks/native/rdb/src/sqlite_global_config.cpp", "../../../frameworks/native/rdb/src/sqlite_shared_result_set.cpp", "../../../frameworks/native/rdb/src/sqlite_sql_builder.cpp", @@ -168,8 +198,6 @@ ohos_unittest("NativeRdbTest") { deps = [ "${relational_store_innerapi_path}/rdb:native_rdb", "//third_party/googletest:gtest_main", - "//third_party/icu/icu4c:shared_icui18n", - "//third_party/icu/icu4c:shared_icuuc", "//third_party/sqlite:sqlite", ] } @@ -179,6 +207,7 @@ group("unittest") { testonly = true deps = [ + ":NativeRdbMultiProcessTest", ":NativeRdbMultiThreadTest", ":NativeRdbTest", ] diff --git a/relational_store/test/native/rdb/fuzztest/rdbstore_fuzzer/rdbstore_fuzzer.cpp b/relational_store/test/native/rdb/fuzztest/rdbstore_fuzzer/rdbstore_fuzzer.cpp index 4c6599924732914511d34ffb108ea18591521839..504dc627d3a219713cc05800fc57c49cc94d734d 100644 --- a/relational_store/test/native/rdb/fuzztest/rdbstore_fuzzer/rdbstore_fuzzer.cpp +++ b/relational_store/test/native/rdb/fuzztest/rdbstore_fuzzer/rdbstore_fuzzer.cpp @@ -30,6 +30,7 @@ public: static void TearDownTestCase(void); static bool InsertData(std::shared_ptr &store, const uint8_t *data, size_t size); + static bool BatchInsertData(std::shared_ptr &store, const uint8_t *data, size_t size); static const std::string DATABASE_NAME; static std::shared_ptr store_; @@ -107,8 +108,47 @@ bool RdbInsertFuzz(const uint8_t *data, size_t size) std::shared_ptr &store = RdbStoreFuzzTest::store_; bool result = true; - int errCode = RdbStoreFuzzTest::InsertData(store, data, size); - if (errCode != E_OK) { + if (!RdbStoreFuzzTest::InsertData(store, data, size)) { + result = false; + } + + store->ExecuteSql("DELETE FROM test"); + return result; +} + +bool RdbStoreFuzzTest::BatchInsertData(std::shared_ptr &store, const uint8_t *data, size_t size) +{ + if (data == nullptr) { + return false; + } + + ValuesBuckets rows; + std::string tableName(data, data + size); + std::string valName(data, data + size); + int valAge = static_cast(size); + double valSalary = static_cast(size); + ValuesBucket value; + value.PutString("name", valName); + value.PutInt("age", valAge); + value.PutDouble("salary", valSalary); + value.PutBlob("blobType", std::vector(data, data + size)); + for (auto i = 0; i < static_cast(data[0]); i++) { + rows.Put(value); + } + auto [code, num] = store->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_NONE); + return code == E_OK; +} + +bool RdbBatchInsertFuzz(const uint8_t *data, size_t size) +{ + if (data == nullptr) { + return false; + } + + std::shared_ptr &store = RdbStoreFuzzTest::store_; + bool result = true; + + if (!RdbStoreFuzzTest::BatchInsertData(store, data, size)) { result = false; } diff --git a/relational_store/test/native/rdb/unittest/common.cpp b/relational_store/test/native/rdb/unittest/common.cpp index 7aa22377e43d6d1dba8852ece6d59ca1de6cfea3..6e5630bdea76813e7a2dd34fa17b81ba04472590 100644 --- a/relational_store/test/native/rdb/unittest/common.cpp +++ b/relational_store/test/native/rdb/unittest/common.cpp @@ -16,7 +16,9 @@ #include "common.h" #include +#include +#include "logger.h" #include "rdb_errno.h" namespace OHOS { @@ -77,6 +79,25 @@ ValuesBucket UTUtils::SetRowDatas(const RowDatas &rowDatas) return value; } +bool UTUtils::DestoryDb(const std::string &path, uint64_t offset, const std::vector &bytes) +{ + std::fstream file(path, std::ios::in | std::ios::out | std::ios::binary); + if (!file.is_open()) { + return false; + } + file.seekp(offset, std::ios::beg); + if (!file.good()) { + return false; + } + file.write(bytes.data(), sizeof(bytes)); + if (!file.good()) { + return false; + } + file.close(); + file.flush(); + return true; +} + const RowDatas UTUtils::gRowDatas[14] = { { 1001, "SunWuKong", 4, ValueObject(1004), "2000-12-17", 8000.00, ValueObject(), 20 }, { 1002, "LuJunYi", 3, ValueObject(1006), "2001-02-20", 16000.00, ValueObject(3000.00), 30 }, diff --git a/relational_store/test/native/rdb/unittest/common.h b/relational_store/test/native/rdb/unittest/common.h index f51aa4465ccdb3f5fdbac34603682dc911e9201d..9a6a625c2a77e513519d6c758c11ce872bdbe002 100644 --- a/relational_store/test/native/rdb/unittest/common.h +++ b/relational_store/test/native/rdb/unittest/common.h @@ -51,6 +51,9 @@ public: static ValuesBucket SetRowDatas(const RowDatas &rowDatas); + static bool DestoryDb( + const std::string &path, uint64_t offset = 30, const std::vector &bytes = { 0x0a, 0x0b }); + static const RowData g_rowData[3]; static const RowDatas gRowDatas[14]; diff --git a/relational_store/test/native/rdb/unittest/multiThread/rdb_store_multiprocess_createDB_test.cpp b/relational_store/test/native/rdb/unittest/multiThread/rdb_store_multiprocess_createDB_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37953ba0e1ceefb967544ebd7a055478dc89dac6 --- /dev/null +++ b/relational_store/test/native/rdb/unittest/multiThread/rdb_store_multiprocess_createDB_test.cpp @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2024 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common.h" +#include "rdb_errno.h" +#include "rdb_helper.h" +#include "rdb_open_callback.h" +#include "rdb_store.h" +#include "rdb_store_impl.h" + +using namespace testing::ext; +using namespace testing::mt; +using namespace OHOS::NativeRdb; + +class RdbMultiProcessCreateDBTest : public testing::Test { +public: + static void SetUpTestCase(){}; + static void TearDownTestCase(){}; + void SetUp(){}; + void TearDown(){}; + static const std::string databaseName; + static const std::string createTabSql; + static void Create(); + + class Callback : public RdbOpenCallback { + public: + int OnCreate(RdbStore &rdbStore) override; + int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override; + }; +}; +const std::string RdbMultiProcessCreateDBTest::databaseName = "multi_process_create_test.db"; +const std::string RdbMultiProcessCreateDBTest::createTabSql = + "CREATE TABLE IF NOT EXISTS test " + "(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age INTEGER, salary REAL, blobType BLOB)"; + +static constexpr uint32_t RETRY_COUNT = 2; +static constexpr int32_t SLEEP_TIME = 500; + +int RdbMultiProcessCreateDBTest::Callback::OnCreate(RdbStore &store) +{ + return store.ExecuteSql(createTabSql); +} + +int RdbMultiProcessCreateDBTest::Callback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion) +{ + return E_OK; +} + +void CheckAge(std::shared_ptr &resultSet) +{ + int columnIndex; + int intVal; + ColumnType columnType; + int ret = resultSet->GetColumnIndex("age", columnIndex); + EXPECT_EQ(ret, E_OK); + ret = resultSet->GetColumnType(columnIndex, columnType); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(columnType, ColumnType::TYPE_INTEGER); + ret = resultSet->GetInt(columnIndex, intVal); + EXPECT_EQ(ret, E_OK); + // 18: age is 18 + EXPECT_EQ(18, intVal); +} + +void CheckSalary(std::shared_ptr &resultSet) +{ + int columnIndex; + double dVal; + ColumnType columnType; + int ret = resultSet->GetColumnIndex("salary", columnIndex); + EXPECT_EQ(ret, E_OK); + ret = resultSet->GetColumnType(columnIndex, columnType); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(columnType, ColumnType::TYPE_FLOAT); + ret = resultSet->GetDouble(columnIndex, dVal); + EXPECT_EQ(ret, E_OK); + // 100.5: salary is 100.5 + EXPECT_EQ(100.5, dVal); +} + +void CheckBlob(std::shared_ptr &resultSet) +{ + int columnIndex; + std::vector blob; + ColumnType columnType; + int ret = resultSet->GetColumnIndex("blobType", columnIndex); + EXPECT_EQ(ret, E_OK); + ret = resultSet->GetColumnType(columnIndex, columnType); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(columnType, ColumnType::TYPE_BLOB); + ret = resultSet->GetBlob(columnIndex, blob); + EXPECT_EQ(ret, E_OK); + // 3: blob size + EXPECT_EQ(3, static_cast(blob.size())); + // 1: blob[0] is 1 + EXPECT_EQ(1, blob[0]); + // 2: blob[1] is 2 + EXPECT_EQ(2, blob[1]); + // 3: blob[2] is 3 + EXPECT_EQ(3, blob[2]); +} + +void CheckResultSet(std::shared_ptr &store) +{ + std::shared_ptr resultSet = + store->QuerySql("SELECT * FROM test WHERE name = ?", std::vector{ "zhangsan" }); + EXPECT_NE(resultSet, nullptr); + + int columnIndex; + int intVal; + std::string strVal; + ColumnType columnType; + int position; + int ret = resultSet->GetRowIndex(position); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(position, -1); + + ret = resultSet->GetColumnType(0, columnType); + EXPECT_EQ(ret, E_ROW_OUT_RANGE); + + ret = resultSet->GoToFirstRow(); + EXPECT_EQ(ret, E_OK); + + ret = resultSet->GetColumnIndex("id", columnIndex); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(columnIndex, 0); + ret = resultSet->GetColumnType(columnIndex, columnType); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(columnType, ColumnType::TYPE_INTEGER); + ret = resultSet->GetInt(columnIndex, intVal); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(1, intVal); + + ret = resultSet->GetColumnIndex("name", columnIndex); + EXPECT_EQ(ret, E_OK); + ret = resultSet->GetColumnType(columnIndex, columnType); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(columnType, ColumnType::TYPE_STRING); + ret = resultSet->GetString(columnIndex, strVal); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ("zhangsan", strVal); + + CheckAge(resultSet); + CheckSalary(resultSet); + CheckBlob(resultSet); + + ret = resultSet->Close(); + EXPECT_EQ(ret, E_OK); +} + +void RdbMultiProcessCreateDBTest::Create() +{ + int errCode = E_OK; + RdbStoreConfig config(RDB_TEST_PATH + RdbMultiProcessCreateDBTest::databaseName); + config.SetEncryptStatus(true); + RdbMultiProcessCreateDBTest::Callback helper; + for (uint32_t retry = 0; retry < RETRY_COUNT; ++retry) { + auto store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + EXPECT_TRUE(errCode == E_SQLITE_BUSY || errCode == E_OK); + if (errCode != E_SQLITE_BUSY) { + EXPECT_NE(store, nullptr); + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME)); + } + auto store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + EXPECT_TRUE(errCode == E_SQLITE_BUSY || errCode == E_OK); + ASSERT_NE(store, nullptr); + + int64_t id; + ValuesBucket values; + values.Put("name", "zhangsan"); + // 18: age is 18 + values.Put("age", 18); + // 100.5: salary is 100.5 + values.Put("salary", 100.5); + values.Put("blobType", std::vector{ 1, 2, 3 }); + int ret = store->Insert(id, "test", values); + EXPECT_EQ(ret, E_OK); + + CheckResultSet(store); + // 2: await 2s + std::this_thread::sleep_for(std::chrono::seconds(2)); + RdbHelper::DeleteRdbStore(RDB_TEST_PATH + RdbMultiProcessCreateDBTest::databaseName); +} + +/* * + * @tc.name: Rdb_ConcurrentCreate_001 + * @tc.desc: tow processes create database at the same time + * @tc.type: FUNC + */ +HWTEST_F(RdbMultiProcessCreateDBTest, Rdb_ConcurrentCreate_001, TestSize.Level1) +{ + int pid = fork(); + if (pid == 0) { + Create(); + } else { + Create(); + } +} \ No newline at end of file diff --git a/relational_store/test/native/rdb/unittest/rdb_corrupt_test.cpp b/relational_store/test/native/rdb/unittest/rdb_corrupt_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..944af040cd0b9aa24a3d7bd219f327dc583b2988 --- /dev/null +++ b/relational_store/test/native/rdb/unittest/rdb_corrupt_test.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2024 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 +#include +#include + +#include "common.h" +#include "logger.h" +#include "rdb_errno.h" +#include "rdb_helper.h" +#include "rdb_open_callback.h" + +using namespace testing::ext; +using namespace OHOS::Rdb; +using namespace OHOS::NativeRdb; + +namespace Test { + +class RdbCorruptTest : public testing::Test { +public: + static void SetUpTestCase(void) {} + static void TearDownTestCase(void) {} + void SetUp(); + void TearDown(); + void GenerateData(int count); + static void DestroyDbFile(const std::string &filePath, size_t offset, size_t len, unsigned char ch); + static constexpr const char *DATABASE_NAME = "corrupt_test.db"; + std::shared_ptr store_; +}; + +class CorruptTestOpenCallback : public RdbOpenCallback { +public: + int OnCreate(RdbStore &store) override; + int OnUpgrade(RdbStore &store, int oldVersion, int newVersion) override; + static constexpr const char *CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test " + "(id INTEGER PRIMARY KEY AUTOINCREMENT, " + "name TEXT NOT NULL, age INTEGER, salary " + "REAL, blobType BLOB)"; +}; + +int CorruptTestOpenCallback::OnCreate(RdbStore &store) +{ + return store.ExecuteSql(CREATE_TABLE_TEST); +} + +int CorruptTestOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion) +{ + return E_OK; +} + +void RdbCorruptTest::SetUp(void) +{ + RdbHelper::ClearCache(); + RdbHelper::DeleteRdbStore(RDB_TEST_PATH + DATABASE_NAME); + RdbStoreConfig sqliteSharedRstConfig(RDB_TEST_PATH + DATABASE_NAME); + CorruptTestOpenCallback openCallback; + int errCode = E_OK; + store_ = RdbHelper::GetRdbStore(sqliteSharedRstConfig, 1, openCallback, errCode); + EXPECT_NE(store_, nullptr); + EXPECT_EQ(errCode, E_OK); + // Preset 1000 entries into database file + GenerateData(1000); + store_ = nullptr; + RdbHelper::ClearCache(); +} + +void RdbCorruptTest::TearDown(void) +{ + RdbHelper::ClearCache(); + RdbHelper::DeleteRdbStore(RDB_TEST_PATH + DATABASE_NAME); +} + +void RdbCorruptTest::GenerateData(int count) +{ + for (int64_t i = 0; i < count; i++) { + // Preset data into database + RowData rowData = {1, "test", 18, 100.5, std::vector{ 1, 2, 3 }}; + rowData.id += i; + rowData.name += std::to_string(i + 1); + rowData.salary += i; + int64_t rowId = 0; + auto ret = store_->Insert(rowId, "test", UTUtils::SetRowData(rowData)); + EXPECT_EQ(E_OK, ret); + EXPECT_EQ(i + 1, rowId); + } +} + +void RdbCorruptTest::DestroyDbFile(const std::string &filePath, size_t offset, size_t len, unsigned char ch) +{ + std::fstream f; + f.open(filePath.c_str()); + + f.seekp(offset, std::ios::beg); + std::vector buf(len, ch); + f.write(buf.data(), len); + f.close(); +} + +/** + * @tc.name: RdbCorruptTest001 + * @tc.desc: test Rdb corruption + * @tc.type: FUNC + */ +HWTEST_F(RdbCorruptTest, RdbCorruptTest001, TestSize.Level2) +{ + // Destroy database file, set 1st byte of 3rd page into undefined flag, which indicate the btree page type + RdbCorruptTest::DestroyDbFile(RDB_TEST_PATH + DATABASE_NAME, 8192, 1, 0xFF); + + // Get RDB store failed as database corrupted + CorruptTestOpenCallback sqliteCallback; + RdbStoreConfig sqliteConfig(RDB_TEST_PATH + DATABASE_NAME); + int errCode = E_OK; + store_ = RdbHelper::GetRdbStore(sqliteConfig, 1, sqliteCallback, errCode); + EXPECT_NE(store_, nullptr); + EXPECT_EQ(errCode, E_OK); + + std::shared_ptr resultSet = store_->QueryByStep("SELECT * FROM test"); + EXPECT_NE(resultSet, nullptr); + + while ((errCode = resultSet->GoToNextRow()) == E_OK) { + } + EXPECT_EQ(errCode, E_SQLITE_CORRUPT); +} +} // namespace Test \ No newline at end of file diff --git a/relational_store/test/native/rdb/unittest/rdb_execute_rd_test.cpp b/relational_store/test/native/rdb/unittest/rdb_execute_rd_test.cpp index 1587db1767b749524e1848585cfeefd2861e0b0e..58b218b052895c69c6ef50b986a17c3973307f48 100644 --- a/relational_store/test/native/rdb/unittest/rdb_execute_rd_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_execute_rd_test.cpp @@ -13,6 +13,7 @@ limitations under the License. */ #include +#include #include #include "common.h" @@ -79,6 +80,8 @@ void RdbExecuteRdTest::SetUp(void) RdbStoreConfig config(RdbExecuteRdTest::databaseName); config.SetIsVector(true); config.SetEncryptStatus(GetParam()); + int num = 300; + config.SetNcandidates(num); ExecuteTestOpenRdCallback helper; RdbExecuteRdTest::store = RdbHelper::GetRdbStore(config, 1, helper, errCode); EXPECT_NE(RdbExecuteRdTest::store, nullptr); @@ -91,6 +94,11 @@ void RdbExecuteRdTest::TearDown(void) RdbHelper::DeleteRdbStore(RdbExecuteRdTest::databaseName); } +// éšæœºæ•°ç”Ÿæˆå™¨ +std::random_device g_rd; // 用于获å–éšæœºç§å­ +std::mt19937 g_gen(g_rd()); // ä»¥éšæœºè®¾å¤‡ä½œä¸ºç§å­çš„Mersenne Twister生æˆå™¨ +std::uniform_real_distribution<> dis(-1.0, 1.0); // 定义一个å‡åŒ€åˆ†å¸ƒçš„实数范围 + /** @tc.name: RdbStore_Execute_001 @tc.desc: test RdbStore Execute in vector mode @@ -258,8 +266,10 @@ HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_006, TestSize.Level1) GRD_DB *db2 = nullptr; GRD_DB *db4 = nullptr; - EXPECT_EQ(RdUtils::RdDbOpen(dbPath.c_str(), configStr.c_str(), GRD_DB_OPEN_CREATE, &db2), E_OK); - EXPECT_EQ(RdUtils::RdDbOpen(dbPath.c_str(), configStr.c_str(), GRD_DB_OPEN_CREATE, &db4), E_OK); + EXPECT_EQ(RdUtils::RdDbOpen(dbPath.c_str(), configStr.c_str(), + GRD_DB_OPEN_CREATE | GRD_DB_OPEN_IGNORE_DATA_CORRPUPTION, &db2), E_OK); + EXPECT_EQ(RdUtils::RdDbOpen(dbPath.c_str(), configStr.c_str(), + GRD_DB_OPEN_CREATE | GRD_DB_OPEN_IGNORE_DATA_CORRPUPTION, &db4), E_OK); GRD_SqlStmt *stmt = nullptr; EXPECT_EQ(RdUtils::RdSqlPrepare(db2, sqlCreateTable.c_str(), sqlCreateTable.size(), &stmt, nullptr), E_OK); @@ -924,6 +934,46 @@ HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_018, TestSize.Level1) } } +/** + * @tc.name: RdbStore_Execute_019 + * @tc.desc: test RdbStore Execute in vector mode + * @tc.type: FUNC + */ +HWTEST_P(RdbExecuteRdTest, RdbStore_Execute_019, TestSize.Level1) +{ + std::shared_ptr &store = RdbExecuteRdTest::store; + const char *sqlCreateTable = "CREATE TABLE vecTable(inode int primary key, embedding floatvector(4));"; + auto res = store->Execute(sqlCreateTable); + EXPECT_EQ(E_OK, res.first); + + const char *sqlCreateIndex = "CREATE INDEX diskann_cos_idx ON vecTable USING GSDISKANN(embedding COSINE);"; + res = store->Execute(sqlCreateIndex); + EXPECT_EQ(E_OK, res.first); + + std::string sqlInsert = "INSERT INTO vecTable VALUES(1, '[1,2,-3,4]'), (2, '[2,2,-3,4]'), (3, '[3,2,3,4]'), (4, " + "'[4,2,3,4]'), (5, '[5,2,-3,4]')"; + for (int i = 6; i <= 1000; i++) { + std::string tmpStr = ", (" + std::to_string(i) + ", '[" + std::to_string(dis(g_gen)) + "," + + std::to_string(dis(g_gen)) + "," + std::to_string(dis(g_gen)) + "," + + std::to_string(dis(g_gen)) + "]')"; + sqlInsert.append(tmpStr); + } + sqlInsert.append(";"); + res = store->Execute(sqlInsert); + EXPECT_EQ(E_OK, res.first); + + const char *sqlSelect = "SELECT inode, embedding, embedding<=>'[1,1,1,1]' AS score FROM vecTable ORDER BY " + "embedding<=>'[1,1,1,1]' LIMIT 501;"; + std::shared_ptr resultSet = store->QueryByStep(sqlSelect, std::vector()); + EXPECT_NE(resultSet, nullptr); + int count = 0; + resultSet->GetRowCount(count); + EXPECT_EQ(count, 299); + const char *sqlDelete = "DELETE FROM vecTable"; + res = store->Execute(sqlDelete); + EXPECT_EQ(E_OK, res.first); +} + /* * * @tc.name: Rdb_BackupRestoreTest_001 * @tc.desc: backup and restore @@ -990,4 +1040,14 @@ HWTEST_P(RdbExecuteRdTest, Rdb_BackupRestoreTest_001, TestSize.Level2) RdbHelper::DeleteRdbStore(RdbExecuteRdTest::restoreDatabaseName); RdbHelper::DeleteRdbStore(RdbExecuteRdTest::backupDatabaseName); +} + +/* * + * @tc.name: Rdb_IsUsingArkDataTest_001 + * @tc.desc: IsUsingArkData function test + * @tc.type: FUNC + */ +HWTEST_P(RdbExecuteRdTest, Rdb_IsUsingArkDataTest_001, TestSize.Level2) +{ + EXPECT_EQ(OHOS::NativeRdb::RdbHelper::IsSupportArkDataDb(), true); } \ No newline at end of file diff --git a/relational_store/test/native/rdb/unittest/rdb_helper_test.cpp b/relational_store/test/native/rdb/unittest/rdb_helper_test.cpp index 4b67b04c4ba44904b1af31e5a19f11a5ae7b878e..a79afd0c4a37a82085904525fa3c952a4edd906f 100644 --- a/relational_store/test/native/rdb/unittest/rdb_helper_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_helper_test.cpp @@ -44,9 +44,13 @@ public: static void TearDownTestCase(void); void SetUp(); void TearDown(); + void InitDb(); + static const std::string rdbStorePath; + static std::shared_ptr store; }; const std::string RdbHelperTest::rdbStorePath = RDB_TEST_PATH + std::string("rdbhelper.db"); +std::shared_ptr RdbHelperTest::store = nullptr; void RdbHelperTest::SetUpTestCase(void) { @@ -79,6 +83,15 @@ public: static const std::string CREATE_TABLE_TEST; }; +void RdbHelperTest::InitDb() +{ + int errCode = E_OK; + RdbStoreConfig config(RdbHelperTest::rdbStorePath); + RdbHelperTestOpenCallback helper; + RdbHelperTest::store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + EXPECT_NE(store, nullptr); +} + const std::string RdbHelperTestWrongSqlOpenCallback::WRONG_SQL_TEST = "CREATE TABL IF NOT EXISTS test " "(id INTEGER PRIMARY KEY AUTOINCREMENT, " "name TEXT NOT NULL, age INTEGER, salary REAL, " @@ -192,6 +205,415 @@ HWTEST_F(RdbHelperTest, DeleteDatabase_003, TestSize.Level1) EXPECT_NE(access(walFileName.c_str(), F_OK), 0); } +/** + * @tc.name: DeleteDatabase_004 + * @tc.desc: Update after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_004, TestSize.Level0) +{ + InitDb(); + int64_t id; + int changedRows; + ValuesBucket values; + + values.PutInt("id", 1); + values.PutString("name", std::string("zhangsan")); + values.PutInt("age", 18); + values.PutDouble("salary", 100.5); + values.PutBlob("blobType", std::vector{ 1, 2, 3 }); + int ret = store->Insert(id, "test", values); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(1, id); + + ret = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(ret, E_OK); + + values.Clear(); + values.PutInt("id", 2); + values.PutString("name", std::string("lisi")); + values.PutInt("age", 19); + values.PutDouble("salary", 200.5); + values.PutBlob("blobType", std::vector{ 4, 5, 6 }); + ret = store->Update(changedRows, "test", values, "id = ?", std::vector{ "1" }); + EXPECT_EQ(ret, E_ALREADY_CLOSED); +} + +/** + * @tc.name: DeleteDatabase_005 + * @tc.desc: Insert after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_005, TestSize.Level0) +{ + InitDb(); + int64_t id; + ValuesBucket values; + + int ret = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(ret, E_OK); + + values.PutInt("id", 1); + values.PutString("name", std::string("zhangsan")); + values.PutInt("age", 18); + values.PutDouble("salary", 100.5); + values.PutBlob("blobType", std::vector{ 1, 2, 3 }); + ret = store->Insert(id, "test", values); + EXPECT_EQ(ret, E_ALREADY_CLOSED); +} + +/** + * @tc.name: DeleteDatabase_006 + * @tc.desc: BatchInsert after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_006, TestSize.Level0) +{ + InitDb(); + int64_t id; + ValuesBucket values; + + int ret = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(ret, E_OK); + + values.PutInt("id", 1); + values.PutString("name", std::string("zhangsan")); + values.PutInt("age", 18); + values.PutDouble("salary", 100.5); + values.PutBlob("blobType", std::vector{ 1, 2, 3 }); + + std::vector valuesBuckets; + for (int i = 0; i < 10; i++) { + valuesBuckets.push_back(values); + } + ret = store->BatchInsert(id, "test", valuesBuckets); + EXPECT_EQ(ret, E_ALREADY_CLOSED); +} + +/** + * @tc.name: DeleteDatabase_007 + * @tc.desc: Delete after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_007, TestSize.Level0) +{ + InitDb(); + int64_t id; + int deletedRows; + ValuesBucket values; + + values.PutInt("id", 1); + values.PutString("name", std::string("zhangsan")); + values.PutInt("age", 18); + values.PutDouble("salary", 100.5); + values.PutBlob("blobType", std::vector{ 1, 2, 3 }); + int ret = store->Insert(id, "test", values); + EXPECT_EQ(ret, E_OK); + + ret = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(ret, E_OK); + + ret = store->Delete(deletedRows, "test", "id = 1"); + EXPECT_EQ(ret, E_ALREADY_CLOSED); +} + +/** + * @tc.name: DeleteDatabase_008 + * @tc.desc: QuerySql after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_008, TestSize.Level0) +{ + InitDb(); + int ret = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(ret, E_OK); + + std::shared_ptr resultSet = + store->QuerySql("SELECT * FROM test WHERE id = ?", std::vector{ "1" }); + EXPECT_EQ(resultSet, nullptr); +} + +/** + * @tc.name: DeleteDatabase_009 + * @tc.desc: QueryByStep after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_009, TestSize.Level0) +{ + InitDb(); + int ret = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(ret, E_OK); + + std::shared_ptr resultSet = + store->QueryByStep("SELECT * FROM test WHERE id = ?", std::vector{ "1" }); + EXPECT_EQ(resultSet, nullptr); +} + +/** + * @tc.name: DeleteDatabase_010 + * @tc.desc: Restore after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_010, TestSize.Level0) +{ + InitDb(); + int ret = store->Backup("backup.db"); + EXPECT_EQ(ret, E_OK); + + ret = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(ret, E_OK); + + ret = store->Restore("backup.db"); + EXPECT_EQ(ret, E_ALREADY_CLOSED); + + RdbHelper::DeleteRdbStore(RDB_TEST_PATH + std::string("backup.db")); +} + +/** + * @tc.name: DeleteDatabase_011 + * @tc.desc: Backup after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_011, TestSize.Level0) +{ + InitDb(); + int ret = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(ret, E_OK); + + ret = store->Backup("backup.db"); + EXPECT_EQ(ret, E_DB_NOT_EXIST); +} + +/** + * @tc.name: DeleteDatabase_012 + * @tc.desc: CleanDirtyData after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_012, TestSize.Level0) +{ + InitDb(); + int ret = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(ret, E_OK); + + uint64_t cursor = UINT64_MAX; + ret = store->CleanDirtyData("test", cursor); + EXPECT_EQ(ret, E_ALREADY_CLOSED); +} + +/** + * @tc.name: DeleteDatabase_013 + * @tc.desc: ExecuteSql after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_013, TestSize.Level0) +{ + InitDb(); + int ret = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(ret, E_OK); + + ret = store->ExecuteSql(RdbHelperTestOpenCallback::CREATE_TABLE_TEST); + EXPECT_EQ(ret, E_ALREADY_CLOSED); +} + +/** + * @tc.name: DeleteDatabase_014 + * @tc.desc: Execute after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_014, TestSize.Level0) +{ + InitDb(); + int ret1 = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(ret1, E_OK); + + auto [ret2, outValue] = store->Execute(RdbHelperTestOpenCallback::CREATE_TABLE_TEST); + EXPECT_EQ(ret2, E_ALREADY_CLOSED); +} + +/** + * @tc.name: DeleteDatabase_015 + * @tc.desc: BeginTransaction after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_015, TestSize.Level0) +{ + InitDb(); + int ret = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(ret, E_OK); + + ret = store->BeginTransaction(); + EXPECT_EQ(ret, E_ALREADY_CLOSED); +} + +/** + * @tc.name: DeleteDatabase_016 + * @tc.desc: Attach after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_016, TestSize.Level0) +{ + InitDb(); + int ret = 0; + std::string attachPath = RDB_TEST_PATH + std::string("attached.db"); + RdbStoreConfig attachedConfig(attachPath); + RdbHelperTestOpenCallback attachedHelper; + std::shared_ptr attachedStore = RdbHelper::GetRdbStore(attachedConfig, 1, attachedHelper, ret); + EXPECT_NE(attachedStore, nullptr); + + ret = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(ret, E_OK); + + int busyTimeout = 2; + std::string attachedName = "attached"; + auto err = store->Attach(attachedConfig, attachedName, busyTimeout); + EXPECT_EQ(err.first, E_ALREADY_CLOSED); + + RdbHelper::DeleteRdbStore(attachPath); +} + +/** + * @tc.name: DeleteDatabase_017 + * @tc.desc: Detach after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_017, TestSize.Level0) +{ + InitDb(); + int ret = 0; + std::string attachPath = RDB_TEST_PATH + std::string("attached.db"); + RdbStoreConfig attachedConfig(attachPath); + RdbHelperTestOpenCallback attachedHelper; + std::shared_ptr attachedStore = RdbHelper::GetRdbStore(attachedConfig, 1, attachedHelper, ret); + EXPECT_NE(attachedStore, nullptr); + + int busyTimeout = 2; + std::string attachedName = "attached"; + auto err = store->Attach(attachedConfig, attachedName, busyTimeout); + EXPECT_EQ(err.first, E_OK); + + ret = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(ret, E_OK); + + err = store->Detach(attachedName); + EXPECT_EQ(err.first, E_ALREADY_CLOSED); + + RdbHelper::DeleteRdbStore(attachPath); +} + +/** + * @tc.name: DeleteDatabase_018 + * @tc.desc: CreateTransaction after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_018, TestSize.Level0) +{ + InitDb(); + int err = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(err, E_OK); + + auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret, E_ALREADY_CLOSED); + ASSERT_EQ(transaction, nullptr); +} + +/** + * @tc.name: DeleteDatabase_019 + * @tc.desc: BeginTrans after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_019, TestSize.Level0) +{ + InitDb(); + int err = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(err, E_OK); + + auto ret = store->BeginTrans(); + ASSERT_EQ(ret.first, E_NOT_SUPPORT); +} + +/** + * @tc.name: DeleteDatabase_020 + * @tc.desc: Commit after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_020, TestSize.Level0) +{ + InitDb(); + int ret = store->BeginTransaction(); + EXPECT_EQ(ret, E_OK); + + ret = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(ret, E_OK); + + ret = store->Commit(); + ASSERT_EQ(ret, E_ALREADY_CLOSED); +} + +/** + * @tc.name: DeleteDatabase_021 + * @tc.desc: GetModifyTime after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_021, TestSize.Level0) +{ + InitDb(); + store->ExecuteSql("CREATE TABLE naturalbase_rdb_aux_rdbstoreimpltest_integer_log " + "(id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER, data_key INTEGER, " + "data3 FLOAT, data4 BLOB, data5 BOOLEAN);"); + int64_t rowId; + ValuesBucket valuesBucket; + valuesBucket.PutInt("data_key", ValueObject(2)); + int errorCode = store->Insert(rowId, "naturalbase_rdb_aux_rdbstoreimpltest_integer_log", valuesBucket); + EXPECT_EQ(E_OK, errorCode); + EXPECT_EQ(1, rowId); + + errorCode = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(errorCode, E_OK); + + std::vector PKey = { 1 }; + std::map result = + store->GetModifyTime("rdbstoreimpltest_integer", "ROWID", PKey); + int size = result.size(); + EXPECT_EQ(0, size); +} + +/** + * @tc.name: DeleteDatabase_022 + * @tc.desc: RollBack after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_022, TestSize.Level0) +{ + InitDb(); + int ret = store->BeginTransaction(); + EXPECT_EQ(ret, E_OK); + + ret = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(ret, E_OK); + + ret = store->RollBack(); + ASSERT_EQ(ret, E_ALREADY_CLOSED); +} + +/** + * @tc.name: DeleteDatabase_023 + * @tc.desc: Transaction insert after deleteRdbStore + * @tc.type: FUNC + */ +HWTEST_F(RdbHelperTest, DeleteDatabase_023, TestSize.Level0) +{ + InitDb(); + auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + int err = RdbHelper::DeleteRdbStore(RdbHelperTest::rdbStorePath); + EXPECT_EQ(err, E_OK); + + auto result = transaction->Insert("test", UTUtils::SetRowData(UTUtils::g_rowData[0])); + ASSERT_EQ(result.first, E_ALREADY_CLOSED); +} + /** * @tc.name: getrdbstore_001 * @tc.desc: get db file with a invalid path @@ -209,7 +631,7 @@ HWTEST_F(RdbHelperTest, GetDatabase_001, TestSize.Level0) HWTEST_F(RdbHelperTest, GetDatabase_002, TestSize.Level0) { - const std::string dbPath = RDB_TEST_PATH + "GetDatabase.db"; + const std::string dbPath = RDB_TEST_PATH + "GetDatabase002.db"; RdbStoreConfig config(dbPath); std::string bundleName = "com.ohos.config.GetDatabase"; config.SetBundleName(bundleName); @@ -234,7 +656,7 @@ HWTEST_F(RdbHelperTest, GetDatabase_002, TestSize.Level0) HWTEST_F(RdbHelperTest, GetDatabase_003, TestSize.Level0) { - const std::string dbPath = RDB_TEST_PATH + "GetDatabase.db"; + const std::string dbPath = RDB_TEST_PATH + "GetDatabase003.db"; RdbStoreConfig config(dbPath); std::string bundleName = "com.ohos.config.GetDatabase"; config.SetBundleName(bundleName); @@ -258,15 +680,12 @@ HWTEST_F(RdbHelperTest, GetDatabase_003, TestSize.Level0) ASSERT_NE(rdbStore2, nullptr); // Ensure that two databases will not be opened after the encrypt parameters are changed - errCode = rdbStore1->BeginTransaction(); - EXPECT_EQ(errCode, E_OK); - errCode = rdbStore2->BeginTransaction(); - EXPECT_EQ(errCode, E_OK); + EXPECT_EQ(rdbStore1, rdbStore2); } HWTEST_F(RdbHelperTest, GetDatabase_004, TestSize.Level0) { - const std::string dbPath = RDB_TEST_PATH + "GetDatabase.db"; + const std::string dbPath = RDB_TEST_PATH + "GetDatabase004.db"; RdbStoreConfig config(dbPath); std::string bundleName = "com.ohos.config.GetDatabase"; config.SetBundleName(bundleName); @@ -287,4 +706,69 @@ HWTEST_F(RdbHelperTest, GetDatabase_004, TestSize.Level0) std::shared_ptr rdbStore2 = RdbHelper::GetRdbStore(config, 1, helper, errCode); EXPECT_NE(errCode, E_OK); EXPECT_EQ(rdbStore2, nullptr); -} \ No newline at end of file +} +// +//HWTEST_F(RdbHelperTest, GetDatabase_007, TestSize.Level0) +//{ +// const std::string dbPath = RDB_TEST_PATH + "GetDatabase007.db"; +// RdbStoreConfig config(dbPath); +// std::string bundleName = "com.ohos.config.GetDatabase"; +// config.SetBundleName(bundleName); +// +// // Ensure that the database returns OK when it is successfully opened +// int errCode = E_ERROR; +// +// RdbHelperTestOpenCallback helper; +// std::shared_ptr rdbStore = RdbHelper::GetRdbStore(config, 1, helper, errCode); +// EXPECT_EQ(errCode, E_OK); +// ASSERT_NE(rdbStore, nullptr); +// rdbStore = nullptr; +// +// ASSERT_TRUE(UTUtils::DestoryDb(dbPath)); +// +// config.SetVisitorDir(dbPath); +// config.SetRoleType(RoleType::VISITOR_WRITE); +// config.SetAllowRebuild(true); +// rdbStore = RdbHelper::GetRdbStore(config, 1, helper, errCode); +// EXPECT_NE(errCode, E_OK); +// ASSERT_EQ(rdbStore, nullptr); +// +// config.SetRoleType(RoleType::OWNER); +// rdbStore = RdbHelper::GetRdbStore(config, 1, helper, errCode); +// EXPECT_EQ(errCode, E_OK); +// ASSERT_NE(rdbStore, nullptr); +// RebuiltType type; +// EXPECT_EQ(rdbStore->GetRebuilt(type), E_OK); +// EXPECT_EQ(type, RebuiltType::REBUILT); +// EXPECT_FALSE(Reportor::IsFlagExist(dbPath)); +//} +// +//HWTEST_F(RdbHelperTest, GetDatabase_008, TestSize.Level0) +//{ +// const std::string dbPath = RDB_TEST_PATH + "GetDatabase008.db"; +// RdbHelper::DeleteRdbStore(dbPath); +// +// RdbStoreConfig config(dbPath); +// std::string bundleName = "com.ohos.config.GetDatabase"; +// config.SetBundleName(bundleName); +// +// const std::string visitorDb = RDB_TEST_PATH + "visitorDb.db"; +// RdbHelper::DeleteRdbStore(visitorDb); +// +// config.SetVisitorDir(visitorDb); +// config.SetRoleType(RoleType::VISITOR_WRITE); +// config.SetAllowRebuild(true); +// +// // Ensure that the database returns OK when it is successfully opened +// int errCode = E_ERROR; +// RdbHelperTestOpenCallback helper; +// auto visitWriterStore = RdbHelper::GetRdbStore(config, 1, helper, errCode); +// EXPECT_EQ(errCode, E_OK); +// ASSERT_NE(visitWriterStore, nullptr); +// +// config.SetRoleType(RoleType::OWNER); +// auto ownerStore = RdbHelper::GetRdbStore(config, 1, helper, errCode); +// EXPECT_NE(errCode, E_OK); +// ASSERT_EQ(ownerStore, nullptr); +// EXPECT_NE(visitWriterStore, ownerStore); +//} \ No newline at end of file diff --git a/relational_store/test/native/rdb/unittest/rdb_read_only_test.cpp b/relational_store/test/native/rdb/unittest/rdb_read_only_test.cpp index 21f6b8228ccb3b570c635d866e51bb1800d30ab0..1552f2f9883260fcf1bbb62a128ef3fdde510ed2 100644 --- a/relational_store/test/native/rdb/unittest/rdb_read_only_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_read_only_test.cpp @@ -510,6 +510,35 @@ HWTEST_F(RdbReadOnlyTest, RdbStore_ReadOnly_0022, TestSize.Level1) EXPECT_EQ(E_NOT_SUPPORT, ret); } +/** + * @tc.name: RdbStore_ReadOnly_0023 + * @tc.desc: test BatchInsertWithConflictResolution + * @tc.type: FUNC + */ +HWTEST_F(RdbReadOnlyTest, RdbStore_ReadOnly_0023, TestSize.Level1) +{ + std::shared_ptr &store = RdbReadOnlyTest::readOnlyStore; + + ValuesBuckets rows; + for (int i = 0; i < 5; i++) { + ValuesBucket row; + row.Put("name", "Jim"); + rows.Put(row); + } + auto ret = store->BatchInsertWithConflictResolution("test", rows, ConflictResolution::ON_CONFLICT_NONE); + EXPECT_EQ(E_NOT_SUPPORT, ret.first); + ret = store->BatchInsertWithConflictResolution("test", rows, ConflictResolution::ON_CONFLICT_ROLLBACK); + EXPECT_EQ(E_NOT_SUPPORT, ret.first); + ret = store->BatchInsertWithConflictResolution("test", rows, ConflictResolution::ON_CONFLICT_ABORT); + EXPECT_EQ(E_NOT_SUPPORT, ret.first); + ret = store->BatchInsertWithConflictResolution("test", rows, ConflictResolution::ON_CONFLICT_FAIL); + EXPECT_EQ(E_NOT_SUPPORT, ret.first); + ret = store->BatchInsertWithConflictResolution("test", rows, ConflictResolution::ON_CONFLICT_IGNORE); + EXPECT_EQ(E_NOT_SUPPORT, ret.first); + ret = store->BatchInsertWithConflictResolution("test", rows, ConflictResolution::ON_CONFLICT_REPLACE); + EXPECT_EQ(E_NOT_SUPPORT, ret.first); +} + /** * @tc.name: RdbStore_CreateTransaction_001 * @tc.desc: test Create Transaction diff --git a/relational_store/test/native/rdb/unittest/rdb_sqlite_shared_result_set_test.cpp b/relational_store/test/native/rdb/unittest/rdb_sqlite_shared_result_set_test.cpp index 759d0f35b81750b933de5ae39434e46c38790e0d..fb785a1caa06fc23781065485c0143e218741eca 100644 --- a/relational_store/test/native/rdb/unittest/rdb_sqlite_shared_result_set_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_sqlite_shared_result_set_test.cpp @@ -752,8 +752,9 @@ HWTEST_F(RdbSqliteSharedResultSetTest, Sqlite_Shared_Result_Set_009, TestSize.Le rstSet->GetColumnIndex("data4", colIndex); EXPECT_EQ(colIndex, 4); - rstSet->GetColumnIndex("datax", colIndex); + int errCode = rstSet->GetColumnIndex("datax", colIndex); EXPECT_EQ(colIndex, -1); + EXPECT_EQ(errCode, E_INVALID_ARGS); rstSet->Close(); bool isClosedFlag = rstSet->IsClosed(); diff --git a/relational_store/test/native/rdb/unittest/rdb_step_result_set_test.cpp b/relational_store/test/native/rdb/unittest/rdb_step_result_set_test.cpp index d997686a29c51f3ed7cf33631dd03cf6540ef5a0..1a9b1dc99926eaa811727aca5b0374aad91cd3b2 100644 --- a/relational_store/test/native/rdb/unittest/rdb_step_result_set_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_step_result_set_test.cpp @@ -775,7 +775,7 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_014, TestSize.Level1) EXPECT_EQ(1, columnIndex); iRet = resultSet->GetColumnIndex("datax", columnIndex); - EXPECT_EQ(E_ERROR, iRet); + EXPECT_EQ(E_INVALID_ARGS, iRet); EXPECT_EQ(-1, columnIndex); } @@ -1658,6 +1658,129 @@ HWTEST_F(RdbStepResultSetTest, testSqlStep022, TestSize.Level1) resultSet->Close(); } + +/* * + * @tc.name: RdbStore_StepResultSet_023 + * @tc.desc: normal testcase of StepResultSet + * @tc.type: FUNC + * @tc.require: AR000FKD4F + */ +HWTEST_F(RdbStepResultSetTest, testSqlStep023, TestSize.Level1) +{ + GenerateDefaultTable(); + std::shared_ptr resultSet = store->QueryByStep("SELECT * FROM test", {}, false); + EXPECT_NE(resultSet, nullptr); + + int count = -1; + resultSet->GetRowCount(count); + EXPECT_EQ(3, count); + + int position = INT_MIN; + int iRet = resultSet->GetRowIndex(position); + EXPECT_EQ(E_OK, iRet); + EXPECT_EQ(-1, position); + + bool bResultSet = true; + resultSet->IsAtFirstRow(bResultSet); + EXPECT_EQ(bResultSet, false); + + EXPECT_EQ(E_OK, resultSet->GoToRow(2)); + + bResultSet = false; + iRet = resultSet->IsAtLastRow(bResultSet); + EXPECT_EQ(E_OK, iRet); + EXPECT_EQ(true, bResultSet); + + EXPECT_EQ(E_OK, resultSet->GoToPreviousRow()); + + iRet = resultSet->GetRowIndex(position); + EXPECT_EQ(E_OK, iRet); + EXPECT_EQ(1, position); + + EXPECT_EQ(E_OK, resultSet->GoToLastRow()); + + bResultSet = false; + iRet = resultSet->IsAtLastRow(bResultSet); + EXPECT_EQ(E_OK, iRet); + EXPECT_EQ(true, bResultSet); + + bResultSet = false; + iRet = resultSet->IsStarted(bResultSet); + EXPECT_EQ(E_OK, iRet); + EXPECT_EQ(bResultSet, true); + + bResultSet = true; + iRet = resultSet->IsEnded(bResultSet); + EXPECT_EQ(E_OK, iRet); + EXPECT_EQ(bResultSet, false); + + resultSet->Close(); +} + +/* * + * @tc.name: RdbStore_StepResultSet_024 + * @tc.desc: normal testcase of StepResultSet for getInt + * @tc.type: FUNC + * @tc.require: AR000FKD4F + */ +HWTEST_F(RdbStepResultSetTest, testSqlStep024, TestSize.Level1) +{ + GenerateDefaultTable(); + std::shared_ptr resultSet = store->QueryByStep("SELECT data1, data2, data3, data4 FROM test", {}, false); + EXPECT_NE(resultSet, nullptr); + + int iValue; + int iRet = resultSet->GetInt(0, iValue); + EXPECT_NE(E_OK, iRet); + + EXPECT_EQ(E_OK, resultSet->GoToFirstRow()); + + iRet = resultSet->GetInt(0, iValue); + EXPECT_EQ(E_OK, iRet); + EXPECT_EQ(0, iValue); + + iRet = resultSet->GetInt(1, iValue); + EXPECT_EQ(E_OK, iRet); + EXPECT_EQ(10, iValue); + + iRet = resultSet->GetInt(2, iValue); + EXPECT_EQ(E_OK, iRet); + EXPECT_EQ(1, iValue); + + iRet = resultSet->GetInt(3, iValue); + EXPECT_EQ(E_OK, iRet); + + int columnCount = 0; + iRet = resultSet->GetColumnCount(columnCount); + EXPECT_EQ(4, columnCount); + iRet = resultSet->GetInt(columnCount, iValue); + EXPECT_NE(E_OK, iRet); + + EXPECT_EQ(E_OK, resultSet->GoToNextRow()); + iRet = resultSet->GetInt(0, iValue); + EXPECT_EQ(E_OK, iRet); + EXPECT_EQ(2, iValue); + + int64_t longValue; + iRet = resultSet->GetLong(0, longValue); + EXPECT_EQ(E_OK, iRet); + EXPECT_EQ(2, longValue); + + iRet = resultSet->GetInt(1, iValue); + EXPECT_EQ(E_OK, iRet); + EXPECT_EQ(-5, iValue); + + iRet = resultSet->GetLong(1, longValue); + EXPECT_EQ(E_OK, iRet); + EXPECT_EQ(-5, longValue); + + iRet = resultSet->GetInt(2, iValue); + EXPECT_EQ(E_OK, iRet); + EXPECT_EQ(2, iValue); + + resultSet->Close(); +} + /** * @tc.name: ResultSetProxy001 * @tc.desc: Abnormal testcase of distributed ResultSetProxy, if resultSet is Empty diff --git a/relational_store/test/native/rdb/unittest/rdb_store_backup_restore_test.cpp b/relational_store/test/native/rdb/unittest/rdb_store_backup_restore_test.cpp index f427e026d96b76c957437b7d9d0237a57af04ffa..1dae3381d9d7e558e9fca2f3129ca0438542e880 100644 --- a/relational_store/test/native/rdb/unittest/rdb_store_backup_restore_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_store_backup_restore_test.cpp @@ -19,6 +19,7 @@ #include #include "common.h" +#include "file_ex.h" #include "rdb_errno.h" #include "rdb_helper.h" #include "rdb_open_callback.h" @@ -282,34 +283,7 @@ HWTEST_F(RdbStoreBackupRestoreTest, Rdb_BackupRestoreTest_004, TestSize.Level2) EXPECT_EQ(ret, E_OK); ret = store->Restore(BACKUP_DATABASE_NAME); - EXPECT_EQ(ret, E_OK); - - std::shared_ptr resultSet = - store->QuerySql("SELECT * FROM test WHERE name = ?", std::vector{ "zhangsan" }); - ret = resultSet->GoToFirstRow(); - EXPECT_EQ(ret, E_OK); - ret = resultSet->GoToNextRow(); - EXPECT_EQ(ret, E_ROW_OUT_RANGE); - ret = resultSet->Close(); - EXPECT_EQ(ret, E_OK); - - values.Clear(); - values.Put("id", 2); - values.Put("name", std::string("lisa")); - values.Put("age", 19); - values.Put("salary", 101); - values.Put("blobType", std::vector{ 4, 5, 6 }); - ret = store->Insert(id, "test", values); - EXPECT_EQ(ret, E_OK); - EXPECT_EQ(2, id); - - resultSet = store->QuerySql("SELECT * FROM test WHERE name = ?", std::vector{ "lisa" }); - ret = resultSet->GoToFirstRow(); - EXPECT_EQ(ret, E_OK); - ret = resultSet->GoToNextRow(); - EXPECT_EQ(ret, E_ROW_OUT_RANGE); - ret = resultSet->Close(); - EXPECT_EQ(ret, E_OK); + EXPECT_EQ(ret, E_ALREADY_CLOSED); } /* * @@ -455,18 +429,6 @@ HWTEST_F(RdbStoreBackupRestoreTest, Rdb_BackupRestoreTest_007, TestSize.Level2) ret = store->Backup(BACKUP_DATABASE_NAME); EXPECT_EQ(ret, E_DB_NOT_EXIST); - EXPECT_NE(0, access(BACKUP_DATABASE_NAME, F_OK)); - EXPECT_NE(0, access(slaveDataBaseName, F_OK)); - - ret = store->Restore(BACKUP_DATABASE_NAME); - EXPECT_EQ(ret, E_INVALID_FILE_PATH); - - std::shared_ptr resultSet = - store->QuerySql("SELECT * FROM test WHERE name = ?", std::vector{ "zhangsan" }); - ret = resultSet->GoToFirstRow(); - EXPECT_EQ(ret, E_SQLITE_IOERR); - ret = resultSet->Close(); - EXPECT_EQ(ret, E_OK); } /* * @@ -519,4 +481,316 @@ HWTEST_F(RdbStoreBackupRestoreTest, Rdb_BackupRestoreTest_008, TestSize.Level2) EXPECT_EQ(0, access(BACKUP_DATABASE_NAME, F_OK)); EXPECT_EQ(0, access(slaveDataBaseName, F_OK)); -} \ No newline at end of file +} + +/* * + * @tc.name: Rdb_BackupRestoreTest_009 + * @tc.desc: sql func empty param test + * @tc.type: FUNC + */ +HWTEST_F(RdbStoreBackupRestoreTest, Rdb_BackupRestoreTest_009, TestSize.Level2) +{ + int errCode = E_OK; + RdbStoreConfig config(RdbStoreBackupRestoreTest::DATABASE_NAME); + config.SetEncryptStatus(false); + RdbStoreBackupRestoreTestOpenCallback helper; + auto store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + EXPECT_EQ(errCode, E_OK); + EXPECT_NE(store, nullptr); + + auto res = store->ExecuteSql("SELECT import_db_from_path()"); + + EXPECT_EQ(res, E_SQLITE_ERROR); + + auto [code, result] = store->Execute("pragma integrity_check"); + std::string val; + result.GetString(val); + EXPECT_EQ(E_OK, code); + EXPECT_EQ("ok", val); + + store = nullptr; + RdbHelper::DeleteRdbStore(RdbStoreBackupRestoreTest::DATABASE_NAME); +} + +/* * + * @tc.name: Rdb_BackupRestoreTest_010 + * @tc.desc: source db empty path test + * @tc.type: FUNC + */ +HWTEST_F(RdbStoreBackupRestoreTest, Rdb_BackupRestoreTest_010, TestSize.Level2) +{ + int errCode = E_OK; + RdbStoreConfig config(RdbStoreBackupRestoreTest::DATABASE_NAME); + config.SetEncryptStatus(false); + RdbStoreBackupRestoreTestOpenCallback helper; + auto store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + EXPECT_EQ(errCode, E_OK); + EXPECT_NE(store, nullptr); + + auto res = store->ExecuteSql("SELECT import_db_from_path('')"); + + EXPECT_EQ(res, E_SQLITE_CANTOPEN); + + auto [code, result] = store->Execute("pragma integrity_check"); + std::string val; + result.GetString(val); + EXPECT_EQ(E_OK, code); + EXPECT_EQ("ok", val); + + store = nullptr; + RdbHelper::DeleteRdbStore(RdbStoreBackupRestoreTest::DATABASE_NAME); +} + +/* * + * @tc.name: Rdb_BackupRestoreTest_011 + * @tc.desc: souce db not exist test + * @tc.type: FUNC + */ +HWTEST_F(RdbStoreBackupRestoreTest, Rdb_BackupRestoreTest_011, TestSize.Level2) +{ + int errCode = E_OK; + RdbStoreConfig config(RdbStoreBackupRestoreTest::DATABASE_NAME); + config.SetEncryptStatus(false); + RdbStoreBackupRestoreTestOpenCallback helper; + auto store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + EXPECT_EQ(errCode, E_OK); + EXPECT_NE(store, nullptr); + + auto res = store->ExecuteSql("SELECT import_db_from_path('/path/not_exist.db')"); + + EXPECT_EQ(res, E_SQLITE_CANTOPEN); + + auto [code, result] = store->Execute("pragma integrity_check"); + std::string val; + result.GetString(val); + EXPECT_EQ(E_OK, code); + EXPECT_EQ("ok", val); + + store = nullptr; + RdbHelper::DeleteRdbStore(RdbStoreBackupRestoreTest::DATABASE_NAME); +} + +/* * + * @tc.name: Rdb_BackupRestoreTest_012 + * @tc.desc: source db corrupt test + * @tc.type: FUNC + */ +HWTEST_F(RdbStoreBackupRestoreTest, Rdb_BackupRestoreTest_012, TestSize.Level2) +{ + int errCode = E_OK; + std::string destDbPath = "/data/test/dest.db"; + std::string sourceDbPath = "/data/test/source.db"; + + RdbStoreConfig config(destDbPath); + config.SetEncryptStatus(false); + RdbStoreBackupRestoreTestOpenCallback helper; + auto dest = RdbHelper::GetRdbStore(config, 1, helper, errCode); + EXPECT_EQ(errCode, E_OK); + EXPECT_NE(dest, nullptr); + + RdbStoreConfig sourceConfig(sourceDbPath); + sourceConfig.SetEncryptStatus(false); + RdbStoreBackupRestoreTestOpenCallback helper1; + auto source = RdbHelper::GetRdbStore(sourceConfig, 1, helper1, errCode); + source = nullptr; + + std::fstream sourceFile(sourceDbPath, std::ios::in | std::ios::out | std::ios::binary); + ASSERT_TRUE(sourceFile.is_open()); + sourceFile.seekp(0x0f40, std::ios::beg); + std::vector buffer(32, 0xFF); + sourceFile.write(buffer.data(), buffer.size()); + sourceFile.close(); + + auto res = dest->ExecuteSql("SELECT import_db_from_path('" + sourceDbPath + "')"); + + EXPECT_EQ(res, E_SQLITE_CORRUPT); + + auto [code, result] = dest->Execute("pragma integrity_check"); + std::string val; + result.GetString(val); + EXPECT_EQ(E_OK, code); + EXPECT_EQ("ok", val); + + dest = nullptr; + RdbHelper::DeleteRdbStore(destDbPath); + RdbHelper::DeleteRdbStore(sourceDbPath); +} + +/* * + * @tc.name: Rdb_BackupRestoreTest_013 + * @tc.desc: import from source db test + * @tc.type: FUNC + */ +HWTEST_F(RdbStoreBackupRestoreTest, Rdb_BackupRestoreTest_013, TestSize.Level2) +{ + int errCode = E_OK; + std::string destDbPath = "/data/test/dest.db"; + std::string sourceDbPath = "/data/test/source.db"; + + RdbStoreConfig config(destDbPath); + config.SetEncryptStatus(false); + RdbStoreBackupRestoreTestOpenCallback helper; + auto dest = RdbHelper::GetRdbStore(config, 1, helper, errCode); + EXPECT_EQ(errCode, E_OK); + EXPECT_NE(dest, nullptr); + + RdbStoreConfig sourceConfig(sourceDbPath); + sourceConfig.SetEncryptStatus(false); + RdbStoreBackupRestoreTestOpenCallback helper1; + auto source = RdbHelper::GetRdbStore(sourceConfig, 1, helper1, errCode); + + for (uint i = 0; i < 100; i++) { + std::vector valuesBuckets; + + for (uint j = 0; j < 100; j++) { + ValuesBucket value; + + value.Put("name", "zhangsan"); + value.PutString("name", "zhangSan"); + valuesBuckets.push_back(std::move(value)); + } + + int64_t insertRowCount; + int error = source->BatchInsert(insertRowCount, "test", valuesBuckets); + EXPECT_EQ(error, E_OK); + } + source = nullptr; + EXPECT_EQ(E_OK, dest->ExecuteSql("SELECT import_db_from_path('" + sourceDbPath + "')")); + + auto resultSet = dest->QuerySql("SELECT * FROM test"); + int rowCount; + EXPECT_EQ(E_OK, resultSet->GetRowCount(rowCount)); + + EXPECT_EQ(rowCount, 10000); + + auto [code, result] = dest->Execute("pragma integrity_check"); + std::string val; + result.GetString(val); + EXPECT_EQ(E_OK, code); + EXPECT_EQ("ok", val); + + dest = nullptr; + RdbHelper::DeleteRdbStore(destDbPath); + RdbHelper::DeleteRdbStore(sourceDbPath); +} + +/* * + * @tc.name: Rdb_BackupRestoreTest_014 + * @tc.desc: sql func empty param test + * @tc.type: FUNC + */ +HWTEST_F(RdbStoreBackupRestoreTest, Rdb_BackupRestoreTest_014, TestSize.Level2) +{ + int errCode = E_OK; + RdbStoreConfig config(RdbStoreBackupRestoreTest::DATABASE_NAME); + config.SetEncryptStatus(false); + RdbStoreBackupRestoreTestOpenCallback helper; + auto store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + EXPECT_EQ(errCode, E_OK); + EXPECT_NE(store, nullptr); + + auto res = store->ExecuteSql("SELECT import_db_from_path"); + + EXPECT_EQ(res, E_SQLITE_SCHEMA); + + auto [code, result] = store->Execute("pragma integrity_check"); + std::string val; + result.GetString(val); + EXPECT_EQ(E_OK, code); + EXPECT_EQ("ok", val); + + store = nullptr; + RdbHelper::DeleteRdbStore(RdbStoreBackupRestoreTest::DATABASE_NAME); +} + +/* * + * @tc.name: Rdb_BackupRestoreTest_015 + * @tc.desc: restore wal file exist test + * @tc.type: FUNC + */ +HWTEST_F(RdbStoreBackupRestoreTest, Rdb_BackupRestoreTest_015, TestSize.Level2) +{ + int errCode = E_OK; + RdbStoreConfig config(RdbStoreBackupRestoreTest::DATABASE_NAME); + config.SetEncryptStatus(false); + RdbStoreBackupRestoreTestOpenCallback helper; + auto store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + EXPECT_EQ(errCode, E_OK); + EXPECT_NE(store, nullptr); + + int ret = store->Backup(BACKUP_DATABASE_NAME); + EXPECT_EQ(ret, E_OK); + + RdbStoreConfig backupConfig(RdbStoreBackupRestoreTest::BACKUP_DATABASE_NAME); + backupConfig.SetEncryptStatus(false); + RdbStoreBackupRestoreTestOpenCallback backupHelper; + auto backupStore = RdbHelper::GetRdbStore(backupConfig, 1, backupHelper, errCode); + EXPECT_EQ(errCode, E_OK); + EXPECT_NE(backupStore, nullptr); + backupStore = nullptr; + + struct stat fileStat; + std::string walFilePath = std::string(RdbStoreBackupRestoreTest::BACKUP_DATABASE_NAME) + "-wal"; + EXPECT_EQ(stat(walFilePath.c_str(), &fileStat), 0); + + ret = store->Restore(RdbStoreBackupRestoreTest::BACKUP_DATABASE_NAME); + EXPECT_EQ(ret, E_OK); + ret = stat(walFilePath.c_str(), &fileStat); + EXPECT_EQ(ret, -1); + EXPECT_EQ(errno, 2); + + store = nullptr; + RdbHelper::DeleteRdbStore(RdbStoreBackupRestoreTest::DATABASE_NAME); + RdbHelper::DeleteRdbStore(RdbStoreBackupRestoreTest::BACKUP_DATABASE_NAME); +} + +/* * + * @tc.name: Rdb_BackupRestoreTest_016 + * @tc.desc: restore wal file not empty + * @tc.type: FUNC + */ +HWTEST_F(RdbStoreBackupRestoreTest, Rdb_BackupRestoreTest_016, TestSize.Level2) +{ + int errCode = E_OK; + RdbStoreConfig config(RdbStoreBackupRestoreTest::DATABASE_NAME); + config.SetEncryptStatus(false); + RdbStoreBackupRestoreTestOpenCallback helper; + auto store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + EXPECT_EQ(errCode, E_OK); + EXPECT_NE(store, nullptr); + + int ret = store->Backup(BACKUP_DATABASE_NAME); + EXPECT_EQ(ret, E_OK); + + RdbStoreConfig backupConfig(RdbStoreBackupRestoreTest::BACKUP_DATABASE_NAME); + backupConfig.SetEncryptStatus(false); + RdbStoreBackupRestoreTestOpenCallback backupHelper; + auto backupStore = RdbHelper::GetRdbStore(backupConfig, 1, backupHelper, errCode); + EXPECT_EQ(errCode, E_OK); + EXPECT_NE(backupStore, nullptr); + + int64_t id; + ValuesBucket values; + + values.PutInt("id", 1); + values.PutString("name", std::string("zhangsan")); + values.PutInt("age", 18); + values.PutDouble("salary", 100.5); + values.PutBlob("blobType", std::vector{ 1, 2, 3 }); + ret = backupStore->Insert(id, "test", values); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(1, id); + + struct stat fileStat; + std::string walFilePath = std::string(RdbStoreBackupRestoreTest::BACKUP_DATABASE_NAME) + "-wal"; + EXPECT_EQ(stat(walFilePath.c_str(), &fileStat), 0); + EXPECT_NE(fileStat.st_size, 0); + + ret = store->Restore(RdbStoreBackupRestoreTest::BACKUP_DATABASE_NAME); + EXPECT_EQ(ret, E_SQLITE_CORRUPT); + + backupStore = nullptr; + store = nullptr; + RdbHelper::DeleteRdbStore(RdbStoreBackupRestoreTest::DATABASE_NAME); + RdbHelper::DeleteRdbStore(RdbStoreBackupRestoreTest::BACKUP_DATABASE_NAME); +} diff --git a/relational_store/test/native/rdb/unittest/rdb_store_impl_test.cpp b/relational_store/test/native/rdb/unittest/rdb_store_impl_test.cpp index ccf8c5eb93247af47e7aa53d1cac7bd43e0df60b..4c64505a2a79a5499da60f3b698215c0fe4f0679 100644 --- a/relational_store/test/native/rdb/unittest/rdb_store_impl_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_store_impl_test.cpp @@ -1009,4 +1009,379 @@ HWTEST_F(RdbStoreImplTest, CreateTransaction_004, TestSize.Level1) ASSERT_NE(trans, nullptr); } ASSERT_EQ(i, 20); +} + +/* * + * @tc.name: BatchInsertWithConflictResolution_001 + * @tc.desc: BatchInsertWithConflictResolution when violation the unique constraint. + * @tc.type: FUNC + */ +HWTEST_F(RdbStoreImplTest, BatchInsertWithConflictResolution_001, TestSize.Level1) +{ + std::string tableName = "BatchInsertWithConflictResolutionTest"; + store_->Execute("DROP TABLE IF EXISTS " + tableName); + auto res = + store_->Execute("CREATE TABLE " + tableName + " (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + + ValuesBuckets rows; + for (int i = 0; i < 5; i++) { + ValuesBucket row; + row.Put("id", i); + row.Put("name", "Jim"); + rows.Put(row); + } + Transaction::Row row; + row.Put("id", 2); + row.Put("name", "Jim"); + auto result = store_->Insert(tableName, row); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 2); + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_NONE); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_ROLLBACK); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_ABORT); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_FAIL); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 2); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_IGNORE); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 2); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_REPLACE); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 5); + + std::shared_ptr resultSet = store_->QueryByStep("SELECT * FROM " + tableName); + ASSERT_NE(resultSet, nullptr); + int rowCount; + ASSERT_EQ(resultSet->GetRowCount(rowCount), E_OK); + ASSERT_EQ(rowCount, 5); +} + +/* * + * @tc.name: BatchInsertWithConflictResolution_002 + * @tc.desc: BatchInsertWithConflictResolution when violation the not null constraint. + * @tc.type: FUNC + */ +HWTEST_F(RdbStoreImplTest, BatchInsertWithConflictResolution_002, TestSize.Level1) +{ + std::string tableName = "BatchInsertWithConflictResolutionTest"; + store_->Execute("DROP TABLE IF EXISTS " + tableName); + auto res = + store_->Execute("CREATE TABLE " + tableName + " (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + + ValuesBuckets rows; + for (int i = 0; i < 5; i++) { + ValuesBucket row; + row.Put("id", i); + row.Put("name", i == 2 ? ValueObject() : "Jim"); + rows.Put(row); + } + auto result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_NONE); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_ROLLBACK); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_ABORT); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_FAIL); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 2); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_IGNORE); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 2); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_REPLACE); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + + std::shared_ptr resultSet = store_->QueryByStep("SELECT * FROM " + tableName); + ASSERT_NE(resultSet, nullptr); + int rowCount; + ASSERT_EQ(resultSet->GetRowCount(rowCount), E_OK); + ASSERT_EQ(rowCount, 4); +} + +/* * + * @tc.name: BatchInsertWithConflictResolution_003 + * @tc.desc: BatchInsertWithConflictResolution when violation the PRIMARY constraint. + * @tc.type: FUNC + */ +HWTEST_F(RdbStoreImplTest, BatchInsertWithConflictResolution_003, TestSize.Level1) +{ + std::string tableName = "BatchInsertWithConflictResolutionTest"; + store_->Execute("DROP TABLE IF EXISTS " + tableName); + auto res = + store_->Execute("CREATE TABLE " + tableName + " (id TEXT PRIMARY KEY, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + + ValuesBuckets rows; + for (int i = 0; i < 5; i++) { + ValuesBucket row; + row.Put("id", std::to_string(i)); + row.Put("name", "Jim"); + rows.Put(row); + } + Transaction::Row row; + row.Put("id", "2"); + row.Put("name", "Jim"); + auto result = store_->Insert(tableName, row); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 1); + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_NONE); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_ROLLBACK); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_ABORT); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_FAIL); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 2); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_IGNORE); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 2); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_REPLACE); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 5); + + std::shared_ptr resultSet = store_->QueryByStep("SELECT * FROM " + tableName); + ASSERT_NE(resultSet, nullptr); + int rowCount; + ASSERT_EQ(resultSet->GetRowCount(rowCount), E_OK); + ASSERT_EQ(rowCount, 5); +} + +/* * + * @tc.name: BatchInsertWithConflictResolution_004 + * @tc.desc: BatchInsertWithConflictResolution when violation the check constraint. + * @tc.type: FUNC + */ +HWTEST_F(RdbStoreImplTest, BatchInsertWithConflictResolution_004, TestSize.Level1) +{ + std::string tableName = "BatchInsertWithConflictResolutionTest"; + store_->Execute("DROP TABLE IF EXISTS " + tableName); + auto res = store_->Execute( + "CREATE TABLE " + tableName + " (id INTEGER PRIMARY KEY CHECK (id >= 3 OR id <= 1), name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + + ValuesBuckets rows; + for (int i = 0; i < 5; i++) { + ValuesBucket row; + row.Put("id", i); + row.Put("name", "Jim"); + rows.Put(row); + } + auto result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_NONE); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_ROLLBACK); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_ABORT); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_FAIL); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 2); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_IGNORE); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 2); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_REPLACE); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + + std::shared_ptr resultSet = store_->QueryByStep("SELECT * FROM " + tableName); + ASSERT_NE(resultSet, nullptr); + int rowCount; + ASSERT_EQ(resultSet->GetRowCount(rowCount), E_OK); + ASSERT_EQ(rowCount, 4); +} + +/* * + * @tc.name: BatchInsertWithConflictResolution_005 + * @tc.desc: BatchInsertWithConflictResolution when busy. + * @tc.type: FUNC + */ +HWTEST_F(RdbStoreImplTest, BatchInsertWithConflictResolution_005, TestSize.Level1) +{ + std::string tableName = "BatchInsertWithConflictResolutionTest"; + store_->Execute("DROP TABLE IF EXISTS " + tableName); + auto res = store_->Execute( + "CREATE TABLE " + tableName + " (id INTEGER PRIMARY KEY CHECK (id >= 3 OR id <= 1), name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + + auto [code, transaction] = store_->CreateTransaction(Transaction::IMMEDIATE); + ASSERT_EQ(code, E_OK); + ASSERT_NE(transaction, nullptr); + + ValuesBuckets rows; + for (int i = 0; i < 5; i++) { + ValuesBucket row; + row.Put("id", i); + row.Put("name", "Jim"); + rows.Put(row); + } + auto result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_NONE); + ASSERT_EQ(result.first, E_SQLITE_BUSY); + ASSERT_EQ(result.second, -1); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_ROLLBACK); + ASSERT_EQ(result.first, E_SQLITE_BUSY); + ASSERT_EQ(result.second, -1); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_ABORT); + ASSERT_EQ(result.first, E_SQLITE_BUSY); + ASSERT_EQ(result.second, -1); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_FAIL); + ASSERT_EQ(result.first, E_SQLITE_BUSY); + ASSERT_EQ(result.second, -1); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_IGNORE); + ASSERT_EQ(result.first, E_SQLITE_BUSY); + ASSERT_EQ(result.second, -1); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_REPLACE); + ASSERT_EQ(result.first, E_SQLITE_BUSY); + ASSERT_EQ(result.second, -1); + + std::shared_ptr resultSet = store_->QueryByStep("SELECT * FROM " + tableName); + ASSERT_NE(resultSet, nullptr); + int rowCount; + ASSERT_EQ(resultSet->GetRowCount(rowCount), E_OK); + ASSERT_EQ(rowCount, 0); +} + +/* * + * @tc.name: BatchInsertWithConflictResolution_006 + * @tc.desc: Normal BatchInsertWithConflictResolution. + * @tc.type: FUNC + */ +HWTEST_F(RdbStoreImplTest, BatchInsertWithConflictResolution_006, TestSize.Level1) +{ + std::string tableName = "BatchInsertWithConflictResolutionTest"; + store_->Execute("DROP TABLE IF EXISTS " + tableName); + auto res = + store_->Execute("CREATE TABLE " + tableName + " (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + + ValuesBuckets rows; + + auto result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_NONE); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 0); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_ROLLBACK); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 0); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_ABORT); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 0); + for (int i = 0; i < 5; i++) { + ValuesBucket row; + row.Put("name", "Jim"); + rows.Put(row); + } + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_FAIL); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 5); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_IGNORE); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 5); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_REPLACE); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 5); + + std::shared_ptr resultSet = store_->QueryByStep("SELECT * FROM " + tableName); + ASSERT_NE(resultSet, nullptr); + int rowCount; + ASSERT_EQ(resultSet->GetRowCount(rowCount), E_OK); + ASSERT_EQ(rowCount, 15); +} + +/* * + * @tc.name: BatchInsertWithConflictResolution_007 + * @tc.desc: over limit params BatchInsertWithConflictResolution. + * @tc.type: FUNC + */ +HWTEST_F(RdbStoreImplTest, BatchInsertWithConflictResolution_007, TestSize.Level1) +{ + std::string tableName = "BatchInsertWithConflictResolutionTest"; + store_->Execute("DROP TABLE IF EXISTS " + tableName); + auto res = + store_->Execute("CREATE TABLE " + tableName + " (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + //sqlite default max param number + int32_t maxNumber = 32766; + int32_t maxRows = maxNumber / 2 + 1; + ValuesBuckets rows; + for (int32_t i = 0; i < maxRows; i++) { + ValuesBucket row; + row.Put("id", i); + row.Put("name", "Jim"); + rows.Put(row); + } + auto result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_NONE); + ASSERT_EQ(result.first, E_INVALID_ARGS); + ASSERT_EQ(result.second, -1); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_ROLLBACK); + ASSERT_EQ(result.first, E_INVALID_ARGS); + ASSERT_EQ(result.second, -1); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_ABORT); + ASSERT_EQ(result.first, E_INVALID_ARGS); + ASSERT_EQ(result.second, -1); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_FAIL); + ASSERT_EQ(result.first, E_INVALID_ARGS); + ASSERT_EQ(result.second, -1); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_IGNORE); + ASSERT_EQ(result.first, E_INVALID_ARGS); + ASSERT_EQ(result.second, -1); + + result = store_->BatchInsertWithConflictResolution(tableName, rows, ConflictResolution::ON_CONFLICT_REPLACE); + ASSERT_EQ(result.first, E_INVALID_ARGS); + ASSERT_EQ(result.second, -1); + + std::shared_ptr resultSet = store_->QueryByStep("SELECT * FROM " + tableName); + ASSERT_NE(resultSet, nullptr); + int rowCount; + ASSERT_EQ(resultSet->GetRowCount(rowCount), E_OK); + ASSERT_EQ(rowCount, 0); } \ No newline at end of file diff --git a/relational_store/test/native/rdb/unittest/rdb_store_rekey_test.cpp b/relational_store/test/native/rdb/unittest/rdb_store_rekey_test.cpp index 4840be058e0309eac06bbc26d05b6fcbfaa470ce..71f4495c836e0f7b68da6f3037cd0afa31c2d3ba 100644 --- a/relational_store/test/native/rdb/unittest/rdb_store_rekey_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_store_rekey_test.cpp @@ -490,4 +490,50 @@ HWTEST_F(RdbRekeyTest, Rdb_Rekey_07, TestSize.Level1) } ASSERT_NE(inodeNumber1, inodeNumber2); +} + +/** +* @tc.name: Rdb_Delete_Rekey_Test_08 +* @tc.desc: test deleting the key file of the encrypted database +* @tc.type: FUNC +*/ +HWTEST_F(RdbRekeyTest, Rdb_Rekey_08, TestSize.Level1) +{ + RdbStoreConfig config(RdbRekeyTest::encryptedDatabasePath); + config.SetSecurityLevel(SecurityLevel::S1); + config.SetAllowRebuild(false); + config.SetEncryptStatus(true); + config.SetBundleName("com.example.test_rekey"); + RekeyTestOpenCallback helper; + int errCode = E_OK; + std::shared_ptr store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + ASSERT_NE(store, nullptr); + ASSERT_EQ(errCode, E_OK); + + std::string keyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key"; + bool isFileExists = OHOS::FileExists(keyPath); + ASSERT_TRUE(isFileExists); + struct stat fileStat; + ino_t inodeNumber1 = -1; + if (stat(keyPath.c_str(), &fileStat) == 0) { + inodeNumber1 = fileStat.st_ino; + } + store = nullptr; + + { + std::ofstream fsDb(encryptedDatabasePath, std::ios_base::binary | std::ios_base::out); + fsDb.seekp(64); + fsDb.write("hello", 5); + fsDb.close(); + } + + store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + isFileExists = OHOS::FileExists(keyPath); + ASSERT_TRUE(isFileExists); + ino_t inodeNumber2 = -1; + if (stat(keyPath.c_str(), &fileStat) == 0) { + inodeNumber2 = fileStat.st_ino; + } + + ASSERT_EQ(inodeNumber1, inodeNumber2); } \ No newline at end of file diff --git a/relational_store/test/native/rdb/unittest/rdb_update_test.cpp b/relational_store/test/native/rdb/unittest/rdb_update_test.cpp index 84d4f09274aabb9334c1da6d04f8d482363275b4..41989402c73364cac8897a1367b920c191abc9de 100644 --- a/relational_store/test/native/rdb/unittest/rdb_update_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_update_test.cpp @@ -50,14 +50,14 @@ public: }; const std::string UpdateTestOpenCallback::CREATE_TABLE_TEST = - std::string("CREATE TABLE IF NOT EXISTS test (") - + std::string("id INTEGER PRIMARY KEY AUTOINCREMENT, ") - + std::string("name TEXT UNIQUE, ") - + std::string("age INTEGER, ") - + std::string("salary REAL, ") - + std::string("blobType BLOB, ") - + std::string("assetType ASSET, ") - + std::string("assetsType ASSETS)"); + std::string("CREATE TABLE IF NOT EXISTS test (") + + std::string("id INTEGER PRIMARY KEY AUTOINCREMENT, ") + + std::string("name TEXT UNIQUE, ") + + std::string("age INTEGER, ") + + std::string("salary REAL, ") + + std::string("blobType BLOB, ") + + std::string("assetType ASSET, ") + + std::string("assetsType ASSETS)"); int UpdateTestOpenCallback::OnCreate(RdbStore &store) { diff --git a/relational_store/test/native/rdb/unittest/sqlite_utils_test.cpp b/relational_store/test/native/rdb/unittest/sqlite_utils_test.cpp index 2b095fbf9d046082797da6848742e1dfac438980..ba5bf657e236d3f999df7cc6917d9cdf9afabaec 100644 --- a/relational_store/test/native/rdb/unittest/sqlite_utils_test.cpp +++ b/relational_store/test/native/rdb/unittest/sqlite_utils_test.cpp @@ -159,174 +159,4 @@ HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0023, TestSize.Level1) { EXPECT_EQ(SqliteUtils::Anonymous("file /data/stage/el2/database/rdb/ddddddd/linker_reborn.db-wal"), "file /***/el2/***/linker_reborn.db-wal"); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0024, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("select value1, value2 from table1 WHERE case = 1."), - "select ***ue1, ***ue2 from ***le1 WHERE *ase = *."); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0025, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("select district value1, value2 from table1 " - "WHERE case = 1 groupby value1 limit 1."), - "select district ***ue1, ***ue2 from ***le1 " - "WHERE *ase = * groupby ***ue1 limit *."); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0026, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("select value1, value2 from table1."), "select ***ue1, ***ue2 from ***le1."); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0027, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("select table1.value1, table2.value2 from table1, table2."), - "select ***le1.***ue1, ***le2.***ue2 from ***le1, ***le2."); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0028, TestSize.Level1) -{ - EXPECT_EQ( - SqliteUtils::AnonySql("select ***le1.***ue1 as *d, ***le2.***ue2 as **lue from ***le1 as A, ***le2 as B."), - "select ***le1.***ue1 as *d, ***le2.***ue2 as **lue from ***le1 as A, ***le2 as B."); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0029, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("SELECT * FROM test."), "SELECT * FROM *est."); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0030, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("SELECT count(*) FROM test."), "SELECT count(*) FROM *est."); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0031, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("SELECT average(*) FROM test."), "SELECT average(*) FROM *est."); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0032, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("INSERT INTO test (data1, data2, data3, data4) VALUES (?, ?, ?, ?);"), - "INSERT INTO *est (**ta1, **ta2, **ta3, **ta4) VALUES (?, ?, ?, ?);"); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0033, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql( - "INSERT INTO test (data1, data2, data3, data4) VALUES (?, ?, ?, ?),(?,?,?,?),(?,?,?,?),(?,?,?,?);"), - "INSERT INTO *est (**ta1, **ta2, **ta3, **ta4) VALUES (?, ?, ?, ?),(?,?,?,?),(?,?,?,?),(?,?,?,?);"); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0034, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("UPDATE test SET age = 8 WHERE id = 1."), "UPDATE *est SET *ge = * WHERE *d = *."); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0035, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("UPDATE test SET age = 8 WHERE id = 1 and id = 1 or id = 1."), - "UPDATE *est SET *ge = * WHERE *d = * and *d = * or *d = *."); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0036, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("DELETE FROM test;"), "DELETE FROM *est;"); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0037, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("DELETE FROM test WHERE time = 3;"), "DELETE FROM *est WHERE *ime = *;"); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0038, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("CREATE DATABASE DBtest.db;"), "CREATE DATABASE ***est.*b;"); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0039, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("CREATE TABLE IF NOT EXISTS TEST (id INT PRIMARY KEY, name TEXT, extend BLOB, " - "code REAL, years UNLIMITED INT, ment ASSET, ments ASSETS)."), - "CREATE TABLE IF NOT EXISTS *EST (*d INT PRIMARY KEY, *ame TEXT, " - "***end BLOB, *ode REAL, **ars UNLIMITED INT, *ent ASSET, **nts ASSETS)."); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0040, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("CREATE TABLE TEST (id INT PRIMARY KEY, name TEXT, " - "extend BLOB, code REAL, years UNLIMITED INT, ment ASSET, ments ASSETS)."), - "CREATE TABLE *EST (*d INT PRIMARY KEY, *ame TEXT, " - "***end BLOB, *ode REAL, **ars UNLIMITED INT, *ent ASSET, **nts ASSETS)."); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0041, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("DROP TABLE IF EXISTS table1;"), "DROP TABLE IF EXISTS ***le1;"); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0042, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("DROP TABLE table1;"), "DROP TABLE ***le1;"); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0043, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("DROP DATABASE IF EXISTS name1;"), "DROP DATABASE IF EXISTS **me1;"); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0044, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("DROP DATABASE name2;"), "DROP DATABASE **me2;"); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0045, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("PRAGMA version = 3"), "PRAGMA ****ion = *"); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0046, TestSize.Level1) -{ - EXPECT_EQ( - SqliteUtils::AnonySql("ALTER TABLE test ADD COLUMN name TEXT;"), "ALTER TABLE *est ADD COLUMN *ame TEXT;"); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0047, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("CREATE TABLE TEST (id INT PRIMARY KEY, name TEXT," - " extend BLOB, code REAL, years UNLIMITED INT, ment ASSET, ments ASSETS)."), - "CREATE TABLE *EST (*d INT PRIMARY KEY, *ame TEXT, " - "***end BLOB, *ode REAL, **ars UNLIMITED INT, *ent ASSET, **nts ASSETS)."); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0048, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("ALTER TABLE test DROP COLUMN name;"), "ALTER TABLE *est DROP COLUMN *ame;"); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0049, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("CREATE TABLE IF NOT EXISTS name AS SELECT order AS old, " - "order AS new UNION SELECT shot AS old, shot AS new ;"), - "CREATE TABLE IF NOT EXISTS *ame AS SELECT **der AS *ld, **der " - "AS *ew UNION SELECT *hot AS *ld, *hot AS *ew ;"); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0050, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("CREATE TABLE IF NOT EXISTS name AS SELECT order AS old \r, " - "order AS new UNION SELECT shot AS old, shot AS new ;"), - "CREATE TABLE IF NOT EXISTS *ame AS SELECT **der AS *ld , **der " - "AS *ew UNION SELECT *hot AS *ld, *hot AS *ew ;"); -} - -HWTEST_F(SqliteUtilsTest, SqliteUtils_Test_0051, TestSize.Level1) -{ - EXPECT_EQ(SqliteUtils::AnonySql("CREATE TABLE IF NOT EXISTS name AS SELECT order AS old \r\n, " - "order AS new UNION SELECT shot AS old, shot AS new ;"), - "CREATE TABLE IF NOT EXISTS *ame AS SELECT **der AS *ld , **der " - "AS *ew UNION SELECT *hot AS *ld, *hot AS *ew ;"); } \ No newline at end of file diff --git a/relational_store/test/native/rdb/unittest/transaction_test.cpp b/relational_store/test/native/rdb/unittest/transaction_test.cpp index 573babacd3dd95153140d6a674eccdec2cdd6d8f..b134d3bfa8c4fa4ef0f26f6b963c966ea38f3b9a 100644 --- a/relational_store/test/native/rdb/unittest/transaction_test.cpp +++ b/relational_store/test/native/rdb/unittest/transaction_test.cpp @@ -364,13 +364,13 @@ HWTEST_F(TransactionTest, RdbStore_Transaction_007, TestSize.Level1) { std::shared_ptr &store = TransactionTest::store_; + store->Execute("DROP TABLE IF EXISTS test1"); + auto res = store->Execute("CREATE TABLE test1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); ASSERT_EQ(ret, E_OK); ASSERT_NE(transaction, nullptr); - auto res = transaction->Execute( - "CREATE TABLE IF NOT EXISTS test1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); - ASSERT_EQ(res.first, E_OK); Transaction::Row row; row.Put("id", 1); row.Put("name", "Jim"); @@ -388,3 +388,570 @@ HWTEST_F(TransactionTest, RdbStore_Transaction_007, TestSize.Level1) EXPECT_EQ(ret, E_OK); EXPECT_EQ(rowCount, 1); } + +/** + * @tc.name: RdbStore_Transaction_008 + * @tc.desc: Insert with ConflictResolution::ON_CONFLICT_ROLLBACK + * @tc.type: FUNC + */ +HWTEST_F(TransactionTest, RdbStore_Transaction_008, TestSize.Level1) +{ + std::shared_ptr &store = TransactionTest::store_; + store->Execute("DROP TABLE IF EXISTS test1"); + auto res = store->Execute("CREATE TABLE test1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + Transaction::Row row; + row.Put("id", 1); + row.Put("name", "Jim"); + auto result = transaction->Insert("test1", row); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 1); + + result = transaction->Insert("test1", row, ConflictResolution::ON_CONFLICT_ROLLBACK); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, -1); + ASSERT_EQ(transaction->Commit(), E_ALREADY_CLOSED); + + auto resultSet = store->QueryByStep("SELECT * FROM test1"); + ASSERT_NE(resultSet, nullptr); + int32_t rowCount{}; + ret = resultSet->GetRowCount(rowCount); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(rowCount, 0); +} + +/** + * @tc.name: RdbStore_Transaction_009 + * @tc.desc: Update with ConflictResolution::ON_CONFLICT_ROLLBACK + * @tc.type: FUNC + */ +HWTEST_F(TransactionTest, RdbStore_Transaction_009, TestSize.Level1) +{ + std::shared_ptr &store = TransactionTest::store_; + store->Execute("DROP TABLE IF EXISTS test1"); + auto res = store->Execute("CREATE TABLE test1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + Transaction::Row row; + row.Put("id", 1); + row.Put("name", "Jim"); + auto result = transaction->Insert("test1", row); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 1); + + row.Put("name", ValueObject()); + result = transaction->Update( + "test1", row, "id = ?", std::vector{ "1" }, ConflictResolution::ON_CONFLICT_ROLLBACK); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + ASSERT_EQ(transaction->Commit(), E_ALREADY_CLOSED); + + auto resultSet = store->QueryByStep("SELECT * FROM test1"); + ASSERT_NE(resultSet, nullptr); + int32_t rowCount{}; + ret = resultSet->GetRowCount(rowCount); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(rowCount, 0); +} + +/** + * @tc.name: RdbStore_Transaction_010 + * @tc.desc: Update with ConflictResolution::ON_CONFLICT_ROLLBACK + * @tc.type: FUNC + */ +HWTEST_F(TransactionTest, RdbStore_Transaction_010, TestSize.Level1) +{ + std::shared_ptr &store = TransactionTest::store_; + store->Execute("DROP TABLE IF EXISTS test1"); + auto res = store->Execute("CREATE TABLE test1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + Transaction::Row row; + row.Put("id", 1); + row.Put("name", "Jim"); + auto result = transaction->Insert("test1", row); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 1); + + row.Put("name", ValueObject()); + AbsRdbPredicates predicates("test1"); + predicates.EqualTo("id", 1); + result = transaction->Update(row, predicates, ConflictResolution::ON_CONFLICT_ROLLBACK); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + ASSERT_EQ(transaction->Commit(), E_ALREADY_CLOSED); + + auto resultSet = store->QueryByStep("SELECT * FROM test1"); + ASSERT_NE(resultSet, nullptr); + int32_t rowCount{}; + ret = resultSet->GetRowCount(rowCount); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(rowCount, 0); +} + +/** + * @tc.name: RdbStore_Transaction_011 + * @tc.desc: BatchInsert with ConflictResolution::ON_CONFLICT_ROLLBACK + * @tc.type: FUNC + */ +HWTEST_F(TransactionTest, RdbStore_Transaction_011, TestSize.Level1) +{ + std::shared_ptr &store = TransactionTest::store_; + store->Execute("DROP TABLE IF EXISTS test1"); + auto res = store->Execute("CREATE TABLE test1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + ValuesBuckets rows; + for (int i = 0; i < 5; i++) { + Transaction::Row row; + row.Put("id", i); + row.Put("name", "Jim"); + rows.Put(row); + } + Transaction::Row row; + row.Put("id", 2); + row.Put("name", "Jim"); + auto result = transaction->Insert("test1", row); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 2); + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_ROLLBACK); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + ASSERT_EQ(transaction->Commit(), E_ALREADY_CLOSED); + + auto resultSet = store->QueryByStep("SELECT * FROM test1"); + ASSERT_NE(resultSet, nullptr); + int32_t rowCount{}; + ret = resultSet->GetRowCount(rowCount); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(rowCount, 0); +} + +/** + * @tc.name: RdbStore_Transaction_012 + * @tc.desc: BatchInsert with ConflictResolution::ON_CONFLICT_ABORT + * @tc.type: FUNC + */ +HWTEST_F(TransactionTest, RdbStore_Transaction_012, TestSize.Level1) +{ + std::shared_ptr &store = TransactionTest::store_; + store->Execute("DROP TABLE IF EXISTS test1"); + auto res = store->Execute("CREATE TABLE test1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + ValuesBuckets rows; + for (int i = 0; i < 5; i++) { + Transaction::Row row; + row.Put("id", i); + row.Put("name", "Jim"); + rows.Put(row); + } + Transaction::Row row; + row.Put("id", 2); + row.Put("name", "Jim"); + auto result = transaction->Insert("test1", row); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 2); + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_ABORT); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + ASSERT_EQ(transaction->Commit(), E_OK); + + auto resultSet = store->QueryByStep("SELECT * FROM test1"); + ASSERT_NE(resultSet, nullptr); + int32_t rowCount{}; + ret = resultSet->GetRowCount(rowCount); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(rowCount, 1); +} + +/** + * @tc.name: RdbStore_Transaction_013 + * @tc.desc: BatchInsert with ConflictResolution::ON_CONFLICT_FAIL + * @tc.type: FUNC + */ +HWTEST_F(TransactionTest, RdbStore_Transaction_013, TestSize.Level1) +{ + std::shared_ptr &store = TransactionTest::store_; + store->Execute("DROP TABLE IF EXISTS test1"); + auto res = store->Execute("CREATE TABLE test1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + ValuesBuckets rows; + for (int i = 0; i < 5; i++) { + Transaction::Row row; + row.Put("id", i); + row.Put("name", "Jim"); + rows.Put(row); + } + Transaction::Row row; + row.Put("id", 2); + row.Put("name", "Jim"); + auto result = transaction->Insert("test1", row); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 2); + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_FAIL); + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 2); + ASSERT_EQ(transaction->Commit(), E_OK); + + auto resultSet = store->QueryByStep("SELECT * FROM test1"); + ASSERT_NE(resultSet, nullptr); + int32_t rowCount{}; + ret = resultSet->GetRowCount(rowCount); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(rowCount, 3); +} + +/** + * @tc.name: RdbStore_Transaction_014 + * @tc.desc: BatchInsert with ConflictResolution::ON_CONFLICT_IGNORE + * @tc.type: FUNC + */ +HWTEST_F(TransactionTest, RdbStore_Transaction_014, TestSize.Level1) +{ + std::shared_ptr &store = TransactionTest::store_; + store->Execute("DROP TABLE IF EXISTS test1"); + auto res = store->Execute("CREATE TABLE test1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + ValuesBuckets rows; + for (int i = 0; i < 5; i++) { + Transaction::Row row; + row.Put("id", i); + row.Put("name", "Jim_batchInsert"); + rows.Put(row); + } + Transaction::Row row; + row.Put("id", 2); + row.Put("name", "Jim_insert"); + auto result = transaction->Insert("test1", row); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 2); + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_IGNORE); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 4); + ASSERT_EQ(transaction->Commit(), E_OK); + + auto resultSet = store->QueryByStep("SELECT * FROM test1"); + ASSERT_NE(resultSet, nullptr); + int32_t rowCount{}; + ret = resultSet->GetRowCount(rowCount); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(rowCount, 5); + resultSet = store->QueryByStep("SELECT * FROM test1 where id = 2"); + ASSERT_NE(resultSet, nullptr); + ASSERT_EQ(resultSet->GoToFirstRow(), E_OK); + int columnIndex = -1; + ASSERT_EQ(resultSet->GetColumnIndex("name", columnIndex), E_OK); + std::string name; + EXPECT_EQ(resultSet->GetString(columnIndex, name), E_OK); + EXPECT_EQ(name, "Jim_insert"); +} + +/** + * @tc.name: RdbStore_Transaction_015 + * @tc.desc: BatchInsert with ConflictResolution::ON_CONFLICT_REPLACE + * @tc.type: FUNC + */ +HWTEST_F(TransactionTest, RdbStore_Transaction_015, TestSize.Level1) +{ + std::shared_ptr &store = TransactionTest::store_; + store->Execute("DROP TABLE IF EXISTS test1"); + auto res = store->Execute("CREATE TABLE test1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + ValuesBuckets rows; + for (int i = 0; i < 5; i++) { + Transaction::Row row; + row.Put("id", i); + row.Put("name", "Jim_batchInsert"); + rows.Put(row); + } + Transaction::Row row; + row.Put("id", 2); + row.Put("name", "Jim_insert"); + auto result = transaction->Insert("test1", row); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 2); + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_REPLACE); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 5); + ASSERT_EQ(transaction->Commit(), E_OK); + + auto resultSet = store->QueryByStep("SELECT * FROM test1"); + ASSERT_NE(resultSet, nullptr); + int32_t rowCount{}; + ret = resultSet->GetRowCount(rowCount); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(rowCount, 5); + resultSet = store->QueryByStep("SELECT * FROM test1 where id = 2"); + ASSERT_NE(resultSet, nullptr); + ASSERT_EQ(resultSet->GoToFirstRow(), E_OK); + int columnIndex = -1; + ASSERT_EQ(resultSet->GetColumnIndex("name", columnIndex), E_OK); + std::string name; + EXPECT_EQ(resultSet->GetString(columnIndex, name), E_OK); + EXPECT_EQ(name, "Jim_batchInsert"); +} + +/** + * @tc.name: RdbStore_Transaction_016 + * @tc.desc: BatchInsert with ConflictResolution::ON_CONFLICT_REPLACE and failed + * @tc.type: FUNC + */ +HWTEST_F(TransactionTest, RdbStore_Transaction_016, TestSize.Level1) +{ + std::shared_ptr &store = TransactionTest::store_; + store->Execute("DROP TABLE IF EXISTS test1"); + auto res = store->Execute("CREATE TABLE test1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + ValuesBuckets rows; + for (int i = 0; i < 5; i++) { + Transaction::Row row; + row.Put("id", i); + row.Put("name", i == 2 ? ValueObject() : "Jim_batchInsert"); + rows.Put(row); + } + Transaction::Row row; + row.Put("id", 2); + row.Put("name", "Jim_insert"); + auto result = transaction->Insert("test1", row); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 2); + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_REPLACE); + // ON_CONFLICT_REPLACE is equivalent to ON_CONFLICT_ABORT after failure + ASSERT_EQ(result.first, E_SQLITE_CONSTRAINT); + ASSERT_EQ(result.second, 0); + ASSERT_EQ(transaction->Commit(), E_OK); + + auto resultSet = store->QueryByStep("SELECT * FROM test1"); + ASSERT_NE(resultSet, nullptr); + ASSERT_EQ(resultSet->GoToFirstRow(), E_OK); + int columnIndex = -1; + ASSERT_EQ(resultSet->GetColumnIndex("name", columnIndex), E_OK); + std::string name; + EXPECT_EQ(resultSet->GetString(columnIndex, name), E_OK); + EXPECT_EQ(name, "Jim_insert"); +} + +/** + * @tc.name: RdbStore_Transaction_017 + * @tc.desc: BatchInsert when busy + * @tc.type: FUNC + */ +HWTEST_F(TransactionTest, RdbStore_Transaction_017, TestSize.Level1) +{ + std::shared_ptr &store = TransactionTest::store_; + store->Execute("DROP TABLE IF EXISTS test1"); + auto res = store->Execute("CREATE TABLE test1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + auto [ret1, transaction1] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret1, E_OK); + ASSERT_NE(transaction1, nullptr); + + auto [ret, transaction] = store->CreateTransaction(Transaction::DEFERRED); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + ValuesBuckets rows; + for (int i = 0; i < 5; i++) { + Transaction::Row row; + row.Put("id", i); + row.Put("name", "Jim_batchInsert"); + rows.Put(row); + } + auto result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_NONE); + ASSERT_EQ(result.first, E_SQLITE_BUSY); + ASSERT_EQ(result.second, -1); + + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_ROLLBACK); + ASSERT_EQ(result.first, E_SQLITE_BUSY); + ASSERT_EQ(result.second, -1); + + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_ABORT); + ASSERT_EQ(result.first, E_SQLITE_BUSY); + ASSERT_EQ(result.second, -1); + + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_FAIL); + ASSERT_EQ(result.first, E_SQLITE_BUSY); + ASSERT_EQ(result.second, -1); + + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_IGNORE); + ASSERT_EQ(result.first, E_SQLITE_BUSY); + ASSERT_EQ(result.second, -1); + + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_REPLACE); + ASSERT_EQ(result.first, E_SQLITE_BUSY); + ASSERT_EQ(result.second, -1); +} + +/** + * @tc.name: RdbStore_Transaction_018 + * @tc.desc: BatchInsert when over limit rows + * @tc.type: FUNC + */ +HWTEST_F(TransactionTest, RdbStore_Transaction_018, TestSize.Level1) +{ + std::shared_ptr &store = TransactionTest::store_; + store->Execute("DROP TABLE IF EXISTS test1"); + auto res = store->Execute("CREATE TABLE test1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + + auto [ret, transaction] = store->CreateTransaction(Transaction::DEFERRED); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + //sqlite default max param number + int32_t maxNumber = 32766; + int32_t maxRows = maxNumber / 2 + 1; + ValuesBuckets rows; + for (int32_t i = 0; i < maxRows; i++) { + Transaction::Row row; + row.Put("id", i); + row.Put("name", "Jim_batchInsert"); + rows.Put(row); + } + auto result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_NONE); + ASSERT_EQ(result.first, E_INVALID_ARGS); + ASSERT_EQ(result.second, -1); + + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_ROLLBACK); + ASSERT_EQ(result.first, E_INVALID_ARGS); + ASSERT_EQ(result.second, -1); + + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_ABORT); + ASSERT_EQ(result.first, E_INVALID_ARGS); + ASSERT_EQ(result.second, -1); + + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_FAIL); + ASSERT_EQ(result.first, E_INVALID_ARGS); + ASSERT_EQ(result.second, -1); + + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_IGNORE); + ASSERT_EQ(result.first, E_INVALID_ARGS); + ASSERT_EQ(result.second, -1); + + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_REPLACE); + ASSERT_EQ(result.first, E_INVALID_ARGS); + ASSERT_EQ(result.second, -1); +} + +/** + * @tc.name: RdbStore_Transaction_019 + * @tc.desc: Normal BatchInsertWithConflictResolution + * @tc.type: FUNC + */ +HWTEST_F(TransactionTest, RdbStore_Transaction_019, TestSize.Level1) +{ + std::shared_ptr &store = TransactionTest::store_; + store->Execute("DROP TABLE IF EXISTS test1"); + auto res = store->Execute("CREATE TABLE test1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); + ASSERT_EQ(res.first, E_OK); + auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); + ASSERT_EQ(ret, E_OK); + ASSERT_NE(transaction, nullptr); + + ValuesBuckets rows; + auto result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_NONE); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 0); + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_ROLLBACK); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 0); + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_ABORT); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 0); + for (int i = 0; i < 2; i++) { + Transaction::Row row; + row.Put("name", "Jim_batchInsert"); + rows.Put(row); + } + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_FAIL); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 2); + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_IGNORE); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 2); + result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_REPLACE); + ASSERT_EQ(result.first, E_OK); + ASSERT_EQ(result.second, 2); + + ASSERT_EQ(transaction->Commit(), E_OK); + auto resultSet = store->QueryByStep("SELECT * FROM test1"); + ASSERT_NE(resultSet, nullptr); + int32_t rowCount{}; + ret = resultSet->GetRowCount(rowCount); + EXPECT_EQ(ret, E_OK); + EXPECT_EQ(rowCount, 6); +} + +///** +// * @tc.name: RdbStore_Transaction_017 +// * @tc.desc: BatchInsert with corrupt +// * @tc.type: FUNC +// */ +//HWTEST_F(TransactionTest, RdbStore_Transaction_017, TestSize.Level1) +//{ +// std::string path = RDB_TEST_PATH + "transaction_test_017.db"; +// RdbHelper::DeleteRdbStore(path); +// RdbStoreConfig config(path); +// TransactionTestOpenCallback helper; +// int errCode = 1; +// auto store = RdbHelper::GetRdbStore(config, 1, helper, errCode); +// ASSERT_NE(store, nullptr); +// ASSERT_EQ(errCode, E_OK); +// store->Execute("DROP TABLE IF EXISTS test1"); +// auto res = store->Execute("CREATE TABLE test1 (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)"); +// ASSERT_EQ(res.first, E_OK); +// +// store = nullptr; +// ASSERT_TRUE(UTUtils::DestoryDb(path, 4096 - 100, std::vector(100, 0x11))); +// store = RdbHelper::GetRdbStore(config, 1, helper, errCode); +// ASSERT_NE(store, nullptr); +// ASSERT_EQ(errCode, E_OK); +// auto [ret, transaction] = store->CreateTransaction(Transaction::EXCLUSIVE); +// ASSERT_EQ(ret, E_OK); +// ASSERT_NE(transaction, nullptr); +// +// ValuesBuckets rows; +// for (int i = 0; i < 2000; i++) { +// Transaction::Row row; +// row.Put("id", i); +// row.Put("name", std::string("JimJimJim1", 10240)); +// rows.Put(row); +// } +// auto result = transaction->BatchInsertWithConflictResolution("test1", rows, ConflictResolution::ON_CONFLICT_NONE); +// ASSERT_EQ(result.first, E_SQLITE_CORRUPT); +// +// RdbHelper::DeleteRdbStore(path); +//} diff --git a/relational_store/test/native/rdb_data_share_adapter/BUILD.gn b/relational_store/test/native/rdb_data_share_adapter/BUILD.gn index 9951632241bb0a3bc4819c1cb05c709e736f870d..0b4d080a2eb47bbf48e8ee16e4657db997ed77f9 100644 --- a/relational_store/test/native/rdb_data_share_adapter/BUILD.gn +++ b/relational_store/test/native/rdb_data_share_adapter/BUILD.gn @@ -34,6 +34,10 @@ config("module_private_config") { "//commonlibrary/c_utils/base/include", ] + cflags = [ + "-fno-access-control", #Ignore Private Member Access Control + ] + if (relational_store_rdb_support_icu) { include_dirs += [ "//third_party/icu/icu4c/source/i18n", diff --git a/relational_store/test/native/rdb_data_share_adapter/unittest/rdb_data_share_adapter_test.cpp b/relational_store/test/native/rdb_data_share_adapter/unittest/rdb_data_share_adapter_test.cpp index 1f4b8481563ba8d677fbfeefda39148512e505e3..2c4ee8c1ef1403b2d3e5378efc401e67344e6c95 100644 --- a/relational_store/test/native/rdb_data_share_adapter/unittest/rdb_data_share_adapter_test.cpp +++ b/relational_store/test/native/rdb_data_share_adapter/unittest/rdb_data_share_adapter_test.cpp @@ -44,6 +44,8 @@ public: void GenerateDefaultEmptyTable(); + int ResultSize(std::shared_ptr resultSet); + static const std::string DATABASE_NAME; static std::shared_ptr store; static const std::string RDB_ADAPTER_TEST_PATH; @@ -139,6 +141,18 @@ void RdbDataShareAdapterTest::GenerateDefaultEmptyTable() store->ExecuteSql(createTableSql); } +int RdbDataShareAdapterTest::ResultSize(std::shared_ptr resultSet) +{ + if (resultSet->GoToFirstRow() != OHOS::NativeRdb::E_OK) { + return 0; + } + int count = 1; + while (resultSet->GoToNextRow() == OHOS::NativeRdb::E_OK) { + count++; + } + return count; +} + /* * * @tc.name: Rdb_DataShare_Adapter_001 * @tc.desc: test RdbDataShareAdapter @@ -453,4 +467,58 @@ HWTEST_F(RdbDataShareAdapterTest, Rdb_DataShare_Adapter_008, TestSize.Level1) int ok = allDataTypes->GetRowCount(rowCount); EXPECT_EQ(ok, OHOS::NativeRdb::E_OK); EXPECT_EQ(1, rowCount); -} \ No newline at end of file +} + +/* * + * @tc.name: Rdb_DataShare_Adapter_009 + * @tc.desc: normal testcase of RdbDataShareAdapter + * @tc.type: FUNC + */ +HWTEST_F(RdbDataShareAdapterTest, Rdb_DataShare_Adapter_009, TestSize.Level1) +{ + std::string createTableSql = std::string("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT,") + + std::string("age INTEGER, salary REAL);"); + store->ExecuteSql(createTableSql); + + DataShareValuesBucket values; + int64_t id; + values.Put("name", std::string("zhangsan")); + values.Put("age", INT64_MIN); + values.Put("salary", DBL_MIN); + int ret1 = store->Insert(id, "test", RdbUtils::ToValuesBucket(values)); + EXPECT_EQ(ret1, OHOS::NativeRdb::E_OK); + EXPECT_EQ(1, id); + + values.Clear(); + values.Put("name", std::string("lisi")); + values.Put("age", INT64_MAX); + values.Put("salary", DBL_MAX); + int ret2 = store->Insert(id, "test", RdbUtils::ToValuesBucket(values)); + EXPECT_EQ(ret2, OHOS::NativeRdb::E_OK); + EXPECT_EQ(2, id); + + std::string table = "test"; + OHOS::DataShare::OperationItem item; + item.singleParams = {}; + RdbPredicates predicates("test"); + RdbUtils::EqualTo(item, predicates); + std::vector columns; + std::shared_ptr allPerson = store->Query(predicates, columns); + EXPECT_EQ(2, ResultSize(allPerson)); + + RdbUtils::GreaterThan(item, predicates); + allPerson = store->Query(predicates, columns); + EXPECT_EQ(2, ResultSize(allPerson)); + + RdbUtils::Limit(item, predicates); + allPerson = store->Query(predicates, columns); + EXPECT_EQ(2, ResultSize(allPerson)); + + RdbUtils::NotEqualTo(item, predicates); + allPerson = store->Query(predicates, columns); + EXPECT_EQ(2, ResultSize(allPerson)); + + RdbUtils::LessThan(item, predicates); + allPerson = store->Query(predicates, columns); + EXPECT_EQ(2, ResultSize(allPerson)); +} diff --git a/relational_store/test/native/relational_store_test/unittest/rdb_store_test.cpp b/relational_store/test/native/relational_store_test/unittest/rdb_store_test.cpp index dc26564948ae633521a9044c6cff7ba8c9dfa50b..6b9ac6a38dd378d1e8ee97e3ca16a9a505cdf23d 100644 --- a/relational_store/test/native/relational_store_test/unittest/rdb_store_test.cpp +++ b/relational_store/test/native/relational_store_test/unittest/rdb_store_test.cpp @@ -857,7 +857,6 @@ HWTEST_F(RdbTest, SetSearchableTest, TestSize.Level2) * @tc.name: RdbStore_Delete_001 * @tc.desc: normal testcase of SqliteSharedResultSet for move * @tc.type: FUNC - * @tc.require: AR000FKD4F */ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_001, TestSize.Level1) { @@ -955,7 +954,6 @@ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_001, TestSize.Level1) * @tc.name: Sqlite_Shared_Result_Set_002 * @tc.desc: normal testcase of SqliteSharedResultSet for goToNextRow * @tc.type: FUNC - * @tc.require: AR000FKD4F */ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_002, TestSize.Level1) { @@ -1040,7 +1038,6 @@ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_002, TestSize.Level1) * @tc.name: Sqlite_Shared_Result_Set_003 * @tc.desc: normal testcase of SqliteSharedResultSet for moveFirst * @tc.type: FUNC - * @tc.require: AR000FKD4F */ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_003, TestSize.Level1) { @@ -1092,7 +1089,6 @@ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_003, TestSize.Level1) * @tc.name: Sqlite_Shared_Result_Set_004 * @tc.desc: normal testcase of SqliteSharedResultSet for getInt * @tc.type: FUNC - * @tc.require: AR000FKD4F */ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_004, TestSize.Level1) { @@ -1134,7 +1130,6 @@ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_004, TestSize.Level1) * @tc.name: Sqlite_Shared_Result_Set_005 * @tc.desc: normal testcase of SqliteSharedResultSet for getString * @tc.type: FUNC - * @tc.require: AR000FKD4F */ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_005, TestSize.Level1) @@ -1188,7 +1183,6 @@ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_005, TestSize.Level1) * @tc.name: Sqlite_Shared_Result_Set_006 * @tc.desc: normal testcase of SqliteSharedResultSet for getDouble * @tc.type: FUNC - * @tc.require: AR000FKD4F */ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_006, TestSize.Level1) { @@ -1240,7 +1234,6 @@ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_006, TestSize.Level1) * @tc.name: Sqlite_Shared_Result_Set_007 * @tc.desc: normal testcase of SqliteSharedResultSet for getBlob * @tc.type: FUNC - * @tc.require: AR000FKD4F */ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_007, TestSize.Level1) { @@ -1278,7 +1271,6 @@ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_007, TestSize.Level1) * @tc.name: Sqlite_Shared_Result_Set_008 * @tc.desc: normal testcase of SqliteSharedResultSet for getColumnTypeForIndex * @tc.type: FUNC - * @tc.require: AR000FKD4F */ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_008, TestSize.Level1) @@ -1329,7 +1321,6 @@ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_008, TestSize.Level1) * @tc.name: Sqlite_Shared_Result_Set_009 * @tc.desc: normal testcase of SqliteSharedResultSet for getColumnIndexForName * @tc.type: FUNC - * @tc.require: AR000FKD4F */ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_009, TestSize.Level1) { @@ -1363,7 +1354,6 @@ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_009, TestSize.Level1) * @tc.name: Sqlite_Shared_Result_Set_010 * @tc.desc: normal testcase of SqliteSharedResultSet for getColumnNameForIndex * @tc.type: FUNC - * @tc.require: AR000FKD4F */ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_010, TestSize.Level1) { @@ -1403,7 +1393,6 @@ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_010, TestSize.Level1) * @tc.name: Sqlite_Shared_Result_Set_011 * @tc.desc: normal testcase of SqliteSharedResultSet * @tc.type: FUNC - * @tc.require: AR000FKD4F */ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_011, TestSize.Level1) { @@ -1436,7 +1425,6 @@ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_011, TestSize.Level1) * @tc.name: Sqlite_Shared_Result_Set_012 * @tc.desc: normal testcase of SqliteSharedResultSet for getLong * @tc.type: FUNC - * @tc.require: AR000FKD4F */ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_012, TestSize.Level1) { @@ -1485,7 +1473,6 @@ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_012, TestSize.Level1) * @tc.name: Sqlite_Shared_Result_Set_013 * @tc.desc: normal testcase of SqliteSharedResultSet for fillBlock * @tc.type: FUNC - * @tc.require: AR000FKD4F */ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_013, TestSize.Level1) { @@ -1506,7 +1493,6 @@ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_013, TestSize.Level1) * @tc.name: Sqlite_Shared_Result_Set_014 * @tc.desc: normal testcase of SqliteSharedResultSet for getBlock * @tc.type: FUNC - * @tc.require: AR000FKD4F */ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_014, TestSize.Level1) { @@ -1538,7 +1524,6 @@ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_014, TestSize.Level1) * @tc.name: Sqlite_Shared_Result_Set_015 * @tc.desc: normal testcase of SqliteSharedResultSet for setBlock * @tc.type: FUNC - * @tc.require: AR000FKD4F */ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_015, TestSize.Level1) { @@ -1570,7 +1555,6 @@ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_015, TestSize.Level1) * @tc.name: Sqlite_Shared_Result_Set_016 * @tc.desc: normal testcase of SqliteSharedResultSet for setFillWindowForwardOnly * @tc.type: FUNC - * @tc.require: AR000FKD4F */ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_016, TestSize.Level1) { @@ -1610,7 +1594,6 @@ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_016, TestSize.Level1) * @tc.name: Sqlite_Shared_Result_Set_017 * @tc.desc: normal testcase of SqliteSharedResultSet for setExtensions and getExtensions * @tc.type: FUNC - * @tc.require: AR000FKD4F */ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_017, TestSize.Level1) { @@ -1630,7 +1613,6 @@ HWTEST_F(RdbTest, Sqlite_Shared_Result_Set_017, TestSize.Level1) * @tc.name: RdbStore_Transaction_001 * @tc.desc: test RdbStore BaseTransaction * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: chenxi */ HWTEST_F(RdbTest, RdbStore_Transaction_001, TestSize.Level1) @@ -1690,7 +1672,6 @@ HWTEST_F(RdbTest, RdbStore_Transaction_001, TestSize.Level1) * @tc.name: RdbStore_Transaction_002 * @tc.desc: test RdbStore BaseTransaction * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: chenxi */ HWTEST_F(RdbTest, RdbStore_Transaction_002, TestSize.Level1) @@ -1757,7 +1738,6 @@ HWTEST_F(RdbTest, RdbStore_Transaction_002, TestSize.Level1) * @tc.name: RdbStore_NestedTransaction_001 * @tc.desc: test RdbStore BaseTransaction * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: chenxi */ HWTEST_F(RdbTest, RdbStore_NestedTransaction_001, TestSize.Level1) @@ -1828,7 +1808,6 @@ HWTEST_F(RdbTest, RdbStore_NestedTransaction_001, TestSize.Level1) * @tc.name: RdbStore_NestedTransaction_002 * @tc.desc: test RdbStore BaseTransaction * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: chenxi */ HWTEST_F(RdbTest, RdbStore_NestedTransaction_002, TestSize.Level1) @@ -1898,7 +1877,6 @@ HWTEST_F(RdbTest, RdbStore_NestedTransaction_002, TestSize.Level1) * @tc.name: RdbStore_NestedTransaction_003 * @tc.desc: test RdbStore BaseTransaction * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: chenxi */ HWTEST_F(RdbTest, RdbStore_NestedTransaction_003, TestSize.Level1) diff --git a/relational_store/test/native/relational_store_test/unittest/relational_store_test.cpp b/relational_store/test/native/relational_store_test/unittest/relational_store_test.cpp index 8490f1fabcd06b42e098465ad31e1cd03ca447d3..2ee9264cab41bb623644b5f7dda3ea646ea9a158 100644 --- a/relational_store/test/native/relational_store_test/unittest/relational_store_test.cpp +++ b/relational_store/test/native/relational_store_test/unittest/relational_store_test.cpp @@ -138,7 +138,6 @@ void RdbTest::TearDown(void) * @tc.name: RdbStore_Attach_001 * @tc.desc: test attach, attach is not supported in wal mode * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, RdbStore_Attach_001, TestSize.Level1) @@ -160,7 +159,6 @@ HWTEST_F(RdbTest, RdbStore_Attach_001, TestSize.Level1) * @tc.name: RdbStore_Attach_002 * @tc.desc: test RdbStore attach * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, RdbStore_Attach_002, TestSize.Level1) @@ -269,7 +267,6 @@ void RdbTest::QueryCheck2(std::shared_ptr &store) const * @tc.name: RdbStore_Delete_001 * @tc.desc: test RdbStore update, select id and update one row * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, RdbStore_Delete_001, TestSize.Level1) @@ -344,7 +341,6 @@ HWTEST_F(RdbTest, RdbStore_Delete_001, TestSize.Level1) * @tc.name: RdbStore_Delete_002 * @tc.desc: test RdbStore update, select id and update one row * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, RdbStore_Delete_002, TestSize.Level1) @@ -661,7 +657,6 @@ HWTEST_F(RdbTest, RdbStore_Encrypt_09, TestSize.Level1) * @tc.name: RdbStore_Execute_001 * @tc.desc: test RdbStore Execute * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, RdbStore_Execute_001, TestSize.Level1) @@ -725,7 +720,6 @@ HWTEST_F(RdbTest, RdbStore_Execute_001, TestSize.Level1) * @tc.name: RdbStore_Execute_002 * @tc.desc: test RdbStore Execute * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, RdbStore_Execute_002, TestSize.Level1) @@ -794,7 +788,6 @@ HWTEST_F(RdbTest, RdbStore_Execute_002, TestSize.Level1) * @tc.name: RdbStore_Execute_003 * @tc.desc: test RdbStore Execute * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, RdbStore_Execute_003, TestSize.Level1) @@ -816,7 +809,6 @@ HWTEST_F(RdbTest, RdbStore_Execute_003, TestSize.Level1) * @tc.name: RdbStore_Insert_001 * @tc.desc: test RdbStore insert * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, RdbStore_Insert_001, TestSize.Level1) @@ -964,7 +956,6 @@ void RdbTest::CheckBlob(std::unique_ptr &resultSet) * @tc.name: RdbStore_Replace_001 * @tc.desc: test RdbStore replace * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, RdbStore_Replace_001, TestSize.Level1) @@ -1039,7 +1030,6 @@ HWTEST_F(RdbTest, RdbStore_Replace_001, TestSize.Level1) * @tc.name: RdbStore_Replace_002 * @tc.desc: test RdbStore replace * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, RdbStore_Replace_002, TestSize.Level1) @@ -1124,7 +1114,6 @@ HWTEST_F(RdbTest, RdbStore_Replace_002, TestSize.Level1) * @tc.name: RdbStore_InsertWithConflictResolution_001_002 * @tc.desc: test RdbStore InsertWithConflictResolution * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, RdbStore_InsertWithConflictResolution_001_002, TestSize.Level1) @@ -1159,7 +1148,6 @@ HWTEST_F(RdbTest, RdbStore_InsertWithConflictResolution_001_002, TestSize.Level1 * @tc.name: RdbStore_InsertWithConflictResolution_003_004 * @tc.desc: test RdbStore InsertWithConflictResolution * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, RdbStore_InsertWithConflictResolution_003_004, TestSize.Level1) @@ -1192,7 +1180,6 @@ HWTEST_F(RdbTest, RdbStore_InsertWithConflictResolution_003_004, TestSize.Level1 * @tc.name: RdbStore_InsertWithConflictResolution_005 * @tc.desc: test RdbStore InsertWithConflictResolution * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, RdbStore_InsertWithConflictResolution_005, TestSize.Level1) @@ -1226,7 +1213,6 @@ HWTEST_F(RdbTest, RdbStore_InsertWithConflictResolution_005, TestSize.Level1) * @tc.name: RdbStore_InsertWithConflictResolution_006_007 * @tc.desc: test RdbStore InsertWithConflictResolution * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, RdbStore_InsertWithConflictResolution_006_007, TestSize.Level1) @@ -1342,7 +1328,6 @@ HWTEST_F(RdbTest, RdbStore_BatchInsert_001, TestSize.Level1) * @tc.name: ValueObject_TEST_001 * @tc.desc: test ValueObject * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, ValueObject_TEST_001, TestSize.Level1) @@ -1356,7 +1341,6 @@ HWTEST_F(RdbTest, ValueObject_TEST_001, TestSize.Level1) * @tc.name: ValueObject_TEST_002 * @tc.desc: test ValueObject * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, ValueObject_TEST_002, TestSize.Level1) @@ -1375,7 +1359,6 @@ HWTEST_F(RdbTest, ValueObject_TEST_002, TestSize.Level1) * @tc.name: ValueObject_TEST_003 * @tc.desc: test ValueObject * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, ValueObject_TEST_003, TestSize.Level1) @@ -1394,7 +1377,6 @@ HWTEST_F(RdbTest, ValueObject_TEST_003, TestSize.Level1) * @tc.name: ValueObject_TEST_004 * @tc.desc: test ValueObject * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, ValueObject_TEST_004, TestSize.Level1) @@ -1413,7 +1395,6 @@ HWTEST_F(RdbTest, ValueObject_TEST_004, TestSize.Level1) * @tc.name: ValueObject_TEST_005 * @tc.desc: test ValueObject * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, ValueObject_TEST_005, TestSize.Level1) @@ -1437,7 +1418,6 @@ HWTEST_F(RdbTest, ValueObject_TEST_005, TestSize.Level1) * @tc.name: ValueObject_TEST_006 * @tc.desc: test ValueObject * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, ValueObject_TEST_006, TestSize.Level1) @@ -1454,7 +1434,6 @@ HWTEST_F(RdbTest, ValueObject_TEST_006, TestSize.Level1) * @tc.name: ValuesBucket_001 * @tc.desc: test ValuesBucket * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, ValuesBucket_001, TestSize.Level1) @@ -1496,7 +1475,6 @@ HWTEST_F(RdbTest, ValuesBucket_001, TestSize.Level1) * @tc.name: ValuesBucket_002 * @tc.desc: test ValuesBucket * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, ValuesBucket_002, TestSize.Level1) @@ -1545,7 +1523,6 @@ HWTEST_F(RdbTest, ValuesBucket_002, TestSize.Level1) * @tc.name: ValuesBucket_003 * @tc.desc: test ValuesBucket * @tc.type: FUNC - * @tc.require: AR000CU2BO * @tc.author: */ HWTEST_F(RdbTest, ValuesBucket_003, TestSize.Level1) diff --git a/relational_store/test/ndk/BUILD.gn b/relational_store/test/ndk/BUILD.gn index eba7c49d3c5ce8c42bb0fb251808a7f8c0a898bd..bac7bfd0aa0d626ff8adaa216859c1098f9db7e5 100644 --- a/relational_store/test/ndk/BUILD.gn +++ b/relational_store/test/ndk/BUILD.gn @@ -34,19 +34,13 @@ ohos_unittest("NativeRdbNdkTest") { module_out_path = module_output_path sources = [ - "${relational_store_base_path}/interfaces/ndk/src/convertor_error_code.cpp", - "${relational_store_base_path}/interfaces/ndk/src/modify_time_cursor.cpp", - "${relational_store_base_path}/interfaces/ndk/src/relational_asset.cpp", - "${relational_store_base_path}/interfaces/ndk/src/relational_cursor.cpp", - "${relational_store_base_path}/interfaces/ndk/src/relational_predicates.cpp", - "${relational_store_base_path}/interfaces/ndk/src/relational_predicates_objects.cpp", - "${relational_store_base_path}/interfaces/ndk/src/relational_store.cpp", - "${relational_store_base_path}/interfaces/ndk/src/relational_values_bucket.cpp", "unittest/rdb_asset_test.cpp", "unittest/rdb_cursor_test.cpp", "unittest/rdb_predicates_test.cpp", "unittest/rdb_store_configv2_test.cpp", "unittest/rdb_store_test.cpp", + "unittest/rdb_transaction_capi_test.cpp", + "unittest/rdb_vector_test.cpp", ] configs = [ ":module_private_config" ] @@ -59,6 +53,7 @@ ohos_unittest("NativeRdbNdkTest") { ] deps = [ + "${relational_store_base_path}/interfaces/ndk/src:native_rdb_ndk", "${relational_store_innerapi_path}/rdb:native_rdb", "//third_party/googletest:gtest_main", ] diff --git a/relational_store/test/ndk/unittest/rdb_store_configv2_test.cpp b/relational_store/test/ndk/unittest/rdb_store_configv2_test.cpp index 5101cb41887a4803e2a65df603256d3ab99ca00d..59536601af32a0eacd2d6a0f5b71544488874535 100644 --- a/relational_store/test/ndk/unittest/rdb_store_configv2_test.cpp +++ b/relational_store/test/ndk/unittest/rdb_store_configv2_test.cpp @@ -196,3 +196,111 @@ HWTEST_F(RdbNativeStoreConfigV2Test, RDB_Native_store_test_004, TestSize.Level1) EXPECT_EQ(OH_Rdb_ErrCode::RDB_E_INVALID_ARGS, OH_Rdb_DestroyConfig(nullptr)); EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_DestroyConfig(config)); } + +void VdbTest003(const OH_Rdb_ConfigV2 *config) +{ + int errCode = OH_Rdb_ErrCode::RDB_OK; + auto store = OH_Rdb_CreateOrOpen(config, &errCode); + EXPECT_NE(store, nullptr); + + char createTableSql[] = "CREATE TABLE t1(id INT PRIMARY KEY, repr floatvector(4));"; + EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_ExecuteByTrxId(store, 0, createTableSql)); + + char createIndexSql[] = "CREATE INDEX diskann_idx ON t1 USING GSDISKANN(repr L2);"; + EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_ExecuteByTrxId(store, 0, createIndexSql)); + + int64_t trxId = 0; + EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_BeginTransWithTrxId(store, &trxId)); + char insertSql[] = "INSERT INTO t1 VALUES(1, '[1, 2, 3, 4]');"; + EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_ExecuteByTrxId(store, trxId, insertSql)); + EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_CommitByTrxId(store, trxId)); + + char insertSql2[] = "INSERT INTO t1 VALUES(2, '[2, 2, 3, 4]');"; + EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_ExecuteByTrxId(store, 0, insertSql2)); + + char deleteSql[] = "DELETE FROM t1 WHERE id = 1;"; + EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_ExecuteByTrxId(store, 0, deleteSql)); + + char dropSql[] = "DROP TABLE IF EXISTS t1;"; + EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_ExecuteByTrxId(store, 0, dropSql)); + + EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_DeleteStoreV2(config)); +} + +HWTEST_F(RdbNativeStoreConfigV2Test, RDB_Native_store_test_005, TestSize.Level1) +{ + auto config = InitRdbConfig(); + int errCode = OH_Rdb_SetDbType(config, RDB_CAYLEY); + EXPECT_TRUE(((!OHOS::NativeRdb::IsUsingArkData()) && errCode == OH_Rdb_ErrCode::RDB_E_NOT_SUPPORTED) || + (OHOS::NativeRdb::IsUsingArkData() && errCode == OH_Rdb_ErrCode::RDB_OK)); + if (OHOS::NativeRdb::IsUsingArkData()) { + VdbTest003(config); + } + OH_Rdb_DestroyConfig(config); +} + +string GetRandVector(uint32_t maxElementNum, uint16_t dim) +{ + auto now = std::chrono::high_resolution_clock::now(); + auto ns = std::chrono::duration_cast(now.time_since_epoch()).count(); + unsigned int randomNumberSeed = static_cast(ns); + std::string res = "["; + for (uint16_t i = 0; i < dim; i++) { + uint32_t intPart = maxElementNum == 0 ? 0 : (rand_r(&randomNumberSeed) % maxElementNum); + intPart += 1; + // 10 is used to limit the number after the decimal point to a maximum of 10. + uint32_t tenths = (rand_r(&randomNumberSeed) % 10); + res += std::to_string(intPart); + res += ".000"; + res += std::to_string(tenths); + res += ", "; + } + res.pop_back(); + res.pop_back(); + res += "]"; + return res; +} + +void VdbTest004(const OH_Rdb_ConfigV2 *config) +{ + int errCode = OH_Rdb_ErrCode::RDB_OK; + auto store = OH_Rdb_CreateOrOpen(config, &errCode); + EXPECT_NE(store, nullptr); + + char createTableSql[] = "CREATE TABLE t1(id INT PRIMARY KEY, repr floatvector(4));"; + EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_ExecuteByTrxId(store, 0, createTableSql)); + + char createIndexSql[] = "CREATE INDEX diskann_idx ON t1 USING GSDISKANN(repr L2);"; + EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_ExecuteByTrxId(store, 0, createIndexSql)); + + uint32_t maxIntPart = 100; + uint32_t numSamples = 100; + uint32_t dim = 4; + + for (uint16_t i = 0; i < numSamples; i++) { + std::string sqlInsert = + "INSERT INTO t1 VALUES(" + std::to_string(i) + ", '" + GetRandVector(maxIntPart, dim) + "');"; + EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_ExecuteByTrxId(store, 0, sqlInsert.data())); + } + for (uint16_t i = 0; i < numSamples; i++) { + std::string sqlDelete = "DELETE FROM t1 WHERE id = " + std::to_string(i) + ";"; + EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_ExecuteByTrxId(store, 0, sqlDelete.data())); + } + + char dropSql[] = "DROP TABLE IF EXISTS t1;"; + EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_ExecuteByTrxId(store, 0, dropSql)); + + EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_DeleteStoreV2(config)); +} + +HWTEST_F(RdbNativeStoreConfigV2Test, RDB_Native_store_test_006, TestSize.Level1) +{ + auto config = InitRdbConfig(); + int errCode = OH_Rdb_SetDbType(config, RDB_CAYLEY); + EXPECT_TRUE(((!OHOS::NativeRdb::IsUsingArkData()) && errCode == OH_Rdb_ErrCode::RDB_E_NOT_SUPPORTED) || + (OHOS::NativeRdb::IsUsingArkData() && errCode == OH_Rdb_ErrCode::RDB_OK)); + if (OHOS::NativeRdb::IsUsingArkData()) { + VdbTest004(config); + } + OH_Rdb_DestroyConfig(config); +} diff --git a/relational_store/test/ndk/unittest/rdb_store_test.cpp b/relational_store/test/ndk/unittest/rdb_store_test.cpp index 6340f98c575aa9b80e2050e38ab5211de792c4a2..48747698f9e0a417819aba72b1e7bd75d20ab32b 100644 --- a/relational_store/test/ndk/unittest/rdb_store_test.cpp +++ b/relational_store/test/ndk/unittest/rdb_store_test.cpp @@ -1491,3 +1491,135 @@ HWTEST_F(RdbNativeStoreTest, RDB_Native_store_test_033, TestSize.Level1) OH_Rdb_Unsubscribe(nullptr, static_cast(RDB_SUBSCRIBE_TYPE_LOCAL_DETAILS + 1), &observer1); EXPECT_EQ(RDB_E_INVALID_ARGS, errCode); } + +/** + * @tc.name: RDB_Native_store_test_034 + * @tc.desc: abNormal testCase for OH_Rdb_Subscribe. + * 1.prams is valid or invalid + * @tc.type: FUNC + */ +HWTEST_F(RdbNativeStoreTest, RDB_Native_store_test_034, TestSize.Level1) +{ + bool isSupported = true; + int errCode = OH_Rdb_IsTokenizerSupported(RDB_NONE_TOKENIZER, &isSupported); + EXPECT_EQ(RDB_OK, errCode); + errCode = OH_Rdb_IsTokenizerSupported(RDB_ICU_TOKENIZER, &isSupported); + EXPECT_EQ(RDB_OK, errCode); + errCode = OH_Rdb_IsTokenizerSupported(RDB_CUSTOM_TOKENIZER, &isSupported); + EXPECT_EQ(RDB_OK, errCode); + errCode = OH_Rdb_IsTokenizerSupported(static_cast(RDB_NONE_TOKENIZER - 1), &isSupported); + EXPECT_EQ(RDB_E_INVALID_ARGS, errCode); + errCode = OH_Rdb_IsTokenizerSupported(static_cast(RDB_CUSTOM_TOKENIZER + 1), &isSupported); + EXPECT_EQ(RDB_E_INVALID_ARGS, errCode); +} + +/** + * @tc.name: RDB_Native_store_test_035 + * @tc.desc: conflict testCase for OH_Rdb_BatchInsert. + * @tc.type: FUNC + */ +HWTEST_F(RdbNativeStoreTest, RDB_Native_store_test_035, TestSize.Level1) +{ + ASSERT_NE(storeTestRdbStore_, nullptr); + OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket(); + valueBucket->putInt64(valueBucket, "id", 12); + valueBucket->putText(valueBucket, "data1", "zhangSan"); + int errCode = OH_Rdb_Insert(storeTestRdbStore_, "store_test", valueBucket); + OH_Data_VBuckets *rows = OH_VBuckets_Create(); + ASSERT_NE(rows, nullptr); + OH_VBucket *vbs[5]; + for (auto i = 0; i < 5; i++) { + OH_VBucket *row = OH_Rdb_CreateValuesBucket(); + ASSERT_NE(row, nullptr); + row->putInt64(row, "id", 10 + i); + row->putText(row, "data1", "test_name"); + vbs[i] = row; + EXPECT_EQ(OH_VBuckets_PutRow(rows, row), RDB_OK); + } + int64_t changes = -1; + int ret = OH_Rdb_BatchInsert(storeTestRdbStore_, "store_test", rows, RDB_CONFLICT_NONE, &changes); + ASSERT_EQ(ret, RDB_E_SQLITE_CONSTRAINT); + ASSERT_EQ(changes, 0); + ret = OH_Rdb_BatchInsert(storeTestRdbStore_, "store_test", rows, RDB_CONFLICT_ROLLBACK, &changes); + ASSERT_EQ(ret, RDB_E_SQLITE_CONSTRAINT); + ASSERT_EQ(changes, 0); + ret = OH_Rdb_BatchInsert(storeTestRdbStore_, "store_test", rows, RDB_CONFLICT_ABORT, &changes); + ASSERT_EQ(ret, RDB_E_SQLITE_CONSTRAINT); + ASSERT_EQ(changes, 0); + ret = OH_Rdb_BatchInsert(storeTestRdbStore_, "store_test", rows, RDB_CONFLICT_FAIL, &changes); + ASSERT_EQ(ret, RDB_E_SQLITE_CONSTRAINT); + ASSERT_EQ(changes, 2); + ret = OH_Rdb_BatchInsert(storeTestRdbStore_, "store_test", rows, RDB_CONFLICT_IGNORE, &changes); + ASSERT_EQ(ret, RDB_OK); + ASSERT_EQ(changes, 2); + ret = OH_Rdb_BatchInsert(storeTestRdbStore_, "store_test", rows, RDB_CONFLICT_REPLACE, &changes); + ASSERT_EQ(ret, RDB_OK); + ASSERT_EQ(changes, 5); + for (OH_VBucket *vb : vbs) { + vb->destroy(vb); + } + OH_VBuckets_Destroy(rows); + char querySql[] = "SELECT * FROM store_test"; + OH_Cursor *cursor = OH_Rdb_ExecuteQuery(storeTestRdbStore_, querySql); + int rowCount = 0; + cursor->getRowCount(cursor, &rowCount); + EXPECT_EQ(rowCount, 6); + cursor->destroy(cursor); +} + +/** + * @tc.name: RDB_Native_store_test_036 + * @tc.desc: normal testCase for OH_Rdb_BatchInsert. + * @tc.type: FUNC + */ +HWTEST_F(RdbNativeStoreTest, RDB_Native_store_test_036, TestSize.Level1) +{ + ASSERT_NE(storeTestRdbStore_, nullptr); + OH_Data_VBuckets *rows = OH_VBuckets_Create(); + ASSERT_NE(rows, nullptr); + OH_VBucket *vbs[2]; + for (auto i = 0; i < 2; i++) { + OH_VBucket *row = OH_Rdb_CreateValuesBucket(); + ASSERT_NE(row, nullptr); + row->putText(row, "data1", "test_name4"); + row->putInt64(row, "data2", 14800); + row->putReal(row, "data3", 300.1); + row->putText(row, "data5", "ABCDEFGHI"); + EXPECT_EQ(OH_VBuckets_PutRow(rows, row), RDB_OK); + vbs[i] = row; + } + int64_t changes = -1; + int ret = OH_Rdb_BatchInsert(storeTestRdbStore_, "store_test", rows, RDB_CONFLICT_NONE, &changes); + ASSERT_EQ(ret, RDB_OK); + ASSERT_EQ(changes, 2); + + ret = OH_Rdb_BatchInsert(storeTestRdbStore_, "store_test", rows, RDB_CONFLICT_ROLLBACK, &changes); + ASSERT_EQ(ret, RDB_OK); + ASSERT_EQ(changes, 2); + + ret = OH_Rdb_BatchInsert(storeTestRdbStore_, "store_test", rows, RDB_CONFLICT_ABORT, &changes); + ASSERT_EQ(ret, RDB_OK); + ASSERT_EQ(changes, 2); + + ret = OH_Rdb_BatchInsert(storeTestRdbStore_, "store_test", rows, RDB_CONFLICT_FAIL, &changes); + ASSERT_EQ(ret, RDB_OK); + ASSERT_EQ(changes, 2); + + ret = OH_Rdb_BatchInsert(storeTestRdbStore_, "store_test", rows, RDB_CONFLICT_IGNORE, &changes); + ASSERT_EQ(ret, RDB_OK); + ASSERT_EQ(changes, 2); + + ret = OH_Rdb_BatchInsert(storeTestRdbStore_, "store_test", rows, RDB_CONFLICT_REPLACE, &changes); + ASSERT_EQ(ret, RDB_OK); + ASSERT_EQ(changes, 2); + for (OH_VBucket *vb : vbs) { + vb->destroy(vb); + } + OH_VBuckets_Destroy(rows); + char querySql[] = "SELECT * FROM store_test"; + OH_Cursor *cursor = OH_Rdb_ExecuteQuery(storeTestRdbStore_, querySql); + int rowCount = 0; + cursor->getRowCount(cursor, &rowCount); + EXPECT_EQ(rowCount, 13); + cursor->destroy(cursor); +} \ No newline at end of file diff --git a/relational_store/test/ndk/unittest/rdb_transaction_capi_test.cpp b/relational_store/test/ndk/unittest/rdb_transaction_capi_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bac6a33ae015fb2028fe6dc38611e225057a1e46 --- /dev/null +++ b/relational_store/test/ndk/unittest/rdb_transaction_capi_test.cpp @@ -0,0 +1,843 @@ +/* + * Copyright (c) 2024 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 +#include +#include "relational_store.h" +#include "oh_values_bucket.h" +#include "oh_values_bucket.h" +#include "common.h" +#include "relational_store_error_code.h" +#include "oh_data_values.h" +#include "oh_data_value.h" + +using namespace testing::ext; +using namespace OHOS::NativeRdb; + +class RdbTransactionCapiTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + static void InitRdbConfig() + { + config_.dataBaseDir = RDB_TEST_PATH; + config_.storeName = "rdb_store_test.db"; + config_.bundleName = "com.ohos.example.distributedndk"; + config_.moduleName = ""; + config_.securityLevel = OH_Rdb_SecurityLevel::S1; + config_.isEncrypt = false; + config_.selfSize = sizeof(OH_Rdb_Config); + config_.area = RDB_SECURITY_AREA_EL1; + } + static OH_Rdb_Config config_; +}; + +static OH_Rdb_Store *g_transStore; +static OH_RDB_TransOptions *g_options; +OH_Rdb_Config RdbTransactionCapiTest::config_ = { 0 }; + +void RdbTransactionCapiTest::SetUpTestCase(void) +{ + InitRdbConfig(); + int chmodValue = 0770; + mkdir(config_.dataBaseDir, chmodValue); + int errCode = 0; + char table[] = "test"; + g_transStore = OH_Rdb_GetOrOpen(&config_, &errCode); + EXPECT_NE(g_transStore, NULL); + + char createTableSql[] = "CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, data1 TEXT, data2 INTEGER, " + "data3 FLOAT, data4 BLOB, data5 TEXT);"; + errCode = OH_Rdb_Execute(g_transStore, createTableSql); + + OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket(); + valueBucket->putInt64(valueBucket, "id", 1); + valueBucket->putText(valueBucket, "data1", "zhangSan"); + // init row one data2 value 12800 + valueBucket->putInt64(valueBucket, "data2", 12800); + // init row one data3 value 100.1 + valueBucket->putReal(valueBucket, "data3", 100.1); + uint8_t arr[] = { 1, 2, 3, 4, 5 }; + int len = sizeof(arr) / sizeof(arr[0]); + valueBucket->putBlob(valueBucket, "data4", arr, len); + valueBucket->putText(valueBucket, "data5", "ABCDEFG"); + errCode = OH_Rdb_Insert(g_transStore, table, valueBucket); + // expect value is 1 + EXPECT_EQ(errCode, 1); + + valueBucket->clear(valueBucket); + // init row two id value 2 + valueBucket->putInt64(valueBucket, "id", 2); + valueBucket->putText(valueBucket, "data1", "liSi"); + // init row two data2 value 13800 + valueBucket->putInt64(valueBucket, "data2", 13800); + // init row two data2 value 200.1 + valueBucket->putReal(valueBucket, "data3", 200.1); + valueBucket->putText(valueBucket, "data5", "ABCDEFGH"); + errCode = OH_Rdb_Insert(g_transStore, table, valueBucket); + // expect value is 2 + EXPECT_EQ(errCode, 2); + + valueBucket->clear(valueBucket); + // init row three id value 3 + valueBucket->putInt64(valueBucket, "id", 3); + valueBucket->putText(valueBucket, "data1", "wangWu"); + // init row three data2 value 14800 + valueBucket->putInt64(valueBucket, "data2", 14800); + // init row three data3 value 300.1 + valueBucket->putReal(valueBucket, "data3", 300.1); + valueBucket->putText(valueBucket, "data5", "ABCDEFGHI"); + errCode = OH_Rdb_Insert(g_transStore, table, valueBucket); + // expect value is 3 + EXPECT_EQ(errCode, 3); + + valueBucket->destroy(valueBucket); + + g_options = OH_RdbTrans_CreateOptions(); + EXPECT_NE(g_options, nullptr); + int ret = OH_RdbTransOption_SetType(g_options, RDB_TRANS_BUTT); + EXPECT_EQ(ret, RDB_E_INVALID_ARGS); + ret = OH_RdbTransOption_SetType(g_options, RDB_TRANS_DEFERRED); + EXPECT_EQ(ret, RDB_OK); +} + +void RdbTransactionCapiTest::TearDownTestCase(void) +{ + char dropTableSql[] = "DROP TABLE IF EXISTS test"; + int errCode = OH_Rdb_Execute(g_transStore, dropTableSql); + EXPECT_EQ(errCode, 0); + delete g_transStore; + g_transStore = NULL; + OH_Rdb_DeleteStore(&config_); + OH_RdbTrans_DestroyOptions(g_options); + g_options = nullptr; +} + +void RdbTransactionCapiTest::SetUp(void) +{ +} + +void RdbTransactionCapiTest::TearDown(void) +{ +} + +static void FillDataValues(OH_Data_Values *values) +{ + EXPECT_NE(values, nullptr); + OH_Data_Value *value = OH_Value_Create(); + int ret = OH_Value_PutInt(nullptr, 1); + EXPECT_EQ(ret, RDB_E_INVALID_ARGS); + ret = OH_Value_PutInt(value, 1); + EXPECT_EQ(ret, RDB_OK); + + ret = OH_Values_Put(nullptr, value); + EXPECT_EQ(ret, RDB_E_INVALID_ARGS); + ret = OH_Values_Put(values, nullptr); + EXPECT_EQ(ret, RDB_E_INVALID_ARGS); + ret = OH_Values_Put(values, value); + EXPECT_EQ(ret, RDB_OK); + ret = OH_Value_Destroy(value); + EXPECT_EQ(ret, RDB_OK); + + // Add int value 2 to values + ret = OH_Values_PutInt(values, 2); + EXPECT_EQ(ret, RDB_OK); + // Add double value 1.1 to values + ret = OH_Values_PutReal(values, 1.1); + EXPECT_EQ(ret, RDB_OK); + ret = OH_Values_PutText(values, "1"); + EXPECT_EQ(ret, RDB_OK); + // init unsigend char 1 and 2 + unsigned char val[] = {1, 2}; + ret = OH_Values_PutBlob(values, val, sizeof(val) / sizeof(val[0])); + EXPECT_EQ(ret, RDB_OK); + + // asset + Data_Asset *asset = OH_Data_Asset_CreateOne(); + ret = OH_Data_Asset_SetName(asset, "name"); + EXPECT_EQ(ret, RDB_OK); + ret = OH_Values_PutAsset(values, asset); + EXPECT_EQ(ret, RDB_OK); + OH_Data_Asset_DestroyOne(asset); + + // asset array + Data_Asset **assets = OH_Data_Asset_CreateMultiple(2); + ret = OH_Data_Asset_SetName(assets[0], "name1"); + EXPECT_EQ(ret, RDB_OK); + ret = OH_Data_Asset_SetName(assets[1], "name2"); + EXPECT_EQ(ret, RDB_OK); + // 2 elements in assets + ret = OH_Values_PutAssets(values, assets, 2); + EXPECT_EQ(ret, RDB_OK); + // 2 elements in assets + ret = OH_Data_Asset_DestroyMultiple(assets, 2); + EXPECT_EQ(ret, RDB_OK); + + // big int + uint64_t bigInt[] = {1, 2, 3, 4, 5}; + ret = OH_Values_PutUnlimitedInt(values, 0, bigInt, sizeof(bigInt) / sizeof(bigInt[0])); + EXPECT_EQ(ret, RDB_OK); +} + +static void ReadDataValuesPartOne(OH_Data_Values *values) +{ + // read + size_t readSize = 0; + int ret = OH_Values_Count(values, &readSize); + EXPECT_EQ(ret, RDB_OK); + // ecpect value is 8 + EXPECT_EQ(readSize, 8); + + OH_ColumnType columnType; + ret = OH_Values_GetType(values, 0, &columnType); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(columnType, TYPE_INT64); + + OH_Data_Value *readData0 = nullptr; + ret = OH_Values_Get(values, 0, &readData0); + EXPECT_EQ(ret, RDB_OK); + EXPECT_NE(readData0, nullptr); + + bool isNull; + ret = OH_Values_IsNull(values, 0, &isNull); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(isNull, false); + + int64_t readData1; + // index 1 in values array + ret = OH_Values_GetInt(values, 1, &readData1); + EXPECT_EQ(ret, RDB_OK); + // ecpect value is 2 + EXPECT_EQ(readData1, 2); + + double readData2; + // index 2 in values array + ret = OH_Values_GetReal(values, 2, &readData2); + EXPECT_EQ(ret, RDB_OK); + // ecpect value is 1.1 + EXPECT_EQ(readData2, 1.1); + + const char *readData3 = nullptr; + // index 3 in values array + ret = OH_Values_GetText(values, 3, &readData3); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(strcmp(readData3, "1"), 0); + + const uint8_t *readData4 = nullptr; + size_t len4; + // index 43 in values array + ret = OH_Values_GetBlob(values, 4, &readData4, &len4); + EXPECT_EQ(ret, RDB_OK); + // ecpect len is 2 + EXPECT_EQ(len4, 2); + EXPECT_EQ(readData4[0], 1); + // ecpect value is 2 + EXPECT_EQ(readData4[1], 2); +} + +static void ReadDataValuesPartTwo(OH_Data_Values *values) +{ + Data_Asset *readData5 = OH_Data_Asset_CreateOne(); + EXPECT_NE(readData5, nullptr); + OH_ColumnType columnType5; + // index 5 in values array + int ret = OH_Values_GetType(values, 5, &columnType5); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(columnType5, TYPE_ASSET); + // index 5 in values array + ret = OH_Values_GetAsset(values, 5, readData5); + EXPECT_EQ(ret, RDB_OK); + char readDataName[32]; + size_t length5 = 32; + ret = OH_Data_Asset_GetName(readData5, readDataName, &length5); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(strcmp(readDataName, "name"), 0); + // expect string length is 4 + EXPECT_EQ(length5, 4); + OH_Data_Asset_DestroyOne(readData5); + + size_t readDataCount6; + // index 6 in values array + ret = OH_Values_GetAssetsCount(values, 6, &readDataCount6); + EXPECT_EQ(ret, RDB_OK); + // 2 is two element in data. + EXPECT_EQ(readDataCount6, 2); + + Data_Asset **readData6 = OH_Data_Asset_CreateMultiple(2); + EXPECT_NE(readData6, nullptr); + size_t out6; + // index 6 in values array, 2 is two element in data. + ret = OH_Values_GetAssets(values, 6, readData6, 2, &out6); + EXPECT_EQ(ret, RDB_OK); + // expect value is 2 + EXPECT_EQ(out6, 2); + // 2 is two element in data. + OH_Data_Asset_DestroyMultiple(readData6, 2); + + size_t readDataLen7; + // index 7 in values array + ret = OH_Values_GetUnlimitedIntBand(values, 7, &readDataLen7); + EXPECT_EQ(ret, RDB_OK); + // expect value is 5 + EXPECT_EQ(readDataLen7, 5); + + int readDataSign7; + uint64_t readData7[5]; + size_t outLen; + // index 7 in values array, 5 is input memory length. + ret = OH_Values_GetUnlimitedInt(values, 7, &readDataSign7, readData7, 5, &outLen); + EXPECT_EQ(ret, RDB_OK); + // expect value is 5 + EXPECT_EQ(outLen, 5); + EXPECT_EQ(readDataSign7, 0); + EXPECT_EQ(readData7[0], 1); + // expect value is 5, 4 is index. + EXPECT_EQ(readData7[4], 5); +} + +/** + * @tc.name: RDB_Transaction_capi_test_001 + * @tc.desc: Normal testCase of store transaction for create. + * @tc.type: FUNC + */ +HWTEST_F(RdbTransactionCapiTest, RDB_Transaction_capi_test_001, TestSize.Level1) +{ + OH_Rdb_Transaction *trans = nullptr; + int ret = OH_Rdb_CreateTransaction(g_transStore, g_options, &trans); + EXPECT_EQ(ret, RDB_OK); + EXPECT_NE(trans, nullptr); +} + +/** + * @tc.name: RDB_Transaction_capi_test_002 + * @tc.desc: Normal testCase of store transaction for create and OH_RdbTrans_Commit + * @tc.type: FUNC + */ +HWTEST_F(RdbTransactionCapiTest, RDB_Transaction_capi_test_002, TestSize.Level1) +{ + OH_Rdb_Transaction *trans = nullptr; + const char *table = "test"; + int ret = OH_Rdb_CreateTransaction(g_transStore, g_options, &trans); + EXPECT_EQ(ret, RDB_OK); + EXPECT_NE(trans, nullptr); + + OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket(); + // init is value is 4 + valueBucket->putInt64(valueBucket, "id", 4); + valueBucket->putText(valueBucket, "data1", "test_name4"); + // init is data2 is 14800 + valueBucket->putInt64(valueBucket, "data2", 14800); + // init is data3 is 300.1 + valueBucket->putReal(valueBucket, "data3", 300.1); + valueBucket->putText(valueBucket, "data5", "ABCDEFGHI"); + int64_t rowId = -1; + ret = OH_RdbTrans_Insert(trans, table, valueBucket, &rowId); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(rowId, 4); + + valueBucket->destroy(valueBucket); + ret = OH_RdbTrans_Destroy(trans); + EXPECT_EQ(ret, RDB_OK); +} + +/** + * @tc.name: RDB_Transaction_capi_test_003 + * @tc.desc: Normal testCase of store transaction for insert and OH_RdbTrans_Rollback + * @tc.type: FUNC + */ +HWTEST_F(RdbTransactionCapiTest, RDB_Transaction_capi_test_003, TestSize.Level1) +{ + OH_Rdb_Transaction *trans = nullptr; + const char *table = "test"; + int ret = OH_Rdb_CreateTransaction(g_transStore, g_options, &trans); + EXPECT_EQ(ret, RDB_OK); + EXPECT_NE(trans, nullptr); + + OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket(); + valueBucket->putText(valueBucket, "data1", "test_name4"); + // init is data2 is 14800 + valueBucket->putInt64(valueBucket, "data2", 14800); + // init is data2 is 300.1 + valueBucket->putReal(valueBucket, "data3", 300.1); + valueBucket->putText(valueBucket, "data5", "ABCDEFGHI"); + int64_t rowId = -1; + ret = OH_RdbTrans_Insert(trans, table, valueBucket, &rowId); + EXPECT_EQ(ret, RDB_OK); + // expect value is 4 + EXPECT_EQ(rowId, 4); + + ret = OH_RdbTrans_Rollback(trans); + EXPECT_EQ(ret, RDB_OK); + + valueBucket->destroy(valueBucket); + ret = OH_RdbTrans_Destroy(trans); + EXPECT_EQ(ret, RDB_OK); +} + +/** + * @tc.name: RDB_Transaction_capi_test_004 + * @tc.desc: Normal testCase of store transaction for OH_RdbTrans_BatchInsert + * OH_VBuckets_RowCount, OH_VBuckets_PutRow, OH_RdbTrans_Destroy, OH_VBuckets_Destroy + * @tc.type: FUNC + */ +HWTEST_F(RdbTransactionCapiTest, RDB_Transaction_capi_test_004, TestSize.Level1) +{ + OH_Rdb_Transaction *trans = nullptr; + const char *table = "test"; + int ret = OH_Rdb_CreateTransaction(g_transStore, g_options, &trans); + EXPECT_EQ(ret, RDB_OK); + EXPECT_NE(trans, nullptr); + + // data row1 + OH_VBucket *row1 = OH_Rdb_CreateValuesBucket(); + EXPECT_NE(row1, nullptr); + row1->putInt64(row1, "id", 4); + row1->putText(row1, "data1", "test_name4"); + row1->putInt64(row1, "data2", 14800); + row1->putReal(row1, "data3", 300.1); + row1->putText(row1, "data5", "ABCDEFGHI"); + + // data row2 + OH_VBucket *row2 = OH_Rdb_CreateValuesBucket(); + EXPECT_NE(row2, nullptr); + row2->putInt64(row2, "id", 5); + row2->putText(row2, "data1", "test_name5"); + row2->putInt64(row2, "data2", 15800); + row2->putReal(row2, "data3", 500.1); + row2->putText(row2, "data5", "ABCDEFGHI"); + + // create rows + OH_Data_VBuckets *rows = OH_VBuckets_Create(); + EXPECT_NE(rows, nullptr); + + // add row1 to rows + ret = OH_VBuckets_PutRow(rows, row1); + EXPECT_EQ(ret, RDB_OK); + size_t count = -1; + ret = OH_VBuckets_RowCount(rows, &count); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(count, 1); + + // add row2 to rows + ret = OH_VBuckets_PutRow(rows, row2); + EXPECT_EQ(ret, RDB_OK); + ret = OH_VBuckets_RowCount(rows, &count); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(count, 2); + + // batch insert + int64_t changes = -1; + ret = OH_RdbTrans_BatchInsert(trans, table, rows, RDB_CONFLICT_NONE, &changes); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(changes, 2); + + + // destroy + row1->destroy(row1); + row2->destroy(row2); + ret = OH_VBuckets_Destroy(rows); + EXPECT_EQ(ret, RDB_OK); + + ret = OH_RdbTrans_Destroy(trans); + EXPECT_EQ(ret, RDB_OK); +} + +/** + * @tc.name: RDB_Transaction_capi_test_005 + * @tc.desc: Normal testCase of store transaction for OH_RdbTrans_BatchInsert + * OH_VBuckets_RowCount, OH_VBuckets_PutRows, OH_RdbTrans_Destroy, OH_VBuckets_Destroy + * @tc.type: FUNC + */ +HWTEST_F(RdbTransactionCapiTest, RDB_Transaction_capi_test_005, TestSize.Level1) +{ + OH_Rdb_Transaction *trans = nullptr; + const char *table = "test"; + int ret = OH_Rdb_CreateTransaction(g_transStore, g_options, &trans); + EXPECT_EQ(ret, RDB_OK); + EXPECT_NE(trans, nullptr); + + // data row1 + OH_VBucket *row1 = OH_Rdb_CreateValuesBucket(); + EXPECT_NE(row1, nullptr); + row1->putInt64(row1, "id", 4); + row1->putText(row1, "data1", "test_name4"); + row1->putInt64(row1, "data2", 14800); + row1->putReal(row1, "data3", 300.1); + row1->putText(row1, "data5", "ABCDEFGHI"); + + // data row2 + OH_VBucket *row2 = OH_Rdb_CreateValuesBucket(); + EXPECT_NE(row2, nullptr); + row2->putInt64(row2, "id", 5); + row2->putText(row2, "data1", "test_name5"); + row2->putInt64(row2, "data2", 15800); + row2->putReal(row2, "data3", 500.1); + row2->putText(row2, "data5", "ABCDEFGHI"); + + // create rows + OH_Data_VBuckets *rows = OH_VBuckets_Create(); + EXPECT_NE(rows, nullptr); + + // add row1 to rows + ret = OH_VBuckets_PutRow(rows, row1); + EXPECT_EQ(ret, RDB_OK); + size_t count = -1; + ret = OH_VBuckets_RowCount(rows, &count); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(count, 1); + + // add row2 to rows + ret = OH_VBuckets_PutRow(rows, row2); + EXPECT_EQ(ret, RDB_OK); + ret = OH_VBuckets_RowCount(rows, &count); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(count, 2); + + + // create rows + OH_Data_VBuckets *rows2 = OH_VBuckets_Create(); + EXPECT_NE(rows, nullptr); + ret = OH_VBuckets_PutRows(rows2, rows); + EXPECT_EQ(ret, RDB_OK); + + // destroy rows + ret = OH_VBuckets_Destroy(rows); + EXPECT_EQ(ret, RDB_OK); + + // batch insert + int64_t changes = -1; + ret = OH_RdbTrans_BatchInsert(trans, table, rows2, RDB_CONFLICT_REPLACE, &changes); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(changes, 2); + + + // destroy + row1->destroy(row1); + row2->destroy(row2); + ret = OH_VBuckets_Destroy(rows2); + EXPECT_EQ(ret, RDB_OK); + + ret = OH_RdbTrans_Destroy(trans); + EXPECT_EQ(ret, RDB_OK); +} + +/** + * @tc.name: RDB_Transaction_capi_test_006 + * @tc.desc: Normal testCase of store transaction for OH_RdbTrans_Update + * @tc.type: FUNC + */ +HWTEST_F(RdbTransactionCapiTest, RDB_Transaction_capi_test_006, TestSize.Level1) +{ + OH_Rdb_Transaction *trans = nullptr; + const char *table = "test"; + int ret = OH_Rdb_CreateTransaction(g_transStore, g_options, &trans); + EXPECT_EQ(ret, RDB_OK); + EXPECT_NE(trans, nullptr); + + // new row + OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket(); + valueBucket->putText(valueBucket, "data1", "liSi"); + // init data2 value is 13800 + valueBucket->putInt64(valueBucket, "data2", 13800); + // init data3 value is 200.1 + valueBucket->putReal(valueBucket, "data3", 200.1); + valueBucket->putNull(valueBucket, "data5"); + + // create predicates + OH_Predicates *predicates = OH_Rdb_CreatePredicates(table); + // create match data + OH_VObject *valueObject = OH_Rdb_CreateValueObject(); + const char *data1Value = "zhangSan"; + valueObject->putText(valueObject, data1Value); + predicates->equalTo(predicates, "data1", valueObject); + + // update + int64_t changes = -1; + ret = OH_RdbTrans_Update(trans, valueBucket, predicates, &changes); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(changes, 1); + + // destroy + valueObject->destroy(valueObject); + valueBucket->destroy(valueBucket); + + ret = OH_RdbTrans_Destroy(trans); + EXPECT_EQ(ret, RDB_OK); +} + +/** + * @tc.name: RDB_Transaction_capi_test_007 + * @tc.desc: Normal testCase of store transaction for OH_RdbTrans_Delete + * @tc.type: FUNC + */ +HWTEST_F(RdbTransactionCapiTest, RDB_Transaction_capi_test_007, TestSize.Level1) +{ + OH_Rdb_Transaction *trans = nullptr; + const char *table = "test"; + int ret = OH_Rdb_CreateTransaction(g_transStore, g_options, &trans); + EXPECT_EQ(ret, RDB_OK); + EXPECT_NE(trans, nullptr); + + // create predicates + OH_Predicates *predicates = OH_Rdb_CreatePredicates(table); + // create match data + OH_VObject *valueObject = OH_Rdb_CreateValueObject(); + const char *data1Value = "liSi"; + valueObject->putText(valueObject, data1Value); + predicates->equalTo(predicates, "data1", valueObject); + + // update + int64_t changes = -1; + ret = OH_RdbTrans_Delete(trans, predicates, &changes); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(changes, 1); + + // destroy + valueObject->destroy(valueObject); + + ret = OH_RdbTrans_Destroy(trans); + EXPECT_EQ(ret, RDB_OK); +} + +/** + * @tc.name: RDB_Transaction_capi_test_008 + * @tc.desc: Normal testCase of store transaction for OH_RdbTrans_Query + * @tc.type: FUNC + */ +HWTEST_F(RdbTransactionCapiTest, RDB_Transaction_capi_test_008, TestSize.Level1) +{ + OH_Rdb_Transaction *trans = nullptr; + const char *table = "test"; + int ret = OH_Rdb_CreateTransaction(g_transStore, g_options, &trans); + EXPECT_EQ(ret, RDB_OK); + EXPECT_NE(trans, nullptr); + + // create predicates + OH_Predicates *predicates = OH_Rdb_CreatePredicates(table); + + const char *columns[] = {"id", "data1"}; + // check args; + OH_Cursor *cursor = OH_RdbTrans_Query(nullptr, predicates, columns, 2); + EXPECT_EQ(cursor, nullptr); + cursor = OH_RdbTrans_Query(trans, nullptr, columns, 2); + EXPECT_EQ(cursor, nullptr); + + cursor = OH_RdbTrans_Query(trans, predicates, nullptr, 0); + EXPECT_NE(cursor, nullptr); + + int rowCount = 0; + cursor->getRowCount(cursor, &rowCount); + EXPECT_EQ(rowCount, 3); + + ret = cursor->goToNextRow(cursor); + EXPECT_EQ(ret, 0); + + int64_t id; + cursor->getInt64(cursor, 0, &id); + EXPECT_EQ(id, 1); + + char data1[15]; + cursor->getText(cursor, 1, data1, 15); + EXPECT_EQ(strcmp(data1, "zhangSan"), 0); + + int64_t data2; + cursor->getInt64(cursor, 2, &data2); + EXPECT_EQ(data2, 12800); + + // destroy + cursor->destroy(cursor); + ret = OH_RdbTrans_Destroy(trans); + EXPECT_EQ(ret, RDB_OK); +} + +/** + * @tc.name: RDB_Transaction_capi_test_009 + * @tc.desc: Normal testCase of store transaction for OH_RdbTrans_QuerySql, OH_Data_Values, OH_Data_Value, + * OH_RdbTrans_Execute + * @tc.type: FUNC + */ +HWTEST_F(RdbTransactionCapiTest, RDB_Transaction_capi_test_009, TestSize.Level1) +{ + OH_Rdb_Transaction *trans = nullptr; + int ret = OH_Rdb_CreateTransaction(g_transStore, g_options, &trans); + EXPECT_EQ(ret, RDB_OK); + EXPECT_NE(trans, nullptr); + + char createTableSql[] = "CREATE TABLE transaction_table (id INTEGER PRIMARY KEY AUTOINCREMENT, data1 INTEGER, " + "data2 INTEGER, data3 FLOAT, data4 TEXT, data5 BLOB, data6 ASSET, data7 ASSETS, data8 UNLIMITED INT, " + "data9 FLOATVECTOR);"; + ret = OH_Rdb_Execute(g_transStore, createTableSql); + EXPECT_EQ(ret, RDB_OK); + + const char *sql = "SELECT id, data1 FROM transaction_table"; + // check args; + OH_Cursor *cursor = OH_RdbTrans_QuerySql(nullptr, sql, nullptr); + EXPECT_EQ(cursor, nullptr); + cursor = OH_RdbTrans_QuerySql(trans, nullptr, nullptr); + EXPECT_EQ(cursor, nullptr); + + cursor = OH_RdbTrans_QuerySql(trans, sql, nullptr); + EXPECT_NE(cursor, nullptr); + cursor->destroy(cursor); + + // create OH_Data_Values + OH_Data_Values *values = OH_Values_Create(); + FillDataValues(values); + + const char *insertSql = "INSERT INTO transaction_table " + "(data1, data2, data3, data4, data5, data6, data7, data8) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; + OH_Data_Value *outValue = nullptr; + ret = OH_RdbTrans_Execute(trans, insertSql, values, &outValue); + EXPECT_EQ(ret, RDB_OK); + EXPECT_NE(outValue, nullptr); + ret = OH_Value_Destroy(outValue); + EXPECT_EQ(ret, RDB_OK); + ret = OH_Values_Destroy(values); + EXPECT_EQ(ret, RDB_OK); + + const char *querySql = "SELECT * FROM transaction_table WHERE data1=?"; + OH_Data_Values *queryValues = OH_Values_Create(); + EXPECT_NE(queryValues, nullptr); + ret = OH_Values_PutInt(queryValues, 1); + EXPECT_EQ(ret, RDB_OK); + OH_Cursor *cursorEnd = OH_RdbTrans_QuerySql(trans, querySql, queryValues); + EXPECT_NE(cursorEnd, nullptr); + int rowCount = 0; + cursorEnd->getRowCount(cursorEnd, &rowCount); + EXPECT_EQ(rowCount, 1); + ret = OH_Values_Destroy(queryValues); + EXPECT_EQ(ret, RDB_OK); + cursorEnd->destroy(cursorEnd); + + ret = OH_RdbTrans_Destroy(trans); + EXPECT_EQ(ret, RDB_OK); +} + +/** + * @tc.name: RDB_Transaction_capi_test_010 + * @tc.desc: Normal testCase of store transaction for OH_Data_Values + * @tc.type: FUNC + */ +HWTEST_F(RdbTransactionCapiTest, RDB_Transaction_capi_test_010, TestSize.Level1) +{ + OH_Data_Values *values = OH_Values_Create(); + FillDataValues(values); + ReadDataValuesPartOne(values); + ReadDataValuesPartTwo(values); + // destroy + int ret = OH_Values_Destroy(values); + EXPECT_EQ(ret, RDB_OK); +} + +/** + * @tc.name: RDB_Transaction_capi_test_011 + * @tc.desc: Normal testCase of store transaction for OH_Data_Values + * @tc.type: FUNC + */ +HWTEST_F(RdbTransactionCapiTest, RDB_Transaction_capi_test_011, TestSize.Level1) +{ + OH_Data_Value *value = OH_Value_Create(); + EXPECT_NE(value, nullptr); + float floatArr[] = {1.0, 2.0, 3.0}; + int ret = OH_Value_PutFloatVector(value, nullptr, 0); + EXPECT_EQ(ret, RDB_E_INVALID_ARGS); + ret = OH_Value_PutFloatVector(value, floatArr, 3); + EXPECT_EQ(ret, RDB_OK); + + OH_ColumnType type; + ret = OH_Value_GetType(value, &type); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(type, TYPE_FLOAT_VECTOR); + size_t length; + ret = OH_Value_GetFloatVectorCount(value, &length); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(length, 3); + float retArray[10]; + size_t outLen; + ret = OH_Value_GetFloatVector(value, retArray, 10, &outLen); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(outLen, 3); + EXPECT_EQ(retArray[0], 1.0); + ret = OH_Value_Destroy(value); + EXPECT_EQ(ret, RDB_OK); +} + +/** + * @tc.name: RDB_Transaction_capi_test_012 + * @tc.desc: Normal testCase of store transaction for OH_Data_Value + * @tc.type: FUNC + */ +HWTEST_F(RdbTransactionCapiTest, RDB_Transaction_capi_test_012, TestSize.Level1) +{ + OH_Data_Value *value = OH_Value_Create(); + EXPECT_NE(value, nullptr); + float floatArr[] = {1.0, 2.0, 3.0}; + int ret = OH_Value_PutFloatVector(value, nullptr, 0); + EXPECT_EQ(ret, RDB_E_INVALID_ARGS); + ret = OH_Value_PutFloatVector(value, floatArr, 0); + EXPECT_EQ(ret, RDB_OK); + + size_t length; + ret = OH_Value_GetFloatVectorCount(value, &length); + EXPECT_EQ(ret, RDB_OK); + EXPECT_EQ(length, 0); + double realValue; + ret = OH_Value_GetReal(value, &realValue); + EXPECT_EQ(ret, RDB_E_TYPE_MISMATCH); + + ret = OH_Value_PutNull(value); + EXPECT_EQ(ret, RDB_OK); + ret = OH_Value_GetReal(value, &realValue); + EXPECT_EQ(ret, RDB_E_DATA_TYPE_NULL); + ret = OH_Value_Destroy(value); + EXPECT_EQ(ret, RDB_OK); +} + +/** + * @tc.name: RDB_Transaction_capi_test_013 + * @tc.desc: Normal testCase of OH_VBucket_PutFloatVector + * @tc.type: FUNC + */ +HWTEST_F(RdbTransactionCapiTest, RDB_Transaction_capi_test_013, TestSize.Level1) +{ + OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket(); + EXPECT_NE(valueBucket, nullptr); + float floatArr[] = { 1.0, 2.0, 3.0 }; + int ret = OH_VBucket_PutFloatVector(valueBucket, "data1", floatArr, 0); + EXPECT_EQ(ret, RDB_OK); + ret = OH_VBucket_PutFloatVector(valueBucket, "data2", floatArr, 3); + EXPECT_EQ(ret, RDB_OK); + valueBucket->destroy(valueBucket); +} + +/** + * @tc.name: RDB_Transaction_capi_test_014 + * @tc.desc: Normal testCase of OH_VBucket_PutUnlimitedInt + * @tc.type: FUNC + */ +HWTEST_F(RdbTransactionCapiTest, RDB_Transaction_capi_test_014, TestSize.Level1) +{ + OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket(); + EXPECT_NE(valueBucket, nullptr); + uint64_t trueForm[] = { 1, 2, 3 }; + int ret = OH_VBucket_PutUnlimitedInt(valueBucket, "data1", 0, trueForm, 0); + EXPECT_EQ(ret, RDB_OK); + ret = OH_VBucket_PutUnlimitedInt(valueBucket, "data2", 1, trueForm, 3); + EXPECT_EQ(ret, RDB_OK); + valueBucket->destroy(valueBucket); +} \ No newline at end of file diff --git a/relational_store/test/ndk/unittest/rdb_vector_test.cpp b/relational_store/test/ndk/unittest/rdb_vector_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c6916d771bfdd272e5a004791ec8d88e975830dd --- /dev/null +++ b/relational_store/test/ndk/unittest/rdb_vector_test.cpp @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2024 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 + +#include + +#include "accesstoken_kit.h" +#include "common.h" +#include "grd_api_manager.h" +#include "rdb_errno.h" +#include "relational_store.h" +#include "relational_store_error_code.h" +#include "relational_store_impl.h" +#include "token_setproc.h" + +using namespace testing::ext; +using namespace OHOS::NativeRdb; +using namespace OHOS::Security::AccessToken; +using namespace OHOS::RdbNdk; + +class RdbVectorTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + static OH_Rdb_ConfigV2 *InitRdbConfig() + { + OH_Rdb_ConfigV2 *config = OH_Rdb_CreateConfig(); + EXPECT_NE(config, nullptr); + OH_Rdb_SetDatabaseDir(config, RDB_TEST_PATH); + OH_Rdb_SetStoreName(config, "rdb_vector_test.db"); + OH_Rdb_SetBundleName(config, "com.ohos.example.distributedndk"); + OH_Rdb_SetEncrypted(config, false); + OH_Rdb_SetSecurityLevel(config, OH_Rdb_SecurityLevel::S1); + OH_Rdb_SetArea(config, RDB_SECURITY_AREA_EL1); + + EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_SetDbType(config, RDB_CAYLEY)); + return config; + } +}; + +OH_Rdb_Store *store_; +OH_Rdb_ConfigV2 *config_; +float test_[] = { 1.2, 2.3 }; + +void RdbVectorTest::SetUpTestCase(void) +{ + config_ = InitRdbConfig(); + mkdir(RDB_TEST_PATH, 0770); + int errCode = 0; + store_ = OH_Rdb_CreateOrOpen(config_, &errCode); + EXPECT_NE(store_, NULL); +} + +void RdbVectorTest::TearDownTestCase(void) +{ + int errCode = OH_Rdb_CloseStore(store_); + EXPECT_EQ(errCode, RDB_OK); + errCode = OH_Rdb_DeleteStoreV2(config_); + EXPECT_EQ(errCode, RDB_OK); +} + +void RdbVectorTest::SetUp(void) +{ + if (!OHOS::NativeRdb::IsUsingArkData()) { + GTEST_SKIP() << "Current testcase is not compatible from current gdb"; + } + char createTableSql[] = "CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, data1 floatvector(2));"; + EXPECT_EQ(OH_Rdb_ErrCode::RDB_OK, OH_Rdb_ExecuteByTrxId(store_, 0, createTableSql)); + OH_Data_Values *values = OH_Values_Create(); + OH_Values_PutInt(values, 1); + size_t len = sizeof(test_) / sizeof(test_[0]); + OH_Values_PutFloatVector(values, test_, len); + char insertSql[] = "INSERT INTO test (id, data1) VALUES (?, ?);"; + auto errCode = OH_Rdb_ExecuteV2(store_, insertSql, values, nullptr); + EXPECT_EQ(errCode, RDB_OK); + OH_Values_Destroy(values); +} + +void RdbVectorTest::TearDown(void) +{ + char dropTableSql[] = "DROP TABLE IF EXISTS test"; + int errCode = OH_Rdb_ExecuteByTrxId(store_, 0, dropTableSql); + EXPECT_EQ(errCode, RDB_OK); +} + +/** + * @tc.name: RDB_vector_test_001 + * @tc.desc: Normal testCase of queryV2. + * @tc.type: FUNC + */ +HWTEST_F(RdbVectorTest, RDB_vector_001, TestSize.Level1) +{ + char querySql[] = "select * from test where id = ?;"; + OH_Data_Values *values = OH_Values_Create(); + OH_Values_PutInt(values, 1); + OH_Cursor *cursor = OH_Rdb_ExecuteQueryV2(store_, querySql, values); + EXPECT_NE(cursor, NULL); + + int rowCount = 0; + cursor->getRowCount(cursor, &rowCount); + EXPECT_EQ(rowCount, 1); + + cursor->goToNextRow(cursor); + size_t count = 0; + auto errCode = OH_Cursor_GetFloatVectorCount(cursor, 1, &count); + EXPECT_EQ(errCode, RDB_OK); + float test[count]; + size_t outLen; + OH_Cursor_GetFloatVector(cursor, 1, test, count, &outLen); + EXPECT_EQ(outLen, 2); + EXPECT_EQ(test[0], test_[0]); + EXPECT_EQ(test[1], test_[1]); + + float test1[10]; + OH_Cursor_GetFloatVector(cursor, 1, test1, 10, &outLen); + EXPECT_EQ(outLen, 2); + EXPECT_EQ(test1[0], test_[0]); + EXPECT_EQ(test1[1], test_[1]); + + OH_Values_Destroy(values); +} + +/** + * @tc.name: RDB_vector_test_002 + * @tc.desc: Abnormal testCase of queryV2. + * @tc.type: FUNC + */ +HWTEST_F(RdbVectorTest, RDB_vector_002, TestSize.Level1) +{ + char querySql[] = "select * from test where id = ?;"; + OH_Data_Values *values = OH_Values_Create(); + OH_Values_PutInt(values, 1); + OH_Cursor *cursor = OH_Rdb_ExecuteQueryV2(nullptr, querySql, values); + EXPECT_EQ(cursor, NULL); + + cursor = OH_Rdb_ExecuteQueryV2(store_, nullptr, values); + EXPECT_EQ(cursor, NULL); + + cursor = OH_Rdb_ExecuteQueryV2(store_, querySql, nullptr); + EXPECT_NE(cursor, NULL); + int rowCount = 0; + cursor->getRowCount(cursor, &rowCount); + EXPECT_EQ(rowCount, 0); + + OH_Values_PutInt(values, 1); + cursor = OH_Rdb_ExecuteQueryV2(store_, querySql, values); + EXPECT_NE(cursor, NULL); + cursor->getRowCount(cursor, &rowCount); + EXPECT_EQ(rowCount, -1); + + OH_Values_Destroy(values); +} + +/** + * @tc.name: RDB_vector_test_003 + * @tc.desc: Abnormal testCase of getFloatVector. + * @tc.type: FUNC + */ +HWTEST_F(RdbVectorTest, RDB_vector_003, TestSize.Level1) +{ + char querySql[] = "select * from test where id = ?;"; + OH_Data_Values *values = OH_Values_Create(); + OH_Values_PutInt(values, 1); + OH_Cursor *cursor = OH_Rdb_ExecuteQueryV2(store_, querySql, values); + EXPECT_NE(cursor, NULL); + + int rowCount = 0; + cursor->getRowCount(cursor, &rowCount); + EXPECT_EQ(rowCount, 1); + + cursor->goToNextRow(cursor); + size_t count = 0; + auto errCode = OH_Cursor_GetFloatVectorCount(cursor, 0, &count); + EXPECT_EQ(errCode, RDB_E_INVALID_ARGS); + float test[count]; + size_t outLen; + errCode = OH_Cursor_GetFloatVector(cursor, 0, test, count, &outLen); + EXPECT_EQ(errCode, RDB_E_INVALID_ARGS); + OH_Values_Destroy(values); +} + +/** + * @tc.name: RDB_vector_test_004 + * @tc.desc: Normal testCase of executeV2. + * @tc.type: FUNC + */ +HWTEST_F(RdbVectorTest, RDB_vector_004, TestSize.Level1) +{ + char querySql[] = "select * from test where id = ?;"; + OH_Data_Values *values = OH_Values_Create(); + OH_Values_PutInt(values, 1); + OH_Cursor *cursor = OH_Rdb_ExecuteQueryV2(store_, querySql, values); + EXPECT_NE(cursor, NULL); + + int rowCount = 0; + cursor->getRowCount(cursor, &rowCount); + EXPECT_EQ(rowCount, 1); + + float test[2] = { 5.5, 6.6 }; + OH_Data_Values *values1 = OH_Values_Create(); + OH_Values_PutFloatVector(values1, test, 2); + OH_Values_PutInt(values1, 1); + auto errCode = OH_Rdb_ExecuteV2(store_, "update test set data1 = ? where id = ?", values1, nullptr); + EXPECT_EQ(errCode, RDB_OK); + + cursor = OH_Rdb_ExecuteQueryV2(store_, querySql, values); + EXPECT_NE(cursor, NULL); + cursor->getRowCount(cursor, &rowCount); + EXPECT_EQ(rowCount, 1); + cursor->goToNextRow(cursor); + size_t count = 0; + errCode = OH_Cursor_GetFloatVectorCount(cursor, 1, &count); + EXPECT_EQ(errCode, RDB_OK); + float test1[count]; + size_t outLen; + OH_Cursor_GetFloatVector(cursor, 1, test1, count, &outLen); + EXPECT_EQ(outLen, 2); + EXPECT_EQ(test1[0], test[0]); + EXPECT_EQ(test1[1], test[1]); + + errCode = OH_Rdb_ExecuteV2(store_, "delete from test where id = ?", values, nullptr); + EXPECT_EQ(errCode, RDB_OK); + cursor = OH_Rdb_ExecuteQueryV2(store_, querySql, values); + EXPECT_NE(cursor, NULL); + cursor->getRowCount(cursor, &rowCount); + EXPECT_EQ(rowCount, 0); + + OH_Values_Destroy(values); + OH_Values_Destroy(values1); +} + +/** + * @tc.name: RDB_vector_test_005 + * @tc.desc: Abnormal testCase of executeV2. + * @tc.type: FUNC + */ +HWTEST_F(RdbVectorTest, RDB_vector_005, TestSize.Level1) +{ + OH_Data_Values *values = OH_Values_Create(); + OH_Values_PutFloatVector(values, test_, 2); + OH_Values_PutInt(values, 1); + auto errCode = OH_Rdb_ExecuteV2(nullptr, "update test set data1 = ? where id = ?", + values, nullptr); + EXPECT_EQ(errCode, RDB_E_INVALID_ARGS); + + errCode = OH_Rdb_ExecuteV2(store_, nullptr, values, nullptr); + EXPECT_EQ(errCode, RDB_E_INVALID_ARGS); + + errCode = OH_Rdb_ExecuteV2(store_, "update test set data1 = ? where id = ?", nullptr, nullptr); + EXPECT_EQ(errCode, RDB_OK); + + OH_Values_PutInt(values, 2); + errCode = OH_Rdb_ExecuteV2(store_, "update test set data1 = ? where id = ?", values, nullptr); + EXPECT_EQ(errCode, RDB_E_ERROR); +} + +/** + * @tc.name: RDB_vector_test_006 + * @tc.desc: Normal testCase of executeQueryV2. + * @tc.type: FUNC + */ +HWTEST_F(RdbVectorTest, RDB_vector_006, TestSize.Level1) +{ + char querySql1[] = "select id, data1 <-> ? from test where id = ?;"; + OH_Data_Values *values = OH_Values_Create(); + float test[] = { 2.1, 3.0 }; + OH_Values_PutFloatVector(values, test, 2); + OH_Values_PutInt(values, 1); + OH_Cursor *cursor = OH_Rdb_ExecuteQueryV2(store_, querySql1, values); + EXPECT_NE(cursor, NULL); + int rowCount = 0; + cursor->getRowCount(cursor, &rowCount); + EXPECT_EQ(rowCount, 1); + + char querySql2[] = "select id, data1 <=> ? from test where id = ?;"; + cursor = OH_Rdb_ExecuteQueryV2(store_, querySql2, values); + EXPECT_NE(cursor, NULL); + cursor->getRowCount(cursor, &rowCount); + EXPECT_EQ(rowCount, 1); + + char querySql3[] = "select id, data1 <-> '[ 2.1, 3.0 ]' from test;"; + cursor = OH_Rdb_ExecuteQueryV2(store_, querySql3, nullptr); + EXPECT_NE(cursor, NULL); + cursor->getRowCount(cursor, &rowCount); + EXPECT_EQ(rowCount, 1); + + char querySql4[] = "select id, data1 <=> '[ 2.1, 3.0 ]' from test;"; + cursor = OH_Rdb_ExecuteQueryV2(store_, querySql4, nullptr); + EXPECT_NE(cursor, NULL); + cursor->getRowCount(cursor, &rowCount); + EXPECT_EQ(rowCount, 1); + + OH_Values_Destroy(values); +} + +/** + * @tc.name: RDB_vector_test_007 + * @tc.desc: Normal testCase of executeQueryV2. + * @tc.type: FUNC + */ +HWTEST_F(RdbVectorTest, RDB_vector_007, TestSize.Level1) +{ + char createTableSql[] = "CREATE TABLE test1 (id INTEGER PRIMARY KEY AUTOINCREMENT, data1 floatvector(2));"; + auto errCode = OH_Rdb_ExecuteV2(store_, createTableSql, nullptr, nullptr); + EXPECT_EQ(errCode, RDB_OK); + char insertSql[] = "INSERT INTO test1 (id, data1) VALUES (1, '[3.1, 2.2]');"; + errCode = OH_Rdb_ExecuteV2(store_, insertSql, nullptr, nullptr); + EXPECT_EQ(errCode, RDB_OK); + + char querySql[] = "select id, data1 <=> '[ 2.1, 3.0 ]' from test where id in (select id from test1);"; + OH_Cursor *cursor = OH_Rdb_ExecuteQueryV2(store_, querySql, nullptr); + EXPECT_NE(cursor, NULL); + int rowCount = 0; + cursor->getRowCount(cursor, &rowCount); + EXPECT_EQ(rowCount, 1); + + char updateSql[] = "update test1 set data1 = '[2.0, 1.0]' where id = 1;"; + errCode = OH_Rdb_ExecuteV2(store_, updateSql, nullptr, nullptr); + EXPECT_EQ(errCode, RDB_OK); + cursor = OH_Rdb_ExecuteQueryV2(store_, "select * from test1 where id = 1;", nullptr); + EXPECT_NE(cursor, NULL); + cursor->goToNextRow(cursor); + float test1[2]; + size_t outLen; + OH_Cursor_GetFloatVector(cursor, 1, test1, 2, &outLen); + EXPECT_EQ(outLen, 2); + EXPECT_EQ(test1[0], 2.0); + EXPECT_EQ(test1[1], 1.0); + + errCode = OH_Rdb_ExecuteV2(store_, "delete from test1 where id = 1", nullptr, nullptr); + EXPECT_EQ(errCode, RDB_OK); + + char dropTableSql[] = "DROP TABLE IF EXISTS test1"; + errCode = OH_Rdb_ExecuteV2(store_, dropTableSql, nullptr, nullptr); + EXPECT_EQ(errCode, RDB_OK); +} + +/** + * @tc.name: RDB_vector_test_008 + * @tc.desc: Normal testCase of executeQueryV2. + * @tc.type: FUNC + */ +HWTEST_F(RdbVectorTest, RDB_vector_008, TestSize.Level1) +{ + char insertSql[] = "INSERT INTO test (id, data1) VALUES (2, '[3.1, 2.2]');"; + auto errCode = OH_Rdb_ExecuteV2(store_, insertSql, nullptr, nullptr); + EXPECT_EQ(errCode, RDB_OK); + + char querySql[] = "select id, data1 from test where id > ? group by id having " + "max(data1<=>?);"; + float test[] = { 2.1, 3.0 }; + OH_Data_Values *values = OH_Values_Create(); + OH_Values_PutInt(values, 0); + OH_Values_PutFloatVector(values, test, 2); + OH_Cursor *cursor = OH_Rdb_ExecuteQueryV2(store_, querySql, values); + EXPECT_NE(cursor, NULL); + int rowCount = 0; + cursor->getRowCount(cursor, &rowCount); + EXPECT_EQ(rowCount, 2); + + OH_Values_Destroy(values); +} \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 05ca3ecc3fabe17d016d6dd815224c95d928ef66..7c5496c65d011c4481388336e1fd1de395edafb4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -74,6 +74,7 @@ target_include_directories(DataMgrServiceTest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR target_include_directories(DataMgrServiceTest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../datamgr_service/services/distributeddataservice/service/matrix/include) target_include_directories(DataMgrServiceTest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../datamgr_service/services/distributeddataservice/service/data_share/common) target_include_directories(DataMgrServiceTest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../datamgr_service/services/distributeddataservice/service/data_share/data) +target_include_directories(DataMgrServiceTest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../datamgr_service/services/distributeddataservice/service/data_share/dfx) target_include_directories(DataMgrServiceTest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../datamgr_service/services/distributeddataservice/service/data_share/strategies) target_include_directories(DataMgrServiceTest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../datamgr_service/services/distributeddataservice/service/data_share/subscriber_managers) target_include_directories(DataMgrServiceTest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../datamgr_service/services/distributeddataservice/service/udmf/lifecycle) @@ -101,6 +102,7 @@ target_include_directories(RDBTest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../relati target_include_directories(RDBTest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../relational_store/frameworks/js/napi/dataability/include) target_include_directories(RDBTest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../relational_store/frameworks/js/napi/rdb/include) target_include_directories(RDBTest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../relational_store/frameworks/native/dataability/src) +target_include_directories(RDBTest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../relational_store/frameworks/native/dfx/include) target_include_directories(RDBTest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../relational_store/frameworks/native/rdb/include) target_include_directories(RDBTest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../relational_store/frameworks/native/rdb_device_manager_adapter/include) #************************************************RDBTest end************************************************# diff --git a/udmf/BUILD.gn b/udmf/BUILD.gn index 9d1989c405fa6b9cd0ef66969e2524fcecebfbbf..e81866df101a05b9ce7a19c2b0d60138f30c21ff 100644 --- a/udmf/BUILD.gn +++ b/udmf/BUILD.gn @@ -18,6 +18,7 @@ group("udmf_packages") { deps = [ "interfaces/innerkits:udmf_client", "interfaces/innerkits:utd_client", + "interfaces/jskits:intelligence_napi", "interfaces/jskits:udmf_data_napi", "interfaces/jskits:unifieddatachannel_napi", "interfaces/jskits:uniformtypedescriptor_napi", diff --git a/udmf/CMakeLists.txt b/udmf/CMakeLists.txt index ba53702c9dbf8d090527a4067cd432226ea51963..464a9a21d6b9b0194b9d30f155aa0694000afe49 100644 --- a/udmf/CMakeLists.txt +++ b/udmf/CMakeLists.txt @@ -15,13 +15,17 @@ aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/framework/common udmf_src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/framework/innerkitsimpl/client udmf_src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/framework/innerkitsimpl/common udmf_src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/framework/innerkitsimpl/convert udmf_src) +list(REMOVE_ITEM udmf_src "${CMAKE_CURRENT_SOURCE_DIR}/framework/innerkitsimpl/convert/data_params_conversion.cpp") + aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/framework/innerkitsimpl/data udmf_src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/framework/innerkitsimpl/service udmf_src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/framework/jskitsimpl/common udmf_channel_src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/framework/jskitsimpl/data udmf_channel_src) -aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/framework/ndkimpl/data udmf_ndk_src) list(REMOVE_ITEM udmf_channel_src "${CMAKE_CURRENT_SOURCE_DIR}/frameworks/jskitsimpl/data/uniform_type_descriptor_napi.cpp") +set(udmf_ndk_src framework/innerkitsimpl/convert/data_params_conversion.cpp) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/framework/ndkimpl/data udmf_ndk_src) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/framework/common) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/framework/innerkitsimpl/service) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/framework/innerkitsimpl/data) diff --git a/udmf/adapter/framework/innerkitsimpl/common/unified_meta.cpp b/udmf/adapter/framework/innerkitsimpl/common/unified_meta.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e184197136fe94d5a4da40fb311576dab346b803 --- /dev/null +++ b/udmf/adapter/framework/innerkitsimpl/common/unified_meta.cpp @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2024 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 "UnifiedMeta" +#include "unified_meta.h" + +#include "logger.h" +#include "unified_key.h" + +namespace OHOS { +namespace UDMF { +static constexpr UtdType UTD_TYPES[] = { + { ENTITY, "ENTITY", "general.entity" }, + { OBJECT, "OBJECT", "general.object" }, + { COMPOSITE_OBJECT, "COMPOSITE_OBJECT", "general.composite-object" }, + { TEXT, "TEXT", "general.text" }, + { PLAIN_TEXT, "PLAIN_TEXT", "general.plain-text" }, + { HTML, "HTML", "general.html" }, + { HYPERLINK, "HYPERLINK", "general.hyperlink" }, + { XML, "XML", "general.xml" }, + { SOURCE_CODE, "SOURCE_CODE", "general.source-code" }, + { SCRIPT, "SCRIPT", "general.script" }, + { SHELL_SCRIPT, "SHELL_SCRIPT", "general.shell-script" }, + { CSH_SCRIPT, "CSH_SCRIPT", "general.csh-script" }, + { PERL_SCRIPT, "PERL_SCRIPT", "general.perl-script" }, + { PHP_SCRIPT, "PHP_SCRIPT", "general.php-script" }, + { PYTHON_SCRIPT, "PYTHON_SCRIPT", "general.python-script" }, + { RUBY_SCRIPT, "RUBY_SCRIPT", "general.ruby-script" }, + { TYPE_SCRIPT, "TYPE_SCRIPT", "general.type-script" }, + { JAVA_SCRIPT, "JAVA_SCRIPT", "general.java-script" }, + { C_HEADER, "C_HEADER", "general.c-header" }, + { C_SOURCE, "C_SOURCE", "general.c-source" }, + { C_PLUS_PLUS_HEADER, "C_PLUS_PLUS_HEADER", "general.c-plus-plus-header" }, + { C_PLUS_PLUS_SOURCE, "C_PLUS_PLUS_SOURCE", "general.c-plus-plus-source" }, + { JAVA_SOURCE, "JAVA_SOURCE", "general.java-source" }, + { EBOOK, "EBOOK", "general.ebook" }, + { EPUB, "EPUB", "general.epub" }, + { AZW, "AZW", "com.amazon.azw" }, + { AZW3, "AZW3", "com.amazon.azw3" }, + { KFX, "KFX", "com.amazon.kfx" }, + { MOBI, "MOBI", "com.amazon.mobi" }, + { MEDIA, "MEDIA", "general.media" }, + { IMAGE, "IMAGE", "general.image" }, + { JPEG, "JPEG", "general.jpeg" }, + { PNG, "PNG", "general.png" }, + { RAW_IMAGE, "RAW_IMAGE", "general.raw-image" }, + { TIFF, "TIFF", "general.tiff" }, + { BMP, "BMP", "com.microsoft.bmp" }, + { ICO, "ICO", "com.microsoft.ico" }, + { PHOTOSHOP_IMAGE, "PHOTOSHOP_IMAGE", "com.adobe.photoshop-image" }, + { AI_IMAGE, "AI_IMAGE", "com.adobe.illustrator.ai-image" }, + { WORD_DOC, "WORD_DOC", "com.microsoft.word.doc" }, + { EXCEL, "EXCEL", "com.microsoft.excel.xls" }, + { PPT, "PPT", "com.microsoft.powerpoint.ppt" }, + { PDF, "PDF", "com.adobe.pdf" }, + { POSTSCRIPT, "POSTSCRIPT", "com.adobe.postscript" }, + { ENCAPSULATED_POSTSCRIPT, "ENCAPSULATED_POSTSCRIPT", "com.adobe.encapsulated-postscript" }, + { VIDEO, "VIDEO", "general.video" }, + { AVI, "AVI", "general.avi" }, + { MPEG, "MPEG", "general.mpeg" }, + { MPEG4, "MPEG4", "general.mpeg-4" }, + { VIDEO_3GPP, "VIDEO_3GPP", "general.3gpp" }, + { VIDEO_3GPP2, "VIDEO_3GPP2", "general.3gpp2" }, + { WINDOWS_MEDIA_WM, "WINDOWS_MEDIA_WM", "com.microsoft.windows-media-wm" }, + { WINDOWS_MEDIA_WMV, "WINDOWS_MEDIA_WMV", "com.microsoft.windows-media-wmv" }, + { WINDOWS_MEDIA_WMP, "WINDOWS_MEDIA_WMP", "com.microsoft.windows-media-wmp" }, + { AUDIO, "AUDIO", "general.audio" }, + { AAC, "AAC", "general.aac" }, + { AIFF, "AIFF", "general.aiff" }, + { ALAC, "ALAC", "general.alac" }, + { FLAC, "FLAC", "general.flac" }, + { MP3, "MP3", "general.mp3" }, + { OGG, "OGG", "general.ogg" }, + { PCM, "PCM", "general.pcm" }, + { WINDOWS_MEDIA_WMA, "WINDOWS_MEDIA_WMA", "com.microsoft.windows-media-wma" }, + { WAVEFORM_AUDIO, "WAVEFORM_AUDIO", "com.microsoft.waveform-audio" }, + { WINDOWS_MEDIA_WMX, "WINDOWS_MEDIA_WMX", "com.microsoft.windows-media-wmx" }, + { WINDOWS_MEDIA_WVX, "WINDOWS_MEDIA_WVX", "com.microsoft.windows-media-wvx" }, + { WINDOWS_MEDIA_WAX, "WINDOWS_MEDIA_WAX", "com.microsoft.windows-media-wax" }, + { FILE, "FILE", "general.file" }, + { DIRECTORY, "DIRECTORY", "general.directory" }, + { FOLDER, "FOLDER", "general.folder" }, + { SYMLINK, "SYMLINK", "general.symlink" }, + { ARCHIVE, "ARCHIVE", "general.archive" }, + { BZ2_ARCHIVE, "BZ2_ARCHIVE", "general.bz2-archive" }, + { DISK_IMAGE, "DISK_IMAGE", "general.disk-image" }, + { TAR_ARCHIVE, "TAR_ARCHIVE", "general.tar-archive" }, + { ZIP_ARCHIVE, "ZIP_ARCHIVE", "general.zip-archive" }, + { JAVA_ARCHIVE, "JAVA_ARCHIVE", "com.sun.java-archive" }, + { GNU_TAR_ARCHIVE, "GNU_TAR_ARCHIVE", "org.gnu.gnu-tar-archive" }, + { GNU_ZIP_ARCHIVE, "GNU_ZIP_ARCHIVE", "org.gnu.gnu-zip-archive" }, + { GNU_ZIP_TAR_ARCHIVE, "GNU_ZIP_TAR_ARCHIVE", "org.gnu.gnu-zip-tar-archive" }, + { CALENDAR, "CALENDAR", "general.calendar" }, + { CONTACT, "CONTACT", "general.contact" }, + { DATABASE, "DATABASE", "general.database" }, + { MESSAGE, "MESSAGE", "general.message" }, + { VCARD, "VCARD", "general.vcard" }, + { NAVIGATION, "NAVIGATION", "general.navigation" }, + { LOCATION, "LOCATION", "general.location" }, + { SYSTEM_DEFINED_RECORD, "SYSTEM_DEFINED_RECORD", "SystemDefinedType" }, + { SYSTEM_DEFINED_FORM, "OPENHARMONY_FORM", "openharmony.form" }, + { SYSTEM_DEFINED_APP_ITEM, "OPENHARMONY_APP_ITEM", "openharmony.app-item" }, + { SYSTEM_DEFINED_PIXEL_MAP, "OPENHARMONY_PIXEL_MAP", "openharmony.pixel-map" }, + { OPENHARMONY_ATOMIC_SERVICE, "OPENHARMONY_ATOMIC_SERVICE", "openharmony.atomic-service" }, + { APPLICATION_DEFINED_RECORD, "APPLICATION_DEFINED_RECORD", "ApplicationDefinedType" }, + { OPENHARMONY_PACKAGE, "OPENHARMONY_PACKAGE", "openharmony.package" }, + { OPENHARMONY_HAP, "OPENHARMONY_HAP", "openharmony.hap" }, + { SMIL, "SMIL", "com.real.smil" }, + { MARKDOWN, "MARKDOWN", "general.markdown" }, + { FAX, "FAX", "general.fax" }, + { JFX_FAX, "JFX_FAX", "com.j2.jfx-fax" }, + { EFX_FAX, "EFX_FAX", "com.js.efx-fax" }, + { XBITMAP_IMAGE, "XBITMAP_IMAGE", "general.xbitmap-image" }, + { TGA_IMAGE, "TGA_IMAGE", "com.truevision.tga-image" }, + { SGI_IMAGE, "SGI_IMAGE", "com.sgi.sgi-image" }, + { OPENEXR_IMAGE, "OPENEXR_IMAGE", "com.ilm.openexr-image" }, + { FLASHPIX_IMAGE, "FLASHPIX_IMAGE", "com.kodak.flashpix.image" }, + { REALMEDIA, "REALMEDIA", "com.real.realmedia" }, + { AU_AUDIO, "AU_AUDIO", "general.au-audio" }, + { AIFC_AUDIO, "AIFC_AUDIO", "general.aifc-audio" }, + { SD2_AUDIO, "SD2_AUDIO", "com.digidesign.sd2-audio" }, + { REALAUDIO, "REALAUDIO", "com.real.realaudio" }, + { OPENXML, "OPENXML", "org.openxmlformats.openxml" }, + { WORDPROCESSINGML_DOCUMENT, "WORDPROCESSINGML_DOCUMENT", + "org.openxmlformats.wordprocessingml.document" }, + { SPREADSHEETML_SHEET, "SPREADSHEETML_SHEET", "org.openxmlformats.spreadsheetml.sheet" }, + { PRESENTATIONML_PRESENTATION, "PRESENTATIONML_PRESENTATION", + "org.openxmlformats.presentationml.presentation" }, + { OPENDOCUMENT, "OPENDOCUMENT", "org.oasis.opendocument" }, + { OPENDOCUMENT_TEXT, "OPENDOCUMENT_TEXT", "org.oasis.opendocument.text" }, + { OPENDOCUMENT_SPREADSHEET, "OPENDOCUMENT_SPREADSHEET", "org.oasis.opendocument.spreadsheet" }, + { OPENDOCUMENT_PRESENTATION, "OPENDOCUMENT_PRESENTATION", "org.oasis.opendocument.presentation" }, + { OPENDOCUMENT_GRAPHICS, "OPENDOCUMENT_GRAPHICS", "org.oasis.opendocument.graphics" }, + { OPENDOCUMENT_FORMULA, "OPENDOCUMENT_FORMULA", "org.oasis.opendocument.formula" }, + { STUFFIT_ARCHIVE, "STUFFIT_ARCHIVE", "com.allume.stuffit-archive" }, + { VCS, "VCS", "general.vcs" }, + { ICS, "ICS", "general.ics" }, + { EXECUTABLE, "EXECUTABLE", "general.executable" }, + { PORTABLE_EXECUTABLE, "PORTABLE_EXECUTABLE", "com.microsoft.portable-executable" }, + { SUN_JAVA_CLASS, "SUN_JAVA_CLASS", "com.sun.java-class" }, + { FONT, "FONT", "general.font" }, + { TRUETYPE_FONT, "TRUETYPE_FONT", "general.truetype-font" }, + { TRUETYPE_COLLECTION_FONT, "TRUETYPE_COLLECTION_FONT", "general.truetype-collection-font" }, + { OPENTYPE_FONT, "OPENTYPE_FONT", "general.opentype-font" }, + { POSTSCRIPT_FONT, "POSTSCRIPT_FONT", "com.adobe.postscript-font" }, + { POSTSCRIPT_PFB_FONT, "POSTSCRIPT_PFB_FONT", "com.adobe.postscript-pfb-font" }, + { POSTSCRIPT_PFA_FONT, "POSTSCRIPT_PFA_FONT", "com.adobe.postscript-pfa-font" }, + { OPENHARMONY_HDOC, "OPENHARMONY_HDOC", "openharmony.hdoc" }, + { OPENHARMONY_HINOTE, "OPENHARMONY_HINOTE", "openharmony.hinote" }, + { OPENHARMONY_STYLED_STRING, "OPENHARMONY_STYLED_STRING", "openharmony.styled-string" }, + { OPENHARMONY_WANT, "OPENHARMONY_WANT", "openharmony.want" }, + { OFD, "OFD", "general.ofd" }, + { OPG, "OPG", "general.opg" }, + { TEX, "TEX", "general.tex" }, + { CSS, "CSS", "general.css" }, + { VOB, "VOB", "general.vob" }, + { DIF_VIDEO, "DIF_VIDEO", "general.dif-video" }, + { DV_VIDEO, "DV_VIDEO", "general.dv-video" }, + { FLC_ANIMATION, "FLC_ANIMATION", "general.flc-animation" }, + { MNG, "MNG", "general.mng" }, + { MPEGURL_VIDEO, "MPEGURL_VIDEO", "general.mpegurl-video" }, + { TS, "TS", "general.ts" }, + { AMR, "AMR", "general.amr" }, + { AMR_WB, "AMR_WB", "general.amr-wb" }, + { GMS, "GSM", "general.gsm" }, + { IMY, "IMY", "general.imy" }, + { KAR, "KAR", "general.kar" }, + { MPEGURL_AUDIO, "MPEGURL_AUDIO", "general.mpegurl-audio" }, + { MPEG_4_AUDIO, "MPEG_4_AUDIO", "general.mpeg-4-audio" }, + { MIDI_AUDIO, "MIDI_AUDIO", "general.midi-audio" }, + { MP2, "MP2", "general.mp2" }, + { MPEG_AUDIO, "MPEG_AUDIO", "general.mpeg-audio" }, + { MXMF, "MXMF", "general.mxmf" }, + { OTA, "OTA", "general.ota" }, + { PLS, "PLS", "general.pls" }, + { RTTTL, "RTTTL", "general.rtttl" }, + { PSID, "PSID", "general.psid" }, + { ULAW_AUDIO, "ULAW_AUDIO", "general.ulaw-audio" }, + { XMF, "XMF", "general.xmf" }, + { GIF, "GIF", "general.gif" }, + { DJVU_IMAGE, "DJVU_IMAGE", "general.djvu-image" }, + { JNG_IMAGE, "JNG_IMAGE", "general.jng-image" }, + { PCX_IMAGE, "PCX_IMAGE", "general.pcx-image" }, + { PBM_IMAGE, "PBM_IMAGE", "general.pbm-image" }, + { PGM_IMAGE, "PGM_IMAGE", "general.pgm-image" }, + { PNM_IMAGE, "PNM_IMAGE", "general.pnm-image" }, + { PPM_IMAGE, "PPM_IMAGE", "general.ppm-image" }, + { RGB_IMAGE, "RGB_IMAGE", "general.rgb-image" }, + { SVG_IMAGE, "SVG_IMAGE", "general.svg-image" }, + { WBMP_IMAGE, "WBMP_IMAGE", "general.wbmp-image" }, + { XPIXMP_IMAGE, "XPIXMAP_IMAGE", "general.xpixmap-image" }, + { XWINDOWDUMP_IMAGE, "XWINDOWDUMP_IMAGE", "general.xwindowdump-image" }, + { HEIF, "HEIF", "general.heif" }, + { HEIC, "HEIC", "general.heic" }, + { VIRTUAL_CD, "VIRTUAL_CD", "general.virtual-cd" }, + { BOO_SOURCE, "BOO_SOURCE", "general.boo-source" }, + { D_SOURCE, "D_SOURCE", "general.d-source" }, + { HTML_COMPONENT, "HTML_COMPONENT", "general.html-component" }, + { PASCAL_SOURCE, "PASCAL_SOURCE", "general.pascal-source" }, + { HASKELL_SCRIPT, "HASKELL_SCRIPT", "general.haskell-script" }, + { LITERATE_HASKELL_SCRIPT, "LITERATE_HASKELL_SCRIPT", "general.literate-haskell-script" }, + { TCL_SCRIPT, "TCL_SCRIPT", "general.tcl-script" }, + { ASC_TEXT, "ASC_TEXT", "general.asc-text" }, + { PORTABLE_OBJECT, "PORTABLE_OBJECT", "general.portable-object" }, + { RICH_TEXT, "RICH_TEXT", "general.rich-text" }, + { DELIMITED_VALUES_TEXT, "DELIMITED_VALUES_TEXT", "general.delimited-values-text" }, + { COMMA_SEPARATED_VALUES_TEXT, "COMMA_SEPARATED_VALUES_TEXT", "general.comma-separated-values-text" }, + { DIFF, "DIFF", "general.diff" }, + { SETEXT, "SETEXT", "general.setext" }, + { GCD, "GCD", "general.gcd" }, + { TAB_SEPARATED_VALUES_TEXT, "TAB_SEPARATED_VALUES_TEXT", "general.tab-separated-values-text" }, + { P7R, "P7R", "general.p7r" }, + { PEM, "PEM", "general.pem" }, + { CHESS_PGN, "CHESS_PGN", "general.chess-pgn" }, + { LHA_ARCHIVE, "LHA_ARCHIVE", "general.lha-archive" }, + { LZH_ARCHIVE, "LZH_ARCHIVE", "general.lzh-archive" }, + { LZX_ARCHIVE, "LZX_ARCHIVE", "general.lzx-archive" }, + { TAZ_ARCHIVE, "TAZ_ARCHIVE", "general.taz-archive" }, + { SHAR_ARCHIVE, "SHAR_ARCHIVE", "general.shar-archive" }, + { CPIO_ARCHIVE, "CPIO_ARCHIVE", "general.cpio-archive" }, + { WEB_ARCHIVE, "WEB_ARCHIVE", "general.web-archive" }, + { USTAR, "USTAR", "general.ustar" }, + { MATHML, "MATHML", "general.mathml" }, + { XHTML, "XHTML", "general.xhtml" }, + { RSS, "RSS", "general.rss" }, + { RDF, "RDF", "general.rdf" }, + { IGES, "IGES", "general.iges" }, + { CAD, "CAD", "general.cad" }, + { OCTET_STREAM, "OCTET_STREAM", "general.octet-stream" }, + { ISO, "ISO", "general.iso" }, + { MESH_MODEL, "MESH_MODEL", "general.mesh-model" }, + { CERTIFICATE, "CERTIFICATE", "general.certificate" }, + { C_OBJECT, "C_OBJECT", "general.c-object" }, + { DVI, "DVI", "general.dvi" }, + { CER_CERTIFICATE, "CER_CERTIFICATE", "general.cer-certificate" }, + { CRT_CERTIFICATE, "CRT_CERTIFICATE", "general.crt-certificate" }, + { CRL_CERTIFICATE, "CRL_CERTIFICATE", "general.crl-certificate" }, + { PRN, "PRN", "general.prn" }, + { OPENDOCUMENT_CHART, "OPENDOCUMENT_CHART", "org.oasis-open.opendocument.chart" }, + { OPENDOCUMENT_TEXT_MASTER, "OPENDOCUMENT_TEXT_MASTER", "org.oasis-open.opendocument.text-master" }, + { OPENDOCUMENT_TEXT_WEB, "OPENDOCUMENT_TEXT_WEB", "org.oasis-open.opendocument.text-web" }, + { OPENDOCUMENT_DATABASE, "OPENDOCUMENT_DATABASE", "org.oasis-open.opendocument.database" }, + { OPENDOCUMENT_IMAGE, "OPENDOCUMENT_IMAGE", "org.oasis-open.opendocument.image" }, + { OPENDOCUMENT_FORMULA_TEMPLATE, "OPENDOCUMENT_FORMULA_TEMPLATE", "org.oasis-open.opendocument.formula-template" }, + { OPENDOCUMENT_CHART_TEMPLATE, "OPENDOCUMENT_CHART_TEMPLATE", "org.oasis-open.opendocument.chart-template" }, + { OPENDOCUMENT_PRESENTATION_TEMPLATE, "OPENDOCUMENT_PRESENTATION_TEMPLATE", + "org.oasis-open.opendocument.presentation-template" }, + { OPENDOCUMENT_IMAGE_TEMPLATE, "OPENDOCUMENT_IMAGE_TEMPLATE", "org.oasis-open.opendocument.image-template" }, + { OPENDOCUMENT_GRAPHICS_TEMPLATE, "OPENDOCUMENT_GRAPHICS_TEMPLATE", + "org.oasis-open.opendocument.graphics-template" }, + { OPENDOCUMENT_SPREADSHEET_TEMPLATE, "OPENDOCUMENT_SPREADSHEET_TEMPLATE", + "org.oasis-open.opendocument.spreadsheet-template" }, + { OPENDOCUMENT_TEXT_TEMPLATE, "OPENDOCUMENT_TEXT_TEMPLATE", "org.oasis-open.opendocument.text-template" }, + { WORD_DOT, "WORD_DOT", "com.microsoft.word.dot" }, + { POWERPOINT_PPS, "POWERPOINT_PPS", "com.microsoft.powerpoint.pps" }, + { POWERPOINT_POT, "POWERPOINT_POT", "com.microsoft.powerpoint.pot" }, + { EXCEL_XLT, "EXCEL_XLT", "com.microsoft.excel.xlt" }, + { VISIO_VSD, "VISIO_VSD", "com.microsoft.visio.vsd" }, + { DRAWINGML_VISIO, "DRAWINGML_VISIO", "org.openxmlformats.drawingml.visio" }, + { DRAWINGML_TEMPLATE, "DRAWINGML_TEMPLATE", "org.openxmlformats.drawingml.template" }, + { DRAWINGML_VISIO_MACROENABLED, "DRAWINGML_VISIO_MACROENABLED", "org.openxmlformats.drawingml.visio.macroenabled" }, + { DRAWINGML_TEMPLATE_MACROENABLED, "DRAWINGML_TEMPLATE_MACROENABLED", + "org.openxmlformats.drawingml.template.macroenabled" }, + { WORDPROCESSINGML_TEMPLATE, "WORDPROCESSINGML_TEMPLATE", "org.openxmlformats.wordprocessingml.template" }, + { PRESENTATIONML_TEMPLATE, "PRESENTATIONML_TEMPLATE", "org.openxmlformats.presentationml.template" }, + { PRESENTATIONML_SLIDESHOW, "PRESENTATIONML_SLIDESHOW", "org.openxmlformats.presentationml.slideshow" }, + { SPREADSHEETML_TEMPLATE, "SPREADSHEETML_TEMPLATE", "org.openxmlformats.spreadsheetml.template" }, + { WORDPROCESSINGML_DOCUMENT_MACROENABLED, "WORDPROCESSINGML_DOCUMENT_MACROENABLED", + "org.openxmlformats.wordprocessingml.document.macroenabled" }, + { WORDPROCESSINGML_TEMPLATE_MACROENABLED, "WORDPROCESSINGML_TEMPLATE_MACROENABLED", + "org.openxmlformats.wordprocessingml.template.macroenabled" }, + { SPREADSHEETML_TEMPLATE_MACROENABLED, "SPREADSHEETML_TEMPLATE_MACROENABLED", + "org.openxmlformats.spreadsheetml.template.macroenabled" }, + { SPREADSHEETML_ADDIN_MACROENABLED, "SPREADSHEETML_ADDIN_MACROENABLED", + "org.openxmlformats.spreadsheetml.addin.macroenabled" }, + { SPREADSHEETML_BINARY_MACROENABLED, "SPREADSHEETML_BINARY_MACROENABLED", + "org.openxmlformats.spreadsheetml.binary.macroenabled" }, + { SPREADSHEETML_SHEET_MACROENABLED, "SPREADSHEETML_SHEET_MACROENABLED", + "org.openxmlformats.spreadsheetml.sheet.macroenabled" }, + { PRESENTATIONALML_ADDIN_MACROENABLED, "PRESENTATIONALML_ADDIN_MACROENABLED", + "org.openxmlformats.presentationml.addin.macroenabled" }, + { PRESENTATIONALML_PRESENTATION_MACROENABLED, "PRESENTATIONALML_PRESENTATION_MACROENABLED", + "org.openxmlformats.presentationml.presentation.macroenabled" }, + { PRESENTATIONALML_SLIDESHOW_MACROENABLED, "PRESENTATIONALML_SLIDESHOW_MACROENABLED", + "org.openxmlformats.presentationml.slideshow.macroenabled" }, + { PRESENTATIONALML_TEMPLATE_MACROENABLED, "PRESENTATIONALML_TEMPLATE_MACROENABLED", + "org.openxmlformats.presentationml.template.macroenabled" }, + { OPENOFFICE, "OPENOFFICE", "org.openoffice" }, + { OPENOFFICE_CALC, "OPENOFFICE_CALC", "org.openoffice.calc" }, + { OPENOFFICE_DRAW, "OPENOFFICE_DRAW", "org.openoffice.draw" }, + { OPENOFFICE_WRITER_GLOBAL, "OPENOFFICE_WRITER_GLOBAL", "org.openoffice.writer-global" }, + { OPENOFFICE_IMPRESS, "OPENOFFICE_IMPRESS", "org.openoffice.impress" }, + { OPENOFFICE_MATH, "OPENOFFICE_MATH", "org.openoffice.math" }, + { OPENOFFICE_WRITER, "OPENOFFICE_WRITER", "org.openoffice.writer" }, + { OPENOFFICE_CALC_TEMPLATE, "OPENOFFICE_CALC_TEMPLATE", "org.openoffice.calc.template" }, + { OPENOFFICE_DRAW_TEMPLATE, "OPENOFFICE_DRAW_TEMPLATE", "org.openoffice.draw.template" }, + { OPENOFFICE_IMPRESS_TEMPLATE, "OPENOFFICE_IMPRESS_TEMPLATE", "org.openoffice.impress.template" }, + { OPENOFFICE_WRITER_TEMPLATE, "OPENOFFICE_WRITER_TEMPLATE", "org.openoffice.writer.template" }, + { STAROFFICE, "STAROFFICE", "com.staroffice" }, + { STAROFFICE_DRAW, "STAROFFICE_DRAW", "com.staroffice.draw" }, + { STAROFFICE_CALC, "STAROFFICE_CALC", "com.staroffice.calc" }, + { STAROFFICE_IMPRESS, "STAROFFICE_IMPRESS", "com.staroffice.impress" }, + { STAROFFICE_WRITER, "STAROFFICE_WRITER", "com.staroffice.writer" }, + { STAROFFICE_CHART, "STAROFFICE_CHART", "com.staroffice.chart" }, + { STAROFFICE_MAIL, "STAROFFICE_MAIL", "com.staroffice.mail" }, + { STAROFFICE_WRITER_GLOBAL, "STAROFFICE_WRITER_GLOBAL", "com.staroffice.writer-global" }, + { STAROFFICE_MATH, "STAROFFICE_MATH", "com.staroffice.math" }, + { STAROFFICE_TEMPLATE, "STAROFFICE_TEMPLATE", "com.staroffice.template" }, + { TUG_BIB, "TUG_BIB", "org.tug.bib" }, + { TUG_CLS, "TUG_CLS", "org.tug.cls" }, + { TUG_STY, "TUG_STY", "org.tug.sty" }, + { TUG_TEX, "TUG_TEX", "org.tug.tex" }, + { LATEX, "LATEX", "org.latex-project.latex" }, + { ADVANCED_SYSTEMS_FORMAT, "ADVANCED_SYSTEMS_FORMAT", "com.microsoft.advanced-systems-format" }, + { ADVANCED_STREAM_REDIRECTOR, "ADVANCED_STREAM_REDIRECTOR", "com.microsoft.advanced-stream-redirector" }, + { MATROSKA_VIDEO, "MATROSKA_VIDEO", "org.matroska.mkv" }, + { MATROSKA_AUDIO, "MATROSKA_AUDIO", "org.matroska.mka" }, + { SGI_MOVIE, "SGI_MOVIE", "com.sgi.movie" }, + { APPLE_M4V, "APPLE_M4V", "com.apple.m4v" }, + { WEBM, "WEBM", "org.webmproject.webm" }, + { QUICKTIME_MOVIE, "QUICKTIME_MOVIE", "com.apple.quicktime-movie" }, + { CORELDRAW_CDR, "CORELDRAW_CDR", "com.coreldraw.cdr" }, + { CORELDRAW_CDT, "CORELDRAW_CDT", "com.coreldraw.cdt" }, + { CORELDRAW_CPT, "CORELDRAW_CPT", "com.coreldraw.cpt" }, + { CORELDRAW_PAT, "CORELDRAW_PAT", "com.coreldraw.pat" }, + { MICROSOFT_CUR, "MICROSOFT_CUR", "com.microsoft.cur" }, + { SUN_RASTER, "SUN_RASTER", "com.sun.raster" }, + { GOOGLE_WEBP, "GOOGLE_WEBP", "com.google.webp" }, + { KOAN_AUDIO, "KOAN_AUDIO", "com.sseyo.koan-audio" }, + { QT_MOC, "QT_MOC", "io.qt.moc" }, + { GHOSTSCRIPT_FONT, "GHOSTSCRIPT_FONT", "com.ghostscript.font" }, + { X_PCF_FONT, "X_PCF_FONT", "org.x.pcf-font" }, + { WINDOWS_MEDIA_WMD, "WINDOWS_MEDIA_WMD", "com.microsoft.windows-media-wmd" }, + { WINDOWS_MEDIA_WMZ, "WINDOWS_MEDIA_WMZ", "com.microsoft.windows-media-wmz" }, + { WINDOWS_INSTALLER, "WINDOWS_INSTALLER", "com.microsoft.windows-installer" }, + { PUBLISHER_PUB, "PUBLISHER_PUB", "com.microsoft.publisher.pub" }, + { WINDOWS_MEDIA_PLAYLIST, "WINDOWS_MEDIA_PLAYLIST", "com.microsoft.windows-media-playlist" }, + { ACCESS_MDB, "ACCESS_MDB", "com.microsoft.access.mdb" }, + { STEREOLITHOGRAPHY, "STEREOLITHOGRAPHY", "com.3dsystems.stereolithography" }, + { APPLE_MEDIA_PLAYLIST, "APPLE_MEDIA_PLAYLIST", "com.apple.media.playlist" }, + { ABISOURCE_WORD, "ABISOURCE_WORD", "com.abisource.word" }, + { ADOBE_FRAMEMAKER, "ADOBE_FRAMEMAKER", "com.adobe.framemaker" }, + { WOLFRAM_CDF, "WOLFRAM_CDF", "com.wolfram.cdf" }, + { CINDERELLA_CDY, "CINDERELLA_CDY", "de.cinderella.cdy" }, + { ADOBE_DCR, "ADOBE_DCR", "com.adobe.dcr" }, + { ADOBE_DIR, "ADOBE_DIR", "com.adobe.dir" }, + { ADOBE_DXR, "ADOBE_DXR", "com.adobe.dxr" }, + { GNUMERIC_SPREADSHEET, "GNUMERIC_SPREADSHEET", "org.gnumeric.spreadsheet" }, + { HDFGROUP_HDF, "HDFGROUP_HDF", "org.hdfgroup.hdf" }, + { BINHEX_ARCHIVE, "BINHEX_ARCHIVE", "com.apple.binhex-archive" }, + { MICROSOFT_HTA, "MICROSOFT_HTA", "com.microsoft.hta" }, + { INTERNET_INS, "INTERNET_INS", "com.microsoft.internet.ins" }, + { INTERNET_ISP, "INTERNET_ISP", "com.microsoft.internet.isp" }, + { TROFF, "TROFF", "org.troff" }, + { ADOBE_MIF, "ADOBE_MIF", "com.adobe.framemaker.mif" }, + { FREEMIND, "FREEMIND", "io.sourceforge.freemind" }, + { YAMAHA_SMAF, "YAMAHA_SMAF", "com.yamaha.smaf" }, + { MATHEMATICA_NOTEBOOK, "MATHEMATICA_NOTEBOOK", "com.wolfram.mathematica.notebook" }, + { XIPH_OGG, "XIPH_OGG", "org.xiph.ogg" }, + { PROXY_AUTOCONFIG, "PROXY_AUTOCONFIG", "com.netscape.proxy-autoconfig" }, + { PKCS_12, "PKCS_12", "com.rsa.pkcs-12" }, + { PGP_SIGNATURE, "PGP_SIGNATURE", "org.openpgp.signature" }, + { QUICKTIME_LINK, "QUICKTIME_LINK", "com.apple.quicktime-link" }, + { RAR_ARCHIVE, "RAR_ARCHIVE", "com.rarlab.rar-archive" }, + { SEVEN_ZIP_ARCHIVE, "SEVEN_ZIP_ARCHIVE", "org.7-zip.7-zip-archive" }, + { RED_BEAN_SGF, "RED_BEAN_SGF", "com.red-bean.sgf" }, + { SIT_ARCHIVE, "SIT_ARCHIVE", "com.stuffit.sit-archive" }, + { FUTURESPLASH, "FUTURESPLASH", "com.adobe.futuresplash" }, + { FLASH, "FLASH", "com.adobe.flash" }, + { TEXINFO, "TEXINFO", "org.gnu.texinfo" }, + { TORRENT, "TORRENT", "org.bittorrent.torrent" }, + { DOOM, "DOOM", "com.idsoftware.doom" }, + { APPLE_WEBARCHIVE, "APPLE_WEBARCHIVE", "com.apple.webarchive" }, + { ANDROID_WEBARCHIVE, "ANDROID_WEBARCHIVE", "com.android.webarchive" }, + { GIMP_XCF, "GIMP_XCF", "org.gimp.xcf" }, + { EDRWMAX, "EDRWMAX", "com.edrawsoft.edrawmax" }, + { EDRWMIND, "EDRWMIND", "com.edrawsoft.edrawmind" }, + { CNKI_CAJ, "CNKI_CAJ", "net.cnki.caj" }, + { DBASE_DBF, "DBASE_DBF", "com.dbase.dbf" }, + { AUTODESK_DWG, "AUTODESK_DWG", "com.autodesk.dwg" }, + { AUTODESK_DXF, "AUTODESK_DXF", "com.autodesk.dxf" }, + { AUTODESK_DWS, "AUTODESK_DWS", "com.autodesk.dws" }, + { AUTODESK_DWT, "AUTODESK_DWT", "com.autodesk.dwt" }, + { AUTODESK_DWF, "AUTODESK_DWF", "com.autodesk.dwf" }, + { AUTODESK_DWFX, "AUTODESK_DWFX", "com.autodesk.dwfx" }, + { AUTODESK_SHP, "AUTODESK_SHP", "com.autodesk.shp" }, + { AUTODESK_SHX, "AUTODESK_SHX", "com.autodesk.shx" }, + { AUTODESK_SLIDE_LIB, "AUTODESK_SLIDE_LIB", "com.autodesk.slide-library" }, + { AUTODESK_LINE, "AUTODESK_LINE", "com.autodesk.line" }, + { AUTODESK_PLOTTER, "AUTODESK_PLOTTER", "com.autodesk.plotter" }, + { HP_GRAPHICS_LANG, "HP_GRAPHICS_LANG", "com.hp.graphics-language" }, + { MICROSOFT_METAFILE, "MICROSOFT_METAFILE", "com.microsoft.metafile" }, + { ACIS_SAT, "ACIS_SAT", "com.spatial.acis.sat" }, + { AVIF_IMAGE, "AVIF_IMAGE", "org.aomedia.avif-image" }, + { MICROSOFT_DDS, "MICROSOFT_DDS", "com.microsoft.dds" }, + { IFF_ILBM, "IFF_ILBM", "com.ea.iff-ilbm" }, + { CR2_RAW_IMAGE, "CR2_RAW_IMAGE", "com.canon.cr2-raw-image" }, + { CR3_RAW_IMAGE, "CR3_RAW_IMAGE", "com.canon.cr3-raw-image" }, + { CRW_RAW_IMAGE, "CRW_RAW_IMAGE", "com.canon.crw-raw-image" }, + { DNG_RAW_IMAGE, "DNG_RAW_IMAGE", "com.adobe.dng-raw-image" }, + { ARW_RAW_IMAGE, "ARW_RAW_IMAGE", "com.sony.arw-raw-image" }, + { NEF_RAW_IMAGE, "NEF_RAW_IMAGE", "com.nikon.nef-raw-image" }, + { MINDMANAGER_MMAP, "MINDMANAGER_MMAP", "com.mindjet.mindmanager.mmap" }, + { MICROSOFT_EMAIL, "MICROSOFT_EMAIL", "com.microsoft.email" }, + { MICROSOFT_MESSAGE, "MICROSOFT_MESSAGE", "com.microsoft.message" }, + { MICROSOFT_PST, "MICROSOFT_PST", "com.microsoft.pst" }, + { KINGSOFT_OFFICE, "KINGSOFT_OFFICE", "com.kingsoft.office general.zip-archive" }, + { KINGSOFT_WRITER_WPS, "KINGSOFT_WRITER_WPS", "com.kingsoft.office.writer.wps" }, + { KINGSOFT_WRITER_WPT, "KINGSOFT_WRITER_WPT", "com.kingsoft.office.writer.wpt" }, + { KINGSOFT_PRESENTATION_DPS, "KINGSOFT_PRESENTATION_DPS", "com.kingsoft.office.presentation.dps" }, + { KINGSOFT_PRESENTATION_TEMPLATE, "KINGSOFT_PRESENTATION_TEMPLATE", "com.kingsoft.office.presentation.template" }, + { KINGSOFT_SPREADSHEETS_ET, "KINGSOFT_SPREADSHEETS_ET", "com.kingsoft.office.spreadsheets.et" }, + { KINGSOFT_SPREADSHEETS_TEMPLATE, "KINGSOFT_SPREADSHEETS_TEMPLATE", "com.kingsoft.office.spreadsheets.template" }, + { MICROSOFT_INI, "MICROSOFT_INI", "com.microsoft.ini" }, + { JSON, "JSON", "general.json" }, + { YAML, "YAML", "general.yaml" }, + { LOG, "LOG", "general.log" }, + { URI, "URI", "general.uri" }, + { FILE_URI, "FILE_URI", "general.file-uri" }, + { TEXT_LST, "TEXT_LST", "general.text-lst" }, + { ANDROID_APK, "ANDROID_APK", "com.android.apk" }, + { BZ_ARCHIVE, "BZ_ARCHIVE", "general.bz-archive" }, + { TBZ_ARCHIVE, "TBZ_ARCHIVE", "general.tar-bzip-archive" }, + { TBZ2_ARCHIVE, "TBZ2_ARCHIVE", "general.tar-bzip2-archive" }, + { XZ_ARCHIVE, "XZ_ARCHIVE", "org.tukaani.xz-archive" }, + { TXZ_ARCHIVE, "TXZ_ARCHIVE", "org.tukaani.tar-xz-archive" }, + { XAR_ARCHIVE, "XAR_ARCHIVE", "general.xar-archive" }, + { CAB_ARCHIVE, "CAB_ARCHIVE", "com.microsoft.cab-archive" }, + { RPM_ARCHIVE, "RPM_ARCHIVE", "redhat.rpm-archive" }, + { TPZ_ARCHIVE, "TPZ_ARCHIVE", "org.godotengine.tpz-archive", }, + { LZA_ARCHIVE, "LZA_ARCHIVE", "general.lza-archive" }, + { ARJ_ARCHIVE, "ARJ_ARCHIVE", "general.arj-archive" }, + { ZIPX_ARCHIVE, "ZIPX_ARCHIVE", "com.winzip.zipx" }, + { LZMA_ARCHIVE, "LZMA_ARCHIVE", "general.lzma-archive" }, + { LZMA86_ARCHIVE, "LZMA86_ARCHIVE", "general.lzma86-archive" }, + { XPI_ARCHIVE, "XPI_ARCHIVE", "org.mozilla.xpinstall" }, + { HFS_DISK_IMAGE, "HFS_DISK_IMAGE", "general.hfs-disk-image" }, + { IMG_DISK_IMAGE, "IMG_DISK_IMAGE", "general.img-disk-image" }, + { ISZ_DISK_IMAGE, "ISZ_DISK_IMAGE", "com.ezbsystems.zipped-iso" }, + { WIM_DISK_IMAGE, "WIM_DISK_IMAGE", "com.microsoft.wim" }, + { SWM_DISK_IMAGE, "SWM_DISK_IMAGE", "com.microsoft.swm" }, + { KINGSOFT_SPREADSHEETS_ETX, "KINGSOFT_SPREADSHEETS_ETX", "com.kingsoft.office.spreadsheets.etx" }, + { KINGSOFT_SPREADSHEETS_ETTX, "KINGSOFT_SPREADSHEETS_ETTX", "com.kingsoft.office.spreadsheets.ettx" }, + { EXCEL_DIF, "EXCEL_DIF", "com.microsoft.excel.dif" }, + { OPENHARMONY_APP, "OPENHARMONY_APP", "openharmony.app" }, + { HMOS_WIFI, "HMOS_WIFI", "com.huawei.hmos.settings.wifi" }, + { TEL, "TEL", "general.tel" }, + { ETS, "ETS", "general.ets" }, + { JSON5, "JSON5", "general.json5" }, + { APE_AUDIO, "APE_AUDIO", "com.monkeysaudio.ape-audio" }, + { OPUS_AUDIO, "OPUS_AUDIO", "org.xiph.opus-audio"}, + { CONF, "CONF", "general.conf" }, + { MICROSOFT_DOS_BATCH, "MICROSOFT_DOS_BATCH", "com.microsoft.dos-batch" }, + { MICROSOFT_VBSCRIPT, "MICROSOFT_VBSCRIPT", "com.microsoft.vbscript" }, + { ION, "ION", "general.ion" }, + { MICROSOFT_REGISTRY, "MICROSOFT_REGISTRY", "com.microsoft.registry" }, + { MICROSOFT_CATALOG, "MICROSOFT_CATALOG", "com.microsoft.catalog" }, + { MICROSOFT_POWERSHELL_SCRIPT, "MICROSOFT_POWERSHELL_SCRIPT", "com.microsoft.powershell-script" }, + { W3_WOFF, "W3_WOFF", "org.w3.woff" }, + { SQLITE_DATABASE, "SQLITE_DATABASE", "org.sqlite.database" }, + { MICROSOFT_SYS, "MICROSOFT_SYS", "com.microsoft.sys" }, + { MICROSOFT_INF, "MICROSOFT_INF", "com.microsoft.inf" }, + { MICROSOFT_PDB, "MICROSOFT_PDB", "com.microsoft.pdb" }, + { MICROSOFT_TLB, "MICROSOFT_TLB", "com.microsoft.tlb" }, + { MICROSOFT_SCCD, "MICROSOFT_SCCD", "com.microsoft.sccd" }, + { ADOBE_F4V, "ADOBE_F4V", "com.adobe.f4v" }, + { MP2T, "MP2T", "general.mp2t" }, + { YOUTUBE_VIDEO, "YOUTUBE_VIDEO", "com.youtube.video" }, + { WEBEX_VIDEO, "WEBEX_VIDEO", "com.cisco.webex-video" }, + { MPEG2, "MPEG2", "general.mpeg-2" }, + { MPEG1, "MPEG1", "general.mpeg-1" }, + { REALMEDIA_VBR, "REALMEDIA_VBR", "com.real.realmedia-vbr" }, + { REAL_REALVIDEO, "REAL_REALVIDEO", "com.real.realvideo" }, + { DIVX_VIDEO, "DIVX_VIDEO", "general.divx-video" }, + { CSIRO_ANNODEX, "CSIRO_ANNODEX", "org.csiro.annodex" }, + { OGV, "OGV", "general.ogv" }, + { LSF_VIDEO, "LSF_VIDEO", "com.microsoft.lsf-video" }, + { H264_VIDEO, "H264_VIDEO", "general.h264-video" }, + { JPEG2000, "JPEG2000", "general.jpeg-2000" }, + { RAF_RAW_IMAGE, "RAF_RAW_IMAGE", "com.fujifilm.raf-raw-image" }, + { NRW_RAW_IMAGE, "NRW_RAW_IMAGE", "com.nikon.nrw-raw-image" }, + { RW2_RAW_IMAGE, "RW2_RAW_IMAGE", "com.panasonic.rw2-raw-image" }, + { PEF_RAW_IMAGE, "PEF_RAW_IMAGE", "com.pentax.pef-raw-image" }, + { SRW_RAW_IMAGE, "SRW_RAW_IMAGE", "com.sumsung.srw-raw-image" }, + { ERF_RAW_IMAGE, "ERF_RAW_IMAGE", "com.epson.erf-raw-image" }, + { ORF_RAW_IMAGE, "ORF_RAW_IMAGE", "com.olympus.orf-raw-image" }, + { IEF_IMAGE, "IEF_IMAGE", "general.ief-image" }, + { ART_IMAGE, "ART_IMAGE", "com.aol.art-image" }, + { CONTENT_FORM, "CONTENT_FORM", "general.content-form" }, + { M4P_AUDIO, "M4P_AUDIO", "com.apple.m4p-audio" }, + { AC3_AUDIO, "AC3_AUDIO", "general.ac3-audio" }, + { OPENHARMONY_HSP, "OPENHARMONY_HSP", "openharmony.hsp" }, + { OPENHARMONY_HAR, "OPENHARMONY_HAR", "openharmony.har" }, + { OPENHARMONY_GOPAINT, "OPENHARMONY_GOPAINT", "openharmony.gopaint" }, + { OPENHARMONY_GOBRUSH, "OPENHARMONY_GOBRUSH", "openharmony.gobrush" }, + { OPENHARMONY_GOBRUSHES, "OPENHARMONY_GOBRUSHES", "openharmony.gobrushes" }, + { OPENHARMONY_GOCOLOR, "OPENHARMONY_GOCOLOR", "openharmony.gocolor" } +}; + +static constexpr std::initializer_list NOT_NEED_COUNT_VALUE_LIST = { + UNIFORM_DATA_TYPE, ARRAY_BUFFER_LENGTH, THUMB_DATA_LENGTH, APP_ICON_LENGTH +}; + +namespace UtdUtils { +bool IsValidUtdId(const std::string &utdId) +{ + for (const auto &item : UTD_TYPES) { + if (item.UtdId == utdId) { + return true; + } + } + return false; +} + +int32_t GetUtdEnumFromUtdId(const std::string &utdId) +{ + for (const auto &item : UTD_TYPES) { + if (item.UtdId == utdId) { + return item.UtdEnum; + } + } + return UD_BUTT; +} + +std::string GetUtdIdFromUtdEnum(int32_t utdType) +{ + for (const auto &item : UTD_TYPES) { + if (item.UtdEnum == utdType) { + return item.UtdId; + } + } + return ""; +} + +std::vector GetUtdTypes() +{ + std::vector utdTypes(UTD_TYPES, UTD_TYPES + sizeof(UTD_TYPES) / sizeof(UtdType)); + return utdTypes; +} +} // namespace UtdUtils + +bool UnifiedDataUtils::IsValidType(int32_t value) +{ + return value >= ENTITY && value < UD_BUTT; +} + +bool UnifiedDataUtils::IsValidIntention(int32_t value) +{ + return value > UD_INTENTION_BASE && value < UD_INTENTION_BUTT; +} + +static constexpr AppShareOption APP_SHARE_OPTIONS[] = { + { IN_APP, "IN_APP"}, + { CROSS_APP, "CROSS_APP"}, +}; + +bool ShareOptionsUtil::IsValid(int32_t shareOption) +{ + if (shareOption < 0 || shareOption >= SHARE_OPTIONS_BUTT) { + return false; + } + return true; +} + +int32_t ShareOptionsUtil::GetEnumNum(const std::string &shareOption) +{ + for (const auto &item : APP_SHARE_OPTIONS) { + if (item.enumStr == shareOption) { + return item.enumNum; + } + } + return SHARE_OPTIONS_BUTT; +} + +std::string ShareOptionsUtil::GetEnumStr(int32_t shareOption) +{ + for (const auto &item : APP_SHARE_OPTIONS) { + if (item.enumNum == shareOption) { + return item.enumStr; + } + } + return ""; +} + +size_t UnifiedDataUtils::GetVariantSize(UDVariant &variant) +{ + auto int32Value = std::get_if(&variant); + if (int32Value != nullptr) { + return sizeof(std::get(variant)); + } + auto int64Value = std::get_if(&variant); + if (int64Value != nullptr) { + return sizeof(std::get(variant)); + } + auto boolValue = std::get_if(&variant); + if (boolValue != nullptr) { + return sizeof(std::get(variant)); + } + auto doubleValue = std::get_if(&variant); + if (doubleValue != nullptr) { + return sizeof(std::get(variant)); + } + auto strValue = std::get_if(&variant); + if (strValue != nullptr) { + return std::get(variant).size(); + } + auto vecValue = std::get_if>(&variant); + if (vecValue != nullptr) { + return std::get>(variant).size(); + } + return 0; +} + +size_t UnifiedDataUtils::GetDetailsSize(UDDetails &details) +{ + size_t total = 0; + for (std::pair prop : details) { + total += prop.first.size(); + total += GetVariantSize(prop.second); + } + return total; +} + +bool UnifiedDataUtils::IsPersist(const Intention &intention) +{ + return intention >= UD_INTENTION_DATA_HUB && intention < UD_INTENTION_BUTT; +} + +bool UnifiedDataUtils::IsPersist(const std::string &intention) +{ + return IsPersist(GetIntentionByString(intention)); +} + +Intention UnifiedDataUtils::GetIntentionByString(const std::string &intention) +{ + for (const auto &it : UD_INTENTION_MAP) { + if (it.second == intention) { + return static_cast(it.first); + } + } + return UD_INTENTION_BUTT; +} + +bool UnifiedDataUtils::IsValidOptions(const std::string &key, std::string &intention) +{ + UnifiedKey unifiedKey(key); + auto isValidKey = unifiedKey.IsValid(); + if (key.empty() && IsPersist(intention)) { + return true; + } + if (intention.empty() && isValidKey && IsPersist(unifiedKey.intention)) { + return true; + } + if (isValidKey && unifiedKey.intention == intention && IsPersist(intention)) { + intention = ""; + return true; + } + return false; +} + +std::shared_ptr ObjectUtils::ConvertToObject(UDDetails &details) +{ + Object object; + for (auto [key, value] : details) { + ConvertVariant(std::move(value), object.value_[key]); + } + return std::make_shared(object); +} + +UDDetails ObjectUtils::ConvertToUDDetails(std::shared_ptr object) +{ + UDDetails details; + if (object == nullptr) { + return details; + } + for (auto [key, value] : object->value_) { + if (!ConvertVariant(std::move(value), details[key])) { + LOG_ERROR(UnifiedRecord, "object convert to UDDetails failed, object key is %{public}s", key.c_str()); + } + } + return details; +} + +int64_t ObjectUtils::GetValueSize(const ValueType &value, bool isCalValueType) +{ + if (value.index() == 0) { + return 0; + } + if (std::holds_alternative(value)) { + return std::get(value).size(); + } + if (std::holds_alternative>(value)) { + return GetObjectValueSize(std::get>(value), isCalValueType); + } + if (std::holds_alternative>(value)) { + return std::get>(value).size(); + } + if (std::holds_alternative>(value)) { + auto pixelMap = std::get>(value); + return pixelMap->GetByteCount(); + } + if (std::holds_alternative>(value)) { + // ArkUI-X does not support want.Marshalling + return 0; + } + return std::visit([] (const auto &val) { return sizeof(val); }, value); +} + +int64_t ObjectUtils::GetObjectValueSize(const std::shared_ptr object, bool isCalValueType) +{ + if (object == nullptr) { + return 0; + } + int64_t size = 0; + for (auto [key, value] : object->value_) { + if (std::find(NOT_NEED_COUNT_VALUE_LIST.begin(), NOT_NEED_COUNT_VALUE_LIST.end(), key) + != NOT_NEED_COUNT_VALUE_LIST.end()) { + continue; + } + if (key == VALUE_TYPE && isCalValueType) { + size += GetValueSize(value, false); + continue; + } + if (key == DETAILS) { + if (!std::holds_alternative>(value)) { + LOG_ERROR(UDMF_FRAMEWORK, "Details is not correct!"); + continue; + } + size += GetAllObjectSize(std::get>(value)); + continue; + } + size += GetValueSize(value, false); + } + return size; +} + + +int64_t ObjectUtils::GetAllObjectSize(const std::shared_ptr object) +{ + if (object == nullptr) { + return 0; + } + int64_t size = 0; + for (auto [key, value] : object->value_) { + size += key.size() + GetValueSize(value, false); + } + return size; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/bundle.json b/udmf/bundle.json index 5ce0aa323df92417d3921432efdf0746d86a18f6..5b94235e09c5109152214f6c8004e0f73f93b6e5 100644 --- a/udmf/bundle.json +++ b/udmf/bundle.json @@ -30,6 +30,7 @@ "bundle_framework", "cJSON", "c_utils", + "dfs_service", "hilog", "hisysevent", "hitrace", @@ -70,6 +71,7 @@ "name": "//foundation/distributeddatamgr/udmf/interfaces/innerkits:udmf_client", "header": { "header_files": [ + "udmf_async_client.h", "udmf_client.h", "utd_client.h" ], @@ -80,7 +82,9 @@ "name": "//foundation/distributeddatamgr/udmf/interfaces/innerkits:udmf_client", "header": { "header_files": [ + "async_task_params.h", "error_code.h", + "progress_queue.h", "unified_key.h", "unified_meta.h", "unified_types.h", @@ -159,6 +163,15 @@ ], "header_base":"//foundation/distributeddatamgr/udmf/interfaces/innerkits/data" } + }, + { + "name": "//foundation/distributeddatamgr/udmf/interfaces/jskits:intelligence_napi", + "header": { + "header_files": [ + "i_aip_core_manager.h" + ], + "header_base":"//foundation/distributeddatamgr/udmf/interfaces/jskits/intelligence" + } } ], "test": [ diff --git a/udmf/framework/common/custom_utd_json_parser.cpp b/udmf/framework/common/custom_utd_json_parser.cpp index 668dc0719d55f4818faeefb1af27127877f37953..4de2c31e9629f19f00a5a77519142f6e215d024b 100644 --- a/udmf/framework/common/custom_utd_json_parser.cpp +++ b/udmf/framework/common/custom_utd_json_parser.cpp @@ -77,6 +77,8 @@ bool CustomUtdJsonParser::ConvertUtdCfgsToJson(const std::vector size_t CountBufferSize(const UnifiedRecord &input, TLVObject &data) { std::string version = UTILS::GetCurrentSdkVersion(); return data.CountHead() + data.Count(version) + data.CountBasic(static_cast(input.GetType())) + - data.Count(input.GetUid()) + CountBufferSize(input.GetOriginValue(), data); + data.Count(input.GetUid()) + CountBufferSize(input.GetOriginValue(), data) + data.Count(input.GetUtdId()) + + CountBufferSize(input.GetInnerEntries(), data); } template <> bool Writing(const UnifiedRecord &input, TLVObject &data, TAG tag) @@ -300,6 +301,12 @@ template <> bool Writing(const UnifiedRecord &input, TLVObject &data, TAG tag) if (!TLVUtil::Writing(input.GetOriginValue(), data, TAG::TAG_RECORD_VALUE)) { return false; } + if (!data.Write(TAG::TAG_RECORD_UTD_ID, input.GetUtdId())) { + return false; + } + if (!TLVUtil::Writing(input.GetInnerEntries(), data, TAG::TAG_RECORD_ENTRIES)) { + return false; + } return data.WriteBackHead(static_cast(tag), tagCursor, data.GetCursor() - tagCursor - sizeof(TLVHead)); } @@ -314,6 +321,8 @@ template <> bool Reading(UnifiedRecord &output, TLVObject &data, const TLVHead & if (!data.ReadHead(headItem)) { return false; } + std::string utdId; + std::shared_ptr> entries; switch (headItem.tag) { case static_cast(TAG::TAG_VERSION): data.Skip(headItem); @@ -336,6 +345,18 @@ template <> bool Reading(UnifiedRecord &output, TLVObject &data, const TLVHead & } output.SetValue(value); break; + case static_cast(TAG::TAG_RECORD_UTD_ID): + if (!data.Read(utdId, headItem)) { + return false; + } + output.SetUtdId(std::move(utdId)); + break; + case static_cast(TAG::TAG_RECORD_ENTRIES): + if (!TLVUtil::Reading(entries, data, headItem)) { + return false; + } + output.SetInnerEntries(entries); + break; default: data.Skip(headItem); } @@ -553,6 +574,32 @@ template <> bool Reading(std::shared_ptr &output, TLVObje return true; } +template <> size_t CountBufferSize(const std::shared_ptr> &input, TLVObject &data) +{ + if (input == nullptr) { + return data.CountHead(); + } + return CountBufferSize(*input, data); +} + +template <> bool Writing(const std::shared_ptr> &input, TLVObject &data, TAG tag) +{ + if (input == nullptr) { + return false; + } + InitWhenFirst(input, data); + return Writing(*input, data, tag); +} + +template <> bool Reading(std::shared_ptr> &output, + TLVObject &data, const TLVHead &head) +{ + if (output == nullptr) { + output = std::make_shared>(); + } + return Reading(*output, data, head); +} + template <> size_t CountBufferSize(const std::shared_ptr &input, TLVObject &data) { Parcel parcel; diff --git a/udmf/framework/common/tlv_util.h b/udmf/framework/common/tlv_util.h index 309d96c37ba533d9990917ff2f10e5f7856e36ab..834de4c5ad5c46bc7d94b339edb4186b0cea97ee 100644 --- a/udmf/framework/common/tlv_util.h +++ b/udmf/framework/common/tlv_util.h @@ -16,7 +16,6 @@ #ifndef UDMF_TLV_UTIL_H #define UDMF_TLV_UTIL_H - #include #include #include "unified_types.h" @@ -106,6 +105,14 @@ template <> bool API_EXPORT Writing(const std::shared_ptr template <> bool API_EXPORT Reading(std::shared_ptr &output, TLVObject &data, const TLVHead &head); +template <> size_t API_EXPORT CountBufferSize(const std::shared_ptr> &input, + TLVObject &data); +template <> bool API_EXPORT Writing(const std::shared_ptr> &input, + TLVObject &data, TAG tag); +template <> +bool API_EXPORT Reading(std::shared_ptr> &output, + TLVObject &data, const TLVHead &head); + template <> size_t API_EXPORT CountBufferSize(const std::shared_ptr &input, TLVObject &data); template <> bool API_EXPORT Writing(const std::shared_ptr &input, TLVObject &data, TAG tag); template <> bool API_EXPORT Reading(std::shared_ptr &output, TLVObject &data, const TLVHead &head); @@ -128,7 +135,7 @@ template bool ReadTlv(T &output, TLVObject &data, TAG tag) return true; } -template void InitWhenFirst(T input, TLVObject &data) +template void InitWhenFirst(const T &input, TLVObject &data) { if (data.GetCursor() == data.GetTotal()) { CountBufferSize(input, data); @@ -292,7 +299,7 @@ template bool Reading(std::map &output, TLVObject return true; } -template size_t CountVariant(TLVObject &data, uint32_t step, const _InTp &intput) +template size_t CountVariant(TLVObject &data, uint32_t step, const _InTp &input) { return 0; } diff --git a/udmf/framework/common/udmf_copy_file.cpp b/udmf/framework/common/udmf_copy_file.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ce892fbc20b63f15bb48631b81e40527c2187b93 --- /dev/null +++ b/udmf/framework/common/udmf_copy_file.cpp @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2025 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 "UdmfCopyFile" + +#include "udmf_copy_file.h" + +#include +#include +#include "copy/file_copy_manager.h" +#include "copy/file_size_utils.h" +#include "file_uri.h" +#include "logger.h" +#include "udmf_async_client.h" + +namespace OHOS { +namespace UDMF { +static constexpr const char* NETWORK_PARA = "?networkid="; +static constexpr int32_t PROGRESS_COPY_START = 20; +static constexpr int32_t PROGRESS_INCRE = 80; +static constexpr int32_t MAX_PROGRESS = 99; +static constexpr int32_t DFS_CANCEL_STATUS = 204; + +UdmfCopyFile &UdmfCopyFile::GetInstance() +{ + static UdmfCopyFile udmfCopyFile; + return udmfCopyFile; +} + +Status UdmfCopyFile::Copy(std::unique_ptr &asyncHelper) +{ + CopyContext context(asyncHelper); + + if (context.asyncHelper->progressQueue.IsCancel()) { + LOG_INFO(UDMF_CLIENT, "Copy file cancel"); + return E_COPY_CANCELED; + } + + if (!IsDirectory(context.asyncHelper->destUri, false)) { + LOG_ERROR(UDMF_CLIENT, "DestUri is not directory."); + return E_FS_ERROR; + } + + for (const auto &record : context.asyncHelper->data->GetRecords()) { + if (!HandleRecord(record, context)) { + break; + } + } + + context.asyncHelper->data = context.processedData; + LOG_INFO(UDMF_CLIENT, "Copy end."); + return context.status; +} + +bool UdmfCopyFile::HandleRecord(const std::shared_ptr &record, CopyContext &context) +{ + std::string srcUri; + if (!record->HasFileType(srcUri)) { + context.processedData->AddRecord(record); + return true; + } + if (IsDirectory(srcUri, true)) { + LOG_ERROR(UDMF_CLIENT, "Source cannot be directory."); + context.status = E_COPY_FILE_FAILED; + return true; + } + + std::string destFileUri = ConstructDestUri(context.asyncHelper->destUri, srcUri); + if (context.asyncHelper->fileConflictOptions == FileConflictOptions::SKIP && IsFile(destFileUri, false)) { + LOG_INFO(UDMF_CLIENT, "File has existed, skip."); + return true; + } + return CopyFile(srcUri, destFileUri, record, context); +} + +bool UdmfCopyFile::CopyFile(const std::string &srcUri, const std::string &destFileUri, + const std::shared_ptr &record, CopyContext &context) +{ + uint64_t fileSize = 0; + using ProcessCallBack = std::function; + ProcessCallBack listener = [&](uint64_t processSize, uint64_t totalFileSize) { + fileSize = totalFileSize; + HandleProgress(srcUri, destFileUri, context, processSize); + }; + auto ret = Storage::DistributedFile::FileCopyManager::GetInstance()->Copy(srcUri, destFileUri, listener); + if (ret == DFS_CANCEL_STATUS) { + context.status = E_COPY_CANCELED; + return false; + } else if (ret != E_OK) { + LOG_ERROR(UDMF_CLIENT, "Copy failed. errno=%{public}d", ret); + context.status = E_COPY_FILE_FAILED; + return true; + } + + context.finishSize += fileSize; + record->SetFileUri(destFileUri); + context.processedData->AddRecord(record); + return true; +} + +void UdmfCopyFile::HandleProgress(const std::string &srcUri, const std::string &destFileUri, + CopyContext &context, uint64_t processSize) +{ + if (context.asyncHelper->progressQueue.IsCancel()) { + LOG_INFO(UDMF_CLIENT, "Cancel copy."); + std::thread([&]() { + auto ret = Storage::DistributedFile::FileCopyManager::GetInstance()->Cancel(srcUri, destFileUri); + if (ret != E_OK) { + LOG_ERROR(UDMF_CLIENT, "Cancel failed. errno=%{public}d", ret); + context.status = E_COPY_FILE_FAILED; + } + }).detach(); + return; + } + + context.totalSize = std::max(context.totalSize, uint64_t(1)); + auto processNum = std::min(PROGRESS_COPY_START + + int32_t((context.finishSize + processSize) * PROGRESS_INCRE / context.totalSize), MAX_PROGRESS); + ProgressInfo progressInfo = { .progress = processNum, .errorCode = E_OK }; + UdmfAsyncClient::GetInstance().CallProgress(context.asyncHelper, progressInfo, nullptr); +} + +std::string UdmfCopyFile::ConstructDestUri(const std::string &destUri, const std::string &srcUri) +{ + std::string destFileUri = destUri; + if (destFileUri.back() != '/') { + destFileUri += '/'; + } + destFileUri += GetFileName(srcUri); + return destFileUri; +} + +int64_t UdmfCopyFile::GetTotalSize(const std::vector &uris) +{ + int64_t totalSize = 0; + std::string srcUri; + for (const auto &srcUri : uris) { + if (IsFile(srcUri, true)) { + totalSize += GetFileSize(srcUri, true); + } + } + return totalSize; +} + +bool UdmfCopyFile::IsDirectory(const std::string &uri, bool isSource) +{ + bool isDir = false; + auto ret = Storage::DistributedFile::FileSizeUtils::IsDirectory(uri, isSource, isDir); + if (ret != E_OK) { + LOG_ERROR(UDMF_CLIENT, "Is dir failed. errno=%{public}d", ret); + return false; + } + return isDir; +} + +bool UdmfCopyFile::IsRemote(const std::string &uri) +{ + return uri.find(NETWORK_PARA) != uri.npos; +} + +std::string UdmfCopyFile::GetFileName(const std::string &path) +{ + std::string realSrc = path; + if (IsRemote(path)) { + int index = path.rfind("?", 0); + realSrc = path.substr(0, index); + } + std::filesystem::path filePath(realSrc); + return filePath.filename(); +} + +bool UdmfCopyFile::IsFile(const std::string &uri, bool isSource) +{ + bool isDir = false; + auto ret = Storage::DistributedFile::FileSizeUtils::IsDirectory(uri, isSource, isDir); + if (ret != E_OK) { + LOG_ERROR(UDMF_CLIENT, "Is dir failed. errno=%{public}d", ret); + return false; + } + return !isDir; +} + +uint64_t UdmfCopyFile::GetFileSize(const std::string &uri, bool isSource) +{ + uint64_t size = 0; + auto ret = Storage::DistributedFile::FileSizeUtils::GetSize(uri, isSource, size); + if (ret != E_OK) { + LOG_ERROR(UDMF_CLIENT, "Get size failed. errno=%{public}d", ret); + return 0; + } + return size; +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/common/udmf_copy_file.h b/udmf/framework/common/udmf_copy_file.h new file mode 100644 index 0000000000000000000000000000000000000000..a45556c140e31d042f9977ac6715fc9d64e48c8e --- /dev/null +++ b/udmf/framework/common/udmf_copy_file.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2025 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 UDMF_COPY_FILE_H +#define UDMF_COPY_FILE_H + +#include +#include + +#include "unified_data.h" +#include "async_task_params.h" + +namespace OHOS { +namespace UDMF { + +class UdmfCopyFile { +public: + static UdmfCopyFile &GetInstance(); + Status Copy(std::unique_ptr &asyncHelper); + +private: + struct CopyContext { + std::unique_ptr &asyncHelper; + uint64_t finishSize = 0; + uint64_t totalSize = 0; + Status status = E_OK; + std::shared_ptr processedData; + + explicit CopyContext(std::unique_ptr &helper) + : asyncHelper(helper), + totalSize(UdmfCopyFile::GetInstance().GetTotalSize(helper->data->GetFileUris())), + processedData(std::make_shared()) {} + }; + + UdmfCopyFile() = default; + ~UdmfCopyFile() = default; + + bool HandleRecord(const std::shared_ptr &record, CopyContext &context); + bool CopyFile(const std::string &srcUri, const std::string &destFileUri, + const std::shared_ptr &record, CopyContext &context); + void HandleProgress(const std::string &srcUri, const std::string &destFileUri, + CopyContext &context, uint64_t processSize); + std::string ConstructDestUri(const std::string &destUri, const std::string &srcUri); + int64_t GetTotalSize(const std::vector &uris); + bool IsDirectory(const std::string &uri, bool isSource); + std::string GetFileName(const std::string &path); + bool IsRemote(const std::string &uri); + bool IsFile(const std::string &uri, bool isSource); + uint64_t GetFileSize(const std::string &uri, bool isSource); +}; + +} // namespace UDMF +} // namespace OHOS +#endif /* UDMF_COPY_FILE_H */ \ No newline at end of file diff --git a/udmf/framework/common/udmf_types_util.cpp b/udmf/framework/common/udmf_types_util.cpp index ad2d572398651023d2721eb4a620d16e8d3c3e54..cabc896d12be26488120645cfb9e7fc622ae4dfc 100644 --- a/udmf/framework/common/udmf_types_util.cpp +++ b/udmf/framework/common/udmf_types_util.cpp @@ -43,8 +43,8 @@ template<> bool Unmarshalling(UnifiedData &output, MessageParcel &parcel) { auto size = parcel.ReadInt32(); - if (size == 0) { - LOG_ERROR(UDMF_SERVICE, "UnifiedData is empty!"); + if (size <= 0 || size > UnifiedData::MAX_DATA_SIZE) { + LOG_ERROR(UDMF_SERVICE, "UnifiedData is empty or too large!"); return false; } auto rawData = parcel.ReadRawData(size); @@ -59,7 +59,6 @@ bool Unmarshalling(UnifiedData &output, MessageParcel &parcel) LOG_ERROR(UDMF_SERVICE, "Unmarshall unified data failed!"); return false; } - UdmfConversion::ConvertRecordToSubclass(output); return true; } @@ -84,8 +83,8 @@ template<> bool Unmarshalling(std::vector &output, MessageParcel &parcel) { auto size = parcel.ReadInt32(); - if (size == 0) { - LOG_ERROR(UDMF_SERVICE, "UnifiedDataSet is empty!"); + if (size <= 0 || size > UnifiedData::MAX_DATA_SIZE) { + LOG_ERROR(UDMF_SERVICE, "UnifiedDataSet is empty or too large!"); return false; } const uint8_t *rawData = reinterpret_cast(parcel.ReadRawData(size)); @@ -99,7 +98,6 @@ bool Unmarshalling(std::vector &output, MessageParcel &parcel) LOG_ERROR(UDMF_SERVICE, "Unmarshall unified data set failed!"); return false; } - UdmfConversion::ConvertRecordToSubclass(output); return true; } @@ -203,7 +201,7 @@ bool API_EXPORT Marshalling(const AsyncProcessInfo &input, MessageParcel &parcel uint32_t syncStatus = input.syncStatus; uint32_t permStatus = input.permStatus; return ITypesUtil::Marshal(parcel, syncStatus, permStatus, input.srcDevName, input.syncFinished, input.syncTotal, - input.syncId, input.permFnished, input.permTotal); + input.syncId, input.permFnished, input.permTotal, input.businessUdKey); } template<> @@ -212,7 +210,7 @@ bool API_EXPORT Unmarshalling(AsyncProcessInfo &output, MessageParcel &parcel) uint32_t syncStatus; uint32_t permStatus; if (!ITypesUtil::Unmarshal(parcel, syncStatus, permStatus, output.srcDevName, output.syncFinished, output.syncTotal, - output.syncId, output.permFnished, output.permTotal)) { + output.syncId, output.permFnished, output.permTotal, output.businessUdKey)) { LOG_ERROR(UDMF_FRAMEWORK, "Unmarshal AsyncProcessInfo failed!"); return false; } diff --git a/udmf/framework/common/udmf_utils.cpp b/udmf/framework/common/udmf_utils.cpp index 0561c64ac4c15221d093ecb41806eae34d667417..13366997da08b851765e8a8e268fbc73fa573510 100644 --- a/udmf/framework/common/udmf_utils.cpp +++ b/udmf/framework/common/udmf_utils.cpp @@ -12,11 +12,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#define LOG_TAG "UdmfUtils" + #include "udmf_utils.h" #include #include #include "accesstoken_kit.h" #include "ipc_skeleton.h" +#include "logger.h" namespace OHOS { namespace UDMF { @@ -81,6 +84,18 @@ std::string GetCurrentSdkVersion() { return GetSdkVersionByToken(IPCSkeleton::GetSelfTokenID()); } + +bool IsTokenNative() +{ + uint32_t tokenId = IPCSkeleton::GetSelfTokenID(); + if (tokenId == 0) { + return false; + } + auto tokenType = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId); + LOG_DEBUG(UDMF_FRAMEWORK, "tokenId=%{public}u, tokenType=%{public}d", tokenId, tokenType); + return tokenType == Security::AccessToken::TypeATokenTypeEnum::TOKEN_NATIVE; +} + } // namespace UTILS } // namespace UDMF } // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/common/udmf_utils.h b/udmf/framework/common/udmf_utils.h index f17a08d2c5efe0b36d6dfd87f842e94d2d246f08..63066cf74e1a994e8259c37bf61732f150ac867a 100644 --- a/udmf/framework/common/udmf_utils.h +++ b/udmf/framework/common/udmf_utils.h @@ -19,6 +19,7 @@ #include #include #include +#include "visibility.h" namespace OHOS { namespace UDMF { namespace UTILS { @@ -26,11 +27,10 @@ std::vector StrSplit(const std::string &str, const std::string &del std::vector Random(int32_t len, int32_t minimum = 0, int32_t maximum = std::numeric_limits::max()); std::string GenerateId(); - std::string GetSdkVersionByToken(uint32_t tokenId); - std::string GetCurrentSdkVersion(); +bool API_EXPORT IsTokenNative(); } // namespace UTILS } // namespace UDMF } // namespace OHOS diff --git a/udmf/framework/common/unittest/BUILD.gn b/udmf/framework/common/unittest/BUILD.gn index 4afce7f08a5738b69be51b4e2be9bdfcfb1c4b47..2103a96deb864733b65d6ade5ca9de3606697b94 100644 --- a/udmf/framework/common/unittest/BUILD.gn +++ b/udmf/framework/common/unittest/BUILD.gn @@ -22,7 +22,6 @@ config("module_private_config") { "${udmf_interfaces_path}/innerkits/convert", "${udmf_framework_path}/innerkitsimpl/data", "${udmf_framework_path}/common", - "${kv_store_path}/frameworks/common", "${udmf_interfaces_path}/innerkits/data", "${udmf_framework_path}/common/unittest/mock/include", "${udmf_framework_path}/innerkitsimpl/client/", @@ -33,6 +32,7 @@ common_deps = [ "${udmf_interfaces_path}/innerkits:udmf_client" ] common_external_deps = [ "ability_base:want", + "ability_base:zuri", "access_token:libaccesstoken_sdk", "access_token:libnativetoken", "access_token:libtoken_setproc", @@ -44,7 +44,6 @@ common_external_deps = [ "hitrace:hitrace_meter", "hitrace:libhitracechain", "image_framework:image", - "image_framework:image", "image_framework:image_native", "image_framework:pixelmap", "ipc:ipc_core", @@ -129,7 +128,10 @@ ohos_unittest("UdmfTypesUtilAbnormalTest") { ohos_unittest("TlvUtilTest") { module_out_path = module_output_path - sources = [ "tlv_util_test.cpp" ] + sources = [ + "${udmf_framework_path}/innerkitsimpl/convert/udmf_conversion.cpp", + "tlv_util_test.cpp", + ] configs = [ ":module_private_config" ] @@ -150,11 +152,32 @@ ohos_unittest("TlvUtilTest") { ] } +ohos_unittest("EndianConverterTest") { + module_out_path = module_output_path + + sources = [ + "${udmf_framework_path}/common/endian_converter.cpp", + "endian_converter_test.cpp", + ] + + configs = [ ":module_private_config" ] + + deps = common_deps + + external_deps = common_external_deps + + defines = [ + "private=public", + "protected=public", + ] +} + ############################################################################### group("unittest") { testonly = true deps = [ + ":EndianConverterTest", ":TlvUtilTest", ":UdmfTypesUtilAbnormalTest", ":UdmfTypesUtilTest", diff --git a/udmf/framework/common/unittest/endian_converter_test.cpp b/udmf/framework/common/unittest/endian_converter_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dfa84a205bee1884a1c0978ab92802797faaac3f --- /dev/null +++ b/udmf/framework/common/unittest/endian_converter_test.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2024 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 "EndianConverterTest" + +#include +#include +#include + +#include "logger.h" +#include "endian_converter.h" + +using namespace testing::ext; +using namespace OHOS::UDMF; +using namespace OHOS; +namespace OHOS::Test { +using namespace std; + +class EndianConverterTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; +}; + +void EndianConverterTest::SetUpTestCase() +{ +} + +void EndianConverterTest::TearDownTestCase() +{ +} + +void EndianConverterTest::SetUp() +{ +} + +void EndianConverterTest::TearDown() +{ +} + +/** +* @tc.name: HostToNet001 +* @tc.desc: Normal testcase of HostToNet +* @tc.type: FUNC +*/ +HWTEST_F(EndianConverterTest, HostToNet001, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "HostToNet001 begin."); + float value = 3.1415926; + float ret = HostToNet(value); + EXPECT_EQ(ret, value); + LOG_INFO(UDMF_TEST, "HostToNet001 end."); +} + +/** +* @tc.name: NetToHost001 +* @tc.desc: Normal testcase of NetToHost +* @tc.type: FUNC +*/ +HWTEST_F(EndianConverterTest, NetToHost001, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "NetToHost001 begin."); + float value = 3.1415926; + float ret = NetToHost(value); + EXPECT_EQ(ret, value); + LOG_INFO(UDMF_TEST, "NetToHost001 end."); +} + +/** +* @tc.name: HostToNet002 +* @tc.desc: Normal testcase of HostToNet +* @tc.type: FUNC +*/ +HWTEST_F(EndianConverterTest, HostToNet002, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "HostToNet002 begin."); + double value = 3.14; + double ret = HostToNet(value); + EXPECT_EQ(ret, value); + LOG_INFO(UDMF_TEST, "HostToNet002 end."); +} + +/** +* @tc.name: NetToHost002 +* @tc.desc: Normal testcase of NetToHost +* @tc.type: FUNC +*/ +HWTEST_F(EndianConverterTest, NetToHost002, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "NetToHost002 begin."); + double value = 3.14; + double ret = NetToHost(value); + EXPECT_EQ(ret, value); + LOG_INFO(UDMF_TEST, "NetToHost002 end."); +} +} // OHOS::Test \ No newline at end of file diff --git a/udmf/framework/common/unittest/udmf_types_util_test.cpp b/udmf/framework/common/unittest/udmf_types_util_test.cpp index c59c22ec2d03be0eed11a36c7771a121c8e4a100..9d3c1b10bb168e6eb61394577c51d4de886c7a38 100644 --- a/udmf/framework/common/unittest/udmf_types_util_test.cpp +++ b/udmf/framework/common/unittest/udmf_types_util_test.cpp @@ -273,10 +273,12 @@ HWTEST_F(UdmfTypesUtilTest, Marshalling005, TestSize.Level1) HWTEST_F(UdmfTypesUtilTest, Unmarshalling008, TestSize.Level1) { LOG_INFO(UDMF_TEST, "Unmarshalling008 begin."); - UDType output = UDType::ENTITY; + UDType input = UDType::ENTITY; MessageParcel parcel; - ITypesUtil::Marshalling(output, parcel); + ITypesUtil::Marshalling(input, parcel); + UDType output; bool ret = ITypesUtil::Unmarshalling(output, parcel); + EXPECT_EQ(input, output); EXPECT_TRUE(ret); LOG_INFO(UDMF_TEST, "Unmarshalling008 end."); } @@ -289,10 +291,12 @@ HWTEST_F(UdmfTypesUtilTest, Unmarshalling008, TestSize.Level1) HWTEST_F(UdmfTypesUtilTest, Unmarshalling009, TestSize.Level1) { LOG_INFO(UDMF_TEST, "Unmarshalling009 begin."); - Intention output = Intention::UD_INTENTION_DRAG; + Intention input = Intention::UD_INTENTION_DRAG; MessageParcel parcel; - ITypesUtil::Marshalling(output, parcel); + ITypesUtil::Marshalling(input, parcel); + Intention output; bool ret = ITypesUtil::Unmarshalling(output, parcel); + EXPECT_EQ(input, output); EXPECT_TRUE(ret); LOG_INFO(UDMF_TEST, "Unmarshalling009 end."); } diff --git a/udmf/framework/innerkitsimpl/client/async_obtain_data.cpp b/udmf/framework/innerkitsimpl/client/async_obtain_data.cpp deleted file mode 100644 index e64b3da343f55c08b8ba929f57cd3df3c28e000f..0000000000000000000000000000000000000000 --- a/udmf/framework/innerkitsimpl/client/async_obtain_data.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2024 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 "async_obtain_data.h" -#define LOG_TAG "AsyncObtainData" -#include -#include -#include "unified_types.h" -#include "logger.h" -#include "udmf_service_client.h" -#include "securec.h" - -namespace OHOS { -namespace UDMF { -static constexpr size_t MAX_THREADS = 2; -static constexpr size_t MIN_THREADS = 0; -static constexpr uint32_t MAX_PROGRESS = 100; -static constexpr double MAX_PROGRESS_DOUBLE = 100.0; -static constexpr double SYNC_COEFF = 0.5; -static constexpr double PERM_COEFF = 0.4; - -AsyncObtainData::AsyncObtainData() : executor_(MAX_THREADS, MIN_THREADS) {} - -Status AsyncObtainData::InitTask(const QueryOption &query, ObtainDataCallback callback) -{ - if (callback == nullptr) { - LOG_ERROR(UDMF_CLIENT, "callback invalid"); - taskStatus_ = ASYNC_FAILURE; - return E_INVALID_PARAMETERS; - } - - serviceClient_ = UdmfServiceClient::GetInstance(); - if (serviceClient_ == nullptr) { - LOG_ERROR(UDMF_CLIENT, "Service unavailable"); - taskStatus_ = ASYNC_FAILURE; - return E_IPC; - } - - initialized_ = true; - query_ = query; - callback_ = callback; - taskStatus_ = ASYNC_RUNNING; - processInfo_.syncStatus = ASYNC_RUNNING; - return E_OK; -} - -Status AsyncObtainData::RunTask() -{ - LOG_DEBUG(UDMF_CLIENT, "Enter"); - if (serviceClient_ == nullptr) { - LOG_ERROR(UDMF_CLIENT, "failed! service client is nullptr"); - return E_IPC; - } - if (!initialized_) { - LOG_ERROR(UDMF_CLIENT, "failed! not init"); - return E_ERROR; - } - obtainDataTaskId_ = executor_.Execute(std::bind(&AsyncObtainData::ObtainDataTask, this)); - progressTaskId_ = executor_.Execute(std::bind(&AsyncObtainData::ProgressTask, this)); - - return E_OK; -} - -void AsyncObtainData::ObtainDataTask() -{ - LOG_DEBUG(UDMF_CLIENT, "Enter"); - if ((taskStatus_ == ASYNC_RUNNING) && (processInfo_.syncStatus == ASYNC_RUNNING)) { - Executor::Duration delay = std::chrono::milliseconds(500); - obtainDataTaskId_ = executor_.Schedule(delay, std::bind(&AsyncObtainData::ObtainDataTask, this)); - return; - } - - UnifiedData unifiedData; - if (taskStatus_ != ASYNC_FAILURE) { - if (serviceClient_ == nullptr) { - LOG_ERROR(UDMF_CLIENT, "failed! serviceClient_ is nullptr"); - return; - } - int32_t ret = serviceClient_->GetData(query_, unifiedData); - if (ret != E_OK) { - LOG_ERROR(UDMF_CLIENT, "failed! ret = %{public}d", ret); - taskStatus_ = ASYNC_FAILURE; - } else { - taskStatus_ = ASYNC_SUCCESS; - } - } - InvokeCallback(unifiedData); - ClearTask(); -} - -void AsyncObtainData::ProgressTask() -{ - LOG_DEBUG(UDMF_CLIENT, "Enter"); - if (serviceClient_ == nullptr) { - LOG_ERROR(UDMF_CLIENT, "failed! serviceClient_ is nullptr"); - return; - } - AsyncProcessInfo processInfo; - int32_t ret = serviceClient_->ObtainAsynProcess(processInfo); - if (ret != E_OK) { - LOG_ERROR(UDMF_CLIENT, "failed! ret = %{public}d", ret); - taskStatus_ = ASYNC_FAILURE; - return; - } - - UpdateProcessInfo(processInfo); - - UnifiedData unifiedData; - InvokeCallback(unifiedData); - - if ((taskStatus_ == ASYNC_RUNNING) && - ((processInfo.syncStatus == ASYNC_RUNNING) || (processInfo.permStatus == ASYNC_RUNNING))) { - Executor::Duration delay = std::chrono::milliseconds(500); - progressTaskId_ = executor_.Schedule(delay, std::bind(&AsyncObtainData::ProgressTask, this)); - } -} - -void AsyncObtainData::InvokeCallback(UnifiedData &data) -{ - ProgressInfo progress{ "", ASYNC_IDLE, 0 }; - progress.status = taskStatus_; - progress.srcDevName = processInfo_.srcDevName; - - progress.progress = CalProgress(); - if (progress.progress <= lastProgress_) { - progress.progress = lastProgress_; - } else { - lastProgress_ = progress.progress; - } - if (callback_ == nullptr) { - LOG_ERROR(UDMF_CLIENT, "failed! callback_ is nullptr"); - return; - } - callback_(progress, data); -} - -void AsyncObtainData::UpdateProcessInfo(AsyncProcessInfo &info) -{ - processInfo_.syncStatus = info.syncStatus; - processInfo_.permStatus = info.permStatus; - processInfo_.srcDevName = (info.syncStatus == ASYNC_IDLE ? "Local" : info.srcDevName); - processInfo_.syncFinished = info.syncFinished; - processInfo_.syncTotal = info.syncTotal; - processInfo_.syncId = info.syncId; - processInfo_.permFnished = info.permFnished; - processInfo_.permTotal = info.permTotal; - - if (processInfo_.syncStatus == ASYNC_FAILURE || processInfo_.permStatus == ASYNC_FAILURE) { - taskStatus_ = ASYNC_FAILURE; - } -} - -void AsyncObtainData::ClearTask() -{ - initialized_ = false; - taskStatus_ = ASYNC_IDLE; - lastProgress_ = 0; - progressTaskId_ = ExecutorPool::INVALID_TASK_ID; - obtainDataTaskId_ = ExecutorPool::INVALID_TASK_ID; - (void)memset_s(&processInfo_, sizeof(processInfo_), 0, sizeof(processInfo_)); - - serviceClient_ = UdmfServiceClient::GetInstance(); - if (serviceClient_ == nullptr) { - return; - } - auto ret = serviceClient_->ClearAsynProcess(); - if (ret != E_OK) { - LOG_ERROR(UDMF_CLIENT, "failed! ret = %{public}d", ret); - } - serviceClient_ = nullptr; -} - -uint32_t AsyncObtainData::CalProgress() -{ - if (taskStatus_ == ASYNC_SUCCESS) { - return MAX_PROGRESS; - } - if ((taskStatus_ == ASYNC_FAILURE) || (processInfo_.syncStatus == ASYNC_FAILURE) || - processInfo_.permStatus == ASYNC_FAILURE) { - return lastProgress_; - } - - uint32_t syncProgress = CalSyncProgress(); - uint32_t permProgress = CalPermProgress(); - double totalProgress = syncProgress * SYNC_COEFF + permProgress * PERM_COEFF; - return static_cast(totalProgress); -} - -uint32_t AsyncObtainData::CalSyncProgress() -{ - if (processInfo_.syncStatus == ASYNC_SUCCESS || processInfo_.syncStatus == ASYNC_IDLE) { - return MAX_PROGRESS; - } - if (processInfo_.syncTotal == 0) { - return 0; - } - return std::min(MAX_PROGRESS, - static_cast(processInfo_.syncFinished * MAX_PROGRESS_DOUBLE / processInfo_.syncTotal)); -} - -uint32_t AsyncObtainData::CalPermProgress() -{ - if (processInfo_.permStatus == ASYNC_SUCCESS) { - return MAX_PROGRESS; - } - if (processInfo_.permTotal == 0) { - return 0; - } - return std::min(MAX_PROGRESS, - static_cast(processInfo_.permFnished * MAX_PROGRESS_DOUBLE / processInfo_.permTotal)); -} -} // namespace UDMF -} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/client/udmf_async_client.cpp b/udmf/framework/innerkitsimpl/client/udmf_async_client.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e9eb8186a6160797fd24b901dfbe620cea6699f6 --- /dev/null +++ b/udmf/framework/innerkitsimpl/client/udmf_async_client.cpp @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2025 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 "UdmfAsyncClient" + +#include "udmf_async_client.h" + +#include "logger.h" +#include "plain_text.h" +#include "progress_callback.h" +#include "udmf_client.h" +#include "udmf_copy_file.h" +#include "udmf_service_client.h" + +namespace OHOS::UDMF { +static constexpr size_t MAX_THREADS = 10; +static constexpr size_t MIN_THREADS = 0; + +static constexpr int32_t START_ABILITY_INTERVAL = 500; +static constexpr int32_t READ_PROGRESS_INTERVAL = 100; +static constexpr int32_t SYNC_INTERVAL = 200; +static constexpr int32_t MAX_SYNC_TIMES = 14; + +static std::unordered_map STATUS_MAP = { + { E_INVALID_PARAMETERS, ListenerStatus::INVALID_PARAMETERS }, + { E_NOT_FOUND, ListenerStatus::DATA_NOT_FOUND }, + { E_SYNC_FAILED, ListenerStatus::SYNC_FAILED }, + { E_COPY_FILE_FAILED, ListenerStatus::COPY_FILE_FAILED }, + { E_COPY_CANCELED, ListenerStatus::CANCEL } +}; + +static constexpr int32_t PROGRESS_ERROR = -1; +static constexpr int32_t PROGRESS_INIT = 0; +static constexpr int32_t PROGRESS_SYNC_FINSHED = 10; +static constexpr int32_t PROGRESS_GET_DATA_FINISHED = 20; +static constexpr int32_t PROGRESS_ALL_FINISHED = 100; + +UdmfAsyncClient::UdmfAsyncClient() : executor_(MAX_THREADS, MIN_THREADS) {} + +UdmfAsyncClient &UdmfAsyncClient::GetInstance() +{ + static UdmfAsyncClient instance; + return instance; +} + +Status UdmfAsyncClient::StartAsyncDataRetrieval(const GetDataParams ¶ms) +{ + if (!IsParamValid(params)) { + return E_INVALID_PARAMETERS; + } + auto status = RegisterAsyncHelper(params); + if (status != E_OK) { + return status; + } + auto &asyncHelper = asyncHelperMap_.at(params.query.key); + if (params.progressIndicator == ProgressIndicator::DEFAULT) { + asyncHelper->progressQueue.SetClearable(false); + asyncHelper->invokeHapTask = executor_.Schedule(std::chrono::milliseconds(START_ABILITY_INTERVAL), + (std::bind(&UdmfAsyncClient::InvokeHapTask, this, params.query.key))); + } + asyncHelper->getDataTask = executor_.Execute(std::bind(&UdmfAsyncClient::GetDataTask, this, params.query)); + asyncHelper->progressTask = executor_.Execute(std::bind(&UdmfAsyncClient::ProgressTask, this, params.query.key)); + return E_OK; +} + +Status UdmfAsyncClient::Cancel(std::string businessUdKey) +{ + std::lock_guard lockMap(mutex_); + if (asyncHelperMap_.find(businessUdKey) == asyncHelperMap_.end()) { + LOG_ERROR(UDMF_CLIENT, "No task can Cancel, key=%{public}s", businessUdKey.c_str()); + return E_ERROR; + } + auto &asyncHelper = asyncHelperMap_.at(businessUdKey); + asyncHelper->progressQueue.Cancel(); + return E_OK; +} + +Status UdmfAsyncClient::CancelOnSingleTask() +{ + std::lock_guard lockMap(mutex_); + if (asyncHelperMap_.empty()) { + LOG_ERROR(UDMF_CLIENT, "No task can cancel"); + return E_ERROR; + } + if (asyncHelperMap_.size() > 1) { + LOG_ERROR(UDMF_CLIENT, "Multiple tasks exist"); + return E_ERROR; + } + LOG_INFO(UDMF_CLIENT, "Cancel task key=%{public}s", asyncHelperMap_.begin()->first.c_str()); + asyncHelperMap_.begin()->second->progressQueue.Cancel(); + return E_OK; +} + +Status UdmfAsyncClient::ProgressTask(const std::string &businessUdKey) +{ + auto &asyncHelper = asyncHelperMap_.at(businessUdKey); + if (asyncHelper->progressIndicator == ProgressIndicator::DEFAULT) { + auto status = SetProgressData(businessUdKey); + if (status != E_OK) { + Clear(businessUdKey); + return status; + } + } + while (asyncHelper->lastProgress >= PROGRESS_INIT && asyncHelper->lastProgress < PROGRESS_ALL_FINISHED) { + auto pair = asyncHelper->progressQueue.Poll(); + if (!pair.first) { + std::this_thread::sleep_for(std::chrono::milliseconds(READ_PROGRESS_INTERVAL)); + continue; + } + auto progressInfo = pair.second; + if (progressInfo->progress >= PROGRESS_INIT && progressInfo->progress <= asyncHelper->lastProgress) { + continue; + } + asyncHelper->lastProgress = progressInfo->progress; + if (asyncHelper->progressIndicator == ProgressIndicator::DEFAULT) { + UpdateProgressData(asyncHelper->processKey, *progressInfo); + } + } + Clear(businessUdKey); + return E_OK; +} + +Status UdmfAsyncClient::GetDataTask(const QueryOption &query) +{ + auto &asyncHelper = asyncHelperMap_.at(query.key); + if (GetDataFromCache(asyncHelper, query) == E_OK) { + ProcessUnifiedData(asyncHelper); + return E_OK; + } + return CheckSync(asyncHelper, query); +} + +Status UdmfAsyncClient::InvokeHapTask(const std::string &businessUdKey) +{ + LOG_INFO(UDMF_CLIENT, "InvokeHap start!"); + auto &asyncHelper = asyncHelperMap_.at(businessUdKey); + if (asyncHelper->progressQueue.IsCancel()) { + LOG_INFO(UDMF_CLIENT, "Finished, not invoke hap."); + Clear(businessUdKey); + return E_OK; + } + if (asyncHelper->processKey.empty()) { + LOG_ERROR(UDMF_CLIENT, "Get key failed, not invoke hap."); + Clear(businessUdKey); + return E_ERROR; + } + sptr callback = new ProgressSignalCallback(); + auto status = UdmfServiceClient::GetInstance()->InvokeHap(asyncHelper->processKey, callback); + if (status != E_OK) { + LOG_ERROR(UDMF_CLIENT, "Invoke hap failed, status=%{public}d", status); + Clear(businessUdKey); + return E_ERROR; + } + Clear(businessUdKey); + return E_OK; +} + +Status UdmfAsyncClient::RegisterAsyncHelper(const GetDataParams ¶ms) +{ + std::lock_guard lock(mutex_); + if (asyncHelperMap_.find(params.query.key) != asyncHelperMap_.end()) { + LOG_ERROR(UDMF_CLIENT, "The same task is running, key = %{public}s", params.query.key.c_str()); + return E_IDEMPOTENT_ERROR; + } + auto asyncHelper = std::make_unique(); + asyncHelper->businessUdKey = params.query.key; + asyncHelper->progressListener = params.progressListener; + asyncHelper->progressIndicator = params.progressIndicator; + asyncHelper->fileConflictOptions = params.fileConflictOptions; + asyncHelper->destUri = params.destUri; + asyncHelperMap_.insert_or_assign(params.query.key, std::move(asyncHelper)); + return E_OK; +} + +Status UdmfAsyncClient::CheckSync(std::unique_ptr &asyncHelper, const QueryOption &query) +{ + AsyncProcessInfo processInfo = { + .businessUdKey = query.key + }; + auto serviceClient = UdmfServiceClient::GetInstance(); + if (serviceClient == nullptr) { + LOG_ERROR(UDMF_CLIENT, "UdmfServiceClient GetInstance failed"); + return E_IPC; + } + auto status = serviceClient->ObtainAsynProcess(processInfo); + if (status != E_OK) { + LOG_ERROR(UDMF_CLIENT, "Sync error status = %{public}d!", status); + ProgressInfo progressInfo = { .progress = PROGRESS_ERROR, .errorCode = E_ERROR }; + CallProgress(asyncHelper, progressInfo, nullptr); + return static_cast(status); + } + if (processInfo.syncStatus == AsyncTaskStatus::ASYNC_FAILURE) { + LOG_ERROR(UDMF_CLIENT, "Sync failed!"); + ProgressInfo progressInfo = { .progress = PROGRESS_ERROR, .errorCode = E_SYNC_FAILED }; + CallProgress(asyncHelper, progressInfo, nullptr); + return E_ERROR; + } + if (processInfo.syncStatus == AsyncTaskStatus::ASYNC_SUCCESS) { + ProgressInfo progressInfo = { .progress = PROGRESS_SYNC_FINSHED, .errorCode = E_OK }; + CallProgress(asyncHelper, progressInfo, nullptr); + return GetDataFromDB(asyncHelper, query); + } + if (asyncHelper->sycnRetryTime > MAX_SYNC_TIMES) { + LOG_ERROR(UDMF_CLIENT, "Sync retry timeout!"); + ProgressInfo progressInfo = { .progress = PROGRESS_ERROR, .errorCode = E_SYNC_FAILED }; + CallProgress(asyncHelper, progressInfo, nullptr); + return E_SYNC_FAILED; + } + (asyncHelper->sycnRetryTime)++; + asyncHelper->getDataTask = executor_.Schedule(std::chrono::milliseconds(SYNC_INTERVAL), + std::bind(&UdmfAsyncClient::GetDataTask, this, query)); + return E_OK; +} + +Status UdmfAsyncClient::GetDataFromDB(std::unique_ptr &asyncHelper, const QueryOption &query) +{ + auto &data = *(asyncHelper->data); + auto status = static_cast(UdmfServiceClient::GetInstance()->GetData(query, data)); + if (status != E_OK) { + LOG_ERROR(UDMF_CLIENT, "GetData error, status = %{public}d", status); + ProgressInfo progressInfo = { + .progress = PROGRESS_ERROR, + .errorCode = status + }; + CallProgress(asyncHelper, progressInfo, nullptr); + return status; + } + return ProcessUnifiedData(asyncHelper); +} + +Status UdmfAsyncClient::GetDataFromCache(std::unique_ptr &asyncHelper, const QueryOption &query) +{ + return UdmfClient::GetInstance().GetDataFromCache(query, *(asyncHelper->data)); +} + +Status UdmfAsyncClient::SetProgressData(const std::string &businessUdKey) +{ + auto serviceClient = UdmfServiceClient::GetInstance(); + if (serviceClient == nullptr) { + LOG_ERROR(UDMF_CLIENT, "UdmfServiceClient GetInstance failed"); + return E_IPC; + } + std::string progressKey; + CustomOption cusomOption = { + .intention = Intention::UD_INTENTION_DATA_HUB + }; + auto obj = std::make_shared(); + auto progressRecord = std::make_shared(UDType::PLAIN_TEXT, obj); + progressRecord->SetContent(std::to_string(PROGRESS_INIT)); + UnifiedData progressData; + progressData.AddRecord(progressRecord); + auto status = serviceClient->SetData(cusomOption, progressData, progressKey); + if (status != E_OK) { + LOG_ERROR(UDMF_CLIENT, "Set progress data error, status = %{public}d", status); + return static_cast<Status>(status); + } + auto &asyncHelper = asyncHelperMap_.at(businessUdKey); + asyncHelper->processKey = progressKey; + return E_OK; +} + +Status UdmfAsyncClient::UpdateProgressData(const std::string &progressUdKey, const ProgressInfo &progressInfo) +{ + auto serviceClient = UdmfServiceClient::GetInstance(); + if (serviceClient == nullptr) { + LOG_ERROR(UDMF_CLIENT, "UdmfServiceClient GetInstance failed"); + return E_IPC; + } + QueryOption queryOption = { + .key = progressUdKey, + .intention = Intention::UD_INTENTION_DATA_HUB + }; + auto obj = std::make_shared<Object>(); + auto progressRecord = std::make_shared<PlainText>(UDType::PLAIN_TEXT, obj); + if (progressInfo.progress < PROGRESS_INIT) { + progressRecord->SetContent(std::to_string(PROGRESS_ALL_FINISHED)); + } else { + progressRecord->SetContent(std::to_string(progressInfo.progress)); + } + UnifiedData progressData; + progressData.AddRecord(progressRecord); + auto status = serviceClient->UpdateData(queryOption, progressData); + if (status != E_OK) { + LOG_ERROR(UDMF_CLIENT, "Update progress data error, status = %{public}d", status); + return static_cast<Status>(status); + } + return E_OK; +} + +Status UdmfAsyncClient::CopyFile(std::unique_ptr<AsyncHelper> &asyncHelper) +{ + if (asyncHelper->destUri.empty()) { + LOG_INFO(UDMF_CLIENT, "No dest path, no copy."); + return E_OK; + } + auto status = UdmfCopyFile::GetInstance().Copy(asyncHelper); + ProgressInfo progressInfo = { + .progress = PROGRESS_ALL_FINISHED, + .errorCode = status + }; + CallProgress(asyncHelper, progressInfo, asyncHelper->data); + return E_OK; +} + +void UdmfAsyncClient::CallProgress(std::unique_ptr<AsyncHelper> &asyncHelper, ProgressInfo &progressInfo, + std::shared_ptr<UnifiedData> data) +{ + if (progressInfo.errorCode == E_OK) { + if (progressInfo.progress == PROGRESS_ALL_FINISHED) { + progressInfo.progressStatus = ListenerStatus::FINISHED; + } else { + progressInfo.progressStatus = ListenerStatus::PROCESSING; + } + } else { + auto it = STATUS_MAP.find(progressInfo.errorCode); + if (it == STATUS_MAP.end()) { + progressInfo.progressStatus = ListenerStatus::INNER_ERROR; + } else { + progressInfo.progressStatus = it->second; + } + } + + asyncHelper->progressListener(progressInfo, data); + asyncHelper->progressQueue.PushBack(progressInfo); +} + +Status UdmfAsyncClient::Clear(const std::string &businessUdKey) +{ + std::lock_guard<std::mutex> lockMap(mutex_); + if (asyncHelperMap_.find(businessUdKey) == asyncHelperMap_.end()) { + LOG_ERROR(UDMF_CLIENT, "No task can Clear, key=%{public}s", businessUdKey.c_str()); + return E_ERROR; + } + auto &asyncHelper = asyncHelperMap_.at(businessUdKey); + if (!asyncHelper->progressQueue.Clear()) { + return E_OK; + } + if (asyncHelper->invokeHapTask != ExecutorPool::INVALID_TASK_ID) { + executor_.Remove(asyncHelper->invokeHapTask); + } + executor_.Remove(asyncHelper->getDataTask); + executor_.Remove(asyncHelper->progressTask); + asyncHelperMap_.erase(businessUdKey); + UdmfServiceClient::GetInstance()->ClearAsynProcessByKey(businessUdKey); + LOG_INFO(UDMF_CLIENT, "Clear task success, key = %{public}s", businessUdKey.c_str()); + return E_OK; +} + +Status UdmfAsyncClient::ProcessUnifiedData(std::unique_ptr<AsyncHelper> &asyncHelper) +{ + if (!asyncHelper->data->HasFileType()) { + ProgressInfo progressInfo = { + .progress = PROGRESS_ALL_FINISHED, + .errorCode = E_OK + }; + CallProgress(asyncHelper, progressInfo, asyncHelper->data); + return E_OK; + } + ProgressInfo progressInfo = { + .progress = PROGRESS_GET_DATA_FINISHED, + .errorCode = E_OK + }; + CallProgress(asyncHelper, progressInfo, nullptr); + return CopyFile(asyncHelper); +} + +bool UdmfAsyncClient::IsParamValid(const GetDataParams &params) +{ + auto query = params.query; + if (query.key.empty() || query.intention != Intention::UD_INTENTION_DRAG) { + LOG_ERROR(UDMF_CLIENT, "Params query invalid. query.key=%{public}s, intention=%{public}d", query.key.c_str(), + query.intention); + return false; + } + if (params.progressListener == nullptr) { + LOG_ERROR(UDMF_CLIENT, "Params progressListener not null."); + return false; + } + return true; +} +} // namespace OHOS::UDMF diff --git a/udmf/framework/innerkitsimpl/client/udmf_client.cpp b/udmf/framework/innerkitsimpl/client/udmf_client.cpp index e7275dc542a1e1e3277b7ac2991a5aa3759142fd..efefc4ae48e03ac96c37dc856bed1b0d3757ae09 100644 --- a/udmf/framework/innerkitsimpl/client/udmf_client.cpp +++ b/udmf/framework/innerkitsimpl/client/udmf_client.cpp @@ -16,6 +16,7 @@ #include "udmf_client.h" #include "dds_trace.h" +#include "udmf_conversion.h" #include "udmf_radar_reporter.h" #include "logger.h" @@ -100,15 +101,12 @@ Status UdmfClient::GetData(const QueryOption &query, UnifiedData &unifiedData) } RadarReporterAdapter::ReportNormal(std::string(__FUNCTION__), BizScene::GET_DATA, GetDataStage::GET_DATA_BEGIN, StageRes::SUCCESS); - auto it = dataCache_.Find(query.key); - if (it.first) { - unifiedData = it.second; - dataCache_.Erase(query.key); + if (GetDataFromCache(query, unifiedData) == E_OK) { RadarReporterAdapter::ReportNormal(std::string(__FUNCTION__), BizScene::GET_DATA, GetDataStage::GET_DATA_END, StageRes::SUCCESS, BizState::DFX_END); return E_OK; } - LOG_WARN(UDMF_CLIENT, "query data from cache failed! key = %{public}s", query.key.c_str()); + LOG_INFO(UDMF_CLIENT, "Data not found in cache. key = %{public}s", query.key.c_str()); int32_t ret = service->GetData(query, unifiedData); if (ret != E_OK) { RadarReporterAdapter::ReportFail(std::string(__FUNCTION__), @@ -180,6 +178,7 @@ Status UdmfClient::GetSummary(const QueryOption &query, Summary &summary) } auto it = dataCache_.Find(query.key); if (it.first) { + UdmfConversion::InitValueObject(it.second); UnifiedDataHelper::GetSummary(it.second, summary); LOG_INFO(UDMF_CLIENT, "GetSummary in cache! key = %{public}s", query.key.c_str()); return E_OK; @@ -304,28 +303,16 @@ std::string UdmfClient::GetSelfBundleName() return hapInfo.bundleName; } -Status UdmfClient::GetDataAsync(const QueryOption &query, ObtainDataCallback callback) +Status UdmfClient::GetDataFromCache(const QueryOption &query, UnifiedData &unifiedData) { - asyncObtainData_.ClearTask(); - - auto it = this->dataCache_.Find(query.key); + auto it = dataCache_.Find(query.key); if (it.first) { + unifiedData = it.second; dataCache_.Erase(query.key); - ProgressInfo info{ "Local", ASYNC_SUCCESS, 100 }; - callback(info, it.second); return E_OK; } - - auto ret = asyncObtainData_.InitTask(query, callback); - if (ret == E_OK) { - ret = asyncObtainData_.RunTask(); - } - if (ret != E_OK) { - LOG_ERROR(UDMF_CLIENT, "InitTask or RunTask faile ret=%{public}d", ret); - asyncObtainData_.ClearTask(); - return ret; - } - return E_OK; + return E_NOT_FOUND; } + } // namespace UDMF } // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/client/utd_client.cpp b/udmf/framework/innerkitsimpl/client/utd_client.cpp index cb33d8dd30fddd9fb73fab1a69960297a32b5fee..f4006efe50a7757e9cfcecdb571333229682fd1e 100644 --- a/udmf/framework/innerkitsimpl/client/utd_client.cpp +++ b/udmf/framework/innerkitsimpl/client/utd_client.cpp @@ -13,11 +13,9 @@ * limitations under the License. */ #define LOG_TAG "UtdClient" -#include "utd_client.h" - -#include <mutex> #include <regex> #include <thread> +#include "utd_client.h" #include "logger.h" #include "utd_graph.h" #include "custom_utd_store.h" @@ -27,6 +25,16 @@ namespace OHOS { namespace UDMF { constexpr const int MAX_UTD_LENGTH = 256; +constexpr const int MAX_FILE_EXTENSION_LENGTH = 14; +constexpr const char *DEFAULT_ANONYMOUS = "******"; +std::string UtdClient::Anonymous(const std::string &fileExtension) +{ + if (fileExtension.length() <= MAX_FILE_EXTENSION_LENGTH) { + return fileExtension; + } + + return (fileExtension.substr(0, MAX_FILE_EXTENSION_LENGTH) + DEFAULT_ANONYMOUS); +} UtdClient::UtdClient() { @@ -184,7 +192,7 @@ Status UtdClient::GetUniformDataTypesByFilenameExtension(const std::string &file } if (!IsValidFileExtension(fileExtension)) { LOG_ERROR(UDMF_CLIENT, "invalid fileExtension. fileExtension:%{public}s, belongsTo:%{public}s ", - fileExtension.c_str(), belongsTo.c_str()); + Anonymous(fileExtension).c_str(), belongsTo.c_str()); return Status::E_INVALID_PARAMETERS; } diff --git a/udmf/framework/innerkitsimpl/common/progress_queue.cpp b/udmf/framework/innerkitsimpl/common/progress_queue.cpp new file mode 100644 index 0000000000000000000000000000000000000000..38986f76197a2da654154e292f5cebc4594ce948 --- /dev/null +++ b/udmf/framework/innerkitsimpl/common/progress_queue.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025 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 "progress_queue.h" + +namespace OHOS::UDMF { + +void ProgressQueue::PushBack(ProgressInfo &progress) +{ + std::lock_guard<std::mutex> lock(mutex_); + queue_.push(progress); +} + +std::pair<bool, std::shared_ptr<ProgressInfo>> ProgressQueue::Poll() +{ + std::lock_guard<std::mutex> lock(mutex_); + if (queue_.empty()) { + return {false, nullptr}; + } + auto progressInfo = std::make_shared<ProgressInfo>(queue_.front()); + queue_.pop(); + return {true, progressInfo}; +} + +bool ProgressQueue::IsCancel() const +{ + std::lock_guard<std::mutex> lock(mutex_); + return cancelFlag_; +} + +void ProgressQueue::Cancel() +{ + std::lock_guard<std::mutex> lock(mutex_); + cancelFlag_ = true; +} + +void ProgressQueue::SetClearable(const bool clearableFlag) +{ + std::lock_guard<std::mutex> lock(mutex_); + clearableFlag_ = clearableFlag; +} + +bool ProgressQueue::Clear() +{ + std::lock_guard<std::mutex> lock(mutex_); + auto oldClearableFlag = clearableFlag_; + clearableFlag_ = true; + return oldClearableFlag; +} + +} // namespace OHOS::UDMF \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/common/unified_meta.cpp b/udmf/framework/innerkitsimpl/common/unified_meta.cpp index 8aa8769056565fe7e7c625c29b9a46ad42abbe87..548944df262d699177a148d7c48602f7df3c66ab 100644 --- a/udmf/framework/innerkitsimpl/common/unified_meta.cpp +++ b/udmf/framework/innerkitsimpl/common/unified_meta.cpp @@ -502,9 +502,16 @@ static constexpr UtdType UTD_TYPES[] = { { M4P_AUDIO, "M4P_AUDIO", "com.apple.m4p-audio" }, { AC3_AUDIO, "AC3_AUDIO", "general.ac3-audio" }, { OPENHARMONY_HSP, "OPENHARMONY_HSP", "openharmony.hsp" }, - { OPENHARMONY_HAR, "OPENHARMONY_HAR", "openharmony.har" } + { OPENHARMONY_HAR, "OPENHARMONY_HAR", "openharmony.har" }, + { OPENHARMONY_GOPAINT, "OPENHARMONY_GOPAINT", "openharmony.gopaint" }, + { OPENHARMONY_GOBRUSH, "OPENHARMONY_GOBRUSH", "openharmony.gobrush" }, + { OPENHARMONY_GOBRUSHES, "OPENHARMONY_GOBRUSHES", "openharmony.gobrushes" }, + { OPENHARMONY_GOCOLOR, "OPENHARMONY_GOCOLOR", "openharmony.gocolor" } }; +static const std::initializer_list<std::string_view> NOT_NEED_COUNT_VALUE_LIST = { UNIFORM_DATA_TYPE, + ARRAY_BUFFER_LENGTH, THUMB_DATA_LENGTH, APP_ICON_LENGTH, APPLICATION_DEFINED_RECORD_MARK }; + namespace UtdUtils { bool IsValidUtdId(const std::string &utdId) { @@ -674,6 +681,9 @@ std::shared_ptr<Object> ObjectUtils::ConvertToObject(UDDetails &details) UDDetails ObjectUtils::ConvertToUDDetails(std::shared_ptr<Object> object) { UDDetails details; + if (object == nullptr) { + return details; + } for (auto [key, value] : object->value_) { if (!ConvertVariant(std::move(value), details[key])) { LOG_ERROR(UnifiedRecord, "object convert to UDDetails failed, object key is %{public}s", key.c_str()); @@ -681,5 +691,76 @@ UDDetails ObjectUtils::ConvertToUDDetails(std::shared_ptr<Object> object) } return details; } + +int64_t ObjectUtils::GetValueSize(const ValueType &value, bool isCalValueType) +{ + if (value.index() == 0) { + return 0; + } + if (std::holds_alternative<std::string>(value)) { + return std::get<std::string>(value).size(); + } + if (std::holds_alternative<std::shared_ptr<Object>>(value)) { + return GetObjectValueSize(std::get<std::shared_ptr<Object>>(value), isCalValueType); + } + if (std::holds_alternative<std::vector<uint8_t>>(value)) { + return std::get<std::vector<uint8_t>>(value).size(); + } + if (std::holds_alternative<std::shared_ptr<OHOS::Media::PixelMap>>(value)) { + auto pixelMap = std::get<std::shared_ptr<OHOS::Media::PixelMap>>(value); + return pixelMap->GetByteCount(); + } + if (std::holds_alternative<std::shared_ptr<OHOS::AAFwk::Want>>(value)) { + auto want = std::get<std::shared_ptr<OHOS::AAFwk::Want>>(value); + Parcel parcel; + if (!want->Marshalling(parcel)) { + LOG_ERROR(UDMF_FRAMEWORK, "Marshalling want error when GetValueSize!"); + return 0; + } + return parcel.GetDataSize(); + } + return std::visit([] (const auto &val) { return sizeof(val); }, value); +} + +int64_t ObjectUtils::GetObjectValueSize(const std::shared_ptr<Object> object, bool isCalValueType) +{ + if (object == nullptr) { + return 0; + } + int64_t size = 0; + for (auto [key, value] : object->value_) { + if (std::find(NOT_NEED_COUNT_VALUE_LIST.begin(), NOT_NEED_COUNT_VALUE_LIST.end(), key) + != NOT_NEED_COUNT_VALUE_LIST.end()) { + continue; + } + if (key == VALUE_TYPE && isCalValueType) { + size += GetValueSize(value, false); + continue; + } + if (key == DETAILS) { + if (!std::holds_alternative<std::shared_ptr<Object>>(value)) { + LOG_ERROR(UDMF_FRAMEWORK, "Details is not correct!"); + continue; + } + size += GetAllObjectSize(std::get<std::shared_ptr<Object>>(value)); + continue; + } + size += GetValueSize(value, false); + } + return size; +} + + +int64_t ObjectUtils::GetAllObjectSize(const std::shared_ptr<Object> object) +{ + if (object == nullptr) { + return 0; + } + int64_t size = 0; + for (auto [key, value] : object->value_) { + size += static_cast<int64_t>(key.size()) + GetValueSize(value, false); + } + return size; +} } // namespace UDMF } // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/convert/data_params_conversion.cpp b/udmf/framework/innerkitsimpl/convert/data_params_conversion.cpp new file mode 100644 index 0000000000000000000000000000000000000000..755b528199215d108a03116bced8a8bb6e52cccf --- /dev/null +++ b/udmf/framework/innerkitsimpl/convert/data_params_conversion.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 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 "data_params_conversion.h" +#include "ndk_data_conversion.h" + +namespace OHOS::UDMF { +Status DataParamsConversion::GetInnerDataParams(OH_UdmfGetDataParams &ndkDataParams, QueryOption &query, + GetDataParams &dataParams) +{ + if (ndkDataParams.dataProgressListener == nullptr || query.key.size() == 0) { + return Status::E_INVALID_PARAMETERS; + } + dataParams.query = query; + if (ndkDataParams.destUri.size() > 0) { + dataParams.destUri = ndkDataParams.destUri; + } + dataParams.fileConflictOptions = static_cast<FileConflictOptions>(ndkDataParams.fileConflictOptions); + dataParams.progressIndicator = static_cast<ProgressIndicator>(ndkDataParams.progressIndicator); + dataParams.progressListener = [ndkDataParams](ProgressInfo progressInfo, std::shared_ptr<UnifiedData> data) { + OH_Udmf_ProgressInfo ndkProgrssInfo; + ndkProgrssInfo.progress = progressInfo.progress; + ndkProgrssInfo.status = progressInfo.progressStatus; + if (data == nullptr) { + ndkDataParams.dataProgressListener(&ndkProgrssInfo, nullptr); + return; + } + OH_UdmfData *ndkData = OH_UdmfData_Create(); + NdkDataConversion::GetNdkUnifiedData(data, ndkData); + ndkDataParams.dataProgressListener(&ndkProgrssInfo, ndkData); + OH_UdmfData_Destroy(ndkData); + }; + return Status::E_OK; +} +} diff --git a/udmf/framework/innerkitsimpl/convert/udmf_conversion.cpp b/udmf/framework/innerkitsimpl/convert/udmf_conversion.cpp index ff3fce704a645debba891d60d25fd191c6b0b340..f1d4a2152118af0cf2999a63db93516483385009 100644 --- a/udmf/framework/innerkitsimpl/convert/udmf_conversion.cpp +++ b/udmf/framework/innerkitsimpl/convert/udmf_conversion.cpp @@ -56,6 +56,8 @@ void UdmfConversion::ConvertRecordToSubclass(std::shared_ptr<UnifiedRecord> &rec auto type = record->GetType(); auto value = record->GetOriginValue(); auto uid = record->GetUid(); + auto entries = record->GetInnerEntries(); + auto utdId = record->GetUtdId(); switch (type) { case UDType::TEXT: { record = std::make_shared<Text>(type, value); @@ -118,6 +120,8 @@ void UdmfConversion::ConvertRecordToSubclass(std::shared_ptr<UnifiedRecord> &rec } } record->SetUid(uid); + record->SetUtdId(utdId); + record->SetInnerEntries(entries); SetValueWhenNotUds(record); } diff --git a/udmf/framework/innerkitsimpl/data/application_defined_record.cpp b/udmf/framework/innerkitsimpl/data/application_defined_record.cpp index 350a3446980c2f29ecd108ccee8882f208a93ef4..3e53f3420ca18a0961006d3c848ebcf8fb209cd0 100644 --- a/udmf/framework/innerkitsimpl/data/application_defined_record.cpp +++ b/udmf/framework/innerkitsimpl/data/application_defined_record.cpp @@ -55,7 +55,7 @@ ApplicationDefinedRecord::ApplicationDefinedRecord(UDType type, ValueType value) int64_t ApplicationDefinedRecord::GetSize() { - return rawData_.size() + applicationDefinedType.size(); + return rawData_.size() + GetInnerEntriesSize(); } std::string ApplicationDefinedRecord::GetApplicationDefinedType() const @@ -97,7 +97,8 @@ void ApplicationDefinedRecord::InitObject() object->value_[UNIFORM_DATA_TYPE] = applicationDefinedType; object->value_[ARRAY_BUFFER] = rawData_; object->value_[ARRAY_BUFFER_LENGTH] = static_cast<int>(rawData_.size()); - object->value_[VALUE_TYPE] = value; + object->value_[APPLICATION_DEFINED_RECORD_MARK] = true; + object->value_.insert_or_assign(VALUE_TYPE, std::move(value)); } } diff --git a/udmf/framework/innerkitsimpl/data/audio.cpp b/udmf/framework/innerkitsimpl/data/audio.cpp index 15682d94777a25e5bc20f7da77afabc3532cc21d..a30e5e222184e172a9accc02d2895b0442afc1d4 100644 --- a/udmf/framework/innerkitsimpl/data/audio.cpp +++ b/udmf/framework/innerkitsimpl/data/audio.cpp @@ -19,16 +19,17 @@ namespace OHOS { namespace UDMF { Audio::Audio() : Audio("") { + SetType(AUDIO); } Audio::Audio(const std::string &uri) : File(uri) { - this->dataType_ = AUDIO; + SetType(AUDIO); } Audio::Audio(UDType type, ValueType value) : File(type, value) { - this->dataType_ = AUDIO; + SetType(AUDIO); } } // namespace UDMF } // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/data/file.cpp b/udmf/framework/innerkitsimpl/data/file.cpp index 43beaed6db3b4669b502d43ba5630cbf21279fa0..445ba1d5a25e21e94ecf8af65b0f760af8d79fdc 100644 --- a/udmf/framework/innerkitsimpl/data/file.cpp +++ b/udmf/framework/innerkitsimpl/data/file.cpp @@ -45,7 +45,8 @@ File::File(UDType type, ValueType value) : UnifiedRecord(type, value) int64_t File::GetSize() { - return this->oriUri_.size() + this->remoteUri_.size(); + return this->oriUri_.size() + this->remoteUri_.size() + UnifiedDataUtils::GetDetailsSize(this->details_) + + GetInnerEntriesSize(); } std::string File::GetUri() const @@ -100,7 +101,7 @@ void File::InitObject() object->value_[ORI_URI] = oriUri_; object->value_[REMOTE_URI] = remoteUri_; object->value_[DETAILS] = ObjectUtils::ConvertToObject(details_); - object->value_[VALUE_TYPE] = value; + object->value_.insert_or_assign(VALUE_TYPE, std::move(value)); } } diff --git a/udmf/framework/innerkitsimpl/data/folder.cpp b/udmf/framework/innerkitsimpl/data/folder.cpp index 3bb45e93fcd697eea507c13fd5bfbd127fbdc002..e6b973f81fc657037b42b6de4b5980ad153d5572 100644 --- a/udmf/framework/innerkitsimpl/data/folder.cpp +++ b/udmf/framework/innerkitsimpl/data/folder.cpp @@ -19,16 +19,17 @@ namespace OHOS { namespace UDMF { Folder::Folder() : Folder("") { + SetType(FOLDER); } Folder::Folder(const std::string &uri) : File(uri) { - this->dataType_ = FOLDER; + SetType(FOLDER); } Folder::Folder(UDType type, ValueType value) : File(type, value) { - this->dataType_ = FOLDER; + SetType(FOLDER); } } // namespace UDMF } // namespace OHOS diff --git a/udmf/framework/innerkitsimpl/data/html.cpp b/udmf/framework/innerkitsimpl/data/html.cpp index 324d9acf5dd96edfad50fbd7096a28a9b052898e..9f2279a7c2fda731273b9f856e2b1c057cb85fc0 100644 --- a/udmf/framework/innerkitsimpl/data/html.cpp +++ b/udmf/framework/innerkitsimpl/data/html.cpp @@ -56,7 +56,8 @@ Html::Html(UDType type, ValueType value) : Text(type, value) int64_t Html::GetSize() { - return UnifiedDataUtils::GetDetailsSize(this->details_) + this->htmlContent_.size() + this->plainContent_.size(); + return UnifiedDataUtils::GetDetailsSize(this->details_) + this->htmlContent_.size() + this->plainContent_.size() + + GetInnerEntriesSize(); } std::string Html::GetHtmlContent() const @@ -104,7 +105,7 @@ void Html::InitObject() object->value_[HTML_CONTENT] = htmlContent_; object->value_[PLAIN_CONTENT] = plainContent_; object->value_[DETAILS] = ObjectUtils::ConvertToObject(details_); - object->value_[VALUE_TYPE] = value; + object->value_.insert_or_assign(VALUE_TYPE, std::move(value)); } } } // namespace UDMF diff --git a/udmf/framework/innerkitsimpl/data/image.cpp b/udmf/framework/innerkitsimpl/data/image.cpp index a2a891d3a0c4e12d26a49326a2e96ccf7aa6f9aa..90846a64b7f2ef71278a62f193d6a8897e4d8bf4 100644 --- a/udmf/framework/innerkitsimpl/data/image.cpp +++ b/udmf/framework/innerkitsimpl/data/image.cpp @@ -19,16 +19,17 @@ namespace OHOS { namespace UDMF { Image::Image() : Image("") { + SetType(IMAGE); } Image::Image(const std::string &uri) : File(uri) { - this->dataType_ = IMAGE; + SetType(IMAGE); } Image::Image(UDType type, ValueType value) : File(type, value) { - this->dataType_ = IMAGE; + SetType(IMAGE); } } // namespace UDMF } // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/data/link.cpp b/udmf/framework/innerkitsimpl/data/link.cpp index ebfe38ea633c8dd852e5fee31248c0c1422c63bd..08b6db39405e8b33a61d02dcbf23f05a815e157f 100644 --- a/udmf/framework/innerkitsimpl/data/link.cpp +++ b/udmf/framework/innerkitsimpl/data/link.cpp @@ -54,7 +54,8 @@ Link::Link(const std::string &url, const std::string &description) int64_t Link::GetSize() { - return UnifiedDataUtils::GetDetailsSize(this->details_) + this->url_.size() + this->description_.size(); + return UnifiedDataUtils::GetDetailsSize(this->details_) + this->url_.size() + this->description_.size() + + GetInnerEntriesSize(); } std::string Link::GetUrl() const @@ -99,7 +100,7 @@ void Link::InitObject() object->value_[URL] = url_; object->value_[DESCRIPTION] = description_; object->value_[DETAILS] = ObjectUtils::ConvertToObject(details_); - object->value_[VALUE_TYPE] = value; + object->value_.insert_or_assign(VALUE_TYPE, std::move(value)); } } } // namespace UDMF diff --git a/udmf/framework/innerkitsimpl/data/plain_text.cpp b/udmf/framework/innerkitsimpl/data/plain_text.cpp index 9a28b4f9adffdaccf2b455804424171192ea200f..6d1ecdf52a8a5961baccd0d8143da927eac682d0 100644 --- a/udmf/framework/innerkitsimpl/data/plain_text.cpp +++ b/udmf/framework/innerkitsimpl/data/plain_text.cpp @@ -21,6 +21,7 @@ namespace OHOS { namespace UDMF { PlainText::PlainText() : PlainText("", "") { + SetType(PLAIN_TEXT); } PlainText::PlainText(const std::string &content, const std::string &abstract) @@ -53,7 +54,8 @@ PlainText::PlainText(UDType type, ValueType value) : Text(type, value) int64_t PlainText::GetSize() { - return UnifiedDataUtils::GetDetailsSize(this->details_) + this->content_.size() + this->abstract_.size(); + return UnifiedDataUtils::GetDetailsSize(this->details_) + this->content_.size() + this->abstract_.size() + + GetInnerEntriesSize(); } std::string PlainText::GetContent() const @@ -102,7 +104,7 @@ void PlainText::InitObject() object->value_[CONTENT] = content_; object->value_[ABSTRACT] = abstract_; object->value_[DETAILS] = ObjectUtils::ConvertToObject(details_); - object->value_[VALUE_TYPE] = value; + object->value_.insert_or_assign(VALUE_TYPE, std::move(value)); } } } // namespace UDMF diff --git a/udmf/framework/innerkitsimpl/data/preset_type_descriptors.cpp b/udmf/framework/innerkitsimpl/data/preset_type_descriptors.cpp index e9e47245da21938cdfa1bf75cb47ac761d0d9278..adbd21febf44ae8afa2404ee6a70689e9faaec0d 100644 --- a/udmf/framework/innerkitsimpl/data/preset_type_descriptors.cpp +++ b/udmf/framework/innerkitsimpl/data/preset_type_descriptors.cpp @@ -3301,6 +3301,34 @@ void PresetTypeDescriptors::InitDescriptors() {}, "Harmony Archive", REFERENCE_URL, + ""}, + {"openharmony.gopaint", + {"general.archive"}, + {".gopaint"}, + {}, + "Gopaint file format defined for Openharmony", + REFERENCE_URL, + ""}, + {"openharmony.gobrush", + {"general.archive"}, + {".gobrush"}, + {}, + "Gobrush file format defined for Openharmony", + REFERENCE_URL, + ""}, + {"openharmony.gobrushes", + {"general.archive"}, + {".gobrushes"}, + {}, + "Gobrushes file format defined for Openharmony", + REFERENCE_URL, + ""}, + {"openharmony.gocolor", + {"general.archive"}, + {".gocolor"}, + {}, + "Gocolor file format defined for Openharmony", + REFERENCE_URL, ""} }; }; diff --git a/udmf/framework/innerkitsimpl/data/system_defined_appitem.cpp b/udmf/framework/innerkitsimpl/data/system_defined_appitem.cpp index 9cfc622c926782b3d02703afac4de8aa481d17cc..c9e680804a94251a150518caa7cef9a53cbb8ea2 100644 --- a/udmf/framework/innerkitsimpl/data/system_defined_appitem.cpp +++ b/udmf/framework/innerkitsimpl/data/system_defined_appitem.cpp @@ -43,8 +43,9 @@ SystemDefinedAppItem::SystemDefinedAppItem(UDType type, ValueType value) : Syste int64_t SystemDefinedAppItem::GetSize() { - return UnifiedDataUtils::GetDetailsSize(this->details_) + this->appId_.size() + this->appName_.size() - + this->appIconId_.size() + this->appLabelId_.size() + this->bundleName_.size() + this->abilityName_.size(); + return UnifiedDataUtils::GetDetailsSize(this->details_) + this->appId_.size() + this->appName_.size() + + this->appIconId_.size() + this->appLabelId_.size() + this->bundleName_.size() + this->abilityName_.size() + + GetInnerEntriesSize(); } std::string SystemDefinedAppItem::GetAppId() const @@ -179,7 +180,7 @@ void SystemDefinedAppItem::InitObject() object->value_[BUNDLE_NAME] = bundleName_; object->value_[ABILITY_NAME] = abilityName_; object->value_[DETAILS] = ObjectUtils::ConvertToObject(details_); - object->value_[VALUE_TYPE] = value; + object->value_.insert_or_assign(VALUE_TYPE, std::move(value)); } } } // namespace UDMF diff --git a/udmf/framework/innerkitsimpl/data/system_defined_form.cpp b/udmf/framework/innerkitsimpl/data/system_defined_form.cpp index 1bfcbc34a6f19a1bebf68d42a92ae38b0ae871b1..e17c5475390b9931ad0c7a290a661ec12616c313 100644 --- a/udmf/framework/innerkitsimpl/data/system_defined_form.cpp +++ b/udmf/framework/innerkitsimpl/data/system_defined_form.cpp @@ -19,12 +19,12 @@ namespace OHOS { namespace UDMF { SystemDefinedForm::SystemDefinedForm() { - this->dataType_ = SYSTEM_DEFINED_FORM; + SetType(SYSTEM_DEFINED_FORM); } SystemDefinedForm::SystemDefinedForm(UDType type, ValueType value) : SystemDefinedRecord(type, value) { - this->dataType_ = SYSTEM_DEFINED_FORM; + SetType(SYSTEM_DEFINED_FORM); if (std::holds_alternative<std::shared_ptr<Object>>(value)) { auto object = std::get<std::shared_ptr<Object>>(value); object->GetValue(FORMID, formId_); @@ -43,7 +43,7 @@ SystemDefinedForm::SystemDefinedForm(UDType type, ValueType value) : SystemDefin int64_t SystemDefinedForm::GetSize() { return UnifiedDataUtils::GetDetailsSize(this->details_) + sizeof(formId_) + this->formName_.size() - + this->bundleName_.size() + this->abilityName_.size() + this->module_.size(); + + this->bundleName_.size() + this->abilityName_.size() + this->module_.size() + GetInnerEntriesSize(); } int32_t SystemDefinedForm::GetFormId() const @@ -165,7 +165,7 @@ void SystemDefinedForm::InitObject() object->value_[ABILITY_NAME] = abilityName_; object->value_[MODULE] = module_; object->value_[DETAILS] = ObjectUtils::ConvertToObject(details_); - object->value_[VALUE_TYPE] = value; + object->value_.insert_or_assign(VALUE_TYPE, std::move(value)); } } diff --git a/udmf/framework/innerkitsimpl/data/system_defined_pixelmap.cpp b/udmf/framework/innerkitsimpl/data/system_defined_pixelmap.cpp index 94d6b3992533e8e593ddfc9670ff7c337fa83347..4e713720d51704dbdbbb275e3d8802bfbd86d0f4 100644 --- a/udmf/framework/innerkitsimpl/data/system_defined_pixelmap.cpp +++ b/udmf/framework/innerkitsimpl/data/system_defined_pixelmap.cpp @@ -61,7 +61,7 @@ SystemDefinedPixelMap::SystemDefinedPixelMap(UDType type, ValueType value) : Sys int64_t SystemDefinedPixelMap::GetSize() { - return UnifiedDataUtils::GetDetailsSize(this->details_) + rawData_.size(); + return UnifiedDataUtils::GetDetailsSize(this->details_) + rawData_.size() + GetInnerEntriesSize(); } std::vector<uint8_t> SystemDefinedPixelMap::GetRawData() const @@ -99,7 +99,7 @@ void SystemDefinedPixelMap::InitObject() } object->value_[UNIFORM_DATA_TYPE] = UtdUtils::GetUtdIdFromUtdEnum(dataType_); object->value_[DETAILS] = ObjectUtils::ConvertToObject(details_); - object->value_[VALUE_TYPE] = value; + object->value_.insert_or_assign(VALUE_TYPE, std::move(value)); } } } // namespace UDMF diff --git a/udmf/framework/innerkitsimpl/data/system_defined_record.cpp b/udmf/framework/innerkitsimpl/data/system_defined_record.cpp index e4dc3e26a84db6c2d61b968f819b1fb3ab38472e..623fcff296dd634ac766ae25600c4aee29ecac61 100644 --- a/udmf/framework/innerkitsimpl/data/system_defined_record.cpp +++ b/udmf/framework/innerkitsimpl/data/system_defined_record.cpp @@ -23,7 +23,7 @@ SystemDefinedRecord::SystemDefinedRecord() : UnifiedRecord(SYSTEM_DEFINED_RECORD int64_t SystemDefinedRecord::GetSize() { - return UnifiedDataUtils::GetDetailsSize(this->details_); + return UnifiedDataUtils::GetDetailsSize(this->details_) + GetInnerEntriesSize(); } SystemDefinedRecord::SystemDefinedRecord(UDType type, ValueType value) : UnifiedRecord(type, value) @@ -81,7 +81,7 @@ void SystemDefinedRecord::InitObject() value_ = std::make_shared<Object>(); auto object = std::get<std::shared_ptr<Object>>(value_); object->value_[DETAILS] = ObjectUtils::ConvertToObject(details_); - object->value_[VALUE_TYPE] = value; + object->value_.insert_or_assign(VALUE_TYPE, std::move(value)); } } } // namespace UDMF diff --git a/udmf/framework/innerkitsimpl/data/text.cpp b/udmf/framework/innerkitsimpl/data/text.cpp index 9d473c8578e818ca1eff3254b0610884540d626f..718fd3992ffa32df0f05153393afe07b439d2dc6 100644 --- a/udmf/framework/innerkitsimpl/data/text.cpp +++ b/udmf/framework/innerkitsimpl/data/text.cpp @@ -41,7 +41,7 @@ Text::Text(UDType type, ValueType value) : UnifiedRecord(type, value) int64_t Text::GetSize() { - return UnifiedDataUtils::GetDetailsSize(this->details_); + return UnifiedDataUtils::GetDetailsSize(this->details_) + GetInnerEntriesSize(); } void Text::SetDetails(UDDetails &variantMap) @@ -64,7 +64,7 @@ void Text::InitObject() value_ = std::make_shared<Object>(); auto object = std::get<std::shared_ptr<Object>>(value_); object->value_[DETAILS] = ObjectUtils::ConvertToObject(details_); - object->value_[VALUE_TYPE] = value; + object->value_.insert_or_assign(VALUE_TYPE, std::move(value)); } } } // namespace UDMF diff --git a/udmf/framework/innerkitsimpl/data/unified_data.cpp b/udmf/framework/innerkitsimpl/data/unified_data.cpp index c1675881e26c8fc7dc90db27177ef54b6179dcf6..37d2664596cb6fadd7cdf0e54ca28e8251796a47 100644 --- a/udmf/framework/innerkitsimpl/data/unified_data.cpp +++ b/udmf/framework/innerkitsimpl/data/unified_data.cpp @@ -14,12 +14,12 @@ */ #define LOG_TAG "UnifiedData" #include "unified_data.h" -#include <chrono> -#include <cinttypes> #include "logger.h" namespace OHOS { namespace UDMF { +static std::set<std::string> FILE_TYPES = { + "general.file", "general.image", "general.video", "general.audio", "general.folder", "general.file-uri" }; UnifiedData::UnifiedData() { properties_ = std::make_shared<UnifiedDataProperties>(); @@ -105,7 +105,9 @@ std::vector<std::string> UnifiedData::GetTypesLabels() const { std::vector<std::string> types; for (const std::shared_ptr<UnifiedRecord> &record : records_) { - types.push_back(UtdUtils::GetUtdIdFromUtdEnum(record->GetType())); + std::vector<std::string> recordTypes = record->GetTypes(); + types.insert(types.end(), + std::make_move_iterator(recordTypes.begin()), std::make_move_iterator(recordTypes.end())); } return types; } @@ -113,7 +115,8 @@ std::vector<std::string> UnifiedData::GetTypesLabels() const bool UnifiedData::HasType(const std::string &type) const { for (const std::shared_ptr<UnifiedRecord> &record : records_) { - if (UtdUtils::GetUtdIdFromUtdEnum(record->GetType()) == type) { + std::vector<std::string> recordTypes = record->GetTypes(); + if (std::find(recordTypes.begin(), recordTypes.end(), type) != recordTypes.end()) { return true; } } @@ -178,12 +181,25 @@ bool UnifiedData::IsComplete() return true; } +bool UnifiedData::HasFileType() const +{ + auto types = GetTypIds(); + std::set<std::string> intersection; + std::set_intersection(FILE_TYPES.begin(), FILE_TYPES.end(), types.begin(), types.end(), + std::inserter(intersection, intersection.begin())); + return !intersection.empty(); +} + void UnifiedData::SetProperties(std::shared_ptr<UnifiedDataProperties> properties) { if (!properties) { LOG_ERROR(UDMF_FRAMEWORK, "properties is null!"); return; } + if (properties_ == nullptr) { + LOG_ERROR(UDMF_FRAMEWORK, "properties_ is nullptr!"); + return; + } properties->timestamp = properties_->timestamp; properties_ = properties; } @@ -207,5 +223,29 @@ void UnifiedData::SetChannelName(const std::string &name) { channelName_ = std::move(name); } + +std::set<std::string> UnifiedData::GetTypIds() const +{ + std::set<std::string> types; + for (const auto &record : records_) { + std::set<std::string> recordTypes = record->GetUtdIds(); + types.insert(recordTypes.begin(), recordTypes.end()); + } + return types; +} + +std::vector<std::string> UnifiedData::GetFileUris() const +{ + std::vector<std::string> uris; + for (auto record : records_) { + std::string oriUri; + if (record == nullptr || !record->HasFileType(oriUri)) { + continue; + } + uris.push_back(oriUri); + } + return uris; +} + } // namespace UDMF } // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/data/unified_data_helper.cpp b/udmf/framework/innerkitsimpl/data/unified_data_helper.cpp index 340885a7f65897087fda4353b91cacb33569c86f..06423fd5b028dc9a0d1679f6f9a4dcf28f379627 100644 --- a/udmf/framework/innerkitsimpl/data/unified_data_helper.cpp +++ b/udmf/framework/innerkitsimpl/data/unified_data_helper.cpp @@ -15,22 +15,24 @@ #define LOG_TAG "UnifiedDataHelper" #include "unified_data_helper.h" -#include <string> -#include <chrono> #include "common_func.h" #include "directory_ex.h" #include "file_ex.h" #include "file_uri.h" +#include "error_code.h" #include "logger.h" #include "tlv_util.h" #include "udmf_conversion.h" +#include "udmf_utils.h" #include "file.h" namespace OHOS { namespace UDMF { constexpr mode_t MODE = 0700; -static constexpr int64_t MAX_KV_RECORD_SIZE = 2 * 1024 * 1024; -static constexpr int64_t MAX_KV_DATA_SIZE = 4 * 1024 * 1024; +static constexpr int64_t MAX_HAP_RECORD_SIZE = 2 * 1024 * 1024; +static constexpr int64_t MAX_HAP_DATA_SIZE = 4 * 1024 * 1024; +static constexpr int64_t MAX_IPC_RAW_DATA_SIZE = 128 * 1024 * 1024; +static constexpr int64_t MAX_SA_DRAG_RECORD_SIZE = 15 * 1024 * 1024 + 512 * 1024; constexpr const char *TEMP_UNIFIED_DATA_ROOT_PATH = "data/storage/el2/base/temp/udata"; constexpr const char *TEMP_UNIFIED_DATA_SUFFIX = ".ud"; @@ -45,16 +47,18 @@ void UnifiedDataHelper::SetRootPath(const std::string &rootPath) bool UnifiedDataHelper::ExceedKVSizeLimit(UnifiedData &data) { - int64_t totalSize = data.GetSize(); - if (data.GetSize() > MAX_KV_DATA_SIZE) { - LOG_DEBUG(UDMF_FRAMEWORK, "Exceeded KV data limit, totalSize:%{public}" PRId64 " !", totalSize); - return true; - } + int64_t totalSize = 0; for (const auto &record : data.GetRecords()) { - if (record->GetSize() > MAX_KV_RECORD_SIZE) { - LOG_DEBUG(UDMF_FRAMEWORK, "Exceeded KV record limit, recordSize:%{public}" PRId64 "!", record->GetSize()); + auto recordSize = record->GetSize(); + if (recordSize > MAX_HAP_RECORD_SIZE) { + LOG_INFO(UDMF_FRAMEWORK, "Exceeded 2M record limit, recordSize:%{public}" PRId64 "!", recordSize); return true; } + totalSize += recordSize; + } + if (totalSize > MAX_HAP_DATA_SIZE) { + LOG_INFO(UDMF_FRAMEWORK, "Exceeded 4M data limit, totalSize:%{public}" PRId64 " !", totalSize); + return true; } return false; } @@ -102,20 +106,14 @@ void UnifiedDataHelper::CreateDirIfNotExist(const std::string& dirPath, const mo void UnifiedDataHelper::GetSummary(const UnifiedData &data, Summary &summary) { for (const auto &record : data.GetRecords()) { - int64_t recordSize = record->GetSize(); - auto udType = UtdUtils::GetUtdIdFromUtdEnum(record->GetType()); - auto it = summary.summary.find(udType); - if (it == summary.summary.end()) { - summary.summary[udType] = recordSize; - } else { - summary.summary[udType] += recordSize; - } - summary.totalSize += recordSize; + CalRecordSummary(*record->GetEntries(), summary); } } bool UnifiedDataHelper::Pack(UnifiedData &data) { + UdmfConversion::InitValueObject(data); + Summary summary; GetSummary(data, summary); @@ -216,5 +214,53 @@ std::string UnifiedDataHelper::GetRootPath() } return rootPath_; } + +int32_t UnifiedDataHelper::ProcessBigData(UnifiedData &data, Intention intention, bool isSaInvoke) +{ + if (!isSaInvoke) { + return UnifiedDataHelper::Pack(data) ? E_OK : E_FS_ERROR; + } + if (intention != Intention::UD_INTENTION_DRAG) { + LOG_ERROR(UDMF_SERVICE, "Non-Drag cannot be used to process big data when SA initiates a request"); + return E_INVALID_PARAMETERS; + } + int64_t dataSize = 0; + for (const auto &record : data.GetRecords()) { + auto recordSize = record->GetSize(); + if (recordSize > MAX_SA_DRAG_RECORD_SIZE) { + LOG_ERROR(UDMF_FRAMEWORK, "Exceeded KV record limit, recordSize:%{public}" PRId64 "!", recordSize); + return E_INVALID_PARAMETERS; + } + dataSize += recordSize; + } + if (dataSize > MAX_IPC_RAW_DATA_SIZE) { + LOG_ERROR(UDMF_SERVICE, "Exceeded ipc-send data limit, totalSize:%{public}" PRId64 " !", dataSize); + return E_INVALID_PARAMETERS; + } + LOG_DEBUG(UDMF_SERVICE, "Processing udmf data in memory"); + return E_OK; +} + +void UnifiedDataHelper::CalRecordSummary(std::map<std::string, ValueType> &entry, Summary &summary) +{ + for (const auto &[utdId, value] : entry) { + auto typeId = utdId; + auto valueSize = ObjectUtils::GetValueSize(value, false); + if (std::holds_alternative<std::shared_ptr<Object>>(value)) { + auto object = std::get<std::shared_ptr<Object>>(value); + if (object->value_.find(APPLICATION_DEFINED_RECORD_MARK) != object->value_.end()) { + typeId = UtdUtils::GetUtdIdFromUtdEnum(APPLICATION_DEFINED_RECORD); + } + } + auto it = summary.summary.find(typeId); + if (it == summary.summary.end()) { + summary.summary[typeId] = valueSize; + } else { + summary.summary[typeId] += valueSize; + } + summary.totalSize += valueSize; + } +} + } // namespace UDMF } // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/data/unified_record.cpp b/udmf/framework/innerkitsimpl/data/unified_record.cpp index 0afab7f22dee1c7c1602abdd299c54260dbd56b9..5cb72c1a21a7f20f8a3e37f2c8e224dbe7a39a2b 100644 --- a/udmf/framework/innerkitsimpl/data/unified_record.cpp +++ b/udmf/framework/innerkitsimpl/data/unified_record.cpp @@ -15,11 +15,15 @@ #define LOG_TAG "UnifiedRecord" #include "unified_record.h" +#include "file.h" #include "getter_system.h" #include "logger.h" namespace OHOS { namespace UDMF { +static constexpr UDType FILE_TYPES[] = {FILE, AUDIO, FOLDER, IMAGE, VIDEO}; +static constexpr const char *FILE_SCHEME = "file"; + UnifiedRecord::UnifiedRecord() { dataType_ = UD_BUTT; @@ -46,6 +50,16 @@ UDType UnifiedRecord::GetType() const return this->dataType_; } +std::vector<std::string> UnifiedRecord::GetTypes() const +{ + std::vector<std::string> types; + for (auto it = entries_->begin(); it != entries_->end(); it++) { + types.push_back(it->first); + } + types.push_back(utdId_); + return types; +} + void UnifiedRecord::SetType(const UDType &type) { dataType_ = type; @@ -54,7 +68,13 @@ void UnifiedRecord::SetType(const UDType &type) int64_t UnifiedRecord::GetSize() { - return 0; + if (std::holds_alternative<std::shared_ptr<Object>>(value_)) { + auto value = std::get<std::shared_ptr<Object>>(value_); + if (value->value_.size() == 1) { + return ObjectUtils::GetValueSize(value_, true) + GetInnerEntriesSize(); + } + } + return ObjectUtils::GetValueSize(value_, false) + GetInnerEntriesSize(); } std::string UnifiedRecord::GetUid() const @@ -92,6 +112,7 @@ bool UnifiedRecord::HasType(const std::string &utdId) const void UnifiedRecord::AddEntry(const std::string &utdId, ValueType &&value) { + std::lock_guard<std::recursive_mutex> lock(mutex_); if (utdId == utdId_ || utdId_.empty()) { utdId_ = utdId; value_ = std::move(value); @@ -108,6 +129,7 @@ void UnifiedRecord::AddEntry(const std::string &utdId, ValueType &&value) ValueType UnifiedRecord::GetEntry(const std::string &utdId) { + std::lock_guard<std::recursive_mutex> lock(mutex_); if (utdId_ == utdId && !(std::holds_alternative<std::monostate>(value_))) { return value_; } @@ -118,21 +140,55 @@ ValueType UnifiedRecord::GetEntry(const std::string &utdId) auto getter = GetterSystem::GetInstance().GetGetter(channelName_); if (getter != nullptr && (utdId_ == utdId || it != entries_->end())) { auto value = getter->GetValueByType(dataId_, recordId_, utdId); + if (std::holds_alternative<std::monostate>(value)) { + LOG_ERROR(UDMF_FRAMEWORK, "get value failed, utdId: %{public}s", utdId.c_str()); + return std::monostate(); + } AddEntry(utdId, ValueType(value)); return value; } return std::monostate(); } -std::shared_ptr<std::map<std::string, ValueType>> UnifiedRecord::GetEntries() const +std::shared_ptr<std::map<std::string, ValueType>> UnifiedRecord::GetEntries() { auto res = std::make_shared<std::map<std::string, ValueType>>(*entries_); if (!utdId_.empty()) { - res->insert_or_assign(utdId_, value_); + if (!std::holds_alternative<std::shared_ptr<Object>>(value_)) { + InitObject(); + ValueType value = value_; + res->insert_or_assign(utdId_, std::move(value)); + auto object = std::get<std::shared_ptr<Object>>(value_); + value_ = object->value_[VALUE_TYPE]; // restore value_ + } else { + res->insert_or_assign(utdId_, value_); + } } return res; } +std::shared_ptr<std::map<std::string, ValueType>> UnifiedRecord::GetInnerEntries() const +{ + return entries_; +} + +void UnifiedRecord::SetInnerEntries(std::shared_ptr<std::map<std::string, ValueType>> entries) +{ + entries_ = entries; +} + +int64_t UnifiedRecord::GetInnerEntriesSize() const +{ + if (entries_ == nullptr) { + return 0; + } + int64_t size = 0; + for (auto &entry : *entries_) { + size += ObjectUtils::GetValueSize(entry.second, false); + } + return size; +} + std::set<std::string> UnifiedRecord::GetUtdIds() const { std::set<std::string> utdIds; @@ -205,7 +261,7 @@ void UnifiedRecord::InitObject() auto value = value_; value_ = std::make_shared<Object>(); auto object = std::get<std::shared_ptr<Object>>(value_); - object->value_[VALUE_TYPE] = value; + object->value_.insert_or_assign(VALUE_TYPE, std::move(value)); } } @@ -214,5 +270,49 @@ bool UnifiedRecord::HasObject() return hasObject_; } +bool UnifiedRecord::HasFileType(std::string &fileUri) const +{ + fileUri.clear(); + if (std::holds_alternative<std::shared_ptr<Object>>(GetOriginValue())) { + auto obj = std::get<std::shared_ptr<Object>>(GetOriginValue()); + if (obj->value_.find(ORI_URI) != obj->value_.end()) { + obj->GetValue(ORI_URI, fileUri); + } + } else if (std::find(std::begin(FILE_TYPES), std::end(FILE_TYPES), GetType()) != std::end(FILE_TYPES)) { + auto file = static_cast<const File*>(this); + fileUri = file->GetUri(); + } else { + return false; + } + + if (fileUri.empty()) { + LOG_ERROR(UDMF_FRAMEWORK, "Get uri empty, plase check the uri."); + return false; + } +#ifndef CROSS_PLATFORM + Uri uri(fileUri); + std::string scheme = uri.GetScheme(); + std::transform(scheme.begin(), scheme.end(), scheme.begin(), ::tolower); + if (uri.GetAuthority().empty() || scheme != FILE_SCHEME) { + LOG_INFO(UDMF_FRAMEWORK, "Get uri authority empty or uri scheme not equals to file."); + return false; + } +#endif + return true; +} + +void UnifiedRecord::SetFileUri(const std::string &fileUri) +{ + if (std::find(std::begin(FILE_TYPES), std::end(FILE_TYPES), GetType()) != std::end(FILE_TYPES)) { + auto file = static_cast<File*>(this); + file->SetUri(fileUri); + } else if (std::holds_alternative<std::shared_ptr<Object>>(GetOriginValue())) { + auto obj = std::get<std::shared_ptr<Object>>(GetOriginValue()); + obj->value_[ORI_URI] = fileUri; + } else { + LOG_ERROR(UDMF_FRAMEWORK, "Record has no uri."); + } +} + } // namespace UDMF } // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/data/video.cpp b/udmf/framework/innerkitsimpl/data/video.cpp index eb186c5c0e8413f93ccd81f315fb39fe19460a7f..afb99239dd0154321915be8de388dd8b7f2a47ca 100644 --- a/udmf/framework/innerkitsimpl/data/video.cpp +++ b/udmf/framework/innerkitsimpl/data/video.cpp @@ -19,16 +19,17 @@ namespace OHOS { namespace UDMF { Video::Video() : Video("") { + SetType(VIDEO); } Video::Video(const std::string &uri) : File(uri) { - this->dataType_ = VIDEO; + SetType(VIDEO); } Video::Video(UDType type, ValueType value) : File(type, value) { - this->dataType_ = VIDEO; + SetType(VIDEO); } } // namespace UDMF } // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/service/distributeddata_udmf_ipc_interface_code.h b/udmf/framework/innerkitsimpl/service/distributeddata_udmf_ipc_interface_code.h index 4ead14c0bf01dff9274e706e49ef393a3ce408da..57f781c525cb995c05b165355b6d00bc8bc48be7 100644 --- a/udmf/framework/innerkitsimpl/service/distributeddata_udmf_ipc_interface_code.h +++ b/udmf/framework/innerkitsimpl/service/distributeddata_udmf_ipc_interface_code.h @@ -33,7 +33,8 @@ enum class UdmfServiceInterfaceCode : uint32_t { GET_APP_SHARE_OPTION, REMOVE_APP_SHARE_OPTION, OBTAIN_ASYN_PROCESS, - CLEAR_ASYN_PROCESS, + CLEAR_ASYN_PROCESS_BY_KEY, + INVOKEN_HAP, CODE_BUTT }; } // namespace OHOS::UDMF diff --git a/udmf/framework/innerkitsimpl/service/progress_callback.cpp b/udmf/framework/innerkitsimpl/service/progress_callback.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f235e18d18211f86c4e353ffecd1d73a03c0f0ed --- /dev/null +++ b/udmf/framework/innerkitsimpl/service/progress_callback.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2025 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 "ProcessCallback" +#include "progress_callback.h" + +#include "error_code.h" +#include "ipc_skeleton.h" +#include "logger.h" +#include "udmf_async_client.h" + + +namespace OHOS { +namespace UDMF { +int32_t ProgressSignalStub::OnRemoteRequest(uint32_t code, + MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + std::u16string myDescriptor = ProgressSignalStub::GetDescriptor(); + std::u16string remoteDescriptor = data.ReadInterfaceToken(); + if (myDescriptor != remoteDescriptor) { + LOG_ERROR(UDMF_SERVICE, "Descriptor checked fail"); + return E_ERROR; + } + pid_t pid = IPCSkeleton::GetCallingPid(); + pid_t uid = IPCSkeleton::GetCallingUid(); + LOG_INFO(UDMF_SERVICE, "CallingPid=%{public}d, CallingUid=%{public}d, code=%{public}u", pid, uid, code); + HandleProgressSignalValue(data); + return E_OK; +} + +void ProgressSignalCallback::HandleProgressSignalValue(MessageParcel &data) +{ + int32_t cancelStatus = 0; + std::string signalValue = data.ReadString(); + + try { + cancelStatus = std::stoi(signalValue); + } catch (const std::exception& e) { + LOG_ERROR(UDMF_CLIENT, "Signal value error, signalValue=%{public}s", signalValue.c_str()); + return; + } + switch (cancelStatus) { + case NORMAL_PASTE: + break; + case CANCEL_PASTE: + UdmfAsyncClient::GetInstance().CancelOnSingleTask(); + break; + case PASTE_TIME_OUT: + LOG_ERROR(UDMF_CLIENT, "Progress timed out"); + break; + default: + LOG_ERROR(UDMF_CLIENT, "status error, status=%{public}d", cancelStatus); + break; + } +} +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/service/progress_callback.h b/udmf/framework/innerkitsimpl/service/progress_callback.h new file mode 100644 index 0000000000000000000000000000000000000000..8fcf2826f55809294e2cc48677d994633746c0c8 --- /dev/null +++ b/udmf/framework/innerkitsimpl/service/progress_callback.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 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_PROGRESS_CALLBACK_H +#define OHOS_PROGRESS_CALLBACK_H + +#include <iremote_broker.h> +#include <iremote_stub.h> + +namespace OHOS { +namespace UDMF { +class IProgressSignal : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.miscservices.dialog.callback"); + virtual void HandleProgressSignalValue(MessageParcel &data) = 0; +}; + +class ProgressSignalStub : public IRemoteStub<IProgressSignal> { +public: + int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; +}; + +class ProgressSignalCallback : public ProgressSignalStub { +public: + void HandleProgressSignalValue(MessageParcel &data) override; +}; +} // namespace UDMF +} // namespace OHOS +#endif // OHOS_PROGRESS_CALLBACK_H \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/service/udmf_service.h b/udmf/framework/innerkitsimpl/service/udmf_service.h index b57208628b5af1618d991b8694792911b877c3c6..4a1ac7d78258e221e2043317c67644dfdc5eb9bd 100644 --- a/udmf/framework/innerkitsimpl/service/udmf_service.h +++ b/udmf/framework/innerkitsimpl/service/udmf_service.h @@ -50,7 +50,8 @@ public: virtual int32_t GetAppShareOption(const std::string &intention, int32_t &shareOption) = 0; virtual int32_t RemoveAppShareOption(const std::string &intention) = 0; virtual int32_t ObtainAsynProcess(AsyncProcessInfo &processInfo) = 0; - virtual int32_t ClearAsynProcess() = 0; + virtual int32_t ClearAsynProcessByKey(const std::string &businessUdKey) = 0; + virtual int32_t InvokeHap(const std::string &progressKey, const sptr<IRemoteObject> &observer) = 0; }; } // namespace UDMF } // namespace OHOS diff --git a/udmf/framework/innerkitsimpl/service/udmf_service_client.cpp b/udmf/framework/innerkitsimpl/service/udmf_service_client.cpp index 43fc593c3906249c8adcd3202054f852fdaa5e63..af11fc83abcfe244ae71c6ef30c42a2669cd6b2e 100644 --- a/udmf/framework/innerkitsimpl/service/udmf_service_client.cpp +++ b/udmf/framework/innerkitsimpl/service/udmf_service_client.cpp @@ -18,6 +18,7 @@ #include "iservice_registry.h" #include "datamgr_service_proxy.h" #include "system_ability_definition.h" +#include "udmf_utils.h" #include "unified_data_helper.h" #include "logger.h" @@ -113,10 +114,16 @@ int32_t UdmfServiceClient::SetData(CustomOption &option, UnifiedData &unifiedDat LOG_ERROR(UDMF_SERVICE, "UnifiedData is invalid."); return E_INVALID_PARAMETERS; } + bool isSaInvoke = UTILS::IsTokenNative(); + if (isSaInvoke && unifiedData.HasFileType()) { + LOG_ERROR(UDMF_SERVICE, "The setting data initiated by the SA cannot contain the file type"); + return E_INVALID_PARAMETERS; + } if (UnifiedDataHelper::ExceedKVSizeLimit(unifiedData)) { - if (!UnifiedDataHelper::Pack(unifiedData)) { - LOG_ERROR(UDMF_SERVICE, "Failed to pack unified data."); - return E_FS_ERROR; + auto status = UnifiedDataHelper::ProcessBigData(unifiedData, option.intention, isSaInvoke); + if (status != E_OK) { + LOG_ERROR(UDMF_SERVICE, "Process big data error, status = %{public}d", status); + return status; } } return udmfProxy_->SetData(option, unifiedData, key); @@ -285,9 +292,14 @@ int32_t UdmfServiceClient::ObtainAsynProcess(AsyncProcessInfo& processInfo) return udmfProxy_->ObtainAsynProcess(processInfo); } -int32_t UdmfServiceClient::ClearAsynProcess() +int32_t UdmfServiceClient::ClearAsynProcessByKey(const std::string &businessUdKey) +{ + return udmfProxy_->ClearAsynProcessByKey(businessUdKey); +} + +int32_t UdmfServiceClient::InvokeHap(const std::string &progressKey, const sptr<IRemoteObject> &observer) { - return udmfProxy_->ClearAsynProcess(); + return udmfProxy_->InvokeHap(progressKey, observer); } } // namespace UDMF } // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/service/udmf_service_client.h b/udmf/framework/innerkitsimpl/service/udmf_service_client.h index 54c594951025866c0b222f9406fdf887cbc5200a..d702cf4dddfc748ae0313d50dfad535e34ed3793 100644 --- a/udmf/framework/innerkitsimpl/service/udmf_service_client.h +++ b/udmf/framework/innerkitsimpl/service/udmf_service_client.h @@ -45,7 +45,8 @@ public: int32_t GetAppShareOption(const std::string &intention, int32_t &shareOption) override; int32_t RemoveAppShareOption(const std::string &intention) override; int32_t ObtainAsynProcess(AsyncProcessInfo& processInfo) override; - int32_t ClearAsynProcess() override; + int32_t ClearAsynProcessByKey(const std::string &businessUdKey) override; + int32_t InvokeHap(const std::string &progressKey, const sptr<IRemoteObject> &observer) override; private: class ServiceDeathRecipient : public IRemoteObject::DeathRecipient { diff --git a/udmf/framework/innerkitsimpl/service/udmf_service_proxy.cpp b/udmf/framework/innerkitsimpl/service/udmf_service_proxy.cpp index f8b6c50bee3a247bf3d3380a50e87757af74f3f5..95b614a0451f08e43a8e3751ed1763609fab9d1f 100644 --- a/udmf/framework/innerkitsimpl/service/udmf_service_proxy.cpp +++ b/udmf/framework/innerkitsimpl/service/udmf_service_proxy.cpp @@ -79,6 +79,7 @@ int32_t UdmfServiceProxy::GetData(const QueryOption &query, UnifiedData &unified LOG_ERROR(UDMF_SERVICE, "Unmarshal UnifiedData failed!"); return E_READ_PARCEL_ERROR; } + UdmfConversion::ConvertRecordToSubclass(unifiedData); return status; } @@ -95,6 +96,7 @@ int32_t UdmfServiceProxy::GetBatchData(const QueryOption &query, std::vector<Uni LOG_ERROR(UDMF_SERVICE, "Unmarshal unifiedDataSet failed!"); return E_READ_PARCEL_ERROR; } + UdmfConversion::ConvertRecordToSubclass(unifiedDataSet); return status; } @@ -123,6 +125,7 @@ int32_t UdmfServiceProxy::DeleteData(const QueryOption &query, std::vector<Unifi LOG_ERROR(UDMF_SERVICE, "Unmarshal unifiedDataSet failed!"); return E_READ_PARCEL_ERROR; } + UdmfConversion::ConvertRecordToSubclass(unifiedDataSet); LOG_DEBUG(UDMF_SERVICE, "end."); return status; } @@ -197,7 +200,7 @@ int32_t UdmfServiceProxy::GetAppShareOption(const std::string &intention, int32_ MessageParcel reply; int32_t status = IPC_SEND(UdmfServiceInterfaceCode::GET_APP_SHARE_OPTION, reply, intention); if (status != E_OK) { - LOG_ERROR(UDMF_SERVICE, "status:0x%{public}x!", status); + LOG_WARN(UDMF_SERVICE, "status:0x%{public}x!", status); return status; } @@ -236,7 +239,7 @@ int32_t UdmfServiceProxy::SendRequest(UdmfServiceInterfaceCode code, MessageParc int32_t UdmfServiceProxy::ObtainAsynProcess(AsyncProcessInfo &processInfo) { MessageParcel reply; - int32_t status = IPC_SEND(UdmfServiceInterfaceCode::OBTAIN_ASYN_PROCESS, reply); + int32_t status = IPC_SEND(UdmfServiceInterfaceCode::OBTAIN_ASYN_PROCESS, reply, processInfo); if (status != E_OK) { LOG_ERROR(UDMF_SERVICE, "status:0x%{public}x", status); return status; @@ -248,10 +251,10 @@ int32_t UdmfServiceProxy::ObtainAsynProcess(AsyncProcessInfo &processInfo) return E_OK; } -int32_t UdmfServiceProxy::ClearAsynProcess() +int32_t UdmfServiceProxy::ClearAsynProcessByKey(const std::string &businessUdKey) { MessageParcel reply; - int32_t status = IPC_SEND(UdmfServiceInterfaceCode::CLEAR_ASYN_PROCESS, reply); + int32_t status = IPC_SEND(UdmfServiceInterfaceCode::CLEAR_ASYN_PROCESS_BY_KEY, reply, businessUdKey); if (status != E_OK) { LOG_ERROR(UDMF_SERVICE, "status:0x%{public}x", status); return status; @@ -259,5 +262,15 @@ int32_t UdmfServiceProxy::ClearAsynProcess() return E_OK; } +int32_t UdmfServiceProxy::InvokeHap(const std::string &progressKey, const sptr<IRemoteObject> &observer) +{ + MessageParcel reply; + int32_t status = IPC_SEND(UdmfServiceInterfaceCode::INVOKEN_HAP, reply, progressKey, observer); + if (status != E_OK) { + LOG_ERROR(UDMF_SERVICE, "status:0x%{public}x", status); + return status; + } + return E_OK; +} } // namespace UDMF } // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/service/udmf_service_proxy.h b/udmf/framework/innerkitsimpl/service/udmf_service_proxy.h index ca576b0bd739262853728e6353f455c3c7674177..3f6f5d6013482c51a8faaafce9cf2a4114b343be 100644 --- a/udmf/framework/innerkitsimpl/service/udmf_service_proxy.h +++ b/udmf/framework/innerkitsimpl/service/udmf_service_proxy.h @@ -48,7 +48,8 @@ public: int32_t GetAppShareOption(const std::string &intention, int32_t &shareOption) override; int32_t RemoveAppShareOption(const std::string &intention) override; int32_t ObtainAsynProcess(AsyncProcessInfo &processInfo) override; - int32_t ClearAsynProcess() override; + int32_t ClearAsynProcessByKey(const std::string &businessUdKey) override; + int32_t InvokeHap(const std::string &progressKey, const sptr<IRemoteObject> &observer) override; private: static inline BrokerDelegator<UdmfServiceProxy> delegator_; int32_t SendRequest(UdmfServiceInterfaceCode code, MessageParcel &data, diff --git a/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/udmf_client_fuzzer.cpp b/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/udmf_client_fuzzer.cpp index c84c0de75947fd1d76e55b9056ad713e35bf3fd7..f9e9495efd1eabaac442e305023b2454dc290185 100644 --- a/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/udmf_client_fuzzer.cpp +++ b/udmf/framework/innerkitsimpl/test/fuzztest/udmfclient_fuzzer/udmf_client_fuzzer.cpp @@ -33,6 +33,8 @@ #include "system_defined_form.h" #include "system_defined_appitem.h" #include "system_defined_pixelmap.h" +#include "udmf_async_client.h" +#include "unified_types.h" using namespace OHOS; using namespace OHOS::Security::AccessToken; @@ -115,12 +117,11 @@ void SetDataTextFuzz(const uint8_t *data, size_t size) std::string svalue(data, data + size); UnifiedData unifiedData; CustomOption option = {.intention = Intention::UD_INTENTION_BUTT}; - Text text; + auto text = std::make_shared<Text>(); UDDetails details; details.insert({skey, svalue}); - text.SetDetails(details); - std::shared_ptr<UnifiedRecord> record = std::make_shared<Text>(text); - unifiedData.AddRecord(record); + text->SetDetails(details); + unifiedData.AddRecord(text); std::string key; UdmfClient::GetInstance().SetData(option, unifiedData, key); @@ -144,16 +145,15 @@ void SetDataPlainTextFuzz(const uint8_t *data, size_t size) std::string svalue(data, data + size); CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; UnifiedData data1; - PlainText plainText1; UDDetails details1; + auto plainText1 = std::make_shared<PlainText>(); details1.insert({skey, svalue}); - plainText1.SetDetails(details1); - plainText1.SetContent(svalue + "content"); - plainText1.SetAbstract(svalue + "abstract"); - plainText1.GetContent(); - plainText1.GetAbstract(); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText1); - data1.AddRecord(record1); + plainText1->SetDetails(details1); + plainText1->SetContent(svalue + "content"); + plainText1->SetAbstract(svalue + "abstract"); + plainText1->GetContent(); + plainText1->GetAbstract(); + data1.AddRecord(plainText1); std::string key; UdmfClient::GetInstance().SetData(option1, data1, key); @@ -178,16 +178,15 @@ void SetDataHtmlFuzz(const uint8_t *data, size_t size) CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; UnifiedData data1; std::string key; - Html html1; + auto html1 = std::make_shared<Html>(); UDDetails details1; details1.insert({skey, svalue}); - html1.SetDetails(details1); - html1.SetHtmlContent(svalue + "htmlcontent"); - html1.SetPlainContent(svalue + "plainContent"); - html1.GetHtmlContent(); - html1.GetPlainContent(); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Html>(html1); - data1.AddRecord(record1); + html1->SetDetails(details1); + html1->SetHtmlContent(svalue + "htmlcontent"); + html1->SetPlainContent(svalue + "plainContent"); + html1->GetHtmlContent(); + html1->GetPlainContent(); + data1.AddRecord(html1); UdmfClient::GetInstance().SetData(option1, data1, key); SetNativeToken(); @@ -211,16 +210,15 @@ void SetDataLinkFuzz(const uint8_t *data, size_t size) CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; UnifiedData data1; std::string key; - Link link1; + auto link1 = std::make_shared<Link>(); UDDetails details1; details1.insert({skey, svalue}); - link1.SetDetails(details1); - link1.SetUrl(svalue + "url"); - link1.SetDescription(svalue + "description"); - link1.GetUrl(); - link1.GetDescription(); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Link>(link1); - data1.AddRecord(record1); + link1->SetDetails(details1); + link1->SetUrl(svalue + "url"); + link1->SetDescription(svalue + "description"); + link1->GetUrl(); + link1->GetDescription(); + data1.AddRecord(link1); UdmfClient::GetInstance().SetData(option1, data1, key); SetNativeToken(); @@ -243,14 +241,13 @@ void SetDataFileFuzz(const uint8_t *data, size_t size) CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; UnifiedData data1; std::string key; - File file1; - file1.SetUri(svalue + "uri"); - file1.SetRemoteUri(svalue + "remoteUri"); - file1.GetUri(); - file1.GetRemoteUri(); - file1.GetSize(); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<File>(file1); - data1.AddRecord(record1); + auto file1 = std::make_shared<File>(); + file1->SetUri(svalue + "uri"); + file1->SetRemoteUri(svalue + "remoteUri"); + file1->GetUri(); + file1->GetRemoteUri(); + file1->GetSize(); + data1.AddRecord(file1); UdmfClient::GetInstance().SetData(option1, data1, key); SetNativeToken(); @@ -273,11 +270,10 @@ void SetDataImageFuzz(const uint8_t *data, size_t size) CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; UnifiedData data1; std::string key; - Image image1; - image1.SetUri(svalue + "uri"); - image1.SetRemoteUri(svalue + "remoteUri"); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Image>(image1); - data1.AddRecord(record1); + auto image1 = std::make_shared<Image>(); + image1->SetUri(svalue + "uri"); + image1->SetRemoteUri(svalue + "remoteUri"); + data1.AddRecord(image1); UdmfClient::GetInstance().SetData(option1, data1, key); SetNativeToken(); @@ -300,11 +296,10 @@ void SetDataVideoFuzz(const uint8_t *data, size_t size) CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; UnifiedData data1; std::string key; - Video video1; - video1.SetUri(svalue + "uri"); - video1.SetRemoteUri(svalue + "remoteUri"); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Video>(video1); - data1.AddRecord(record1); + auto video1 = std::make_shared<Video>(); + video1->SetUri(svalue + "uri"); + video1->SetRemoteUri(svalue + "remoteUri"); + data1.AddRecord(video1); UdmfClient::GetInstance().SetData(option1, data1, key); SetNativeToken(); @@ -328,12 +323,11 @@ void SetDataSystemDefinedRecordFuzz(const uint8_t *data, size_t size) CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; UnifiedData data1; std::string key; - SystemDefinedRecord systemDefinedRecord1; + auto systemDefinedRecord1 = std::make_shared<SystemDefinedRecord>(); UDDetails details1; details1.insert({skey, svalue}); - systemDefinedRecord1.SetDetails(details1); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedRecord>(systemDefinedRecord1); - data1.AddRecord(record1); + systemDefinedRecord1->SetDetails(details1); + data1.AddRecord(systemDefinedRecord1); UdmfClient::GetInstance().SetData(option1, data1, key); SetNativeToken(); @@ -357,23 +351,22 @@ void SetDataSystemDefinedFormFuzz(const uint8_t *data, size_t size) CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; UnifiedData data1; std::string key; - SystemDefinedForm systemDefinedForm1; + auto systemDefinedForm1 = std::make_shared<SystemDefinedForm>(); UDDetails details1; details1.insert({skey, svalue}); - systemDefinedForm1.SetDetails(details1); + systemDefinedForm1->SetDetails(details1); auto formId = 123; - systemDefinedForm1.SetFormId(formId); - systemDefinedForm1.SetFormName(svalue + "formName"); - systemDefinedForm1.SetModule(svalue + "module"); - systemDefinedForm1.SetAbilityName(svalue + "abilityName"); - systemDefinedForm1.SetBundleName(svalue + "bundleName"); - systemDefinedForm1.GetFormId(); - systemDefinedForm1.GetFormName(); - systemDefinedForm1.GetBundleName(); - systemDefinedForm1.GetAbilityName(); - systemDefinedForm1.GetModule(); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedForm>(systemDefinedForm1); - data1.AddRecord(record1); + systemDefinedForm1->SetFormId(formId); + systemDefinedForm1->SetFormName(svalue + "formName"); + systemDefinedForm1->SetModule(svalue + "module"); + systemDefinedForm1->SetAbilityName(svalue + "abilityName"); + systemDefinedForm1->SetBundleName(svalue + "bundleName"); + systemDefinedForm1->GetFormId(); + systemDefinedForm1->GetFormName(); + systemDefinedForm1->GetBundleName(); + systemDefinedForm1->GetAbilityName(); + systemDefinedForm1->GetModule(); + data1.AddRecord(systemDefinedForm1); UdmfClient::GetInstance().SetData(option1, data1, key); SetNativeToken(); @@ -397,24 +390,23 @@ void SetDataSystemDefinedAppItemFuzz(const uint8_t *data, size_t size) CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; UnifiedData data1; std::string key; - SystemDefinedAppItem systemDefinedAppItem1; + auto systemDefinedAppItem1 = std::make_shared<SystemDefinedAppItem>(); UDDetails details1; details1.insert({skey, svalue}); - systemDefinedAppItem1.SetDetails(details1); - systemDefinedAppItem1.SetAppId(svalue + "appId"); - systemDefinedAppItem1.SetAppName(svalue + "appName"); - systemDefinedAppItem1.SetAppIconId(svalue + "appIconId"); - systemDefinedAppItem1.SetAppLabelId(svalue + "appLabelId"); - systemDefinedAppItem1.SetBundleName(svalue + "bundleName"); - systemDefinedAppItem1.SetAbilityName(svalue + "abilityName"); - systemDefinedAppItem1.GetAppId(); - systemDefinedAppItem1.GetAppName(); - systemDefinedAppItem1.GetBundleName(); - systemDefinedAppItem1.GetAbilityName(); - systemDefinedAppItem1.GetAppIconId(); - systemDefinedAppItem1.GetAppLabelId(); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedAppItem>(systemDefinedAppItem1); - data1.AddRecord(record1); + systemDefinedAppItem1->SetDetails(details1); + systemDefinedAppItem1->SetAppId(svalue + "appId"); + systemDefinedAppItem1->SetAppName(svalue + "appName"); + systemDefinedAppItem1->SetAppIconId(svalue + "appIconId"); + systemDefinedAppItem1->SetAppLabelId(svalue + "appLabelId"); + systemDefinedAppItem1->SetBundleName(svalue + "bundleName"); + systemDefinedAppItem1->SetAbilityName(svalue + "abilityName"); + systemDefinedAppItem1->GetAppId(); + systemDefinedAppItem1->GetAppName(); + systemDefinedAppItem1->GetBundleName(); + systemDefinedAppItem1->GetAbilityName(); + systemDefinedAppItem1->GetAppIconId(); + systemDefinedAppItem1->GetAppLabelId(); + data1.AddRecord(systemDefinedAppItem1); UdmfClient::GetInstance().SetData(option1, data1, key); SetNativeToken(); @@ -438,14 +430,13 @@ void SetDataSystemDefinedPixelMapFuzz(const uint8_t *data, size_t size) CustomOption option1 = {.intention = Intention::UD_INTENTION_DRAG}; UnifiedData data1; std::string key; - SystemDefinedPixelMap systemDefinedPixelMap1; + auto systemDefinedPixelMap1 = std::make_shared<SystemDefinedPixelMap>(); UDDetails details1; details1.insert({skey, svalue}); - systemDefinedPixelMap1.SetDetails(details1); + systemDefinedPixelMap1->SetDetails(details1); std::vector<uint8_t> rawData1 = {1, 2, 3, 4, 5}; - systemDefinedPixelMap1.SetRawData(rawData1); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedPixelMap>(systemDefinedPixelMap1); - data1.AddRecord(record1); + systemDefinedPixelMap1->SetRawData(rawData1); + data1.AddRecord(systemDefinedPixelMap1); UdmfClient::GetInstance().SetData(option1, data1, key); SetNativeToken(); @@ -473,45 +464,39 @@ void GetSummaryFuzz(const uint8_t *data, size_t size) UDDetails details; details.insert({skey, svalue}); - Text text; - text.SetDetails(details); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Text>(text); - UData.AddRecord(record1); - - PlainText plainText; - plainText.SetDetails(details); - plainText.SetContent(svalue + "content"); - plainText.SetAbstract(svalue + "abstract"); - std::shared_ptr<UnifiedRecord> record2 = std::make_shared<PlainText>(plainText); - UData.AddRecord(record2); - - File file; - file.SetUri(svalue + "uri"); - file.SetRemoteUri(svalue + "remoteUri"); - std::shared_ptr<UnifiedRecord> record3 = std::make_shared<File>(file); - UData.AddRecord(record3); - - Image image; - image.SetUri(svalue + "uri"); - image.SetRemoteUri(svalue + "remoteUri"); - std::shared_ptr<UnifiedRecord> record4 = std::make_shared<Image>(image); - UData.AddRecord(record4); - - SystemDefinedRecord systemDefinedRecord; - systemDefinedRecord.SetDetails(details); - std::shared_ptr<UnifiedRecord> record5 = std::make_shared<SystemDefinedRecord>(systemDefinedRecord); - UData.AddRecord(record5); - - SystemDefinedForm systemDefinedForm; - systemDefinedForm.SetDetails(details); + auto text = std::make_shared<Text>(); + text->SetDetails(details); + UData.AddRecord(text); + + auto plainText = std::make_shared<PlainText>(); + plainText->SetDetails(details); + plainText->SetContent(svalue + "content"); + plainText->SetAbstract(svalue + "abstract"); + UData.AddRecord(plainText); + + auto file = std::make_shared<File>(); + file->SetUri(svalue + "uri"); + file->SetRemoteUri(svalue + "remoteUri"); + UData.AddRecord(file); + + auto image = std::make_shared<Image>(); + image->SetUri(svalue + "uri"); + image->SetRemoteUri(svalue + "remoteUri"); + UData.AddRecord(image); + + auto systemDefinedRecord = std::make_shared<SystemDefinedRecord>(); + systemDefinedRecord->SetDetails(details); + UData.AddRecord(systemDefinedRecord); + + auto systemDefinedForm = std::make_shared<SystemDefinedForm>(); + systemDefinedForm->SetDetails(details); auto formId = 123; - systemDefinedForm.SetFormId(formId); - systemDefinedForm.SetFormName(svalue + "formName"); - systemDefinedForm.SetModule(svalue + "module"); - systemDefinedForm.SetAbilityName(svalue + "abilityName"); - systemDefinedForm.SetBundleName(svalue + "bundleName"); - std::shared_ptr<UnifiedRecord> record6 = std::make_shared<SystemDefinedForm>(systemDefinedForm); - UData.AddRecord(record6); + systemDefinedForm->SetFormId(formId); + systemDefinedForm->SetFormName(svalue + "formName"); + systemDefinedForm->SetModule(svalue + "module"); + systemDefinedForm->SetAbilityName(svalue + "abilityName"); + systemDefinedForm->SetBundleName(svalue + "bundleName"); + UData.AddRecord(systemDefinedForm); UdmfClient::GetInstance().SetData(option1, UData, key); @@ -528,9 +513,8 @@ void GetBatchDataByKeyFuzz(const uint8_t *data, size_t size) CustomOption option1 = { .intention = UD_INTENTION_DATA_HUB }; UnifiedData data1; std::string key; - PlainText plainText(skey, skey); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText); - data1.AddRecord(record1); + auto plainText = std::make_shared<PlainText>(); + data1.AddRecord(plainText); UdmfClient::GetInstance().SetData(option1, data1, key); SetHapToken(); @@ -550,9 +534,8 @@ void GetBatchDataByIntentionFuzz(const uint8_t *data, size_t size) CustomOption option1 = { .intention = UD_INTENTION_DATA_HUB }; UnifiedData data1; std::string key; - PlainText plainText(skey, skey); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText); - data1.AddRecord(record1); + auto plainText = std::make_shared<PlainText>(); + data1.AddRecord(plainText); UdmfClient::GetInstance().SetData(option1, data1, key); SetHapToken(); @@ -568,9 +551,8 @@ void DeleteDataByKeyFuzz(const uint8_t *data, size_t size) CustomOption option1 = { .intention = UD_INTENTION_DATA_HUB }; UnifiedData data1; std::string key; - PlainText plainText(skey, skey); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText); - data1.AddRecord(record1); + auto plainText = std::make_shared<PlainText>(); + data1.AddRecord(plainText); UdmfClient::GetInstance().SetData(option1, data1, key); SetHapToken(); @@ -590,9 +572,8 @@ void DeleteDataByIntentionFuzz(const uint8_t *data, size_t size) CustomOption option1 = { .intention = UD_INTENTION_DATA_HUB }; UnifiedData data1; std::string key; - PlainText plainText(skey, skey); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText); - data1.AddRecord(record1); + auto plainText = std::make_shared<PlainText>(); + data1.AddRecord(plainText); UdmfClient::GetInstance().SetData(option1, data1, key); SetHapToken(); @@ -608,64 +589,61 @@ void UpdateDataFuzz(const uint8_t *data, size_t size) CustomOption option1 = { .intention = UD_INTENTION_DATA_HUB }; UnifiedData data1; std::string key; - PlainText plainText(skey, skey); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText); - data1.AddRecord(record1); + auto plainText = std::make_shared<PlainText>(); + data1.AddRecord(plainText); UdmfClient::GetInstance().SetData(option1, data1, key); SetHapToken(); UnifiedData data2; - PlainText plainText2(skey + "2", skey + "2"); - record1 = std::make_shared<PlainText>(plainText2); - data2.AddRecord(record1); + data2.AddRecord(plainText); QueryOption option2 = { .key = key }; UdmfClient::GetInstance().UpdateData(option2, data2); SetHapToken(); UnifiedData data3; - PlainText plainText3(skey + "3", skey + "3"); - record1 = std::make_shared<PlainText>(plainText3); - data3.AddRecord(record1); + data3.AddRecord(plainText); QueryOption option3 = { .key = skey }; UdmfClient::GetInstance().UpdateData(option3, data3); } -void GetDataAsyncByKeyFuzz(const uint8_t *data, size_t size) +void StartAsyncDataRetrievalFuzz(const uint8_t *data, size_t size) { - std::string skey(data, data + size); CustomOption option1 = { .intention = UD_INTENTION_DATA_HUB }; UnifiedData data1; std::string key; - PlainText plainText(skey, skey); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText); - data1.AddRecord(record1); + auto plainText = std::make_shared<PlainText>(); + std::string content(data, data + size); + plainText->SetContent(content); + data1.AddRecord(plainText); UdmfClient::GetInstance().SetData(option1, data1, key); - SetHapToken(); - QueryOption option2 = { .key = skey }; - auto callback = [](ProgressInfo progress, UnifiedData &outputData) { - }; - UdmfClient::GetInstance().GetDataAsync(option2, callback); + QueryOption query = {.key = key, .intention = UDMF::UD_INTENTION_DRAG}; + GetDataParams params = {.query = query}; + params.progressIndicator = ProgressIndicator::DEFAULT; + params.progressListener = [](ProgressInfo progressInfo, std::shared_ptr<UnifiedData> data) {}; + UdmfAsyncClient::GetInstance().StartAsyncDataRetrieval(params); std::this_thread::sleep_for(std::chrono::seconds(1)); } -void GetDataAsyncByIntentionFuzz(const uint8_t *data, size_t size) +void CancelAsyncDataRetrievalFuzz(const uint8_t *data, size_t size) { - std::string skey(data, data + size); CustomOption option1 = { .intention = UD_INTENTION_DATA_HUB }; UnifiedData data1; std::string key; - PlainText plainText(skey, skey); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText); - data1.AddRecord(record1); + auto plainText = std::make_shared<PlainText>(); + std::string content(data, data + size); + plainText->SetContent(content); + data1.AddRecord(plainText); UdmfClient::GetInstance().SetData(option1, data1, key); - SetHapToken(); - Intention intention = UnifiedDataUtils::GetIntentionByString(skey); - QueryOption option2 = { .intention = intention }; - auto callback = [](ProgressInfo progress, UnifiedData &outputData) { + QueryOption query = {.key = key, .intention = UDMF::UD_INTENTION_DRAG}; + GetDataParams params = {.query = query}; + params.progressIndicator = ProgressIndicator::NONE; + params.progressListener = [](ProgressInfo progressInfo, std::shared_ptr<UnifiedData> data) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); }; - UdmfClient::GetInstance().GetDataAsync(option2, callback); + UdmfAsyncClient::GetInstance().StartAsyncDataRetrieval(params); + UdmfAsyncClient::GetInstance().Cancel(key); std::this_thread::sleep_for(std::chrono::seconds(1)); } } @@ -692,8 +670,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) OHOS::DeleteDataByKeyFuzz(data, size); OHOS::DeleteDataByIntentionFuzz(data, size); OHOS::UpdateDataFuzz(data, size); + OHOS::StartAsyncDataRetrievalFuzz(data, size); + OHOS::CancelAsyncDataRetrievalFuzz(data, size); OHOS::TearDown(); - OHOS::GetDataAsyncByKeyFuzz(data, size); - OHOS::GetDataAsyncByIntentionFuzz(data, size); return 0; } \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/test/unittest/BUILD.gn b/udmf/framework/innerkitsimpl/test/unittest/BUILD.gn index 974e0568cad5d4eb458dbebab1ddf12bc47eeda5..8a7fcd328d7efbc835da5a3fcec8ca756eabdccf 100644 --- a/udmf/framework/innerkitsimpl/test/unittest/BUILD.gn +++ b/udmf/framework/innerkitsimpl/test/unittest/BUILD.gn @@ -67,7 +67,6 @@ ohos_unittest("UdmfClientTest") { sources = [ "${udmf_framework_path}/common/graph.cpp", - "${udmf_framework_path}/innerkitsimpl/client/async_obtain_data.cpp", "${udmf_framework_path}/innerkitsimpl/convert/udmf_conversion.cpp", "${udmf_framework_path}/innerkitsimpl/service/udmf_service_proxy.cpp", "udmf_client_test.cpp", @@ -97,6 +96,47 @@ ohos_unittest("UdmfClientSystemHapTest") { external_deps = common_external_deps } +ohos_unittest("UdmfClientHapPermissionTest") { + module_out_path = module_output_path + + sources = [ "udmf_client_hap_permission_test.cpp" ] + + include_dirs = [ + "${udmf_interfaces_path}/innerkits/client", + "${udmf_interfaces_path}/innerkits/common", + "${udmf_interfaces_path}/innerkits/data", + "${udmf_interfaces_path}/innerkits/convert", + "${udmf_framework_path}/common", + "${udmf_framework_path}/innerkits/service", + "${udmf_framework_path}/innerkitsimpl/client/", + "${udmf_framework_path}/innerkitsimpl/test/unittest/mock/include", + ] + + deps = common_deps + + external_deps = common_external_deps +} + +ohos_unittest("UdmfClientSaInvokeTest") { + module_out_path = module_output_path + + sources = [ "udmf_client_sa_invoke_test.cpp" ] + + deps = [ "${udmf_interfaces_path}/innerkits:udmf_client" ] + + external_deps = common_external_deps +} + +ohos_unittest("UdmfAsyncClientTest") { + module_out_path = module_output_path + + sources = [ "udmf_async_client_test.cpp" ] + + deps = common_deps + + external_deps = common_external_deps +} + ohos_unittest("UtdClientTest") { module_out_path = module_output_path @@ -429,7 +469,6 @@ ohos_unittest("UdmfClientAbnormalTest") { "${udmf_framework_path}/common/udmf_radar_reporter.cpp", "${udmf_framework_path}/common/udmf_types_util.cpp", "${udmf_framework_path}/common/udmf_utils.cpp", - "${udmf_framework_path}/innerkitsimpl/client/async_obtain_data.cpp", "${udmf_framework_path}/innerkitsimpl/client/udmf_client.cpp", "${udmf_framework_path}/innerkitsimpl/common/unified_key.cpp", "${udmf_framework_path}/innerkitsimpl/common/unified_meta.cpp", @@ -492,7 +531,10 @@ group("unittest") { ":SystemDefinedPixelMapTest", ":SystemDefinedRecordTest", ":TextTest", + ":UdmfAsyncClientTest", ":UdmfClientAbnormalTest", + ":UdmfClientHapPermissionTest", + ":UdmfClientSaInvokeTest", ":UdmfClientSystemHapTest", ":UdmfClientTest", ":UnifiedDataHelperTest", diff --git a/udmf/framework/innerkitsimpl/test/unittest/image_test.cpp b/udmf/framework/innerkitsimpl/test/unittest/image_test.cpp index 20e65aa1e6488b63bdd6347b18164eccbf1ad196..043cf3b7ed5be792a9b7aa47b17ffe88bc1b2e2d 100644 --- a/udmf/framework/innerkitsimpl/test/unittest/image_test.cpp +++ b/udmf/framework/innerkitsimpl/test/unittest/image_test.cpp @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#define LOG_TAG "ApplicationUtdJsonParserTest" +#define LOG_TAG "ImageTest" #include <unistd.h> #include <gtest/gtest.h> diff --git a/udmf/framework/innerkitsimpl/test/unittest/link_test.cpp b/udmf/framework/innerkitsimpl/test/unittest/link_test.cpp index 420152eec4c71aadc20476f9d6a8b5a57e2562ea..a7eb33662fe45a5005387a275dcead7653899e3b 100644 --- a/udmf/framework/innerkitsimpl/test/unittest/link_test.cpp +++ b/udmf/framework/innerkitsimpl/test/unittest/link_test.cpp @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#define LOG_TAG "ApplicationUtdJsonParserTest" +#define LOG_TAG "LinkTest" #include <unistd.h> #include <gtest/gtest.h> diff --git a/udmf/framework/innerkitsimpl/test/unittest/mock/include/udmf_service_client_mock.h b/udmf/framework/innerkitsimpl/test/unittest/mock/include/udmf_service_client_mock.h index 4ee008d7d5a0d20cc6f92f4ce3d901f66e0d4b98..db9c45a508165d9a029e08b6b03b78afec7dc7fa 100644 --- a/udmf/framework/innerkitsimpl/test/unittest/mock/include/udmf_service_client_mock.h +++ b/udmf/framework/innerkitsimpl/test/unittest/mock/include/udmf_service_client_mock.h @@ -42,7 +42,7 @@ public: virtual int32_t GetAppShareOption(const std::string &, int32_t &) = 0; virtual int32_t RemoveAppShareOption(const std::string &) = 0; virtual int32_t ObtainAsynProcess(AsyncProcessInfo&) = 0; - virtual int32_t ClearAsynProcess() = 0; + virtual int32_t ClearAsynProcessByKey(const std::string &businessUdKey) = 0; public: static inline std::shared_ptr<MUdmfServiceClient> udmfServiceClient = nullptr; }; @@ -63,7 +63,7 @@ public: MOCK_METHOD(int32_t, GetAppShareOption, (const std::string &, int32_t &)); MOCK_METHOD(int32_t, RemoveAppShareOption, (const std::string &)); MOCK_METHOD(int32_t, ObtainAsynProcess, (AsyncProcessInfo&)); - MOCK_METHOD(int32_t, ClearAsynProcess, ()); + MOCK_METHOD(int32_t, ClearAsynProcessByKey, (const std::string &)); }; } // namespace UDMF } // namespace OHOS diff --git a/udmf/framework/innerkitsimpl/test/unittest/mock/udmf_service_client_mock.cpp b/udmf/framework/innerkitsimpl/test/unittest/mock/udmf_service_client_mock.cpp index e906556bb7ec9660dd801923e08217a6b21728bd..9239fa589d56556085ec1de86f59fd6680042c7a 100644 --- a/udmf/framework/innerkitsimpl/test/unittest/mock/udmf_service_client_mock.cpp +++ b/udmf/framework/innerkitsimpl/test/unittest/mock/udmf_service_client_mock.cpp @@ -107,12 +107,12 @@ int32_t UdmfServiceClient::Sync(const QueryOption &query, const std::vector<std: } } -int32_t UdmfServiceClient::ClearAsynProcess() +int32_t UdmfServiceClient::ClearAsynProcessByKey(const std::string &businessUdKey) { if (MUdmfServiceClient::udmfServiceClient == nullptr) { return -1; } else { - return MUdmfServiceClient::udmfServiceClient->ClearAsynProcess(); + return MUdmfServiceClient::udmfServiceClient->ClearAsynProcessByKey(businessUdKey); } } diff --git a/udmf/framework/innerkitsimpl/test/unittest/ndk_data_conversion_test.cpp b/udmf/framework/innerkitsimpl/test/unittest/ndk_data_conversion_test.cpp index 3ccf608df6cc98b872366f8969e36059b8088584..082398dbe30d57a335d04c2a8f00172f8f11a42a 100644 --- a/udmf/framework/innerkitsimpl/test/unittest/ndk_data_conversion_test.cpp +++ b/udmf/framework/innerkitsimpl/test/unittest/ndk_data_conversion_test.cpp @@ -152,12 +152,11 @@ void NdkDataConversionTest::SetHapToken1() HWTEST_F(NdkDataConversionTest, GetNativeUnifiedData_001, TestSize.Level1) { LOG_INFO(UDMF_TEST, "GetNativeUnifiedData_001 begin."); - UnifiedRecord unifiedRecord; + auto unifiedRecord = std::make_shared<UnifiedRecord>(); const std::string uid("typeId"); - unifiedRecord.SetUid(uid); + unifiedRecord->SetUid(uid); OH_UdmfData *ndkData = OH_UdmfData_Create(); - const std::shared_ptr<UnifiedRecord> recordPtr = std::make_shared<UnifiedRecord>(unifiedRecord); - ndkData->unifiedData_->AddRecord(recordPtr); + ndkData->unifiedData_->AddRecord(unifiedRecord); auto data = std::make_shared<UnifiedData>(); Status status = NdkDataConversion::GetNativeUnifiedData(ndkData, data); @@ -200,12 +199,11 @@ HWTEST_F(NdkDataConversionTest, GetNativeUnifiedData_002, TestSize.Level1) HWTEST_F(NdkDataConversionTest, GetNdkUnifiedData_001, TestSize.Level1) { LOG_INFO(UDMF_TEST, "GetNdkUnifiedData_001 begin."); - UnifiedRecord unifiedRecord; + auto unifiedRecord = std::make_shared<UnifiedRecord>(); const std::string uid("typeId"); - unifiedRecord.SetUid(uid); - const std::shared_ptr<UnifiedRecord> recordPtr = std::make_shared<UnifiedRecord>(unifiedRecord); + unifiedRecord->SetUid(uid); auto data = std::make_shared<UnifiedData>(); - data->AddRecord(recordPtr); + data->AddRecord(unifiedRecord); OH_UdmfData *ndkData = OH_UdmfData_Create(); Status status = NdkDataConversion::GetNdkUnifiedData(data, ndkData); ASSERT_EQ(E_OK, status); diff --git a/udmf/framework/innerkitsimpl/test/unittest/udmf_client_system_hap_test.cpp b/udmf/framework/innerkitsimpl/test/unittest/udmf_client_system_hap_test.cpp index 84532d170adc70775ded648a13e6c0f18c21ccba..3cc9b3715cbb0f1f7f41ea52c8e8d3d3f9849a1d 100644 --- a/udmf/framework/innerkitsimpl/test/unittest/udmf_client_system_hap_test.cpp +++ b/udmf/framework/innerkitsimpl/test/unittest/udmf_client_system_hap_test.cpp @@ -264,10 +264,9 @@ HWTEST_F(UdmfClientSystemHapTest, systemAppSetData001, TestSize.Level1) CustomOption customOption = { .intention = UD_INTENTION_DRAG }; UnifiedData data; - PlainText plainText; - plainText.SetContent("systemApptestcontent1"); - std::shared_ptr<UnifiedRecord> record = std::make_shared<PlainText>(plainText); - data.AddRecord(record); + auto plainText = std::make_shared<PlainText>(); + plainText->SetContent("systemApptestcontent1"); + data.AddRecord(plainText); std::string key; status = UdmfClient::GetInstance().SetData(customOption, data, key); ASSERT_EQ(status, E_OK); @@ -305,10 +304,9 @@ HWTEST_F(UdmfClientSystemHapTest, systemAppSetData002, TestSize.Level1) LOG_INFO(UDMF_TEST, "systemAppSetData002 SetAppShareOption success."); CustomOption customOption = { .intention = UD_INTENTION_DRAG }; UnifiedData data; - PlainText plainText; - plainText.SetContent("systemApptestcontent1"); - std::shared_ptr<UnifiedRecord> record = std::make_shared<PlainText>(plainText); - data.AddRecord(record); + auto plainText = std::make_shared<PlainText>(); + plainText->SetContent("systemApptestcontent1"); + data.AddRecord(plainText); std::string key; status = UdmfClient::GetInstance().SetData(customOption, data, key); ASSERT_EQ(status, E_OK); diff --git a/udmf/framework/innerkitsimpl/test/unittest/udmf_client_test.cpp b/udmf/framework/innerkitsimpl/test/unittest/udmf_client_test.cpp index bd3a3df79cd8532cb1805ce88aa95c0e32a7f9cc..415c5ef3f16d058c749ee15ea9dca83ece6efe81 100644 --- a/udmf/framework/innerkitsimpl/test/unittest/udmf_client_test.cpp +++ b/udmf/framework/innerkitsimpl/test/unittest/udmf_client_test.cpp @@ -237,12 +237,11 @@ HWTEST_F(UdmfClientTest, SetData001, TestSize.Level1) EXPECT_EQ(status, E_INVALID_PARAMETERS); option = { .intention = Intention::UD_INTENTION_BUTT }; - Text text; + auto text = std::make_shared<Text>(); UDDetails details; details.insert({ "udmf_key", "udmf_value" }); - text.SetDetails(details); - std::shared_ptr<UnifiedRecord> record = std::make_shared<Text>(text); - data.AddRecord(record); + text->SetDetails(details); + data.AddRecord(text); status = UdmfClient::GetInstance().SetData(option, data, key); EXPECT_EQ(status, E_INVALID_PARAMETERS); @@ -267,12 +266,11 @@ HWTEST_F(UdmfClientTest, SetData002, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; - Text text1; + auto text1 = std::make_shared<Text>(); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); - text1.SetDetails(details1); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Text>(text1); - data1.AddRecord(record1); + text1->SetDetails(details1); + data1.AddRecord(text1); std::string key; auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -309,14 +307,13 @@ HWTEST_F(UdmfClientTest, SetData003, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; - PlainText plainText1; + auto plainText1 = std::make_shared<PlainText>(); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); - plainText1.SetDetails(details1); - plainText1.SetContent("content"); - plainText1.SetAbstract("abstract"); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText1); - data1.AddRecord(record1); + plainText1->SetDetails(details1); + plainText1->SetContent("content"); + plainText1->SetAbstract("abstract"); + data1.AddRecord(plainText1); std::string key; auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -339,8 +336,8 @@ HWTEST_F(UdmfClientTest, SetData003, TestSize.Level1) auto plainText2 = static_cast<PlainText *>(record2.get()); ASSERT_NE(plainText2, nullptr); - EXPECT_EQ(plainText1.GetContent(), plainText2->GetContent()); - EXPECT_EQ(plainText1.GetAbstract(), plainText2->GetAbstract()); + EXPECT_EQ(plainText1->GetContent(), plainText2->GetContent()); + EXPECT_EQ(plainText1->GetAbstract(), plainText2->GetAbstract()); GetEmptyData(option2); @@ -359,14 +356,13 @@ HWTEST_F(UdmfClientTest, SetData004, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; std::string key; - Html html1; + auto html1 = std::make_shared<Html>(); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); - html1.SetDetails(details1); - html1.SetHtmlContent("htmlcontent"); - html1.SetPlainContent("plainContent"); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Html>(html1); - data1.AddRecord(record1); + html1->SetDetails(details1); + html1->SetHtmlContent("htmlcontent"); + html1->SetPlainContent("plainContent"); + data1.AddRecord(html1); auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -388,8 +384,8 @@ HWTEST_F(UdmfClientTest, SetData004, TestSize.Level1) auto html2 = static_cast<Html *>(record2.get()); ASSERT_NE(html2, nullptr); - EXPECT_EQ(html1.GetHtmlContent(), html2->GetHtmlContent()); - EXPECT_EQ(html1.GetPlainContent(), html2->GetPlainContent()); + EXPECT_EQ(html1->GetHtmlContent(), html2->GetHtmlContent()); + EXPECT_EQ(html1->GetPlainContent(), html2->GetPlainContent()); GetEmptyData(option2); @@ -408,14 +404,13 @@ HWTEST_F(UdmfClientTest, SetData005, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; std::string key; - Link link1; + auto link1 = std::make_shared<Link>(); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); - link1.SetDetails(details1); - link1.SetUrl("url"); - link1.SetDescription("description"); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Link>(link1); - data1.AddRecord(record1); + link1->SetDetails(details1); + link1->SetUrl("url"); + link1->SetDescription("description"); + data1.AddRecord(link1); auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -437,8 +432,8 @@ HWTEST_F(UdmfClientTest, SetData005, TestSize.Level1) auto link2 = static_cast<Link *>(record2.get()); ASSERT_NE(link2, nullptr); - EXPECT_EQ(link1.GetUrl(), link2->GetUrl()); - EXPECT_EQ(link1.GetDescription(), link2->GetDescription()); + EXPECT_EQ(link1->GetUrl(), link2->GetUrl()); + EXPECT_EQ(link1->GetDescription(), link2->GetDescription()); GetEmptyData(option2); @@ -457,13 +452,12 @@ HWTEST_F(UdmfClientTest, SetData006, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; std::string key; - File file1; - file1.SetRemoteUri("remoteUri"); + auto file1 = std::make_shared<File>(); + file1->SetRemoteUri("remoteUri"); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); - file1.SetDetails(details1); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<File>(file1); - data1.AddRecord(record1); + file1->SetDetails(details1); + data1.AddRecord(file1); auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -481,7 +475,7 @@ HWTEST_F(UdmfClientTest, SetData006, TestSize.Level1) auto file2 = static_cast<File *>(record2.get()); ASSERT_NE(file2, nullptr); - EXPECT_EQ(file1.GetRemoteUri(), file2->GetRemoteUri()); + EXPECT_EQ(file1->GetRemoteUri(), file2->GetRemoteUri()); CompareDetails(file2->GetDetails()); GetEmptyData(option2); @@ -501,13 +495,12 @@ HWTEST_F(UdmfClientTest, SetData007, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; std::string key; - Image image1; + auto image1 = std::make_shared<Image>(); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); - image1.SetDetails(details1); - image1.SetRemoteUri("remoteUri"); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Image>(image1); - data1.AddRecord(record1); + image1->SetDetails(details1); + image1->SetRemoteUri("remoteUri"); + data1.AddRecord(image1); auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -529,7 +522,7 @@ HWTEST_F(UdmfClientTest, SetData007, TestSize.Level1) auto image2 = static_cast<Image *>(record2.get()); ASSERT_NE(image2, nullptr); - EXPECT_EQ(image1.GetRemoteUri(), image2->GetRemoteUri()); + EXPECT_EQ(image1->GetRemoteUri(), image2->GetRemoteUri()); GetEmptyData(option2); @@ -548,13 +541,12 @@ HWTEST_F(UdmfClientTest, SetData008, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; std::string key; - Video video1; + auto video1 = std::make_shared<Video>(); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); - video1.SetDetails(details1); - video1.SetRemoteUri("remoteUri"); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Video>(video1); - data1.AddRecord(record1); + video1->SetDetails(details1); + video1->SetRemoteUri("remoteUri"); + data1.AddRecord(video1); auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -576,7 +568,7 @@ HWTEST_F(UdmfClientTest, SetData008, TestSize.Level1) auto video2 = static_cast<Video *>(record2.get()); ASSERT_NE(video2, nullptr); - EXPECT_EQ(video1.GetRemoteUri(), video2->GetRemoteUri()); + EXPECT_EQ(video1->GetRemoteUri(), video2->GetRemoteUri()); GetEmptyData(option2); @@ -595,13 +587,12 @@ HWTEST_F(UdmfClientTest, SetData009, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; std::string key; - Audio audio1; + auto audio1 = std::make_shared<Audio>(); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); - audio1.SetDetails(details1); - audio1.SetRemoteUri("remoteUri"); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Audio>(audio1); - data1.AddRecord(record1); + audio1->SetDetails(details1); + audio1->SetRemoteUri("remoteUri"); + data1.AddRecord(audio1); auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -623,7 +614,7 @@ HWTEST_F(UdmfClientTest, SetData009, TestSize.Level1) auto audio2 = static_cast<Audio *>(record2.get()); ASSERT_NE(audio2, nullptr); - EXPECT_EQ(audio1.GetRemoteUri(), audio2->GetRemoteUri()); + EXPECT_EQ(audio1->GetRemoteUri(), audio2->GetRemoteUri()); GetEmptyData(option2); @@ -642,13 +633,12 @@ HWTEST_F(UdmfClientTest, SetData010, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; std::string key; - Folder folder1; + auto folder1 = std::make_shared<Folder>(); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); - folder1.SetDetails(details1); - folder1.SetRemoteUri("remoteUri"); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Folder>(folder1); - data1.AddRecord(record1); + folder1->SetDetails(details1); + folder1->SetRemoteUri("remoteUri"); + data1.AddRecord(folder1); auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -670,7 +660,7 @@ HWTEST_F(UdmfClientTest, SetData010, TestSize.Level1) auto folder2 = static_cast<Folder *>(record2.get()); ASSERT_NE(folder2, nullptr); - EXPECT_EQ(folder1.GetRemoteUri(), folder2->GetRemoteUri()); + EXPECT_EQ(folder1->GetRemoteUri(), folder2->GetRemoteUri()); GetEmptyData(option2); @@ -689,12 +679,11 @@ HWTEST_F(UdmfClientTest, SetData011, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; std::string key; - SystemDefinedRecord systemDefinedRecord1; + auto systemDefinedRecord1 = std::make_shared<SystemDefinedRecord>(); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); - systemDefinedRecord1.SetDetails(details1); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedRecord>(systemDefinedRecord1); - data1.AddRecord(record1); + systemDefinedRecord1->SetDetails(details1); + data1.AddRecord(systemDefinedRecord1); auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -731,17 +720,16 @@ HWTEST_F(UdmfClientTest, SetData012, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; std::string key; - SystemDefinedForm systemDefinedForm1; + auto systemDefinedForm1 = std::make_shared<SystemDefinedForm>(); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); - systemDefinedForm1.SetDetails(details1); - systemDefinedForm1.SetFormId(123); - systemDefinedForm1.SetFormName("formName"); - systemDefinedForm1.SetModule("module"); - systemDefinedForm1.SetAbilityName("abilityName"); - systemDefinedForm1.SetBundleName("bundleName"); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedForm>(systemDefinedForm1); - data1.AddRecord(record1); + systemDefinedForm1->SetDetails(details1); + systemDefinedForm1->SetFormId(123); + systemDefinedForm1->SetFormName("formName"); + systemDefinedForm1->SetModule("module"); + systemDefinedForm1->SetAbilityName("abilityName"); + systemDefinedForm1->SetBundleName("bundleName"); + data1.AddRecord(systemDefinedForm1); auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -763,11 +751,11 @@ HWTEST_F(UdmfClientTest, SetData012, TestSize.Level1) auto systemDefinedForm2 = static_cast<SystemDefinedForm *>(record2.get()); ASSERT_NE(systemDefinedForm2, nullptr); - EXPECT_EQ(systemDefinedForm1.GetFormId(), systemDefinedForm2->GetFormId()); - EXPECT_EQ(systemDefinedForm1.GetFormName(), systemDefinedForm2->GetFormName()); - EXPECT_EQ(systemDefinedForm1.GetBundleName(), systemDefinedForm2->GetBundleName()); - EXPECT_EQ(systemDefinedForm1.GetAbilityName(), systemDefinedForm2->GetAbilityName()); - EXPECT_EQ(systemDefinedForm1.GetModule(), systemDefinedForm2->GetModule()); + EXPECT_EQ(systemDefinedForm1->GetFormId(), systemDefinedForm2->GetFormId()); + EXPECT_EQ(systemDefinedForm1->GetFormName(), systemDefinedForm2->GetFormName()); + EXPECT_EQ(systemDefinedForm1->GetBundleName(), systemDefinedForm2->GetBundleName()); + EXPECT_EQ(systemDefinedForm1->GetAbilityName(), systemDefinedForm2->GetAbilityName()); + EXPECT_EQ(systemDefinedForm1->GetModule(), systemDefinedForm2->GetModule()); GetEmptyData(option2); @@ -786,18 +774,17 @@ HWTEST_F(UdmfClientTest, SetData013, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; std::string key; - SystemDefinedAppItem systemDefinedAppItem1; + auto systemDefinedAppItem1 = std::make_shared<SystemDefinedAppItem>(); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); - systemDefinedAppItem1.SetDetails(details1); - systemDefinedAppItem1.SetAppId("appId"); - systemDefinedAppItem1.SetAppName("appName"); - systemDefinedAppItem1.SetAppIconId("appIconId"); - systemDefinedAppItem1.SetAppLabelId("appLabelId"); - systemDefinedAppItem1.SetBundleName("bundleName"); - systemDefinedAppItem1.SetAbilityName("abilityName"); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedAppItem>(systemDefinedAppItem1); - data1.AddRecord(record1); + systemDefinedAppItem1->SetDetails(details1); + systemDefinedAppItem1->SetAppId("appId"); + systemDefinedAppItem1->SetAppName("appName"); + systemDefinedAppItem1->SetAppIconId("appIconId"); + systemDefinedAppItem1->SetAppLabelId("appLabelId"); + systemDefinedAppItem1->SetBundleName("bundleName"); + systemDefinedAppItem1->SetAbilityName("abilityName"); + data1.AddRecord(systemDefinedAppItem1); auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -819,12 +806,12 @@ HWTEST_F(UdmfClientTest, SetData013, TestSize.Level1) auto systemDefinedAppItem2 = static_cast<SystemDefinedAppItem *>(record2.get()); ASSERT_NE(systemDefinedAppItem2, nullptr); - EXPECT_EQ(systemDefinedAppItem1.GetAppId(), systemDefinedAppItem2->GetAppId()); - EXPECT_EQ(systemDefinedAppItem1.GetAppName(), systemDefinedAppItem2->GetAppName()); - EXPECT_EQ(systemDefinedAppItem1.GetBundleName(), systemDefinedAppItem2->GetBundleName()); - EXPECT_EQ(systemDefinedAppItem1.GetAbilityName(), systemDefinedAppItem2->GetAbilityName()); - EXPECT_EQ(systemDefinedAppItem1.GetAppIconId(), systemDefinedAppItem2->GetAppIconId()); - EXPECT_EQ(systemDefinedAppItem1.GetAppLabelId(), systemDefinedAppItem2->GetAppLabelId()); + EXPECT_EQ(systemDefinedAppItem1->GetAppId(), systemDefinedAppItem2->GetAppId()); + EXPECT_EQ(systemDefinedAppItem1->GetAppName(), systemDefinedAppItem2->GetAppName()); + EXPECT_EQ(systemDefinedAppItem1->GetBundleName(), systemDefinedAppItem2->GetBundleName()); + EXPECT_EQ(systemDefinedAppItem1->GetAbilityName(), systemDefinedAppItem2->GetAbilityName()); + EXPECT_EQ(systemDefinedAppItem1->GetAppIconId(), systemDefinedAppItem2->GetAppIconId()); + EXPECT_EQ(systemDefinedAppItem1->GetAppLabelId(), systemDefinedAppItem2->GetAppLabelId()); GetEmptyData(option2); @@ -843,10 +830,10 @@ HWTEST_F(UdmfClientTest, SetData014, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; std::string key; - SystemDefinedPixelMap systemDefinedPixelMap1; + auto systemDefinedPixelMap1 = std::make_shared<SystemDefinedPixelMap>(); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); - systemDefinedPixelMap1.SetDetails(details1); + systemDefinedPixelMap1->SetDetails(details1); std::vector<uint8_t> rawData1; uint32_t color[100] = { 3, 7, 9, 9, 7, 6 }; @@ -858,9 +845,8 @@ HWTEST_F(UdmfClientTest, SetData014, TestSize.Level1) std::shared_ptr<OHOS::Media::PixelMap> pixelMapIn = move(pixelMap); pixelMapIn->EncodeTlv(rawData1); - systemDefinedPixelMap1.SetRawData(rawData1); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedPixelMap>(systemDefinedPixelMap1); - data1.AddRecord(record1); + systemDefinedPixelMap1->SetRawData(rawData1); + data1.AddRecord(systemDefinedPixelMap1); auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -905,12 +891,11 @@ HWTEST_F(UdmfClientTest, SetData015, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; std::string key; - ApplicationDefinedRecord applicationDefinedRecord1; - applicationDefinedRecord1.SetApplicationDefinedType("applicationDefinedType"); + auto applicationDefinedRecord1 = std::make_shared<ApplicationDefinedRecord>(); + applicationDefinedRecord1->SetApplicationDefinedType("applicationDefinedType"); std::vector<uint8_t> rawData1 = { 1, 2, 3, 4, 5 }; - applicationDefinedRecord1.SetRawData(rawData1); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<ApplicationDefinedRecord>(applicationDefinedRecord1); - data1.AddRecord(record1); + applicationDefinedRecord1->SetRawData(rawData1); + data1.AddRecord(applicationDefinedRecord1); auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -928,7 +913,7 @@ HWTEST_F(UdmfClientTest, SetData015, TestSize.Level1) auto applicationDefinedRecord2 = static_cast<ApplicationDefinedRecord *>(record2.get()); ASSERT_NE(applicationDefinedRecord2, nullptr); - EXPECT_EQ(applicationDefinedRecord1.GetApplicationDefinedType(), + EXPECT_EQ(applicationDefinedRecord1->GetApplicationDefinedType(), applicationDefinedRecord2->GetApplicationDefinedType()); auto rawData2 = applicationDefinedRecord2->GetRawData(); EXPECT_EQ(rawData1.size(), rawData2.size()); @@ -1030,10 +1015,9 @@ HWTEST_F(UdmfClientTest, SetData018, TestSize.Level1) value += "11"; } details.insert({ value, value }); - Text text; - text.SetDetails(details); - std::shared_ptr<UnifiedRecord> record = std::make_shared<Text>(text); - inputData.AddRecord(record); + auto text = std::make_shared<Text>(); + text->SetDetails(details); + inputData.AddRecord(text); auto status = UdmfClient::GetInstance().SetData(customOption, inputData, key); ASSERT_EQ(status, E_OK); @@ -1066,10 +1050,9 @@ HWTEST_F(UdmfClientTest, SetData019, TestSize.Level1) } details.insert({ value, value }); details.insert({ "udmf_key", "udmf_value" }); - Text text; - text.SetDetails(details); - std::shared_ptr<UnifiedRecord> record = std::make_shared<Text>(text); - inputData.AddRecord(record); + auto text = std::make_shared<Text>(); + text->SetDetails(details); + inputData.AddRecord(text); UnifiedDataHelper::SetRootPath("/data/udmf_test/"); auto status = UdmfClient::GetInstance().SetData(customOption, inputData, key); @@ -1103,11 +1086,10 @@ HWTEST_F(UdmfClientTest, SetData020, TestSize.Level1) value += "11"; } details.insert({ value, value }); - Text text; - text.SetDetails(details); - std::shared_ptr<UnifiedRecord> record = std::make_shared<Text>(text); + auto text = std::make_shared<Text>(); + text->SetDetails(details); for (int i = 0; i < 2; ++i) { - inputData.AddRecord(record); + inputData.AddRecord(text); } auto status = UdmfClient::GetInstance().SetData(customOption, inputData, key); ASSERT_EQ(status, E_OK); @@ -1185,53 +1167,56 @@ HWTEST_F(UdmfClientTest, GetSummary001, TestSize.Level1) UDDetails details; details.insert({ "udmf_key", "udmf_value" }); - Text text; - text.SetDetails(details); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Text>(text); - data.AddRecord(record1); - - PlainText plainText; - plainText.SetDetails(details); - plainText.SetContent("content"); - plainText.SetAbstract("abstract"); - std::shared_ptr<UnifiedRecord> record2 = std::make_shared<PlainText>(plainText); - data.AddRecord(record2); - - File file; - file.SetDetails(details); - file.SetUri("uri"); - file.SetRemoteUri("remoteUri"); - std::shared_ptr<UnifiedRecord> record3 = std::make_shared<File>(file); - data.AddRecord(record3); - - Image image; - file.SetDetails(details); - image.SetUri("uri"); - image.SetRemoteUri("remoteUri"); - std::shared_ptr<UnifiedRecord> record4 = std::make_shared<Image>(image); - data.AddRecord(record4); - - SystemDefinedRecord systemDefinedRecord; - systemDefinedRecord.SetDetails(details); - std::shared_ptr<UnifiedRecord> record5 = std::make_shared<SystemDefinedRecord>(systemDefinedRecord); - data.AddRecord(record5); - - SystemDefinedForm systemDefinedForm; - systemDefinedForm.SetDetails(details); - systemDefinedForm.SetFormId(123); - systemDefinedForm.SetFormName("formName"); - systemDefinedForm.SetModule("module"); - systemDefinedForm.SetAbilityName("abilityName"); - systemDefinedForm.SetBundleName("bundleName"); - std::shared_ptr<UnifiedRecord> record6 = std::make_shared<SystemDefinedForm>(systemDefinedForm); - data.AddRecord(record6); - - ApplicationDefinedRecord applicationDefinedRecord; - applicationDefinedRecord.SetApplicationDefinedType("applicationDefinedType"); + auto text = std::make_shared<Text>(); + text->SetDetails(details); + data.AddRecord(text); + + auto plainText = std::make_shared<PlainText>(); + plainText->SetDetails(details); + plainText->SetContent("content"); + plainText->SetAbstract("abstract"); + data.AddRecord(plainText); + + auto file = std::make_shared<File>(); + file->SetDetails(details); + file->SetUri("uri"); + file->SetRemoteUri("remoteUri"); + data.AddRecord(file); + + auto image = std::make_shared<Image>(); + file->SetDetails(details); + image->SetUri("uri"); + image->SetRemoteUri("remoteUri"); + data.AddRecord(image); + + auto systemDefinedRecord = std::make_shared<SystemDefinedRecord>(); + systemDefinedRecord->SetDetails(details); + data.AddRecord(systemDefinedRecord); + + auto systemDefinedForm = std::make_shared<SystemDefinedForm>(); + systemDefinedForm->SetDetails(details); + systemDefinedForm->SetFormId(123); + systemDefinedForm->SetFormName("formName"); + systemDefinedForm->SetModule("module"); + systemDefinedForm->SetAbilityName("abilityName"); + systemDefinedForm->SetBundleName("bundleName"); + data.AddRecord(systemDefinedForm); + + auto applicationDefinedRecord = std::make_shared<ApplicationDefinedRecord>(); + applicationDefinedRecord->SetApplicationDefinedType("applicationDefinedType"); std::vector<uint8_t> rawData = { 1, 2, 3, 4, 5 }; - applicationDefinedRecord.SetRawData(rawData); - std::shared_ptr<UnifiedRecord> record7 = std::make_shared<ApplicationDefinedRecord>(applicationDefinedRecord); - data.AddRecord(record7); + applicationDefinedRecord->SetRawData(rawData); + data.AddRecord(applicationDefinedRecord); + + std::shared_ptr<Object> obj = std::make_shared<Object>(); + obj->value_[UNIFORM_DATA_TYPE] = "general.file-uri"; + obj->value_[FILE_URI_PARAM] = "http://demo.com"; + obj->value_[FILE_TYPE] = "abcdefg"; + auto record8 = std::make_shared<UnifiedRecord>(FILE_URI, obj); + data.AddRecord(record8); + + auto record9 = std::make_shared<UnifiedRecord>(PNG, "http://demo.com"); + data.AddRecord(record9); auto status = UdmfClient::GetInstance().SetData(option1, data, key); ASSERT_EQ(status, E_OK); @@ -1240,23 +1225,27 @@ HWTEST_F(UdmfClientTest, GetSummary001, TestSize.Level1) Summary summary; status = UdmfClient::GetInstance().GetSummary(option2, summary); - auto size = record1->GetSize(); - size += record2->GetSize(); - size += record3->GetSize(); - size += record4->GetSize(); - size += record5->GetSize(); - size += record6->GetSize(); - size += record7->GetSize(); - - ASSERT_EQ(status, E_OK); - ASSERT_EQ(summary.totalSize, size); - ASSERT_EQ(summary.summary["general.text"], record1->GetSize()); - ASSERT_EQ(summary.summary["general.plain-text"], record2->GetSize()); - ASSERT_EQ(summary.summary["general.file"], record3->GetSize()); - ASSERT_EQ(summary.summary["general.image"], record4->GetSize()); - ASSERT_EQ(summary.summary["SystemDefinedType"], record5->GetSize()); - ASSERT_EQ(summary.summary["openharmony.form"], record6->GetSize()); - ASSERT_EQ(summary.summary["ApplicationDefinedType"], record7->GetSize()); + auto size = text->GetSize(); + size += plainText->GetSize(); + size += file->GetSize(); + size += image->GetSize(); + size += systemDefinedRecord->GetSize(); + size += systemDefinedForm->GetSize(); + size += applicationDefinedRecord->GetSize(); + size += record8->GetSize(); + size += record9->GetSize(); + + EXPECT_EQ(status, E_OK); + EXPECT_EQ(summary.totalSize, size); + EXPECT_EQ(summary.summary["general.text"], text->GetSize()); + EXPECT_EQ(summary.summary["general.plain-text"], plainText->GetSize()); + EXPECT_EQ(summary.summary["general.file"], file->GetSize()); + EXPECT_EQ(summary.summary["general.image"], image->GetSize()); + EXPECT_EQ(summary.summary["SystemDefinedType"], systemDefinedRecord->GetSize()); + EXPECT_EQ(summary.summary["openharmony.form"], systemDefinedForm->GetSize()); + EXPECT_EQ(summary.summary["ApplicationDefinedType"], applicationDefinedRecord->GetSize()); + EXPECT_EQ(summary.summary["general.file-uri"], record8->GetSize()); + EXPECT_EQ(summary.summary["general.png"], record9->GetSize()); LOG_INFO(UDMF_TEST, "GetSummary001 end."); } @@ -1322,12 +1311,11 @@ HWTEST_F(UdmfClientTest, AddPrivilege001, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data; - Text text; + auto text = std::make_shared<Text>(); UDDetails details; details.insert({ "udmf_key", "udmf_value" }); - text.SetDetails(details); - std::shared_ptr<UnifiedRecord> record = std::make_shared<Text>(text); - data.AddRecord(record); + text->SetDetails(details); + data.AddRecord(text); std::string key; auto status = UdmfClient::GetInstance().SetData(option1, data, key); ASSERT_EQ(status, E_OK); @@ -1405,12 +1393,11 @@ HWTEST_F(UdmfClientTest, AddPrivilege003, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DATA_HUB }; UnifiedData data; - Text text; + auto text = std::make_shared<Text>(); UDDetails details; details.insert({ "udmf_key", "udmf_value" }); - text.SetDetails(details); - std::shared_ptr<UnifiedRecord> record = std::make_shared<Text>(text); - data.AddRecord(record); + text->SetDetails(details); + data.AddRecord(text); std::string key; auto status = UdmfClient::GetInstance().SetData(option1, data, key); ASSERT_EQ(status, E_OK); @@ -1438,12 +1425,11 @@ HWTEST_F(UdmfClientTest, AddPrivilege004, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data; - Text text; + auto text = std::make_shared<Text>(); UDDetails details; details.insert({ "udmf_key", "udmf_value" }); - text.SetDetails(details); - std::shared_ptr<UnifiedRecord> record = std::make_shared<Text>(text); - data.AddRecord(record); + text->SetDetails(details); + data.AddRecord(text); std::string key; auto status = UdmfClient::GetInstance().SetData(option1, data, key); ASSERT_EQ(status, E_OK); @@ -1471,12 +1457,11 @@ HWTEST_F(UdmfClientTest, AddPrivilege005, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data; - Text text; + auto text = std::make_shared<Text>(); UDDetails details; details.insert({ "udmf_key", "udmf_value" }); - text.SetDetails(details); - std::shared_ptr<UnifiedRecord> record = std::make_shared<Text>(text); - data.AddRecord(record); + text->SetDetails(details); + data.AddRecord(text); std::string key; auto status = UdmfClient::GetInstance().SetData(option1, data, key); ASSERT_EQ(status, E_OK); @@ -1522,13 +1507,12 @@ HWTEST_F(UdmfClientTest, GetSelfData001, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; std::string key; - File file1; - file1.SetRemoteUri("remoteUri"); + auto file1 = std::make_shared<File>(); + file1->SetRemoteUri("remoteUri"); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); - file1.SetDetails(details1); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<File>(file1); - data1.AddRecord(record1); + file1->SetDetails(details1); + data1.AddRecord(file1); auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -1544,7 +1528,7 @@ HWTEST_F(UdmfClientTest, GetSelfData001, TestSize.Level1) auto file2 = static_cast<File *>(record2.get()); ASSERT_NE(file2, nullptr); - EXPECT_EQ(file1.GetRemoteUri(), file2->GetRemoteUri()); + EXPECT_EQ(file1->GetRemoteUri(), file2->GetRemoteUri()); CompareDetails(file2->GetDetails()); GetEmptyData(option2); @@ -1564,13 +1548,12 @@ HWTEST_F(UdmfClientTest, GetSelfData002, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; std::string key; - File file1; - file1.SetRemoteUri("remoteUri"); + auto file1 = std::make_shared<File>(); + file1->SetRemoteUri("remoteUri"); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); - file1.SetDetails(details1); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<File>(file1); - data1.AddRecord(record1); + file1->SetDetails(details1); + data1.AddRecord(file1); auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -1588,7 +1571,7 @@ HWTEST_F(UdmfClientTest, GetSelfData002, TestSize.Level1) auto file2 = static_cast<File *>(record2.get()); ASSERT_NE(file2, nullptr); - EXPECT_EQ(file1.GetRemoteUri(), file2->GetRemoteUri()); + EXPECT_EQ(file1->GetRemoteUri(), file2->GetRemoteUri()); CompareDetails(file2->GetDetails()); GetEmptyData(option2); @@ -1615,19 +1598,15 @@ HWTEST_F(UdmfClientTest, SetData021, TestSize.Level1) CustomOption customOption = { .intention = Intention::UD_INTENTION_DATA_HUB }; UnifiedData data1; - PlainText plainText1; - plainText1.SetContent("content1"); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText1); - data1.AddRecord(record1); + auto plainText1 = std::make_shared<PlainText>(); + plainText1->SetContent("content1"); + data1.AddRecord(plainText1); std::string key; status = UdmfClient::GetInstance().SetData(customOption, data1, key); ASSERT_EQ(status, E_OK); - UnifiedData data2; - PlainText plainText2; - plainText1.SetContent("content2"); - std::shared_ptr<UnifiedRecord> record2 = std::make_shared<PlainText>(plainText1); - data2.AddRecord(record2); + plainText1->SetContent("content2"); + data2.AddRecord(plainText1); status = UdmfClient::GetInstance().SetData(customOption, data2, key); ASSERT_EQ(status, E_OK); @@ -1659,10 +1638,9 @@ HWTEST_F(UdmfClientTest, UpdateData001, TestSize.Level1) CustomOption customOption = { .intention = Intention::UD_INTENTION_DATA_HUB }; UnifiedData data1; - PlainText plainText1; - plainText1.SetContent("content1"); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText1); - data1.AddRecord(record1); + auto plainText1 = std::make_shared<PlainText>(); + plainText1->SetContent("content1"); + data1.AddRecord(plainText1); std::string key; status = UdmfClient::GetInstance().SetData(customOption, data1, key); ASSERT_EQ(status, E_OK); @@ -1684,17 +1662,15 @@ HWTEST_F(UdmfClientTest, UpdateData002, TestSize.Level1) LOG_INFO(UDMF_TEST, "UpdateData002 begin."); UnifiedData data; - PlainText plainText; - plainText.SetContent("content"); - std::shared_ptr<UnifiedRecord> record = std::make_shared<PlainText>(plainText); - data.AddRecord(record); + auto plainText = std::make_shared<PlainText>(); + plainText->SetContent("content"); + data.AddRecord(plainText); CustomOption customOption = { .intention = Intention::UD_INTENTION_DATA_HUB }; UnifiedData data1; - PlainText plainText1; - plainText1.SetContent("content1"); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<PlainText>(plainText1); - data1.AddRecord(record1); + auto plainText1 = std::make_shared<PlainText>(); + plainText1->SetContent("content1"); + data1.AddRecord(plainText1); std::string key; auto status = UdmfClient::GetInstance().SetData(customOption, data1, key); @@ -1771,10 +1747,9 @@ HWTEST_F(UdmfClientTest, QueryData002, TestSize.Level1) CustomOption customOption = { .intention = Intention::UD_INTENTION_DATA_HUB }; UnifiedData data; - PlainText plainText; - plainText.SetContent("content1"); - std::shared_ptr<UnifiedRecord> record = std::make_shared<PlainText>(plainText); - data.AddRecord(record); + auto plainText = std::make_shared<PlainText>(); + plainText->SetContent("content1"); + data.AddRecord(plainText); std::string key; status = UdmfClient::GetInstance().SetData(customOption, data, key); ASSERT_EQ(status, E_OK); @@ -1792,9 +1767,9 @@ HWTEST_F(UdmfClientTest, QueryData002, TestSize.Level1) ASSERT_EQ(plainText2->GetContent(), "content1"); UnifiedData data2; - plainText.SetContent("content2"); - record = std::make_shared<PlainText>(plainText); - data2.AddRecord(record); + plainText = std::make_shared<PlainText>(); + plainText->SetContent("content2"); + data2.AddRecord(plainText); status = UdmfClient::GetInstance().SetData(customOption, data2, key); ASSERT_EQ(status, E_OK); @@ -1863,10 +1838,9 @@ HWTEST_F(UdmfClientTest, DeleteData002, TestSize.Level1) CustomOption customOption = { .intention = UD_INTENTION_DATA_HUB }; UnifiedData data; - PlainText plainText; - plainText.SetContent("content1"); - std::shared_ptr<UnifiedRecord> record = std::make_shared<PlainText>(plainText); - data.AddRecord(record); + auto plainText = std::make_shared<PlainText>(); + plainText->SetContent("content1"); + data.AddRecord(plainText); std::string key; auto status = UdmfClient::GetInstance().SetData(customOption, data, key); ASSERT_EQ(status, E_OK); @@ -1926,11 +1900,10 @@ HWTEST_F(UdmfClientTest, SetData022, TestSize.Level1) } details.insert({ value, value }); details.insert({ "udmf_key", "udmf_value" }); - Text text; - text.SetDetails(details); - std::shared_ptr<UnifiedRecord> record = std::make_shared<Text>(text); + auto text = std::make_shared<Text>(); + text->SetDetails(details); for (int i = 0; i < 2; ++i) { - inputData.AddRecord(record); + inputData.AddRecord(text); } UnifiedDataHelper::SetRootPath("/data/udmf_test/"); auto status = UdmfClient::GetInstance().SetData(customOption, inputData, key); @@ -1967,7 +1940,7 @@ HWTEST_F(UdmfClientTest, SetData023, TestSize.Level1) Text text; text.SetDetails(details); for (int64_t i = 0; i < 100; ++i) { - auto record = std::make_shared<Text>(text); + auto record = std::make_shared<Text>(); inputData.AddRecord(record); } auto records = inputData.GetRecords(); @@ -2004,11 +1977,10 @@ HWTEST_F(UdmfClientTest, SetData024, TestSize.Level1) value += "11"; } details.insert({ value, value }); - Text text; - text.SetDetails(details); + auto text = std::make_shared<Text>(); + text->SetDetails(details); for (int64_t i = 0; i < 101; ++i) { - auto record = std::make_shared<Text>(text); - inputData.AddRecord(record); + inputData.AddRecord(text); } auto records = inputData.GetRecords(); LOG_INFO(UDMF_TEST, "SetData024 inputData.size() = %{public}zu", records.size()); @@ -2033,15 +2005,14 @@ HWTEST_F(UdmfClientTest, SetData025, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; std::string key; - SystemDefinedPixelMap systemDefinedPixelMap1; + auto systemDefinedPixelMap1 = std::make_shared<SystemDefinedPixelMap>(); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); - systemDefinedPixelMap1.SetDetails(details1); + systemDefinedPixelMap1->SetDetails(details1); std::vector<uint8_t> rawData1 = { 1, 2, 3, 4, 5 }; - systemDefinedPixelMap1.SetRawData(rawData1); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedPixelMap>(systemDefinedPixelMap1); - data1.AddRecord(record1); + systemDefinedPixelMap1->SetRawData(rawData1); + data1.AddRecord(systemDefinedPixelMap1); auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -2084,16 +2055,15 @@ HWTEST_F(UdmfClientTest, SetData026, TestSize.Level1) CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; UnifiedData data1; std::string key; - SystemDefinedPixelMap systemDefinedPixelMap1; + auto systemDefinedPixelMap1 = std::make_shared<SystemDefinedPixelMap>(); UDDetails details1; details1.insert({ "udmf_key", "udmf_value" }); - systemDefinedPixelMap1.SetDetails(details1); + systemDefinedPixelMap1->SetDetails(details1); std::vector<uint8_t> rawData1 = { 1, 2, 3, 4, 5 }; - systemDefinedPixelMap1.SetRawData(rawData1); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<SystemDefinedPixelMap>(systemDefinedPixelMap1); + systemDefinedPixelMap1->SetRawData(rawData1); std::shared_ptr<UnifiedRecord> record2 = std::make_shared<PlainText>(UDType::PLAIN_TEXT, "this is a content"); - data1.AddRecord(record1); + data1.AddRecord(systemDefinedPixelMap1); data1.AddRecord(record2); auto status = UdmfClient::GetInstance().SetData(option1, data1, key); ASSERT_EQ(status, E_OK); @@ -2152,17 +2122,15 @@ HWTEST_F(UdmfClientTest, GetSummary003, TestSize.Level1) } details.insert({ value, value }); - Text text; - text.SetDetails(details); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Text>(text); - data.AddRecord(record1); + auto text = std::make_shared<Text>(); + text->SetDetails(details); + data.AddRecord(text); - PlainText plainText; - plainText.SetDetails(details); - plainText.SetContent("content"); - plainText.SetAbstract("abstract"); - std::shared_ptr<UnifiedRecord> record2 = std::make_shared<PlainText>(plainText); - data.AddRecord(record2); + auto plainText = std::make_shared<PlainText>(); + plainText->SetDetails(details); + plainText->SetContent("content"); + plainText->SetAbstract("abstract"); + data.AddRecord(plainText); UnifiedDataHelper::SetRootPath("/data/udmf_test/"); auto status = UdmfClient::GetInstance().SetData(option1, data, key); @@ -2173,13 +2141,13 @@ HWTEST_F(UdmfClientTest, GetSummary003, TestSize.Level1) Summary summary; status = UdmfClient::GetInstance().GetSummary(option2, summary); - auto size = record1->GetSize(); - size += record2->GetSize(); + auto size = text->GetSize(); + size += plainText->GetSize(); ASSERT_EQ(status, E_OK); ASSERT_EQ(summary.totalSize, size); - ASSERT_EQ(summary.summary["general.text"], record1->GetSize()); - ASSERT_EQ(summary.summary["general.plain-text"], record2->GetSize()); + ASSERT_EQ(summary.summary["general.text"], text->GetSize()); + ASSERT_EQ(summary.summary["general.plain-text"], plainText->GetSize()); LOG_INFO(UDMF_TEST, "GetSummary003 end."); } @@ -2200,17 +2168,15 @@ HWTEST_F(UdmfClientTest, IsRemoteData001, TestSize.Level1) UDDetails details; details.insert({ "udmf_key", "udmf_value" }); - Text text; - text.SetDetails(details); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Text>(text); - data.AddRecord(record1); + auto text = std::make_shared<Text>(); + text->SetDetails(details); + data.AddRecord(text); - PlainText plainText; - plainText.SetDetails(details); - plainText.SetContent("content"); - plainText.SetAbstract("abstract"); - std::shared_ptr<UnifiedRecord> record2 = std::make_shared<PlainText>(plainText); - data.AddRecord(record2); + auto plainText = std::make_shared<PlainText>(); + plainText->SetDetails(details); + plainText->SetContent("content"); + plainText->SetAbstract("abstract"); + data.AddRecord(plainText); auto status = UdmfClient::GetInstance().SetData(option1, data, key); ASSERT_EQ(status, E_OK); @@ -2236,13 +2202,11 @@ HWTEST_F(UdmfClientTest, GetTypesLabels001, TestSize.Level1) UnifiedData data; UDDetails details; details.insert({ "udmf_key", "udmf_value" }); - Text text; - text.SetDetails(details); - std::shared_ptr<UnifiedRecord> record1 = std::make_shared<Text>(text); - PlainText plainText; - plainText.SetDetails(details); - std::shared_ptr<UnifiedRecord> record2 = std::make_shared<PlainText>(plainText); - std::vector<std::shared_ptr<UnifiedRecord>> records = {record1, record2}; + auto text = std::make_shared<Text>(); + text->SetDetails(details); + auto plainText = std::make_shared<PlainText>(); + plainText->SetDetails(details); + std::vector<std::shared_ptr<UnifiedRecord>> records = {text, plainText}; data.AddRecords(records); std::vector<std::string> types = {"general.text", "general.plain-text"}; @@ -2560,122 +2524,219 @@ HWTEST_F(UdmfClientTest, QueryUDSData005, TestSize.Level1) } /** -* @tc.name: GetDataAsync01 -* @tc.desc: Set multiple record with valid params and async get data +* @tc.name: GetSelfBundleName001 +* @tc.desc: Nrmal testcase of GetSelfBundleName +* @tc.type: FUNC +*/ +HWTEST_F(UdmfClientTest, GetSelfBundleName001, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "GetSelfBundleName001 begin."); + UdmfClient udmfClient; + std::string ret = udmfClient.GetSelfBundleName(); + EXPECT_NE(ret, ""); + LOG_INFO(UDMF_TEST, "GetSelfBundleName001 end."); +} + +/** +* @tc.name: GetSummary004 +* @tc.desc: Get summary data for entries * @tc.type: FUNC */ -HWTEST_F(UdmfClientTest, GetDataAsync01, TestSize.Level1) +HWTEST_F(UdmfClientTest, GetSummary004, TestSize.Level1) { - LOG_INFO(UDMF_TEST, "GetDataAsync01 begin."); + LOG_INFO(UDMF_TEST, "GetSummary004 begin."); - CustomOption customOption = {.intention = Intention::UD_INTENTION_DRAG}; + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data; std::string key; - UnifiedData inputData; - std::vector<std::shared_ptr<UnifiedRecord>> inputRecords = { - std::make_shared<Text>(), - std::make_shared<PlainText>(), - std::make_shared<File>(), - std::make_shared<Image>(), - std::make_shared<SystemDefinedRecord>(), - std::make_shared<SystemDefinedForm>(), - std::make_shared<ApplicationDefinedRecord>() - }; - inputData.SetRecords(inputRecords); - auto status = UdmfClient::GetInstance().SetData(customOption, inputData, key); - ASSERT_EQ(status, E_OK); + UDDetails details; + details.insert({ "udmf_key", "udmf_value" }); - auto callback = [this, inputRecords](ProgressInfo progress, UnifiedData &outputData) { - LOG_INFO(UDMF_TEST, "GetDataAsync01 callback begin status=%{public}u, progress=%{public}u, name=%{public}s.", - progress.status, progress.progress, progress.srcDevName.c_str()); - if (progress.status == ASYNC_IDLE || progress.status == ASYNC_RUNNING) { - return; - } - ASSERT_EQ(progress.status, ASYNC_SUCCESS); - ASSERT_EQ(progress.progress, 100); - auto outputRecords = outputData.GetRecords(); - ASSERT_EQ(inputRecords.size(), outputRecords.size()); - for (size_t i = 0; i < outputRecords.size(); ++i) { - ASSERT_EQ(outputRecords[i]->GetType(), inputRecords[i]->GetType()); - } - LOG_INFO(UDMF_TEST, "GetDataAsync01 callback end."); - }; - QueryOption queryOption = { .key = key }; - status = UdmfClient::GetInstance().GetDataAsync(queryOption, callback); + std::shared_ptr<Object> obj = std::make_shared<Object>(); + obj->value_[UNIFORM_DATA_TYPE] = "general.file-uri"; + obj->value_[FILE_URI_PARAM] = "http://demo.com"; + obj->value_[FILE_TYPE] = "abcdefg"; + auto record = std::make_shared<UnifiedRecord>(FILE_URI, obj); + auto size0 = record->GetSize(); + + auto plainText = PlainText("content", "abstract"); + auto size1 = plainText.GetSize(); + plainText.InitObject(); + record->AddEntry(plainText.GetUtdId(), plainText.GetOriginValue()); + + auto image = Image("uri"); + image.SetDetails(details); + auto size2 = image.GetSize(); + image.InitObject(); + record->AddEntry(image.GetUtdId(), image.GetOriginValue()); + + std::vector<uint8_t> raw = {1, 2, 3, 4, 5}; + SystemDefinedPixelMap pixelMap = SystemDefinedPixelMap(raw); + pixelMap.SetDetails(details); + auto size3 = pixelMap.GetSize(); + pixelMap.InitObject(); + record->AddEntry(pixelMap.GetUtdId(), pixelMap.GetOriginValue()); + + raw = {1, 2, 3, 4, 5}; + auto applicationDefinedRecord = ApplicationDefinedRecord("my.type", raw); + auto size4 = applicationDefinedRecord.GetSize(); + applicationDefinedRecord.InitObject(); + record->AddEntry(applicationDefinedRecord.GetUtdId(), applicationDefinedRecord.GetOriginValue()); + + data.AddRecord(record); + + auto status = UdmfClient::GetInstance().SetData(option1, data, key); ASSERT_EQ(status, E_OK); - std::this_thread::sleep_for(std::chrono::seconds(1)); - LOG_INFO(UDMF_TEST, "GetDataAsync01 end."); -} + QueryOption option2 = { .key = key }; + Summary summary; + status = UdmfClient::GetInstance().GetSummary(option2, summary); -/** -* @tc.name: GetDataAsync02 -* @tc.desc: Set multiple record with invalid params and async get data -* @tc.type: FUNC -*/ -HWTEST_F(UdmfClientTest, GetDataAsync02, TestSize.Level1) -{ - LOG_INFO(UDMF_TEST, "GetDataAsync02 begin."); - QueryOption queryOption; - auto status = UdmfClient::GetInstance().GetDataAsync(queryOption, nullptr); - ASSERT_NE(status, E_OK); - LOG_INFO(UDMF_TEST, "GetDataAsync02 end."); + ASSERT_EQ(status, E_OK); + EXPECT_EQ(summary.summary["general.file-uri"], size0); + EXPECT_EQ(summary.summary["general.plain-text"], size1); + EXPECT_EQ(summary.summary["general.image"], size2); + EXPECT_EQ(summary.summary["openharmony.pixel-map"], size3); + EXPECT_EQ(summary.summary["ApplicationDefinedType"], size4); + + EXPECT_EQ(summary.totalSize, record->GetSize()); + + UnifiedData readData; + status = UdmfClient::GetInstance().GetData(option2, readData); + ASSERT_EQ(E_OK, status); + ASSERT_EQ(1, readData.GetRecords().size()); + auto readRecord = readData.GetRecordAt(0); + auto entries = readRecord->GetEntries(); + ASSERT_EQ(5, entries->size()); + auto readFileUri = std::get<std::shared_ptr<Object>>(entries->at("general.file-uri")); + EXPECT_EQ("abcdefg", std::get<std::string>(readFileUri->value_[FILE_TYPE])); + auto readPlainText = std::get<std::shared_ptr<Object>>(entries->at("general.plain-text")); + EXPECT_EQ("abstract", std::get<std::string>(readPlainText->value_[ABSTRACT])); + auto readImage = std::get<std::shared_ptr<Object>>(entries->at("general.image")); + EXPECT_EQ("uri", std::get<std::string>(readImage->value_[ORI_URI])); + auto readPixelMap = std::get<std::shared_ptr<Object>>(entries->at("openharmony.pixel-map")); + EXPECT_EQ(5, std::get<std::vector<uint8_t>>(readPixelMap->value_[PIXEL_MAP]).size()); + auto readDefinedRecord = std::get<std::shared_ptr<Object>>(entries->at("my.type")); + EXPECT_EQ(5, std::get<std::vector<uint8_t>>(readDefinedRecord->value_[ARRAY_BUFFER]).size()); + auto value = std::get<std::shared_ptr<Object>>(readRecord->GetValue()); + EXPECT_EQ("abcdefg", std::get<std::string>(value->value_[FILE_TYPE])); + LOG_INFO(UDMF_TEST, "GetSummary004 end."); } /** -* @tc.name: GetDataAsync03 -* @tc.desc: Set multiple record with invalid params and async get data +* @tc.name: GetSummary005 +* @tc.desc: Get summary data for entries * @tc.type: FUNC */ -HWTEST_F(UdmfClientTest, GetDataAsync03, TestSize.Level1) +HWTEST_F(UdmfClientTest, GetSummary005, TestSize.Level1) { - LOG_INFO(UDMF_TEST, "GetDataAsync03 begin."); + LOG_INFO(UDMF_TEST, "GetSummary005 begin."); - CustomOption customOption = {.intention = Intention::UD_INTENTION_DRAG}; + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data; std::string key; - UnifiedData inputData; - std::vector<std::shared_ptr<UnifiedRecord>> inputRecords = { - std::make_shared<Text>(), - std::make_shared<PlainText>(), - std::make_shared<File>(), - std::make_shared<Image>(), - std::make_shared<SystemDefinedRecord>(), - std::make_shared<SystemDefinedForm>(), - std::make_shared<ApplicationDefinedRecord>() - }; - inputData.SetRecords(inputRecords); - auto status = UdmfClient::GetInstance().SetData(customOption, inputData, key); - ASSERT_EQ(status, E_OK); + UDDetails details; + details.insert({ "udmf_key", "udmf_value" }); - auto callback = [this, inputRecords](ProgressInfo progress, UnifiedData &outputData) { - LOG_INFO(UDMF_TEST, "GetDataAsync03 callback begin status=%{public}u, progress=%{public}u, name=%{public}s.", - progress.status, progress.progress, progress.srcDevName.c_str()); - if (progress.status == ASYNC_IDLE || progress.status == ASYNC_RUNNING) { - return; - } - ASSERT_EQ(progress.status, ASYNC_FAILURE); - LOG_INFO(UDMF_TEST, "GetDataAsync03 callback end."); - }; - QueryOption queryOption = { .key = "123456" }; - status = UdmfClient::GetInstance().GetDataAsync(queryOption, callback); + auto record = std::make_shared<Html>("content1", "content2"); + auto size0 = record->GetSize(); + + auto link = Link("url", "descritpion"); + auto size1 = link.GetSize(); + link.InitObject(); + record->AddEntry(link.GetUtdId(), link.GetOriginValue()); + + auto folder = Folder("uri"); + folder.SetDetails(details); + auto size2 = folder.GetSize(); + folder.InitObject(); + record->AddEntry(folder.GetUtdId(), folder.GetOriginValue()); + + std::vector<uint8_t> raw = {1, 2, 3, 4, 5}; + auto applicationDefinedRecord1 = ApplicationDefinedRecord("your.type", raw); + auto size3 = applicationDefinedRecord1.GetSize(); + applicationDefinedRecord1.InitObject(); + record->AddEntry(applicationDefinedRecord1.GetUtdId(), applicationDefinedRecord1.GetOriginValue()); + + raw = {1, 2, 3, 4, 5}; + auto applicationDefinedRecord2 = ApplicationDefinedRecord("my.type", raw); + auto size4 = applicationDefinedRecord2.GetSize(); + applicationDefinedRecord2.InitObject(); + record->AddEntry(applicationDefinedRecord2.GetUtdId(), applicationDefinedRecord2.GetOriginValue()); + + auto form = SystemDefinedForm(); + form.SetDetails(details); + form.SetDetails(details); + form.SetFormId(123); + form.SetFormName("formName"); + form.SetModule("module"); + form.SetAbilityName("abilityName"); + form.SetBundleName("bundleName"); + auto size5 = form.GetSize(); + form.InitObject(); + record->AddEntry(form.GetUtdId(), form.GetOriginValue()); + + raw = {1, 2, 3, 4, 5}; + std::shared_ptr<Object> obj = std::make_shared<Object>(); + obj->value_[UNIFORM_DATA_TYPE] = "general.content-form"; + obj->value_[THUMB_DATA] = raw; + obj->value_[THUMB_DATA_LENGTH] = 5; + obj->value_[DESCRIPTION] = "descritpion"; + obj->value_[TITLE] = "title"; + obj->value_[APP_ICON] = raw; + obj->value_[APP_ICON_LENGTH] = 5; + obj->value_[APP_NAME] = "appName"; + obj->value_[LINK_URL] = "linkUri"; + auto contentForm = UnifiedRecord(CONTENT_FORM, obj); + auto size6 = contentForm.GetSize(); + record->AddEntry(contentForm.GetUtdId(), contentForm.GetOriginValue()); + + data.AddRecord(record); + + auto status = UdmfClient::GetInstance().SetData(option1, data, key); ASSERT_EQ(status, E_OK); - std::this_thread::sleep_for(std::chrono::seconds(1)); - LOG_INFO(UDMF_TEST, "GetDataAsync03 end."); -} + QueryOption option2 = { .key = key }; + Summary summary; + status = UdmfClient::GetInstance().GetSummary(option2, summary); -/** -* @tc.name: GetSelfBundleName001 -* @tc.desc: Nrmal testcase of GetSelfBundleName -* @tc.type: FUNC -*/ -HWTEST_F(UdmfClientTest, GetSelfBundleName001, TestSize.Level1) -{ - LOG_INFO(UDMF_TEST, "GetSelfBundleName001 begin."); - UdmfClient udmfClient; - std::string ret = udmfClient.GetSelfBundleName(); - EXPECT_NE(ret, ""); - LOG_INFO(UDMF_TEST, "GetSelfBundleName001 end."); + LOG_INFO(UDMF_TEST, "GetSummary005 GetSummary."); + + ASSERT_EQ(status, E_OK); + EXPECT_EQ(summary.summary["general.html"], size0); + EXPECT_EQ(summary.summary["general.hyperlink"], size1); + EXPECT_EQ(summary.summary["general.folder"], size2); + EXPECT_EQ(summary.summary["ApplicationDefinedType"], size3 + size4); + EXPECT_EQ(summary.summary["openharmony.form"], size5); + EXPECT_EQ(summary.summary["general.content-form"], size6); + + EXPECT_EQ(summary.totalSize, record->GetSize()); + + UnifiedData readData; + status = UdmfClient::GetInstance().GetData(option2, readData); + LOG_INFO(UDMF_TEST, "GetSummary005 GetSummary1."); + ASSERT_EQ(E_OK, status); + ASSERT_EQ(1, readData.GetRecords().size()); + auto readRecord = readData.GetRecordAt(0); + ValueType recordVal = readRecord->GetValue(); + auto entries = readRecord->GetEntries(); + ASSERT_EQ(7, entries->size()); + auto readHtml = std::get<std::shared_ptr<Object>>(entries->at("general.html")); + EXPECT_EQ("content1", std::get<std::string>(readHtml->value_[HTML_CONTENT])); + auto readHyperlink = std::get<std::shared_ptr<Object>>(entries->at("general.hyperlink")); + EXPECT_EQ("descritpion", std::get<std::string>(readHyperlink->value_[DESCRIPTION])); + auto readFolder = std::get<std::shared_ptr<Object>>(entries->at("general.folder")); + EXPECT_EQ("uri", std::get<std::string>(readFolder->value_[ORI_URI])); + auto readDefinedRecord = std::get<std::shared_ptr<Object>>(entries->at("your.type")); + EXPECT_EQ(5, std::get<std::vector<uint8_t>>(readDefinedRecord->value_[ARRAY_BUFFER]).size()); + auto readDefinedRecord2 = std::get<std::shared_ptr<Object>>(entries->at("my.type")); + EXPECT_EQ(5, std::get<std::vector<uint8_t>>(readDefinedRecord2->value_[ARRAY_BUFFER]).size()); + auto readForm = std::get<std::shared_ptr<Object>>(entries->at("openharmony.form")); + EXPECT_EQ("module", std::get<std::string>(readForm->value_[MODULE])); + auto readCotentForm = std::get<std::shared_ptr<Object>>(entries->at("general.content-form")); + EXPECT_EQ("title", std::get<std::string>(readCotentForm->value_[TITLE])); + LOG_INFO(UDMF_TEST, "GetSummary005 end."); } } // OHOS::Test \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/test/unittest/unified_record_test.cpp b/udmf/framework/innerkitsimpl/test/unittest/unified_record_test.cpp index d43a1c70521a78ca2038741236c63b3b48eda13c..acbf01b501d4f9f3dde0a504224be57c01adcc4d 100644 --- a/udmf/framework/innerkitsimpl/test/unittest/unified_record_test.cpp +++ b/udmf/framework/innerkitsimpl/test/unittest/unified_record_test.cpp @@ -15,6 +15,7 @@ #define LOG_TAG "UnifiedRecordTest" #include <unistd.h> +#include <thread> #include <gtest/gtest.h> #include <string> @@ -131,7 +132,8 @@ HWTEST_F(UnifiedRecordTest, Constructor_002, TestSize.Level0) auto entries = record.GetEntries(); auto it = entries->find(utdId); ASSERT_TRUE(it != entries->end()); - EXPECT_TRUE(std::holds_alternative<std::monostate>(it->second)); + EXPECT_FALSE(std::holds_alternative<std::monostate>(it->second)); + EXPECT_TRUE(std::holds_alternative<std::shared_ptr<Object>>(it->second)); } /** @@ -162,8 +164,65 @@ HWTEST_F(UnifiedRecordTest, Constructor_003, TestSize.Level0) auto it = entries->find(utdId); ASSERT_TRUE(it != entries->end()); auto entry2 = it->second; - EXPECT_TRUE(std::holds_alternative<std::string>(entry2)); - auto entryStr2 = std::get_if<std::string>(&entry2); - EXPECT_EQ(*entryStr2, "123456"); + EXPECT_TRUE(std::holds_alternative<std::shared_ptr<Object>>(entry2)); +} + +/** + * @tc.name: AddEntry_001 + * @tc.desc: Normal testcase of AddEntry + * @tc.type: FUNC + */ +HWTEST_F(UnifiedRecordTest, AddEntry_001, TestSize.Level0) +{ + std::string utdId = "utdId"; + ValueType value = "value"; + UnifiedRecord unifiedRecord; + std::thread t1(&UnifiedRecord::AddEntry, std::ref(unifiedRecord), utdId, value); + EXPECT_NO_FATAL_FAILURE(t1.join()); + + std::string utdId1 = "utdId1"; + ValueType value1 = "value1"; + std::thread t2(&UnifiedRecord::AddEntry, std::ref(unifiedRecord), utdId1, value1); + EXPECT_NO_FATAL_FAILURE(t2.join()); + + std::string utdId2 = "utdId2"; + ValueType value2 = "value2"; + std::thread t3(&UnifiedRecord::AddEntry, std::ref(unifiedRecord), utdId2, value2); + EXPECT_NO_FATAL_FAILURE(t3.join()); + + std::string utdId3 = "utdId3"; + ValueType value3 = "value3"; + std::thread t4(&UnifiedRecord::AddEntry, std::ref(unifiedRecord), utdId3, value3); + EXPECT_NO_FATAL_FAILURE(t4.join()); + + std::string utdId4 = "utdId4"; + ValueType value4 = "value4"; + std::thread t5(&UnifiedRecord::AddEntry, std::ref(unifiedRecord), utdId4, value4); + EXPECT_NO_FATAL_FAILURE(t5.join()); + + std::string utdId5 = "utdId5"; + ValueType value5 = "value5"; + std::thread t6(&UnifiedRecord::AddEntry, std::ref(unifiedRecord), utdId5, value5); + EXPECT_NO_FATAL_FAILURE(t6.join()); + + std::string utdId6 = "utdId6"; + ValueType value6 = "value6"; + std::thread t7(&UnifiedRecord::AddEntry, std::ref(unifiedRecord), utdId6, value6); + EXPECT_NO_FATAL_FAILURE(t7.join()); + + std::string utdId7 = "utdId7"; + ValueType value7 = "value7"; + std::thread t8(&UnifiedRecord::AddEntry, std::ref(unifiedRecord), utdId7, value7); + EXPECT_NO_FATAL_FAILURE(t8.join()); + + std::string utdId8 = "utdId8"; + ValueType value8 = "value8"; + std::thread t9(&UnifiedRecord::AddEntry, std::ref(unifiedRecord), utdId8, value8); + EXPECT_NO_FATAL_FAILURE(t9.join()); + + std::string utdId9 = "utdId9"; + ValueType value9 = "value9"; + std::thread t10(&UnifiedRecord::AddEntry, std::ref(unifiedRecord), utdId9, value9); + EXPECT_NO_FATAL_FAILURE(t10.join()); } } // OHOS::Test \ No newline at end of file diff --git a/udmf/framework/innerkitsimpl/test/unittest/utd_client_test.cpp b/udmf/framework/innerkitsimpl/test/unittest/utd_client_test.cpp index ba7b4caf96ce4d119159d483cbd88e27362e3218..361ebd48c29d49f4d79e3b84f634f5c2d9a01514 100644 --- a/udmf/framework/innerkitsimpl/test/unittest/utd_client_test.cpp +++ b/udmf/framework/innerkitsimpl/test/unittest/utd_client_test.cpp @@ -447,7 +447,6 @@ HWTEST_F(UtdClientTest, GetUniformDataTypeByMIMEType007, TestSize.Level1) LOG_INFO(UDMF_TEST, "GetUniformDataTypeByMIMEType007 end."); } - /** * @tc.name: BelongsTo001 * @tc.desc: Normal testcase of BelongsTo @@ -1764,6 +1763,23 @@ HWTEST_F(UtdClientTest, GetUniformDataTypesByFilenameExtension005, TestSize.Leve LOG_INFO(UDMF_TEST, "GetUniformDataTypesByFilenameExtension005 end."); } +/** +* @tc.name: GetUniformDataTypesByFilenameExtension006 +* @tc.desc: Normal testcase of GetUniformDataTypesByFilenameExtension, fileExtension is invaild +* @tc.type: FUNC +*/ +HWTEST_F(UtdClientTest, GetUniformDataTypesByFilenameExtension006, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "GetUniformDataTypesByFilenameExtension006 begin."); + std::string filenameExtension = "?application/x-mobi8-ebook"; + std::vector<std::string> currTypes; + std::string blongsToType = "general.plain-text"; + Status status = + UtdClient::GetInstance().GetUniformDataTypesByFilenameExtension(filenameExtension, currTypes, blongsToType); + ASSERT_EQ(status, Status::E_INVALID_PARAMETERS); + LOG_INFO(UDMF_TEST, "GetUniformDataTypesByFilenameExtension006 end."); +} + /** * @tc.name: GetTypeIdFromCfg001 * @tc.desc: Abnormal testcase of GetTypeIdFromCfg, mimeType is not empty, mimeType.back() is not '*' diff --git a/udmf/framework/jskitsimpl/common/napi_data_utils.cpp b/udmf/framework/jskitsimpl/common/napi_data_utils.cpp index 8f0306fd00adaae61a2a24839fba161fc3982de4..d404084f78ac233353174e39d7556a9feed558ef 100644 --- a/udmf/framework/jskitsimpl/common/napi_data_utils.cpp +++ b/udmf/framework/jskitsimpl/common/napi_data_utils.cpp @@ -376,8 +376,8 @@ napi_status NapiDataUtils::GetValue(napi_env env, napi_value in, std::shared_ptr napi_status status = napi_typeof(env, in, &type); LOG_ERROR_RETURN((status == napi_ok) && (type == napi_object), "invalid type", napi_invalid_arg); TypeDescriptorNapi *descriptorNapi = nullptr; - napi_unwrap(env, in, reinterpret_cast<void **>(&descriptorNapi)); - LOG_ERROR_RETURN((descriptorNapi != nullptr), "invalid type", napi_invalid_arg); + auto unwrap = napi_unwrap(env, in, reinterpret_cast<void **>(&descriptorNapi)); + LOG_ERROR_RETURN((descriptorNapi != nullptr || unwrap == napi_ok), "invalid type", napi_invalid_arg); descriptor = descriptorNapi->value_; if (descriptor == nullptr) { LOG_DEBUG(UDMF_KITS_NAPI, "napi_value -> GetValue TypeDescriptor failed "); @@ -526,6 +526,21 @@ napi_status NapiDataUtils::SetValue(napi_env env, const nullptr_t &in, napi_valu return napi_get_null(env, &out); } +napi_status NapiDataUtils::SetValue(napi_env env, const ProgressInfo &in, napi_value &out) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "napi_value <- ProgressInfo"); + napi_create_object(env, &out); + + napi_value jsPercentage = nullptr; + SetValue(env, in.progress, jsPercentage); + napi_set_named_property(env, out, "percentage", jsPercentage); + + napi_value jsListenerStatus = nullptr; + SetValue(env, in.progressStatus, jsListenerStatus); + napi_set_named_property(env, out, "status", jsListenerStatus); + return napi_ok; +} + bool NapiDataUtils::IsTypeForNapiValue(napi_env env, napi_value param, napi_valuetype expectType) { napi_valuetype valueType = napi_undefined; diff --git a/udmf/framework/jskitsimpl/data/application_defined_record_napi.cpp b/udmf/framework/jskitsimpl/data/application_defined_record_napi.cpp index e63b9146d9df1db483202851d989920a1b03fb49..3b6a48f2bccfb43e7b2b73cd16c3c1a187a7710d 100644 --- a/udmf/framework/jskitsimpl/data/application_defined_record_napi.cpp +++ b/udmf/framework/jskitsimpl/data/application_defined_record_napi.cpp @@ -27,6 +27,10 @@ napi_value ApplicationDefinedRecordNapi::Constructor(napi_env env) /* ApplicationDefinedRecord extends UnifiedRecord */ DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), DECLARE_NAPI_FUNCTION("getValue", UnifiedRecordNapi::GetValue), + DECLARE_NAPI_FUNCTION("addEntry", UnifiedRecordNapi::AddEntry), + DECLARE_NAPI_FUNCTION("getEntry", UnifiedRecordNapi::GetEntry), + DECLARE_NAPI_FUNCTION("getEntries", UnifiedRecordNapi::GetEntries), + DECLARE_NAPI_FUNCTION("getTypes", UnifiedRecordNapi::GetTypes), /* ApplicationDefinedRecord properties */ DECLARE_NAPI_GETTER_SETTER("applicationDefinedType", GetApplicationDefinedType, SetApplicationDefinedType), DECLARE_NAPI_GETTER_SETTER("rawData", GetRawData, SetRawData), diff --git a/udmf/framework/jskitsimpl/data/audio_napi.cpp b/udmf/framework/jskitsimpl/data/audio_napi.cpp index a692aefefceabf9af02fda7387f36e7e204a774d..3b67bb7132f344f150c47b3c0161ba65215d549d 100644 --- a/udmf/framework/jskitsimpl/data/audio_napi.cpp +++ b/udmf/framework/jskitsimpl/data/audio_napi.cpp @@ -28,6 +28,10 @@ napi_value AudioNapi::Constructor(napi_env env) /* Audio extends UnifiedRecord */ DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), DECLARE_NAPI_FUNCTION("getValue", UnifiedRecordNapi::GetValue), + DECLARE_NAPI_FUNCTION("addEntry", UnifiedRecordNapi::AddEntry), + DECLARE_NAPI_FUNCTION("getEntry", UnifiedRecordNapi::GetEntry), + DECLARE_NAPI_FUNCTION("getEntries", UnifiedRecordNapi::GetEntries), + DECLARE_NAPI_FUNCTION("getTypes", UnifiedRecordNapi::GetTypes), /* Audio extends File */ DECLARE_NAPI_GETTER_SETTER("details", FileNapi::GetDetails, FileNapi::SetDetails), DECLARE_NAPI_GETTER_SETTER("uri", FileNapi::GetUri, FileNapi::SetUri), diff --git a/udmf/framework/jskitsimpl/data/file_napi.cpp b/udmf/framework/jskitsimpl/data/file_napi.cpp index bcc65eab7b0b823e5e3b92f32e4c75373d8e433a..1ccfe0b47cfcc0cd119fa856c01aff79c9d31d80 100644 --- a/udmf/framework/jskitsimpl/data/file_napi.cpp +++ b/udmf/framework/jskitsimpl/data/file_napi.cpp @@ -27,6 +27,10 @@ napi_value FileNapi::Constructor(napi_env env) /* File extends UnifiedRecord */ DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), DECLARE_NAPI_FUNCTION("getValue", UnifiedRecordNapi::GetValue), + DECLARE_NAPI_FUNCTION("addEntry", UnifiedRecordNapi::AddEntry), + DECLARE_NAPI_FUNCTION("getEntry", UnifiedRecordNapi::GetEntry), + DECLARE_NAPI_FUNCTION("getEntries", UnifiedRecordNapi::GetEntries), + DECLARE_NAPI_FUNCTION("getTypes", UnifiedRecordNapi::GetTypes), /* File properties */ DECLARE_NAPI_GETTER_SETTER("details", GetDetails, SetDetails), DECLARE_NAPI_GETTER_SETTER("uri", GetUri, SetUri), diff --git a/udmf/framework/jskitsimpl/data/folder_napi.cpp b/udmf/framework/jskitsimpl/data/folder_napi.cpp index 9ec6a6ff310c59bf28f3b4ca70a71791e1626526..2f46119951f4a9d1909df2c7c67dd0af3e433b6b 100644 --- a/udmf/framework/jskitsimpl/data/folder_napi.cpp +++ b/udmf/framework/jskitsimpl/data/folder_napi.cpp @@ -28,6 +28,10 @@ napi_value FolderNapi::Constructor(napi_env env) /* Folder extends UnifiedRecord */ DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), DECLARE_NAPI_FUNCTION("getValue", UnifiedRecordNapi::GetValue), + DECLARE_NAPI_FUNCTION("addEntry", UnifiedRecordNapi::AddEntry), + DECLARE_NAPI_FUNCTION("getEntry", UnifiedRecordNapi::GetEntry), + DECLARE_NAPI_FUNCTION("getEntries", UnifiedRecordNapi::GetEntries), + DECLARE_NAPI_FUNCTION("getTypes", UnifiedRecordNapi::GetTypes), /* Folder extends File */ DECLARE_NAPI_GETTER_SETTER("details", FileNapi::GetDetails, FileNapi::SetDetails), DECLARE_NAPI_GETTER_SETTER("uri", FileNapi::GetUri, FileNapi::SetUri), diff --git a/udmf/framework/jskitsimpl/data/get_data_params_napi.cpp b/udmf/framework/jskitsimpl/data/get_data_params_napi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..43794a97e908a39d32bdb283c8e8d64b65dc9593 --- /dev/null +++ b/udmf/framework/jskitsimpl/data/get_data_params_napi.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2025 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 "GetDataParamsNapi" +#include "get_data_params_napi.h" + +#include "logger.h" +#include "napi_data_utils.h" +#include "unified_data_napi.h" + +namespace OHOS { +namespace UDMF { +static constexpr int32_t PROGRESS_INIT = 0; +static constexpr int32_t PROGRESS_ALL_FINISHED = 100; +ConcurrentMap<std::string, napi_threadsafe_function> GetDataParamsNapi::tsfns; + +bool GetDataParamsNapi::Convert2NativeValue(napi_env env, napi_value in, + GetDataParams &getDataParams, const std::string &key) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "Start."); + + napi_value jsProgressIndicator = nullptr; + NAPI_CALL_BASE(env, napi_get_named_property(env, in, "progressIndicator", &jsProgressIndicator), false); + int32_t progressIndicator = static_cast<int32_t>(ProgressIndicator::NONE); + NAPI_CALL_BASE(env, NapiDataUtils::GetValue(env, jsProgressIndicator, progressIndicator), false); + getDataParams.progressIndicator = static_cast<ProgressIndicator>(progressIndicator); + + napi_value JsListener = nullptr; + NAPI_CALL_BASE(env, napi_get_named_property(env, in, "dataProgressListener", &JsListener), false); + napi_valuetype valueType = napi_undefined; + NAPI_CALL_BASE(env, napi_typeof(env, JsListener, &valueType), false); + NAPI_ASSERT_BASE(env, valueType == napi_function, "progressListener type must be DataProgressListener", false); + if (!SetProgressListener(env, getDataParams, JsListener, key)) { + LOG_ERROR(UDMF_KITS_NAPI, "SetProgressListener failed."); + return false; + } + + bool hasDestUri = false; + NAPI_CALL_BASE(env, napi_has_named_property(env, in, "destUri", &hasDestUri), false); + if (hasDestUri) { + napi_value jsDestUri = nullptr; + NAPI_CALL_BASE(env, napi_get_named_property(env, in, "destUri", &jsDestUri), false); + NAPI_CALL_BASE(env, NapiDataUtils::GetValue(env, jsDestUri, getDataParams.destUri), false); + } + + bool hasFileConflictOptions = false; + NAPI_CALL_BASE(env, napi_has_named_property(env, in, "fileConflictOptions", &hasFileConflictOptions), false); + if (hasFileConflictOptions) { + napi_value jsFileConflictOptions = nullptr; + NAPI_CALL_BASE(env, napi_get_named_property(env, in, "fileConflictOptions", &jsFileConflictOptions), false); + int32_t fileConflictOptions = static_cast<int32_t>(FileConflictOptions::OVERWRITE); + NAPI_CALL_BASE(env, NapiDataUtils::GetValue(env, jsFileConflictOptions, fileConflictOptions), false); + getDataParams.fileConflictOptions = static_cast<FileConflictOptions>(fileConflictOptions); + } + + return true; +} + +bool GetDataParamsNapi::SetProgressListener(napi_env env, GetDataParams &getDataParams, + napi_value callback, const std::string &key) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "Start."); + tsfns.Compute(key, [&](const std::string &key, napi_threadsafe_function &tsfn) { + if (tsfn != nullptr) { + LOG_WARN(UDMF_KITS_NAPI, "Listener has existed!"); + napi_release_threadsafe_function(tsfn, napi_tsfn_release); + tsfn = nullptr; + } + napi_value workName; + napi_create_string_utf8(env, "threadsafe_function", NAPI_AUTO_LENGTH, &workName); + auto status = napi_create_threadsafe_function(env, callback, nullptr, workName, 0, 1, nullptr, + nullptr, nullptr, CallProgressListener, &tsfn); + if (status != napi_ok) { + LOG_ERROR(UDMF_KITS_NAPI, "napi_create_threadsafe_function failed, status=%{public}d", status); + return false; + } + return true; + }); + + getDataParams.progressListener = [key](ProgressInfo progressInfo, std::shared_ptr<UnifiedData> data) { + bool listenerExist = tsfns.ComputeIfPresent(key, [&](const std::string &key, napi_threadsafe_function &tsfn) { + auto listenerArgs = CreateListenerArgs(progressInfo, data); + if (listenerArgs == nullptr) { + return false; + } + auto status = napi_call_threadsafe_function(tsfn, listenerArgs, napi_tsfn_blocking); + if (status != napi_ok) { + LOG_ERROR(UDMF_KITS_NAPI, "napi_call_threadsafe_function failed, status=%{public}d", status); + return false; + } + if (progressInfo.progress >= PROGRESS_ALL_FINISHED || + progressInfo.progress < PROGRESS_INIT) { + napi_release_threadsafe_function(tsfn, napi_tsfn_release); + return false; + } + return true; + }); + if (!listenerExist) { + LOG_INFO(UDMF_KITS_NAPI, "No listener exist."); + } + }; + return true; +} + +void GetDataParamsNapi::CallProgressListener(napi_env env, napi_value callback, void *context, void *data) +{ + ListenerArgs* listenerArgs = static_cast<ListenerArgs*>(data); + napi_value param[ListenerArgs::ARGV_SIZE]; + + NapiDataUtils::SetValue(env, listenerArgs->progressInfo, param[0]); + + if (listenerArgs->unifiedData == nullptr) { + NapiDataUtils::SetValue(env, nullptr, param[1]); + } else { + std::shared_ptr<UnifiedData> unifiedData = std::make_shared<UnifiedData>(); + unifiedData->SetRecords(listenerArgs->unifiedData->GetRecords()); + UnifiedDataNapi::NewInstance(env, unifiedData, param[1]); + } + + auto status = napi_call_function(env, nullptr, callback, ListenerArgs::ARGV_SIZE, param, nullptr); + if (status != napi_ok) { + LOG_ERROR(UDMF_KITS_NAPI, "napi_call_function failed, status=%{public}d", status); + } + + DeleteListenerArgs(listenerArgs); +} + +GetDataParamsNapi::ListenerArgs* GetDataParamsNapi::CreateListenerArgs( + ProgressInfo progressInfo, std::shared_ptr<UnifiedData> data) +{ + auto listenerArgs = new (std::nothrow) ListenerArgs; + if (listenerArgs == nullptr) { + LOG_ERROR(UDMF_KITS_NAPI, "No memory for listenerArgs malloc"); + return nullptr; + } + listenerArgs->progressInfo = progressInfo; + listenerArgs->unifiedData = nullptr; + if (data != nullptr) { + listenerArgs->unifiedData = new (std::nothrow) UnifiedData; + if (listenerArgs->unifiedData == nullptr) { + LOG_ERROR(UDMF_KITS_NAPI, "No memory for unifiedData malloc"); + delete listenerArgs; + return nullptr; + } + listenerArgs->unifiedData->SetRecords(data->GetRecords()); + } + return listenerArgs; +} + +void GetDataParamsNapi::DeleteListenerArgs(ListenerArgs *listenerArgs) +{ + if (listenerArgs->unifiedData != nullptr) { + delete listenerArgs->unifiedData; + listenerArgs->unifiedData = nullptr; + } + delete listenerArgs; + listenerArgs = nullptr; +} + +} // namespace UDMF +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/html_napi.cpp b/udmf/framework/jskitsimpl/data/html_napi.cpp index 49e43b8c27c6b72fd0af5a09cd45ae7432dfda80..47d9b996c9b33769525ca61536a95e2f6e960e3c 100644 --- a/udmf/framework/jskitsimpl/data/html_napi.cpp +++ b/udmf/framework/jskitsimpl/data/html_napi.cpp @@ -28,6 +28,10 @@ napi_value HtmlNapi::Constructor(napi_env env) /* Html extends UnifiedRecord */ DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), DECLARE_NAPI_FUNCTION("getValue", UnifiedRecordNapi::GetValue), + DECLARE_NAPI_FUNCTION("addEntry", UnifiedRecordNapi::AddEntry), + DECLARE_NAPI_FUNCTION("getEntry", UnifiedRecordNapi::GetEntry), + DECLARE_NAPI_FUNCTION("getEntries", UnifiedRecordNapi::GetEntries), + DECLARE_NAPI_FUNCTION("getTypes", UnifiedRecordNapi::GetTypes), /* Html extends Text */ DECLARE_NAPI_GETTER_SETTER("details", TextNapi::GetDetails, TextNapi::SetDetails), /* Html properties */ diff --git a/udmf/framework/jskitsimpl/data/image_napi.cpp b/udmf/framework/jskitsimpl/data/image_napi.cpp index 8df4f80ea70fea10c204c9ae53b3a56c1d64417a..972fdbefed77becaaac9e7a522ed16f75a21ad8a 100644 --- a/udmf/framework/jskitsimpl/data/image_napi.cpp +++ b/udmf/framework/jskitsimpl/data/image_napi.cpp @@ -28,6 +28,10 @@ napi_value ImageNapi::Constructor(napi_env env) /* Image extends UnifiedRecord */ DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), DECLARE_NAPI_FUNCTION("getValue", UnifiedRecordNapi::GetValue), + DECLARE_NAPI_FUNCTION("addEntry", UnifiedRecordNapi::AddEntry), + DECLARE_NAPI_FUNCTION("getEntry", UnifiedRecordNapi::GetEntry), + DECLARE_NAPI_FUNCTION("getEntries", UnifiedRecordNapi::GetEntries), + DECLARE_NAPI_FUNCTION("getTypes", UnifiedRecordNapi::GetTypes), /* Image extends File */ DECLARE_NAPI_GETTER_SETTER("details", FileNapi::GetDetails, FileNapi::SetDetails), DECLARE_NAPI_GETTER_SETTER("uri", FileNapi::GetUri, FileNapi::SetUri), diff --git a/udmf/framework/jskitsimpl/data/link_napi.cpp b/udmf/framework/jskitsimpl/data/link_napi.cpp index 641defef40211599f301cc3e86274132575c3bda..0fe74ede33e0774bb3a975c617594015cac34eb7 100644 --- a/udmf/framework/jskitsimpl/data/link_napi.cpp +++ b/udmf/framework/jskitsimpl/data/link_napi.cpp @@ -28,6 +28,10 @@ napi_value LinkNapi::Constructor(napi_env env) /* Link extends UnifiedRecord */ DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), DECLARE_NAPI_FUNCTION("getValue", UnifiedRecordNapi::GetValue), + DECLARE_NAPI_FUNCTION("addEntry", UnifiedRecordNapi::AddEntry), + DECLARE_NAPI_FUNCTION("getEntry", UnifiedRecordNapi::GetEntry), + DECLARE_NAPI_FUNCTION("getEntries", UnifiedRecordNapi::GetEntries), + DECLARE_NAPI_FUNCTION("getTypes", UnifiedRecordNapi::GetTypes), /* Link extends Text */ DECLARE_NAPI_GETTER_SETTER("details", TextNapi::GetDetails, TextNapi::SetDetails), /* Link properties */ diff --git a/udmf/framework/jskitsimpl/data/plain_text_napi.cpp b/udmf/framework/jskitsimpl/data/plain_text_napi.cpp index 9ba459fdcf8280fe5215ef3d1d51a4d0d851615e..449f0e718bd1565928b00d28ba8f5603c8e94345 100644 --- a/udmf/framework/jskitsimpl/data/plain_text_napi.cpp +++ b/udmf/framework/jskitsimpl/data/plain_text_napi.cpp @@ -28,6 +28,10 @@ napi_value PlainTextNapi::Constructor(napi_env env) /* PlainText extends UnifiedRecord */ DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), DECLARE_NAPI_FUNCTION("getValue", UnifiedRecordNapi::GetValue), + DECLARE_NAPI_FUNCTION("addEntry", UnifiedRecordNapi::AddEntry), + DECLARE_NAPI_FUNCTION("getEntry", UnifiedRecordNapi::GetEntry), + DECLARE_NAPI_FUNCTION("getEntries", UnifiedRecordNapi::GetEntries), + DECLARE_NAPI_FUNCTION("getTypes", UnifiedRecordNapi::GetTypes), /* PlainText extends Text */ DECLARE_NAPI_GETTER_SETTER("details", TextNapi::GetDetails, TextNapi::SetDetails), /* PlainText properties */ diff --git a/udmf/framework/jskitsimpl/data/system_defined_appitem_napi.cpp b/udmf/framework/jskitsimpl/data/system_defined_appitem_napi.cpp index 2401a64cac39cc92f013ce508d0e3a968937b3f1..ce83d27d414d7456e1d8f0dc04d145e6b6095152 100644 --- a/udmf/framework/jskitsimpl/data/system_defined_appitem_napi.cpp +++ b/udmf/framework/jskitsimpl/data/system_defined_appitem_napi.cpp @@ -28,6 +28,10 @@ napi_value SystemDefinedAppItemNapi::Constructor(napi_env env) /* SystemDefinedAppItem extends UnifiedRecord */ DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), DECLARE_NAPI_FUNCTION("getValue", UnifiedRecordNapi::GetValue), + DECLARE_NAPI_FUNCTION("addEntry", UnifiedRecordNapi::AddEntry), + DECLARE_NAPI_FUNCTION("getEntry", UnifiedRecordNapi::GetEntry), + DECLARE_NAPI_FUNCTION("getEntries", UnifiedRecordNapi::GetEntries), + DECLARE_NAPI_FUNCTION("getTypes", UnifiedRecordNapi::GetTypes), /* SystemDefinedAppItem extends SystemDefinedRecord */ DECLARE_NAPI_GETTER_SETTER("details", SystemDefinedRecordNapi::GetDetails, SystemDefinedRecordNapi::SetDetails), /* SystemDefinedAppItem properties */ diff --git a/udmf/framework/jskitsimpl/data/system_defined_form_napi.cpp b/udmf/framework/jskitsimpl/data/system_defined_form_napi.cpp index 41ae7bca17c988ea9a3ae88d8667b6209f42731a..0b8a90124488ca6a8a89633b83676af89634fefc 100644 --- a/udmf/framework/jskitsimpl/data/system_defined_form_napi.cpp +++ b/udmf/framework/jskitsimpl/data/system_defined_form_napi.cpp @@ -28,6 +28,10 @@ napi_value SystemDefinedFormNapi::Constructor(napi_env env) /* SystemDefinedForm extends UnifiedRecord */ DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), DECLARE_NAPI_FUNCTION("getValue", UnifiedRecordNapi::GetValue), + DECLARE_NAPI_FUNCTION("addEntry", UnifiedRecordNapi::AddEntry), + DECLARE_NAPI_FUNCTION("getEntry", UnifiedRecordNapi::GetEntry), + DECLARE_NAPI_FUNCTION("getEntries", UnifiedRecordNapi::GetEntries), + DECLARE_NAPI_FUNCTION("getTypes", UnifiedRecordNapi::GetTypes), /* SystemDefinedForm extends SystemDefinedRecord */ DECLARE_NAPI_GETTER_SETTER("details", SystemDefinedRecordNapi::GetDetails, SystemDefinedRecordNapi::SetDetails), /* SystemDefinedForm properties */ diff --git a/udmf/framework/jskitsimpl/data/system_defined_pixelmap_napi.cpp b/udmf/framework/jskitsimpl/data/system_defined_pixelmap_napi.cpp index 20dba8471c93fc1418a2e0f54052001378577426..097aec8683bbada40ac0c7f17d9a2388bb56b495 100644 --- a/udmf/framework/jskitsimpl/data/system_defined_pixelmap_napi.cpp +++ b/udmf/framework/jskitsimpl/data/system_defined_pixelmap_napi.cpp @@ -28,6 +28,10 @@ napi_value SystemDefinedPixelMapNapi::Constructor(napi_env env) /* SystemDefinedPixelMap extends UnifiedRecord */ DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), DECLARE_NAPI_FUNCTION("getValue", UnifiedRecordNapi::GetValue), + DECLARE_NAPI_FUNCTION("addEntry", UnifiedRecordNapi::AddEntry), + DECLARE_NAPI_FUNCTION("getEntry", UnifiedRecordNapi::GetEntry), + DECLARE_NAPI_FUNCTION("getEntries", UnifiedRecordNapi::GetEntries), + DECLARE_NAPI_FUNCTION("getTypes", UnifiedRecordNapi::GetTypes), /* SystemDefinedPixelMap extends SystemDefinedRecord */ DECLARE_NAPI_GETTER_SETTER("details", SystemDefinedRecordNapi::GetDetails, SystemDefinedRecordNapi::SetDetails), /* SystemDefinedPixelMap properties */ diff --git a/udmf/framework/jskitsimpl/data/system_defined_record_napi.cpp b/udmf/framework/jskitsimpl/data/system_defined_record_napi.cpp index b27f9d78d67d242a9a2e5cdb8f3d79a80a89d7f7..513c506c0aea190defc58e7c99f178104fcd9207 100644 --- a/udmf/framework/jskitsimpl/data/system_defined_record_napi.cpp +++ b/udmf/framework/jskitsimpl/data/system_defined_record_napi.cpp @@ -27,6 +27,10 @@ napi_value SystemDefinedRecordNapi::Constructor(napi_env env) /* SystemDefinedRecord extends UnifiedRecord */ DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), DECLARE_NAPI_FUNCTION("getValue", UnifiedRecordNapi::GetValue), + DECLARE_NAPI_FUNCTION("addEntry", UnifiedRecordNapi::AddEntry), + DECLARE_NAPI_FUNCTION("getEntry", UnifiedRecordNapi::GetEntry), + DECLARE_NAPI_FUNCTION("getEntries", UnifiedRecordNapi::GetEntries), + DECLARE_NAPI_FUNCTION("getTypes", UnifiedRecordNapi::GetTypes), /* SystemDefinedRecord properties */ DECLARE_NAPI_GETTER_SETTER("details", GetDetails, SetDetails), }; diff --git a/udmf/framework/jskitsimpl/data/text_napi.cpp b/udmf/framework/jskitsimpl/data/text_napi.cpp index fe97fea2bd614bcfe489db7cdec2413142829a13..267976cb2007946ceba45c1db116bf45ce85d3d0 100644 --- a/udmf/framework/jskitsimpl/data/text_napi.cpp +++ b/udmf/framework/jskitsimpl/data/text_napi.cpp @@ -27,6 +27,10 @@ napi_value TextNapi::Constructor(napi_env env) /* Text extends UnifiedRecord */ DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), DECLARE_NAPI_FUNCTION("getValue", UnifiedRecordNapi::GetValue), + DECLARE_NAPI_FUNCTION("addEntry", UnifiedRecordNapi::AddEntry), + DECLARE_NAPI_FUNCTION("getEntry", UnifiedRecordNapi::GetEntry), + DECLARE_NAPI_FUNCTION("getEntries", UnifiedRecordNapi::GetEntries), + DECLARE_NAPI_FUNCTION("getTypes", UnifiedRecordNapi::GetTypes), /* Text properties */ DECLARE_NAPI_GETTER_SETTER("details", GetDetails, SetDetails), }; diff --git a/udmf/framework/jskitsimpl/data/unified_data_channel_napi.cpp b/udmf/framework/jskitsimpl/data/unified_data_channel_napi.cpp index 8daaaeaf8f2515d4705fd4614ecf9a09606b4f58..579e351311a3a6f76a16e63f12a41a88d8b857e2 100644 --- a/udmf/framework/jskitsimpl/data/unified_data_channel_napi.cpp +++ b/udmf/framework/jskitsimpl/data/unified_data_channel_napi.cpp @@ -15,8 +15,8 @@ #define LOG_TAG "UnifiedDataChannelNapi" #include "unified_data_channel_napi.h" +#include "async_task_params.h" #include "napi_data_utils.h" -#include "udmf_client.h" #include "unified_data_napi.h" namespace OHOS { @@ -35,6 +35,9 @@ napi_value UnifiedDataChannelNapi::UnifiedDataChannelInit(napi_env env, napi_val DECLARE_NAPI_GETTER("ShareOptions", CreateShareOptions), DECLARE_NAPI_FUNCTION("setAppShareOptions", SetAppShareOptions), DECLARE_NAPI_FUNCTION("removeAppShareOptions", RemoveAppShareOptions), + DECLARE_NAPI_GETTER("FileConflictOptions", CreateFileConflictOptions), + DECLARE_NAPI_GETTER("ProgressIndicator", CreateProgressIndicator), + DECLARE_NAPI_GETTER("ListenerStatus", CreateListenerStatus), }; NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); @@ -84,6 +87,8 @@ napi_value UnifiedDataChannelNapi::InsertData(napi_env env, napi_callback_info i ASSERT_BUSINESS_ERR(ctxt, argc >= 2, E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified"); ctxt->status = GetNamedProperty(env, argv[0], "intention", intention); + ASSERT_BUSINESS_ERR(ctxt, UnifiedDataUtils::GetIntentionByString(intention) != UD_INTENTION_DRAG, + E_INVALID_PARAMETERS, "Parameter error: The intention parameter is invalid"); ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok && UnifiedDataUtils::IsPersist(intention), E_INVALID_PARAMETERS, "Parameter error: parameter options intention type must correspond to Intention"); ctxt->status = napi_unwrap(env, argv[1], reinterpret_cast<void **>(&unifiedDataNapi)); @@ -136,7 +141,8 @@ napi_value UnifiedDataChannelNapi::UpdateData(napi_env env, napi_callback_info i auto execute = [ctxt]() { QueryOption option = { .key = ctxt->key }; auto status = UdmfClient::GetInstance().UpdateData(option, *(ctxt->unifiedData)); - ASSERT_WITH_ERRCODE(ctxt, status == E_OK, status, "UpdateData failed!"); + ASSERT_WITH_ERRCODE(ctxt, status == E_OK, E_INVALID_PARAMETERS, + "Parameter error: The unifiedData parameter is invalid!"); }; return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute); } @@ -160,6 +166,8 @@ napi_value UnifiedDataChannelNapi::QueryData(napi_env env, napi_callback_info in auto options = argv[0]; keyStatus = GetNamedProperty(env, options, "key", ctxt->key); intentionStatus = GetNamedProperty(env, options, "intention", intention); + ASSERT_BUSINESS_ERR(ctxt, UnifiedDataUtils::GetIntentionByString(intention) != UD_INTENTION_DRAG, + E_INVALID_PARAMETERS, "Parameter error: The intention parameter is invalid"); ASSERT_BUSINESS_ERR(ctxt, (keyStatus == napi_ok || intentionStatus == napi_ok) && UnifiedDataUtils::IsValidOptions(ctxt->key, intention), E_INVALID_PARAMETERS, "Parameter error: parameter options intention type must correspond to Intention"); @@ -177,19 +185,10 @@ napi_value UnifiedDataChannelNapi::QueryData(napi_env env, napi_callback_info in ASSERT_WITH_ERRCODE(ctxt, status == E_OK, status, "QueryData failed!"); }; auto output = [env, ctxt](napi_value &result) { - ASSERT_WITH_ERRCODE(ctxt, !ctxt->unifiedDataSet.empty(), E_ERROR, "unifiedDataSet is empty!"); - ctxt->status = napi_create_array_with_length(env, ctxt->unifiedDataSet.size(), &ctxt->output); - ASSERT_WITH_ERRCODE(ctxt, ctxt->status == napi_ok, E_ERROR, "napi_create_array_with_length failed!"); - int index = 0; - for (const UnifiedData &data : ctxt->unifiedDataSet) { - std::shared_ptr<UnifiedData> unifiedData = std::make_shared<UnifiedData>(); - unifiedData->SetRecords(data.GetRecords()); - napi_value dataNapi = nullptr; - UnifiedDataNapi::NewInstance(env, unifiedData, dataNapi); - ctxt->status = napi_set_element(env, ctxt->output, index++, dataNapi); - ASSERT_WITH_ERRCODE(ctxt, ctxt->status == napi_ok, E_ERROR, "napi_set_element failed!"); - } - result = ctxt->output; + ASSERT_WITH_ERRCODE(ctxt, !ctxt->unifiedDataSet.empty(), E_INVALID_PARAMETERS, + "Parameter error: The unifiedDataSet parameter is empty!"); + ctxt->status = ConvertUnifiedDataSetToNapi(env, ctxt->unifiedDataSet, result); + ASSERT_WITH_ERRCODE(ctxt, ctxt->status == napi_ok, E_ERROR, "ConvertUnifiedDataSetToNapi failed!"); }; return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output); } @@ -213,6 +212,9 @@ napi_value UnifiedDataChannelNapi::DeleteData(napi_env env, napi_callback_info i napi_value options = argv[0]; keyStatus = GetNamedProperty(env, options, "key", ctxt->key); intentionStatus = GetNamedProperty(env, options, "intention", intention); + ASSERT_BUSINESS_ERR(ctxt, intention.empty() || + UnifiedDataUtils::GetIntentionByString(intention) == UD_INTENTION_DATA_HUB, + E_INVALID_PARAMETERS, "Parameter error: The intention parameter is invalid"); ASSERT_BUSINESS_ERR(ctxt, (keyStatus == napi_ok || intentionStatus == napi_ok) && UnifiedDataUtils::IsValidOptions(ctxt->key, intention), @@ -231,18 +233,8 @@ napi_value UnifiedDataChannelNapi::DeleteData(napi_env env, napi_callback_info i }; auto output = [env, ctxt](napi_value &result) { - ctxt->status = napi_create_array_with_length(env, ctxt->unifiedDataSet.size(), &ctxt->output); - ASSERT_WITH_ERRCODE(ctxt, ctxt->status == napi_ok, E_ERROR, "napi_create_array_with_length failed!"); - int index = 0; - for (const UnifiedData &data : ctxt->unifiedDataSet) { - std::shared_ptr<UnifiedData> unifiedData = std::make_shared<UnifiedData>(); - unifiedData->SetRecords(data.GetRecords()); - napi_value dataNapi = nullptr; - UnifiedDataNapi::NewInstance(env, unifiedData, dataNapi); - ctxt->status = napi_set_element(env, ctxt->output, index++, dataNapi); - ASSERT_WITH_ERRCODE(ctxt, ctxt->status == napi_ok, E_ERROR, "napi_set_element failed!"); - } - result = ctxt->output; + ctxt->status = ConvertUnifiedDataSetToNapi(env, ctxt->unifiedDataSet, result); + ASSERT_WITH_ERRCODE(ctxt, ctxt->status == napi_ok, E_ERROR, "ConvertUnifiedDataSetToNapi failed!"); }; return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output); } @@ -322,7 +314,7 @@ napi_value UnifiedDataChannelNapi::SetAppShareOptions(napi_env env, napi_callbac std::transform(intention.begin(), intention.end(), intention.begin(), ::tolower); // js : Drag --> drag status = UdmfClient::GetInstance().SetAppShareOption(intention, static_cast<ShareOptions>(shareOptionValue)); ASSERT_BUSINESS_ERR_VOID(ctxt, !(status == E_SETTINGS_EXISTED), E_SETTINGS_EXISTED, "Settings already exist!"); - ASSERT_BUSINESS_ERR_VOID(ctxt, !(status == E_NO_PERMISSION), E_NO_SYSTEM_PERMISSION, "Permission denied!"); + ASSERT_BUSINESS_ERR_VOID(ctxt, status != E_NO_PERMISSION, E_NO_PERMISSION, "Permission denied!"); ASSERT_ERR(ctxt->env, status == E_OK, status, "invalid arguments!"); return nullptr; } @@ -348,9 +340,93 @@ napi_value UnifiedDataChannelNapi::RemoveAppShareOptions(napi_env env, napi_call std::transform(intention.begin(), intention.end(), intention.begin(), ::tolower); // js : Drag --> drag auto status = E_OK; status = UdmfClient::GetInstance().RemoveAppShareOption(intention); - ASSERT_BUSINESS_ERR_VOID(ctxt, !(status == E_NO_PERMISSION), E_NO_SYSTEM_PERMISSION, "Permission denied!"); + ASSERT_BUSINESS_ERR_VOID(ctxt, status != E_NO_PERMISSION, E_NO_PERMISSION, "Permission denied!"); ASSERT_ERR(ctxt->env, status == E_OK, status, "invalid arguments!"); return nullptr; } + +napi_status UnifiedDataChannelNapi::ConvertUnifiedDataSetToNapi( + napi_env env, const std::vector<UnifiedData> &dataSet, napi_value &output) +{ + auto status = napi_create_array_with_length(env, dataSet.size(), &output); + if (status != napi_ok) { + LOG_ERROR(UDMF_KITS_NAPI, "napi_create_array_with_length failed!"); + return napi_generic_failure; + } + int index = 0; + for (const UnifiedData &data : dataSet) { + std::shared_ptr<UnifiedData> unifiedData = std::make_shared<UnifiedData>(); + unifiedData->SetRecords(data.GetRecords()); + napi_value dataNapi = nullptr; + UnifiedDataNapi::NewInstance(env, unifiedData, dataNapi); + status = napi_set_element(env, output, index++, dataNapi); + if (status != napi_ok) { + LOG_ERROR(UDMF_KITS_NAPI, "napi_set_element failed!"); + return napi_generic_failure; + } + } + return napi_ok; +} + +napi_value UnifiedDataChannelNapi::CreateFileConflictOptions(napi_env env, napi_callback_info info) +{ + napi_value jsFileOptions = nullptr; + napi_create_object(env, &jsFileOptions); + + napi_value jsOverWrite; + NapiDataUtils::SetValue(env, static_cast<int32_t>(FileConflictOptions::OVERWRITE), jsOverWrite); + NAPI_CALL(env, napi_set_named_property(env, jsFileOptions, "OVERWRITE", jsOverWrite)); + + napi_value jsSkip; + NapiDataUtils::SetValue(env, static_cast<int32_t>(FileConflictOptions::SKIP), jsSkip); + NAPI_CALL(env, napi_set_named_property(env, jsFileOptions, "SKIP", jsSkip)); + return jsFileOptions; +} + +napi_value UnifiedDataChannelNapi::CreateProgressIndicator(napi_env env, napi_callback_info info) +{ + napi_value jsProgressIndicator = nullptr; + napi_create_object(env, &jsProgressIndicator); + + napi_value jsNone; + NapiDataUtils::SetValue(env, static_cast<int32_t>(ProgressIndicator::NONE), jsNone); + NAPI_CALL(env, napi_set_named_property(env, jsProgressIndicator, "NONE", jsNone)); + + napi_value jsDefault; + NapiDataUtils::SetValue(env, static_cast<int32_t>(ProgressIndicator::DEFAULT), jsDefault); + NAPI_CALL(env, napi_set_named_property(env, jsProgressIndicator, "DEFAULT", jsDefault)); + return jsProgressIndicator; +} + +napi_value UnifiedDataChannelNapi::CreateListenerStatus(napi_env env, napi_callback_info info) +{ + napi_value jsListenerStatus = nullptr; + napi_create_object(env, &jsListenerStatus); + + napi_value jsFinished; + NapiDataUtils::SetValue(env, static_cast<int32_t>(ListenerStatus::FINISHED), jsFinished); + NAPI_CALL(env, napi_set_named_property(env, jsListenerStatus, "FINISHED", jsFinished)); + + napi_value jsProcessing; + NapiDataUtils::SetValue(env, static_cast<int32_t>(ListenerStatus::PROCESSING), jsProcessing); + NAPI_CALL(env, napi_set_named_property(env, jsListenerStatus, "PROCESSING", jsProcessing)); + + napi_value jsInnerError; + NapiDataUtils::SetValue(env, static_cast<int32_t>(ListenerStatus::INNER_ERROR), jsInnerError); + NAPI_CALL(env, napi_set_named_property(env, jsListenerStatus, "INNER_ERROR", jsInnerError)); + + napi_value jsInvalidPara; + NapiDataUtils::SetValue(env, static_cast<int32_t>(ListenerStatus::INVALID_PARAMETERS), jsInvalidPara); + NAPI_CALL(env, napi_set_named_property(env, jsListenerStatus, "INVALID_PARAMETERS", jsInvalidPara)); + + napi_value jsSyncFail; + NapiDataUtils::SetValue(env, static_cast<int32_t>(ListenerStatus::SYNC_FAILED), jsSyncFail); + NAPI_CALL(env, napi_set_named_property(env, jsListenerStatus, "SYNC_FAILED", jsSyncFail)); + + napi_value jsCopyFail; + NapiDataUtils::SetValue(env, static_cast<int32_t>(ListenerStatus::COPY_FILE_FAILED), jsCopyFail); + NAPI_CALL(env, napi_set_named_property(env, jsListenerStatus, "COPY_FILE_FAILED", jsCopyFail)); + return jsListenerStatus; +} } // namespace UDMF } // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/unified_data_napi.cpp b/udmf/framework/jskitsimpl/data/unified_data_napi.cpp index 905e8cae19068950f9ed8afcdbb889c84130ddfd..f88a80c71dd7aec6f4ddc40f03012799380adc51 100644 --- a/udmf/framework/jskitsimpl/data/unified_data_napi.cpp +++ b/udmf/framework/jskitsimpl/data/unified_data_napi.cpp @@ -78,6 +78,9 @@ napi_value UnifiedDataNapi::New(napi_env env, napi_callback_info info) UnifiedDataPropertiesNapi::Constructor(env)); if (propertiesNapi == nullptr) { LOG_ERROR(UDMF_KITS_NAPI, "new UnifiedDataPropertiesNapi failed!"); + if (uData->propertyRef_ != nullptr) { + napi_delete_reference(env, uData->propertyRef_); + } delete(uData); return nullptr; } diff --git a/udmf/framework/jskitsimpl/data/unified_record_napi.cpp b/udmf/framework/jskitsimpl/data/unified_record_napi.cpp index 67a83a5e1d2c5a65977209d36fdaa475c24e037b..c7cfd4beaabd91142d442ea03f69cd599d664e0f 100644 --- a/udmf/framework/jskitsimpl/data/unified_record_napi.cpp +++ b/udmf/framework/jskitsimpl/data/unified_record_napi.cpp @@ -36,6 +36,10 @@ napi_value UnifiedRecordNapi::Constructor(napi_env env) /* UnifiedRecord properties */ DECLARE_NAPI_FUNCTION("getType", GetType), DECLARE_NAPI_FUNCTION("getValue", GetValue), + DECLARE_NAPI_FUNCTION("addEntry", AddEntry), + DECLARE_NAPI_FUNCTION("getEntry", GetEntry), + DECLARE_NAPI_FUNCTION("getEntries", GetEntries), + DECLARE_NAPI_FUNCTION("getTypes", GetTypes), }; size_t count = sizeof(properties) / sizeof(properties[0]); return NapiDataUtils::DefineClass(env, "UnifiedRecord", properties, count, UnifiedRecordNapi::New); @@ -53,7 +57,7 @@ napi_value UnifiedRecordNapi::New(napi_env env, napi_callback_info info) if (argc >= 2) { ctxt->status = NapiDataUtils::GetValue(env, argv[0], type); ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok && !type.empty(), - Status::E_INVALID_PARAMETERS, "Parameter error: parameter type type must be string"); + Status::E_INVALID_PARAMETERS, "Parameter error: parameter type must be string"); value = argv[1]; } }; @@ -197,6 +201,17 @@ napi_value UnifiedRecordNapi::GetType(napi_env env, napi_callback_info info) return ctxt->output; } +napi_value UnifiedRecordNapi::GetTypes(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto uRecord = GetUnifiedRecord(env, info, ctxt); + ASSERT_ERR(ctxt->env, (uRecord != nullptr && uRecord->value_ != nullptr), Status::E_ERROR, "invalid object!"); + ctxt->status = NapiDataUtils::SetValue(env, uRecord->value_->GetTypes(), ctxt->output); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, "set type failed!"); + return ctxt->output; +} + napi_value UnifiedRecordNapi::GetValue(napi_env env, napi_callback_info info) { LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi"); @@ -218,5 +233,94 @@ napi_value UnifiedRecordNapi::GetValue(napi_env env, napi_callback_info info) } return ctxt->output; } + +napi_value UnifiedRecordNapi::AddEntry(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string type; + napi_value napiValue = nullptr; + auto input = [env, ctxt, &type, &napiValue](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc == 0 || argc >= 2, + Status::E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified"); + if (argc >= 2) { + ctxt->status = NapiDataUtils::GetValue(env, argv[0], type); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok && !type.empty(), + Status::E_INVALID_PARAMETERS, "Parameter error: parameter type must be string"); + napiValue = argv[1]; + } + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, ctxt->error); + auto uRecord = static_cast<UnifiedRecordNapi *>(ctxt->native); + ASSERT_ERR(ctxt->env, (uRecord != nullptr && uRecord->value_ != nullptr), Status::E_ERROR, "invalid object!"); + ValueType value; + GetNativeValue(env, type, napiValue, value); + uRecord->value_->AddEntry(type, std::move(value)); + return nullptr; +} + +napi_value UnifiedRecordNapi::GetEntry(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi"); + auto ctxt = std::make_shared<ContextBase>(); + std::string type; + auto input = [env, ctxt, &type](size_t argc, napi_value *argv) { + ASSERT_BUSINESS_ERR(ctxt, argc == 0 || argc >= 1, + Status::E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified"); + if (argc >= 1) { + ctxt->status = NapiDataUtils::GetValue(env, argv[0], type); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok && !type.empty(), + Status::E_INVALID_PARAMETERS, "Parameter error: parameter type must be string"); + } + }; + ctxt->GetCbInfoSync(env, info, input); + ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, ctxt->error); + auto uRecord = static_cast<UnifiedRecordNapi *>(ctxt->native); + ASSERT_ERR(ctxt->env, (uRecord != nullptr && uRecord->value_ != nullptr), Status::E_ERROR, "invalid object!"); + ValueType entry = uRecord->value_->GetEntry(type); + if (std::holds_alternative<std::vector<uint8_t>>(entry)) { + auto value = std::get<std::vector<uint8_t>>(entry); + void *data = nullptr; + size_t len = value.size(); + NAPI_CALL(env, napi_create_arraybuffer(env, len, &data, &ctxt->output)); + if (memcpy_s(data, len, reinterpret_cast<const void *>(value.data()), len) != 0) { + LOG_ERROR(UDMF_KITS_NAPI, "memcpy_s failed"); + return nullptr; + } + } else { + std::visit([&](const auto &value) { NapiDataUtils::SetValue(env, value, ctxt->output); }, + entry); + } + return ctxt->output; +} + +napi_value UnifiedRecordNapi::GetEntries(napi_env env, napi_callback_info info) +{ + LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi"); + auto ctxt = std::make_shared<ContextBase>(); + auto uRecord = GetUnifiedRecord(env, info, ctxt); + ASSERT_ERR(ctxt->env, (uRecord != nullptr && uRecord->value_ != nullptr), Status::E_ERROR, "invalid object!"); + std::shared_ptr<std::map<std::string, ValueType>> entries = uRecord->value_->GetEntries(); + napi_create_object(env, &ctxt->output); + for (auto &entry : *entries) { + napi_value napiValue = nullptr; + if (std::holds_alternative<std::vector<uint8_t>>(entry.second)) { + auto vecVal = std::get<std::vector<uint8_t>>(entry.second); + void *data = nullptr; + size_t len = vecVal.size(); + NAPI_CALL(env, napi_create_arraybuffer(env, len, &data, &napiValue)); + if (memcpy_s(data, len, reinterpret_cast<const void *>(vecVal.data()), len) != 0) { + LOG_ERROR(UDMF_KITS_NAPI, "memcpy_s failed"); + return nullptr; + } + } else { + std::visit([&](const auto &value) { NapiDataUtils::SetValue(env, value, napiValue); }, + entry.second); + } + napi_set_named_property(env, ctxt->output, entry.first.c_str(), napiValue); + } + return ctxt->output; +} } // namespace UDMF } // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/data/video_napi.cpp b/udmf/framework/jskitsimpl/data/video_napi.cpp index 2dbe64a6d947f6d75a41cbf1edb27231f25d937a..afee53d136d47f9558dd15636c22549d47c1c534 100644 --- a/udmf/framework/jskitsimpl/data/video_napi.cpp +++ b/udmf/framework/jskitsimpl/data/video_napi.cpp @@ -28,6 +28,10 @@ napi_value VideoNapi::Constructor(napi_env env) /* Video extends UnifiedRecord */ DECLARE_NAPI_FUNCTION("getType", UnifiedRecordNapi::GetType), DECLARE_NAPI_FUNCTION("getValue", UnifiedRecordNapi::GetValue), + DECLARE_NAPI_FUNCTION("addEntry", UnifiedRecordNapi::AddEntry), + DECLARE_NAPI_FUNCTION("getEntry", UnifiedRecordNapi::GetEntry), + DECLARE_NAPI_FUNCTION("getEntries", UnifiedRecordNapi::GetEntries), + DECLARE_NAPI_FUNCTION("getTypes", UnifiedRecordNapi::GetTypes), /* Video extends File */ DECLARE_NAPI_GETTER_SETTER("details", FileNapi::GetDetails, FileNapi::SetDetails), DECLARE_NAPI_GETTER_SETTER("uri", FileNapi::GetUri, FileNapi::SetUri), diff --git a/udmf/framework/jskitsimpl/intelligence/aip_napi_error.cpp b/udmf/framework/jskitsimpl/intelligence/aip_napi_error.cpp new file mode 100644 index 0000000000000000000000000000000000000000..44b455e1d91ebf69ce5e94b5de2f05daa47e8343 --- /dev/null +++ b/udmf/framework/jskitsimpl/intelligence/aip_napi_error.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025 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 "aip_napi_error.h" + +#include <optional> + +#include "aip_log.h" + +#undef LOG_TAG +#define LOG_TAG "AipNapiError" + +namespace OHOS { +namespace DataIntelligence { +napi_value CreateIntelligenceError(const napi_env &env, int32_t errorCode, const std::string &errorMsg) +{ + napi_value businessError = nullptr; + napi_value code = nullptr; + napi_value msg = nullptr; + NAPI_CALL(env, napi_create_int32(env, errorCode, &code)); + NAPI_CALL(env, napi_create_string_utf8(env, errorMsg.c_str(), NAPI_AUTO_LENGTH, &msg)); + napi_create_error(env, nullptr, msg, &businessError); + napi_set_named_property(env, businessError, "code", code); + return businessError; +} + +std::optional<std::string> GetIntelligenceErrMsg(int32_t errorCode) +{ + auto iter = ERROR_MESSAGES.find(errorCode); + if (iter != ERROR_MESSAGES.end()) { + return iter->second; + } + AIP_HILOGE("Error, messages not found"); + return std::nullopt; +} + +void ThrowIntelligenceErr(const napi_env &env, int32_t errorCode, const std::string &printMsg) +{ + AIP_HILOGE("printMsg:%{public}s, errorCode:%{public}d", printMsg.c_str(), errorCode); + std::optional<std::string> msg = GetIntelligenceErrMsg(errorCode); + if (!msg) { + AIP_HILOGE("errorCode:%{public}d is invalid", errorCode); + return; + } + napi_value error = CreateIntelligenceError(env, errorCode, msg.value()); + napi_throw(env, error); +} + +void ThrowIntelligenceErrByPromise(const napi_env &env, int32_t errorCode, const std::string &printMsg, + napi_value &value) +{ + AIP_HILOGE("printMsg:%{public}s, errorCode:%{public}d", printMsg.c_str(), errorCode); + std::optional<std::string> msg = GetIntelligenceErrMsg(errorCode); + if (!msg) { + AIP_HILOGE("errorCode:%{public}d is invalid", errorCode); + return; + } + value = CreateIntelligenceError(env, errorCode, msg.value()); +} +} // namespace DataIntelligence +} // namespae OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/intelligence/aip_napi_utils.cpp b/udmf/framework/jskitsimpl/intelligence/aip_napi_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4733256a7f03c72927af0b5bc881150937a4b848 --- /dev/null +++ b/udmf/framework/jskitsimpl/intelligence/aip_napi_utils.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2025 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 a + * + * 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 "aip_napi_utils.h" + +#include <dlfcn.h> + +#include "aip_log.h" + +#undef LOG_TAG +#define LOG_TAG "AipNapiUtils" + +namespace OHOS { +namespace DataIntelligence { +namespace { +static constexpr uint32_t MAX_STR_PARAM_LEN = 512; +} // namespace +bool AipNapiUtils::LoadAlgoLibrary(const std::string &algoPath, AipCoreManagerHandle &aipMgrHandler) +{ + AIP_HILOGD("Enter"); + if (aipMgrHandler.handle != nullptr) { + AIP_HILOGE("handle has exists"); + return false; + } + + if (algoPath.empty()) { + AIP_HILOGE("algoPath is empty"); + return false; + } + char libRealPath[PATH_MAX] = {}; + if (realpath(algoPath.c_str(), libRealPath) == nullptr) { + AIP_HILOGE("get absolute algoPath error, %{public}d", errno); + return false; + } + + aipMgrHandler.handle = dlopen(libRealPath, RTLD_LAZY); + if (aipMgrHandler.handle == nullptr) { + AIP_HILOGE("cannot load lib error: %{public}s", dlerror()); + return false; + } + + aipMgrHandler.create = reinterpret_cast<IAipCoreManager *(*)()>(dlsym(aipMgrHandler.handle, "Create")); + aipMgrHandler.destroy = reinterpret_cast<void (*)(const IAipCoreManager *)>(dlsym(aipMgrHandler.handle, "Destroy")); + if (aipMgrHandler.create == nullptr || aipMgrHandler.destroy == nullptr) { + dlclose(aipMgrHandler.handle); + aipMgrHandler.Clear(); + AIP_HILOGE("Failed to create and destroy algo"); + return false; + } + + aipMgrHandler.pAipManager = aipMgrHandler.create(); + AIP_HILOGD("Exit"); + return true; +} + + +bool AipNapiUtils::UnLoadAlgoLibrary(AipCoreManagerHandle &aipMgrHandler) +{ + AIP_HILOGD("Enter"); + if (aipMgrHandler.handle == nullptr) { + AIP_HILOGE("handle is nullptr"); + return false; + } + + if (aipMgrHandler.pAipManager != nullptr && aipMgrHandler.destroy != nullptr) { + aipMgrHandler.destroy(aipMgrHandler.pAipManager); + aipMgrHandler.pAipManager = nullptr; + } + + dlclose(aipMgrHandler.handle); + aipMgrHandler.Clear(); + AIP_HILOGD("Exit"); + return true; +} + +IAipCoreManager *AipNapiUtils::GetAlgoObj(AipCoreManagerHandle &aipMgrHandler) +{ + AIP_HILOGD("Enter"); + if (aipMgrHandler.handle == nullptr) { + AIP_HILOGE("handle is nullptr"); + return nullptr; + } + + if (aipMgrHandler.pAipManager != nullptr) { + AIP_HILOGD("pAipManager already exists"); + return aipMgrHandler.pAipManager; + } + + if (aipMgrHandler.create == nullptr) { + AIP_HILOGE("create is nullptr"); + return nullptr; + } + + aipMgrHandler.pAipManager = aipMgrHandler.create(); + AIP_HILOGD("Exit"); + return aipMgrHandler.pAipManager; +} + +bool AipNapiUtils::ValidateArgsType(napi_env env, napi_value *args, size_t argc, + const std::vector<std::string> &expectedTypes) +{ + AIP_HILOGD("Enter"); + napi_status status = napi_ok; + napi_valuetype valueType = napi_undefined; + + if (argc != expectedTypes.size()) { + AIP_HILOGE("Wrong number of arguments"); + return false; + } + + for (size_t i = 0; i < argc; ++i) { + status = napi_typeof(env, args[i], &valueType); + if (status != napi_ok) { + AIP_HILOGE("Error while checking arguments types"); + return false; + } + std::string expectedType = expectedTypes[i]; + if ((expectedType == "string" && valueType != napi_string) || + (expectedType == "object" && valueType != napi_object) || + (expectedType == "number" && valueType != napi_number) || + (expectedType == "function" && valueType != napi_function)) { + AIP_HILOGE("Wrong argument type"); + return false; + } + } + return true; +} + +bool AipNapiUtils::TransJsToStr(napi_env env, napi_value value, std::string &str) +{ + size_t strlen = 0; + napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &strlen); + if (status != napi_ok) { + AIP_HILOGE("Error string length invalid"); + return false; + } + if (strlen < 0 || strlen > MAX_STR_PARAM_LEN) { + AIP_HILOGE("The string length invalid"); + return false; + } + std::vector<char> buf(strlen + 1); + status = napi_get_value_string_utf8(env, value, buf.data(), strlen + 1, &strlen); + if (status != napi_ok) { + AIP_HILOGE("napi_get_value_string_utf8 failed"); + return false; + } + str = buf.data(); + return true; +} + +bool AipNapiUtils::TransJsToStrUnlimited(napi_env env, napi_value value, std::string &str) +{ + size_t strlen = 0; + napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &strlen); + if (status != napi_ok) { + AIP_HILOGE("Error string length invalid"); + return false; + } + if (strlen < 0) { + AIP_HILOGE("The string length invalid"); + return false; + } + std::vector<char> buf(strlen + 1); + status = napi_get_value_string_utf8(env, value, buf.data(), strlen + 1, &strlen); + if (status != napi_ok) { + AIP_HILOGE("napi_get_value_string_utf8 failed"); + return false; + } + str = buf.data(); + return true; +} + +bool AipNapiUtils::TransJsToInt32(napi_env env, napi_value value, int32_t &res) +{ + napi_status status = napi_get_value_int32(env, value, &res); + if (status != napi_ok) { + AIP_HILOGE("napi_get_value_int32 failed"); + return false; + } + return true; +} + +bool AipNapiUtils::TransJsToDouble(napi_env env, napi_value value, double &res) +{ + napi_status status = napi_get_value_double(env, value, &res); + if (status != napi_ok) { + AIP_HILOGE("napi_get_value_double failed"); + return false; + } + return true; +} + +bool AipNapiUtils::TransJsToBool(napi_env env, napi_value value, bool &res) +{ + napi_status status = napi_get_value_bool(env, value, &res); + if (status != napi_ok) { + return false; + } + return true; +} + +void AipNapiUtils::CreateStringData(napi_env env, napi_value aipServiceValue, napi_value result, const std::string name, + std::string &content) +{ + napi_status ret = napi_create_string_utf8(env, content.c_str(), NAPI_AUTO_LENGTH, &aipServiceValue); + if (ret != napi_ok) { + AIP_HILOGE("napi_create_string_utf8 failed"); + return; + } + + ret = napi_set_named_property(env, result, name.c_str(), aipServiceValue); + if (ret != napi_ok) { + AIP_HILOGE("napi_set_named_property failed"); + } +} + +void AipNapiUtils::CreateInt32Data(napi_env env, napi_value aipServiceValue, napi_value result, const std::string name, + int32_t value) +{ + napi_status ret = napi_create_int32(env, value, &aipServiceValue); + if (ret != napi_ok) { + AIP_HILOGE("napi_create_int32 failed"); + return; + } + + ret = napi_set_named_property(env, result, name.c_str(), aipServiceValue); + if (ret != napi_ok) { + AIP_HILOGE("napi_set_named_property failed"); + } +} + +void AipNapiUtils::CreateDoubleData(napi_env env, double value, napi_value *result) +{ + napi_status ret = napi_create_double(env, value, result); + if (ret != napi_ok) { + AIP_HILOGE("napi_create_int32 failed"); + return; + } +} +} // namespace DataIntelligence +} // namespace OHOS diff --git a/udmf/framework/jskitsimpl/intelligence/i_aip_core_manager_impl.cpp b/udmf/framework/jskitsimpl/intelligence/i_aip_core_manager_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..614a32e9aadb3ae91cb87d14e969b75486012153 --- /dev/null +++ b/udmf/framework/jskitsimpl/intelligence/i_aip_core_manager_impl.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2025 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 a + * + * 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 "i_aip_core_manager_impl.h" + +#include "aip_napi_error.h" + +#undef LOG_TAG +#define LOG_TAG "IAipCoreManagerImpl" + +namespace OHOS { +namespace DataIntelligence { +int32_t IAipCoreManagerImpl::InitTextModel(const ModelConfigData &config) +{ + return DEVICE_EXCEPTION; +} + +int32_t IAipCoreManagerImpl::InitImageModel(const ModelConfigData &config) +{ + return DEVICE_EXCEPTION; +} + +int32_t IAipCoreManagerImpl::LoadTextModel() +{ + return DEVICE_EXCEPTION; +} + +int32_t IAipCoreManagerImpl::ReleaseTextModel() +{ + return DEVICE_EXCEPTION; +} + +int32_t IAipCoreManagerImpl::GetTextEmbedding(std::string file, std::vector<float> &results) +{ + return DEVICE_EXCEPTION; +} + +int32_t IAipCoreManagerImpl::GetTextEmbedding(const std::vector<std::string> &files, + std::vector<std::vector<float>> &results) +{ + return DEVICE_EXCEPTION; +} + +int32_t IAipCoreManagerImpl::LoadImageModel() +{ + return DEVICE_EXCEPTION; +} + +int32_t IAipCoreManagerImpl::ReleaseImageModel() +{ + return DEVICE_EXCEPTION; +} + +int32_t IAipCoreManagerImpl::GetImageEmbedding(std::string uri, std::vector<float> &results) +{ + return DEVICE_EXCEPTION; +} + +int32_t IAipCoreManagerImpl::SplitText(std::string text, int32_t size, float overlap, + std::vector<std::string> &results) +{ + return DEVICE_EXCEPTION; +} +} // namespace DataIntelligence +} // namespace OHOS diff --git a/udmf/framework/jskitsimpl/intelligence/image_embedding_napi.cpp b/udmf/framework/jskitsimpl/intelligence/image_embedding_napi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..71d3ee16801282db192a5e98c451fd8cbb9b817f --- /dev/null +++ b/udmf/framework/jskitsimpl/intelligence/image_embedding_napi.cpp @@ -0,0 +1,716 @@ +/* + * Copyright (c) 2025 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 "image_embedding_napi.h" + +#include <dlfcn.h> + +#include "aip_log.h" +#include "aip_napi_error.h" +#include "aip_napi_utils.h" +#include "i_aip_core_manager_impl.h" + +#undef LOG_TAG +#define LOG_TAG "ImageEmbeddingNapi" + +namespace OHOS { +namespace DataIntelligence { +namespace { +const int32_t ERR_OK = 0; +static constexpr uint8_t ARG_0 = 0; +static constexpr uint8_t ARG_1 = 1; +static constexpr uint8_t NUM_0 = 0; +static constexpr uint8_t NUM_1 = 1; +static const std::string CLASS_NAME = "ImageEmbedding"; +const std::vector<std::string> EXPECTED_GET_ARG_TYPES = { "string" }; +const std::vector<std::string> EXPECTED_GET_IMG_MODEL_ARG_TYPES = { "object" }; +const std::string AIP_MANAGER_PATH = "/system/lib64/platformsdk/libaip_core.z.so"; +} // namespace + +AipCoreManagerHandle ImageEmbeddingNapi::imgAipCoreMgrHandle_{}; +thread_local napi_ref ImageEmbeddingNapi::sConstructor_ = nullptr; +IAipCoreManager *ImageEmbeddingNapi::imageAipCoreManager_ = nullptr; + +struct ImageEmbeddingConstructorInfo { + std::string className; + napi_ref *classRef; + napi_callback constructor; + const napi_property_descriptor *property; + size_t propertyCount; + const napi_property_descriptor *staticProperty; + size_t staticPropertyCount; +}; + +struct LoadCallbackData { + napi_async_work asyncWork; + napi_deferred deferred; + int32_t ret; +}; + +struct ReleaseCallbackData { + napi_async_work asyncWork; + napi_deferred deferred; + int32_t ret; +}; + +struct ImageCallbackData { + napi_async_work asyncWork; + napi_deferred deferred; + std::string strArg; + int32_t dataRet; + std::vector<float> ret; +}; + +ImageEmbeddingNapi::ImageEmbeddingNapi() : env_(nullptr) {} + +ImageEmbeddingNapi::~ImageEmbeddingNapi() +{ + AipNapiUtils::UnLoadAlgoLibrary(imgAipCoreMgrHandle_); + imageAipCoreManager_ = nullptr; + delete imageAipCoreManager_; +} + +static napi_value StartInit(napi_env env, napi_value exports, struct ImageEmbeddingConstructorInfo info) +{ + napi_value constructor = nullptr; + napi_status status = napi_define_class(env, info.className.c_str(), NAPI_AUTO_LENGTH, info.constructor, nullptr, + info.propertyCount, info.property, &constructor); + if (status != napi_ok) { + AIP_HILOGE("define class fail"); + return nullptr; + } + + status = napi_create_reference(env, constructor, NUM_1, info.classRef); + if (status != napi_ok) { + AIP_HILOGE("create reference fail"); + return nullptr; + } + + napi_value global = nullptr; + status = napi_get_global(env, &global); + if (status != napi_ok) { + AIP_HILOGE("create global fail"); + return nullptr; + } + + status = napi_set_named_property(env, global, info.className.c_str(), constructor); + if (status != napi_ok) { + AIP_HILOGE("Init::set global named property fail"); + return nullptr; + } + + status = napi_define_properties(env, exports, info.staticPropertyCount, info.staticProperty); + if (status != napi_ok) { + AIP_HILOGE("define properties fail"); + return nullptr; + } + return exports; +} + +napi_value ImageEmbeddingNapi::Init(napi_env env, napi_value exports) +{ + AIP_HILOGD("Enter"); + if (!AipNapiUtils::LoadAlgoLibrary(AIP_MANAGER_PATH, imgAipCoreMgrHandle_)) { + AIP_HILOGE("LoadAlgoLibrary failed"); + } + + if (imgAipCoreMgrHandle_.pAipManager != nullptr) { + imageAipCoreManager_ = AipNapiUtils::GetAlgoObj(imgAipCoreMgrHandle_); + } else { + imageAipCoreManager_ = new IAipCoreManagerImpl(); + } + + if (imageAipCoreManager_ == nullptr) { + AIP_HILOGE("GetAlgoObj failed"); + return nullptr; + } + + napi_property_descriptor properties[] = { + DECLARE_NAPI_FUNCTION("loadModel", LoadModel), + DECLARE_NAPI_FUNCTION("releaseModel", ReleaseModel), + DECLARE_NAPI_FUNCTION("getEmbedding", GetEmbedding), + }; + + napi_property_descriptor static_prop[] = { + DECLARE_NAPI_STATIC_FUNCTION("getImageEmbeddingModel", GetImageEmbeddingModel), + }; + + struct ImageEmbeddingConstructorInfo info = { + .className = CLASS_NAME, + .classRef = &sConstructor_, + .constructor = Constructor, + .property = properties, + .propertyCount = sizeof(properties) / sizeof(properties[NUM_0]), + .staticProperty = static_prop, + .staticPropertyCount = sizeof(static_prop) / sizeof(static_prop[NUM_0]), + }; + + if (StartInit(env, exports, info)) { + return nullptr; + } + return exports; +} + +napi_value ImageEmbeddingNapi::Constructor(napi_env env, napi_callback_info info) +{ + napi_value undefineValue = nullptr; + napi_get_undefined(env, &undefineValue); + + napi_status status; + napi_value thisVar = nullptr; + status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr); + if (status == napi_ok && thisVar != nullptr) { + std::unique_ptr<ImageEmbeddingNapi> imgEmbNapi = std::make_unique<ImageEmbeddingNapi>(); + if (imgEmbNapi != nullptr) { + imgEmbNapi->env_ = env; + status = napi_wrap(env, thisVar, reinterpret_cast<void *>(imgEmbNapi.get()), ImageEmbeddingNapi::Destructor, + nullptr, nullptr); + if (status == napi_ok) { + imgEmbNapi.release(); + return thisVar; + } else { + AIP_HILOGE("Failure wrapping js to native napi"); + } + } + } + return undefineValue; +} + +void ImageEmbeddingNapi::Destructor(napi_env env, void *nativeObject, void *finalize) +{ + AIP_HILOGD("TextEmbeddingNapi, Destructor"); +} + +napi_value ImageEmbeddingNapi::GetImageEmbeddingModel(napi_env env, napi_callback_info info) +{ + AIP_HILOGE("Enter"); + size_t argc = ARG_1; + napi_value args[ARG_1] = { nullptr }; + napi_value jsThis = nullptr; + + napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr); + if (status != napi_ok) { + AIP_HILOGE("napi_get_cb_info failed"); + ThrowIntelligenceErr(env, INNER_ERROR, "napi_get_cb_info failed."); + return nullptr; + } + + if (!AipNapiUtils::ValidateArgsType(env, args, argc, EXPECTED_GET_IMG_MODEL_ARG_TYPES)) { + AIP_HILOGE("ValidateArgsType failed"); + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "wrong params type."); + return nullptr; + } + + ModelConfigData imgModelConfig; + if (!ParseModelConfig(env, args, argc, &imgModelConfig)) { + AIP_HILOGE("ParseModelConfig failed"); + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "wrong params type."); + return nullptr; + } + + napi_value promise = nullptr; + napi_deferred deferred = nullptr; + status = napi_create_promise(env, &deferred, &promise); + if (status != napi_ok) { + AIP_HILOGE("create promise failed"); + ThrowIntelligenceErr(env, INNER_ERROR, "create promise failed"); + return nullptr; + } + + auto asyncGetImgEmbeddingModelData = new AsyncGetImageEmbeddingModelData{ + .asyncWork = nullptr, + .deferred = deferred, + .config = imgModelConfig, + }; + + if (!CreateAsyncImgModelExecution(env, asyncGetImgEmbeddingModelData)) { + AIP_HILOGE("create AsyncTextModelExecution failed"); + ThrowIntelligenceErr(env, INNER_ERROR, "create AsyncTextModelExecution failed"); + delete asyncGetImgEmbeddingModelData; + return nullptr; + } + + return promise; +} + +bool ImageEmbeddingNapi::ParseModelConfig(napi_env env, napi_value *args, size_t argc, ModelConfigData *modelConfig) +{ + AIP_HILOGI("Enter"); + napi_value version, isNPUAvailable, cachePath; + + napi_status status = napi_get_named_property(env, args[ARG_0], "version", &version); + if (status != napi_ok) { + AIP_HILOGE("napi get version property failed"); + return false; + } + + status = napi_get_named_property(env, args[ARG_0], "isNpuAvailable", &isNPUAvailable); + if (status != napi_ok) { + AIP_HILOGE("napi get isNpuAvailable property failed"); + return false; + } + + status = napi_get_named_property(env, args[ARG_0], "cachePath", &cachePath); + if (status != napi_ok) { + AIP_HILOGE("napi get cachePath property failed"); + return false; + } + + if (!AipNapiUtils::TransJsToInt32(env, version, modelConfig->versionValue)) { + AIP_HILOGE("Trans version failed"); + return false; + } + + if (!AipNapiUtils::TransJsToBool(env, isNPUAvailable, modelConfig->isNPUAvailableValue)) { + AIP_HILOGE("Trans isNPUAvailable failed"); + return false; + } + + if (!AipNapiUtils::TransJsToStr(env, cachePath, modelConfig->cachePathValue)) { + AIP_HILOGE("Trans cachePath failed"); + return false; + } + return true; +} + + +bool ImageEmbeddingNapi::CreateAsyncImgModelExecution(napi_env env, AsyncGetImageEmbeddingModelData *asyncModelData) +{ + AIP_HILOGI("Enter"); + napi_value resourceName; + napi_status status = napi_create_string_utf8(env, "GetIamgeEmbeddingModel", NAPI_AUTO_LENGTH, &resourceName); + if (status != napi_ok) { + AIP_HILOGE(" napi_create_string_utf8 failed"); + return false; + } + + status = napi_create_async_work(env, nullptr, resourceName, GetImgEmbeddingModelExecutionCB, + GetImgEmbeddingModelCompleteCB, static_cast<void *>(asyncModelData), &asyncModelData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_create_async_work failed"); + return false; + } + + status = napi_queue_async_work_with_qos(env, asyncModelData->asyncWork, napi_qos_default); + if (status != napi_ok) { + AIP_HILOGE("napi_queue_async_work_with_qos failed"); + return false; + } + return true; +} + +void ImageEmbeddingNapi::GetImgEmbeddingModelExecutionCB(napi_env env, void *data) +{ + AIP_HILOGD("Enter"); + AsyncGetImageEmbeddingModelData *modelData = static_cast<AsyncGetImageEmbeddingModelData *>(data); + if (imageAipCoreManager_ == nullptr) { + AIP_HILOGE("pAipManager is nullptr"); + return; + } + auto config = modelData->config; + int32_t result = imageAipCoreManager_->InitImageModel(config); + modelData->ret = result; +} + +void ImageEmbeddingNapi::GetImgEmbeddingModelCompleteCB(napi_env env, napi_status status, void *data) +{ + AIP_HILOGD("Enter"); + AsyncGetImageEmbeddingModelData *modelData = static_cast<AsyncGetImageEmbeddingModelData *>(data); + auto ret = modelData->ret; + napi_value result = nullptr; + if (ret != ERR_OK) { + if (ret == DEVICE_EXCEPTION) { + ThrowIntelligenceErrByPromise(env, DEVICE_EXCEPTION, "GetImgEmbeddingModelCompleteCB failed", result); + } else { + ThrowIntelligenceErrByPromise(env, INNER_ERROR, "GetImgEmbeddingModelCompleteCB failed", result); + } + napi_reject_deferred(env, modelData->deferred, result); + } else { + napi_value constructor = nullptr; + status = napi_get_reference_value(env, sConstructor_, &constructor); + if (status != napi_ok) { + AIP_HILOGE("napi_get_reference_value failed"); + napi_get_undefined(env, &result); + delete modelData; + return; + } + + status = napi_new_instance(env, constructor, 0, nullptr, &result); + if (status != napi_ok) { + AIP_HILOGE("napi_new_instance failed"); + napi_get_undefined(env, &result); + return; + } + + status = napi_resolve_deferred(env, modelData->deferred, result); + if (status != napi_ok) { + AIP_HILOGE(" napi_resolve_deferred failed"); + } + } + + status = napi_delete_async_work(env, modelData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_delete_async_work failed"); + } + delete modelData; +} + +napi_value ImageEmbeddingNapi::GetEmbedding(napi_env env, napi_callback_info info) +{ + AIP_HILOGE("Enter"); + size_t argc = ARG_1; + napi_value args[ARG_1] = { nullptr }; + napi_value jsThis = nullptr; + + napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr); + if (status != napi_ok) { + ThrowIntelligenceErr(env, INNER_ERROR, "napi_get_cb_info failed"); + return nullptr; + } + + if (!AipNapiUtils::ValidateArgsType(env, args, argc, EXPECTED_GET_ARG_TYPES)) { + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "napi_get_cb_info failed"); + return nullptr; + } + + std::string strArg; + if (!AipNapiUtils::TransJsToStr(env, args[ARG_0], strArg)) { + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "napi_get_cb_info failed"); + return nullptr; + } + + napi_value promise = nullptr; + napi_deferred deferred = nullptr; + status = napi_create_promise(env, &deferred, &promise); + if (status != napi_ok) { + ThrowIntelligenceErr(env, INNER_ERROR, "napi_create_promise failed"); + return nullptr; + } + + if (!GetEmbeddingAsyncExecution(env, deferred, strArg)) { + ThrowIntelligenceErr(env, INNER_ERROR, "GetEmbeddingAsyncExecution failed"); + return nullptr; + } + + return promise; +} + +bool ImageEmbeddingNapi::GetEmbeddingAsyncExecution(napi_env env, napi_deferred deferred, std::string strArg) +{ + AIP_HILOGD("Enter"); + auto imageCallbackData = new ImageCallbackData{ + .asyncWork = nullptr, + .deferred = deferred, + .strArg = strArg, + }; + + napi_value resourceName; + napi_status status = napi_create_string_utf8(env, "ImageGetEmbedding", NAPI_AUTO_LENGTH, &resourceName); + if (status != napi_ok) { + AIP_HILOGE("napi_create_string_utf8 failed"); + delete imageCallbackData; + return false; + } + + status = napi_create_async_work(env, nullptr, resourceName, GetEmbeddingExecuteCB, GetEmbeddingCompleteCB, + static_cast<void *>(imageCallbackData), &imageCallbackData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_create_async_work failed"); + delete imageCallbackData; + return false; + } + + status = napi_queue_async_work_with_qos(env, imageCallbackData->asyncWork, napi_qos_default); + if (status != napi_ok) { + AIP_HILOGE("napi_queue_async_work_with_qos failed"); + napi_delete_async_work(env, imageCallbackData->asyncWork); + delete imageCallbackData; + return false; + } + return true; +} + +void ImageEmbeddingNapi::GetEmbeddingExecuteCB(napi_env env, void *data) +{ + AIP_HILOGD("Enter"); + ImageCallbackData *imageCallbackData = static_cast<ImageCallbackData *>(data); + std::string strArg = imageCallbackData->strArg; + std::vector<float> result; + int32_t ret = imageAipCoreManager_->GetImageEmbedding(strArg, result); + imageCallbackData->dataRet = ret; + imageCallbackData->ret = result; + AIP_HILOGD("Exit"); +} + +void ImageEmbeddingNapi::GetEmbeddingCompleteCB(napi_env env, napi_status status, void *data) +{ + AIP_HILOGD("Enter"); + ImageCallbackData *imageCallbackData = static_cast<ImageCallbackData *>(data); + napi_value value; + auto ret = imageCallbackData->ret; + auto dataRet = imageCallbackData->dataRet; + + if (dataRet != ERR_OK) { + if (dataRet == DEVICE_EXCEPTION) { + ThrowIntelligenceErrByPromise(env, DEVICE_EXCEPTION, " GetEmbeddingCompleteCB failed", value); + } else { + ThrowIntelligenceErrByPromise(env, INNER_ERROR, "GetEmbeddingCompleteCB failed", value); + } + napi_reject_deferred(env, imageCallbackData->deferred, value); + } else { + status = napi_create_array(env, &value); + if (status != napi_ok) { + AIP_HILOGE("napi_create_array failed"); + } else { + for (size_t i = 0; i < ret.size(); i++) { + napi_value jsDouble = nullptr; + AipNapiUtils::CreateDoubleData(env, static_cast<double>(ret[i]), &jsDouble); + napi_set_element(env, value, i, jsDouble); + } + status = napi_resolve_deferred(env, imageCallbackData->deferred, value); + if (status != napi_ok) { + AIP_HILOGE(" napi_resolve_deferred failed"); + } + } + } + + status = napi_delete_async_work(env, imageCallbackData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_delete_async_work failed"); + } + delete imageCallbackData; +} + +napi_value ImageEmbeddingNapi::LoadModel(napi_env env, napi_callback_info info) +{ + AIP_HILOGD("Enter"); + size_t argc = ARG_0; + napi_value args[ARG_1] = { nullptr }; + napi_value jsThis = nullptr; + + napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr); + if (status != napi_ok) { + ThrowIntelligenceErr(env, INNER_ERROR, "napi_get_cb_info failed"); + return nullptr; + } + + if (argc != ARG_0) { + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "param size error"); + return nullptr; + } + + napi_value promise = nullptr; + napi_deferred deferred = nullptr; + status = napi_create_promise(env, &deferred, &promise); + if (status != napi_ok) { + AIP_HILOGE("create promise failed"); + ThrowIntelligenceErr(env, INNER_ERROR, "create promise failed"); + return nullptr; + } + + if (!LoadAsyncExecution(env, deferred)) { + ThrowIntelligenceErr(env, INNER_ERROR, "LoadAsyncExecution failed"); + return nullptr; + } + + AIP_HILOGD("Exit"); + return promise; +} + +bool ImageEmbeddingNapi::LoadAsyncExecution(napi_env env, napi_deferred deferred) +{ + AIP_HILOGD("Enter"); + auto loadCallbackData = new LoadCallbackData{ + .asyncWork = nullptr, + .deferred = deferred, + }; + + napi_value resourceName; + napi_status status = napi_create_string_utf8(env, "imageLoad", NAPI_AUTO_LENGTH, &resourceName); + if (status != napi_ok) { + AIP_HILOGE("napi_create_string_utf8 failed"); + delete loadCallbackData; + return false; + } + + status = napi_create_async_work(env, nullptr, resourceName, LoadExecuteCB, LoadCompleteCB, + static_cast<void *>(loadCallbackData), &loadCallbackData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_create_async_work failed"); + delete loadCallbackData; + return false; + } + + status = napi_queue_async_work_with_qos(env, loadCallbackData->asyncWork, napi_qos_default); + if (status != napi_ok) { + AIP_HILOGE("napi_queue_async_work_with_qos failed"); + napi_delete_async_work(env, loadCallbackData->asyncWork); + delete loadCallbackData; + return false; + } + return true; +} + + +void ImageEmbeddingNapi::LoadExecuteCB(napi_env env, void *data) +{ + AIP_HILOGD("Enter"); + LoadCallbackData *loadCallbackData = static_cast<LoadCallbackData *>(data); + auto ret = imageAipCoreManager_->LoadImageModel(); + loadCallbackData->ret = ret; + AIP_HILOGD("Exit"); +} + +void ImageEmbeddingNapi::LoadCompleteCB(napi_env env, napi_status status, void *data) +{ + AIP_HILOGD("Enter"); + LoadCallbackData *loadCallbackData = static_cast<LoadCallbackData *>(data); + napi_value value = nullptr; + auto ret = loadCallbackData->ret; + if (ret != ERR_OK) { + if (ret == DEVICE_EXCEPTION) { + ThrowIntelligenceErrByPromise(env, DEVICE_EXCEPTION, "LoadCompleteCB failed", value); + } else { + ThrowIntelligenceErrByPromise(env, INNER_ERROR, "LoadCompleteCB failed", value); + } + napi_reject_deferred(env, loadCallbackData->deferred, value); + } else { + status = napi_get_undefined(env, &value); + if (status != napi_ok) { + AIP_HILOGE(" napi_get_undefined failed"); + } + status = napi_resolve_deferred(env, loadCallbackData->deferred, value); + if (status != napi_ok) { + AIP_HILOGE(" napi_resolve_deferred failed"); + } + } + + status = napi_delete_async_work(env, loadCallbackData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_delete_async_work failed"); + } + delete loadCallbackData; +} + +napi_value ImageEmbeddingNapi::ReleaseModel(napi_env env, napi_callback_info info) +{ + AIP_HILOGD("Enter"); + size_t argc = ARG_0; + napi_value args[ARG_1] = { nullptr }; + napi_value jsThis = nullptr; + + napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr); + if (status != napi_ok) { + AIP_HILOGE("napi_get_cb_info failed"); + ThrowIntelligenceErr(env, INNER_ERROR, "napi_get_cb_info failed"); + return nullptr; + } + + if (argc != ARG_0) { + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "param size error"); + return nullptr; + } + + napi_value promise = nullptr; + napi_deferred deferred = nullptr; + status = napi_create_promise(env, &deferred, &promise); + if (status != napi_ok) { + ThrowIntelligenceErr(env, INNER_ERROR, "create promise failed"); + return nullptr; + } + + if (!ReleaseAsyncExecution(env, deferred)) { + ThrowIntelligenceErr(env, INNER_ERROR, "ReleaseAsyncExecution failed"); + return nullptr; + } + + AIP_HILOGD("Exit"); + return promise; +} + +bool ImageEmbeddingNapi::ReleaseAsyncExecution(napi_env env, napi_deferred deferred) +{ + AIP_HILOGD("Enter"); + auto releaseCallbackData = new ReleaseCallbackData{ + .asyncWork = nullptr, + .deferred = deferred, + }; + + napi_value resourceName; + napi_status status = napi_create_string_utf8(env, "textLoad", NAPI_AUTO_LENGTH, &resourceName); + if (status != napi_ok) { + AIP_HILOGE("napi_create_string_utf8 failed"); + delete releaseCallbackData; + return false; + } + + status = napi_create_async_work(env, nullptr, resourceName, ReleaseExecuteCB, ReleaseCompleteCB, + static_cast<void *>(releaseCallbackData), &releaseCallbackData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_create_async_work failed"); + delete releaseCallbackData; + return false; + } + + status = napi_queue_async_work_with_qos(env, releaseCallbackData->asyncWork, napi_qos_default); + if (status != napi_ok) { + AIP_HILOGE("napi_queue_async_work_with_qos failed"); + napi_delete_async_work(env, releaseCallbackData->asyncWork); + delete releaseCallbackData; + return false; + } + return true; +} +void ImageEmbeddingNapi::ReleaseExecuteCB(napi_env env, void *data) +{ + AIP_HILOGD("Enter"); + ReleaseCallbackData *releaseCallbackData = static_cast<ReleaseCallbackData *>(data); + auto ret = imageAipCoreManager_->ReleaseImageModel(); + releaseCallbackData->ret = ret; + AIP_HILOGD("Exit"); +} + +void ImageEmbeddingNapi::ReleaseCompleteCB(napi_env env, napi_status status, void *data) +{ + AIP_HILOGD("Enter"); + ReleaseCallbackData *releaseCallbackData = static_cast<ReleaseCallbackData *>(data); + napi_value value = nullptr; + auto ret = releaseCallbackData->ret; + if (ret != ERR_OK) { + if (ret == DEVICE_EXCEPTION) { + ThrowIntelligenceErrByPromise(env, DEVICE_EXCEPTION, "ReleaseCompleteCB failed", value); + } else { + ThrowIntelligenceErrByPromise(env, INNER_ERROR, "ReleaseCompleteCB failed", value); + } + napi_reject_deferred(env, releaseCallbackData->deferred, value); + } else { + status = napi_get_undefined(env, &value); + if (status != napi_ok) { + AIP_HILOGE(" napi_get_undefined failed"); + } + status = napi_resolve_deferred(env, releaseCallbackData->deferred, value); + if (status != napi_ok) { + AIP_HILOGE(" napi_resolve_deferred failed"); + } + } + + status = napi_delete_async_work(env, releaseCallbackData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_delete_async_work failed"); + } + delete releaseCallbackData; +} +} // namespace DataIntelligence +} // namespace OHOS diff --git a/udmf/framework/jskitsimpl/intelligence/native_module_intelligence.cpp b/udmf/framework/jskitsimpl/intelligence/native_module_intelligence.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d92b1ca14488a6a09ed15f730a22406758fdd86 --- /dev/null +++ b/udmf/framework/jskitsimpl/intelligence/native_module_intelligence.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 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 "native_module_intelligence.h" + +#include "aip_log.h" + +#undef LOG_TAG +#define LOG_TAG "NativeModuleIntelligence" + +namespace OHOS { +namespace DataIntelligence { +static napi_value Export(napi_env env, napi_value exports) +{ + AIP_HILOGD("NativeModuleIntelligence call"); + TextEmbeddingNapi::Init(env, exports); + ImageEmbeddingNapi::Init(env, exports); + return exports; +} + +static napi_module DataIntelligenceModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Export, + .nm_modname = "data.intelligence", + .nm_priv = ((void *)0), + .reserved = { 0 } +}; + +extern "C" __attribute__((constructor)) void RegisterModule(void) +{ + napi_module_register(&DataIntelligenceModule); +} +} // namespace DataIntelligence +} // namespace OHOS \ No newline at end of file diff --git a/udmf/framework/jskitsimpl/intelligence/text_embedding_napi.cpp b/udmf/framework/jskitsimpl/intelligence/text_embedding_napi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4758fbe7743b79ae5fdf0bb64146e48ac8cb4c04 --- /dev/null +++ b/udmf/framework/jskitsimpl/intelligence/text_embedding_napi.cpp @@ -0,0 +1,1072 @@ +/* + * Copyright (c) 2025 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 "text_embedding_napi.h" + +#include <dlfcn.h> + +#include "aip_log.h" +#include "aip_napi_error.h" +#include "aip_napi_utils.h" +#include "i_aip_core_manager_impl.h" + +#undef LOG_TAG +#define LOG_TAG "TextEmbeddingNapi" + +namespace OHOS { +namespace DataIntelligence { +namespace { +const int32_t ERR_OK = 0; +static constexpr uint8_t ARG_0 = 0; +static constexpr uint8_t ARG_1 = 1; +static constexpr uint8_t ARG_2 = 2; + +static constexpr uint8_t NUM_0 = 0; +static constexpr uint8_t NUM_1 = 1; +static constexpr uint32_t MAX_STR_PARAM_LEN = 512; +static const std::string CLASS_NAME = "TextEmbedding"; +const std::vector<std::string> EXPECTED_SPLITTEXT_ARG_TYPES = { "string", "object" }; +const std::vector<std::string> EXPECTED_GET_TEXT_MODEL_ARG_TYPES = { "object" }; +const std::string AIP_MANAGER_PATH = "/system/lib64/platformsdk/libaip_core.z.so"; +} // namespace +AipCoreManagerHandle TextEmbeddingNapi::textAipCoreMgrHandle_{}; +thread_local napi_ref TextEmbeddingNapi::sConstructor_ = nullptr; +IAipCoreManager *TextEmbeddingNapi::textAipCoreManager_ = nullptr; + +struct LoadCallbackData { + napi_async_work asyncWork; + napi_deferred deferred; + int32_t ret; +}; + +struct ReleaseCallbackData { + napi_async_work asyncWork; + napi_deferred deferred; + int32_t ret; +}; + +struct TextStringCallbackData { + napi_async_work asyncWork; + napi_deferred deferred; + std::string strArg; + int32_t dataRet; + std::vector<float> ret; +}; + +struct TextArrayCallbackData { + napi_async_work asyncWork; + napi_deferred deferred; + std::vector<std::string> text; + int32_t dataRet; + std::vector<std::vector<float>> ret; +}; + + +struct SplitTextCallbackData { + napi_async_work asyncWork; + napi_deferred deferred; + std::string strArg; + int32_t configSize; + double configOverlap; + int32_t dataRet; + std::vector<std::string> ret; +}; + +struct TextEmbeddingConstructorInfo { + std::string className; + napi_ref *classRef; + napi_callback constructor; + const napi_property_descriptor *property; + size_t propertyCount; + const napi_property_descriptor *staticProperty; + size_t staticPropertyCount; +}; + +TextEmbeddingNapi::TextEmbeddingNapi() : env_(nullptr) {} + +TextEmbeddingNapi::~TextEmbeddingNapi() +{ + AIP_HILOGI("Enter"); + AipNapiUtils::UnLoadAlgoLibrary(textAipCoreMgrHandle_); + delete textAipCoreManager_; +} + +static napi_value StartInit(napi_env env, napi_value exports, struct TextEmbeddingConstructorInfo info) +{ + napi_value constructor = nullptr; + napi_status status = napi_define_class(env, info.className.c_str(), NAPI_AUTO_LENGTH, info.constructor, nullptr, + info.propertyCount, info.property, &constructor); + if (status != napi_ok) { + AIP_HILOGE("define class fail"); + return nullptr; + } + + status = napi_create_reference(env, constructor, NUM_1, info.classRef); + if (status != napi_ok) { + AIP_HILOGE("create reference fail"); + return nullptr; + } + + napi_value global = nullptr; + status = napi_get_global(env, &global); + if (status != napi_ok) { + AIP_HILOGE("create global fail"); + return nullptr; + } + + status = napi_set_named_property(env, global, info.className.c_str(), constructor); + if (status != napi_ok) { + AIP_HILOGE("Init::set global named property fail"); + return nullptr; + } + + status = napi_define_properties(env, exports, info.staticPropertyCount, info.staticProperty); + if (status != napi_ok) { + AIP_HILOGE("define properties fail"); + return nullptr; + } + return exports; +} + +napi_value TextEmbeddingNapi::Init(napi_env env, napi_value exports) +{ + AIP_HILOGD("Enter"); + if (!AipNapiUtils::LoadAlgoLibrary(AIP_MANAGER_PATH, textAipCoreMgrHandle_)) { + AIP_HILOGE("LoadAlgoLibrary failed"); + } + + if (textAipCoreMgrHandle_.pAipManager != nullptr) { + textAipCoreManager_ = AipNapiUtils::GetAlgoObj(textAipCoreMgrHandle_); + } else { + textAipCoreManager_ = new IAipCoreManagerImpl(); + } + + if (textAipCoreManager_ == nullptr) { + AIP_HILOGE("GetAlgoObj failed"); + return nullptr; + } + + napi_property_descriptor properties[] = { + DECLARE_NAPI_FUNCTION("loadModel", LoadModel), + DECLARE_NAPI_FUNCTION("releaseModel", ReleaseModel), + DECLARE_NAPI_FUNCTION("getEmbedding", GetEmbedding), + }; + + napi_property_descriptor static_prop[] = { + DECLARE_NAPI_STATIC_FUNCTION("getTextEmbeddingModel", GetTextEmbeddingModel), + DECLARE_NAPI_STATIC_FUNCTION("splitText", SplitText), + }; + + struct TextEmbeddingConstructorInfo info = { + .className = CLASS_NAME, + .classRef = &sConstructor_, + .constructor = TextConstructor, + .property = properties, + .propertyCount = sizeof(properties) / sizeof(properties[NUM_0]), + .staticProperty = static_prop, + .staticPropertyCount = sizeof(static_prop) / sizeof(static_prop[NUM_0]), + }; + + if (StartInit(env, exports, info)) { + return nullptr; + } + return exports; +} + +napi_value TextEmbeddingNapi::TextConstructor(napi_env env, napi_callback_info info) +{ + napi_value undefineValue = nullptr; + napi_get_undefined(env, &undefineValue); + + napi_status status; + napi_value thisVar = nullptr; + status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr); + if (status == napi_ok && thisVar != nullptr) { + std::unique_ptr<TextEmbeddingNapi> txtEmbNapi = std::make_unique<TextEmbeddingNapi>(); + if (txtEmbNapi != nullptr) { + txtEmbNapi->env_ = env; + status = napi_wrap(env, thisVar, reinterpret_cast<void *>(txtEmbNapi.get()), TextEmbeddingNapi::Destructor, + nullptr, nullptr); + if (status == napi_ok) { + txtEmbNapi.release(); + return thisVar; + } else { + AIP_HILOGE("Failure wrapping js to native napi"); + } + } + } + return undefineValue; +} + +void TextEmbeddingNapi::Destructor(napi_env env, void *nativeObject, void *finalize) +{ + AIP_HILOGD("TextEmbeddingNapi, Destructor"); +} + +napi_value TextEmbeddingNapi::GetTextEmbeddingModel(napi_env env, napi_callback_info info) +{ + AIP_HILOGE("Enter"); + size_t argc = ARG_1; + napi_value args[ARG_1] = { nullptr }; + napi_value jsThis = nullptr; + + napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr); + if (status != napi_ok) { + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "napi_get_cb_info failed"); + return nullptr; + } + + if (!AipNapiUtils::ValidateArgsType(env, args, argc, EXPECTED_GET_TEXT_MODEL_ARG_TYPES)) { + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "ValidateArgsType failed"); + return nullptr; + } + + ModelConfigData textModelConfig; + if (!ParseModelConfig(env, args, argc, &textModelConfig)) { + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "ParseModelConfig failed"); + return nullptr; + } + + napi_value promise = nullptr; + napi_deferred deferred = nullptr; + status = napi_create_promise(env, &deferred, &promise); + if (status != napi_ok) { + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "create promise failed"); + return nullptr; + } + + auto asyncGetTextEmbeddingModelData = new AsyncGetTextEmbeddingModelData{ + .asyncWork = nullptr, + .deferred = deferred, + .config = textModelConfig, + }; + + if (!CreateAsyncTextModelExecution(env, asyncGetTextEmbeddingModelData)) { + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "create AsyncTextModelExecution failed"); + delete asyncGetTextEmbeddingModelData; + return nullptr; + } + + return promise; +} + +bool TextEmbeddingNapi::ParseModelConfig(napi_env env, napi_value *args, size_t argc, ModelConfigData *textModelConfig) +{ + AIP_HILOGI("Enter"); + napi_value version, isNPUAvailable, cachePath; + + napi_status status = napi_get_named_property(env, args[ARG_0], "version", &version); + if (status != napi_ok) { + AIP_HILOGE("napi get version property failed"); + return false; + } + + status = napi_get_named_property(env, args[ARG_0], "isNpuAvailable", &isNPUAvailable); + if (status != napi_ok) { + AIP_HILOGE("napi get isNpuAvailable property failed"); + return false; + } + + status = napi_get_named_property(env, args[ARG_0], "cachePath", &cachePath); + if (status != napi_ok) { + AIP_HILOGE("napi get cachePath property failed"); + return false; + } + + if (!AipNapiUtils::TransJsToInt32(env, version, textModelConfig->versionValue)) { + AIP_HILOGE("Trans version failed"); + return false; + } + + if (!AipNapiUtils::TransJsToBool(env, isNPUAvailable, textModelConfig->isNPUAvailableValue)) { + AIP_HILOGE("Trans isNPUAvailable failed"); + return false; + } + + if (!AipNapiUtils::TransJsToStr(env, cachePath, textModelConfig->cachePathValue)) { + AIP_HILOGE("Trans cachePath failed"); + return false; + } + return true; +} + +bool TextEmbeddingNapi::CreateAsyncTextModelExecution(napi_env env, AsyncGetTextEmbeddingModelData *asyncModelData) +{ + AIP_HILOGI("Enter"); + napi_value resourceName; + napi_status status = napi_create_string_utf8(env, "GetTextEmbeddingModel", NAPI_AUTO_LENGTH, &resourceName); + if (status != napi_ok) { + AIP_HILOGE(" napi_create_string_utf8 failed"); + return false; + } + + status = napi_create_async_work(env, nullptr, resourceName, GetTextEmbeddingModelExecutionCB, + GetTextEmbeddingModelCompleteCB, static_cast<void *>(asyncModelData), &asyncModelData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_create_async_work failed"); + return false; + } + + status = napi_queue_async_work_with_qos(env, asyncModelData->asyncWork, napi_qos_default); + if (status != napi_ok) { + AIP_HILOGE("napi_queue_async_work_with_qos failed"); + return false; + } + return true; +} + + +void TextEmbeddingNapi::GetTextEmbeddingModelExecutionCB(napi_env env, void *data) +{ + AIP_HILOGD("Enter"); + AsyncGetTextEmbeddingModelData *modelData = static_cast<AsyncGetTextEmbeddingModelData *>(data); + if (textAipCoreManager_ == nullptr) { + AIP_HILOGE("pAipManager is nullptr"); + return; + } + auto config = modelData->config; + int32_t result = textAipCoreManager_->InitTextModel(config); + modelData->ret = result; + AIP_HILOGD("Exit"); +} + +void TextEmbeddingNapi::GetTextEmbeddingModelCompleteCB(napi_env env, napi_status status, void *data) +{ + AIP_HILOGD("Enter"); + AsyncGetTextEmbeddingModelData *modelData = static_cast<AsyncGetTextEmbeddingModelData *>(data); + auto ret = modelData->ret; + napi_value result = nullptr; + napi_value constructor = nullptr; + if (ret != ERR_OK) { + if (ret == DEVICE_EXCEPTION) { + ThrowIntelligenceErrByPromise(env, DEVICE_EXCEPTION, "GetTextEmbeddingModelCompleteCB failed", result); + } else { + ThrowIntelligenceErrByPromise(env, INNER_ERROR, "GetTextEmbeddingModelCompleteCB failed", result); + } + napi_reject_deferred(env, modelData->deferred, result); + } else { + status = napi_get_reference_value(env, sConstructor_, &constructor); + if (status != napi_ok) { + AIP_HILOGE("napi_get_reference_value failed"); + napi_get_undefined(env, &result); + delete modelData; + return; + } + + status = napi_new_instance(env, constructor, 0, nullptr, &result); + if (status != napi_ok) { + AIP_HILOGE("napi_new_instance failed"); + napi_get_undefined(env, &result); + return; + } + + status = napi_resolve_deferred(env, modelData->deferred, result); + if (status != napi_ok) { + AIP_HILOGE(" napi_resolve_deferred failed"); + } + } + + status = napi_delete_async_work(env, modelData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_delete_async_work failed"); + } + delete modelData; +} + + +napi_value TextEmbeddingNapi::SplitText(napi_env env, napi_callback_info info) +{ + AIP_HILOGI("Enter"); + size_t argc = ARG_2; + napi_value args[ARG_2] = { nullptr }; + napi_value jsThis = nullptr; + + napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr); + if (status != napi_ok) { + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "napi_get_cb_info failed"); + return nullptr; + } + + if (!AipNapiUtils::ValidateArgsType(env, args, argc, EXPECTED_SPLITTEXT_ARG_TYPES)) { + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "ValidateArgsType failed"); + return nullptr; + } + + std::string strArg; + if (!AipNapiUtils::TransJsToStrUnlimited(env, args[ARG_0], strArg)) { + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "TransJsToStrUnlimited failed"); + return nullptr; + } + AIP_HILOGI("string strArg: %{public}s", strArg.c_str()); + + napi_value cfgSize; + napi_value cfgOverlap; + if (!GetProperties(env, args[ARG_1], cfgSize, cfgOverlap)) { + AIP_HILOGE("content property failed"); + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "content property failed"); + return nullptr; + } + int32_t configSize; + double configOverlap; + AipNapiUtils::TransJsToInt32(env, cfgSize, configSize); + AipNapiUtils::TransJsToDouble(env, cfgOverlap, configOverlap); + AIP_HILOGI("string strArg: %{public}d", configSize); + AIP_HILOGI("string strArg: %{public}f", configOverlap); + + napi_value promise = nullptr; + napi_deferred deferred = nullptr; + status = napi_create_promise(env, &deferred, &promise); + if (status != napi_ok) { + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "create promise failed"); + return nullptr; + } + + if (!SplitTextAsyncExecution(env, deferred, strArg, configSize, configOverlap)) { + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "create split text async execution failed"); + return nullptr; + } + AIP_HILOGD("Exit"); + return promise; +} + +bool TextEmbeddingNapi::SplitTextAsyncExecution(napi_env env, napi_deferred deferred, std::string strArg, + int32_t configSize, double configOverlap) +{ + AIP_HILOGD("Enter"); + auto splitTextCallbackData = new SplitTextCallbackData{ + .asyncWork = nullptr, + .deferred = deferred, + .strArg = strArg, + .configSize = configSize, + .configOverlap = configOverlap, + }; + + napi_value resourceName; + napi_status status = napi_create_string_utf8(env, "SplitText", NAPI_AUTO_LENGTH, &resourceName); + if (status != napi_ok) { + AIP_HILOGE("napi_create_string_utf8 failed"); + delete splitTextCallbackData; + return false; + } + + status = napi_create_async_work(env, nullptr, resourceName, SplitTextExecuteCB, SplitTextCompleteCB, + static_cast<void *>(splitTextCallbackData), &splitTextCallbackData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_create_async_work failed"); + delete splitTextCallbackData; + return false; + } + + status = napi_queue_async_work_with_qos(env, splitTextCallbackData->asyncWork, napi_qos_default); + if (status != napi_ok) { + AIP_HILOGE("napi_queue_async_work_with_qos failed"); + napi_delete_async_work(env, splitTextCallbackData->asyncWork); + delete splitTextCallbackData; + return false; + } + return true; +} + +void TextEmbeddingNapi::SplitTextExecuteCB(napi_env env, void *data) +{ + AIP_HILOGD("Enter"); + SplitTextCallbackData *splitTextCallbackData = static_cast<SplitTextCallbackData *>(data); + std::string strArg = splitTextCallbackData->strArg; + int32_t configSize = splitTextCallbackData->configSize; + double configOverlap = splitTextCallbackData->configOverlap; + std::vector<std::string> result; + int32_t ret = textAipCoreManager_->SplitText(strArg, configSize, static_cast<float>(configOverlap), result); + if (ret != ERR_OK) { + AIP_HILOGE("SplitText failed"); + result = {}; + } + splitTextCallbackData->ret = result; + splitTextCallbackData->dataRet = ret; + AIP_HILOGD("Exit"); +} +void TextEmbeddingNapi::SplitTextCompleteCB(napi_env env, napi_status status, void *data) +{ + AIP_HILOGD("Enter"); + SplitTextCallbackData *splitTextCallbackData = static_cast<SplitTextCallbackData *>(data); + napi_value value = nullptr; + std::vector<std::string> ret = splitTextCallbackData->ret; + int32_t dataRet = splitTextCallbackData->dataRet; + if (dataRet != ERR_OK) { + if (dataRet == DEVICE_EXCEPTION) { + ThrowIntelligenceErrByPromise(env, DEVICE_EXCEPTION, "SplitTextCompleteCB failed", value); + } else { + ThrowIntelligenceErrByPromise(env, INNER_ERROR, "SplitTextCompleteCB failed", value); + } + napi_reject_deferred(env, splitTextCallbackData->deferred, value); + } else { + status = napi_create_array(env, &value); + if (status != napi_ok) { + AIP_HILOGE("napi_create_array failed"); + } else { + for (size_t i = 0; i < ret.size(); i++) { + napi_value jsStr = nullptr; + napi_create_string_utf8(env, ret[i].c_str(), NAPI_AUTO_LENGTH, &jsStr); + napi_set_element(env, value, i, jsStr); + } + status = napi_resolve_deferred(env, splitTextCallbackData->deferred, value); + if (status != napi_ok) { + AIP_HILOGE("napi_resolve_deferred failed"); + } + } + } + + status = napi_delete_async_work(env, splitTextCallbackData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_delete_async_work failed"); + } + delete splitTextCallbackData; +} + + +bool TextEmbeddingNapi::GetProperties(napi_env env, napi_value args, napi_value &cfgSize, napi_value &cfgOverlap) +{ + napi_status status = napi_get_named_property(env, args, "size", &cfgSize); + if (status != napi_ok) { + AIP_HILOGE("napi get size property failed"); + return false; + } + + status = napi_get_named_property(env, args, "overlapRatio", &cfgOverlap); + if (status != napi_ok) { + AIP_HILOGE("napi get overlapRatio property failed"); + return false; + } + return true; +} + +napi_value TextEmbeddingNapi::GetEmbedding(napi_env env, napi_callback_info info) +{ + AIP_HILOGE("Enter"); + size_t argc = ARG_1; + napi_value args[ARG_1] = { nullptr }; + napi_value jsThis = nullptr; + + napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr); + if (status != napi_ok) { + ThrowIntelligenceErr(env, INNER_ERROR, "napi_get_cb_info failed"); + return nullptr; + } + + if (argc != ARG_1) { + AIP_HILOGE("param size error"); + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "param size error"); + return nullptr; + } + + napi_valuetype valueType = napi_undefined; + status = napi_typeof(env, args[ARG_0], &valueType); + napi_value promise = nullptr; + napi_deferred deferred = nullptr; + status = napi_create_promise(env, &deferred, &promise); + if (status != napi_ok) { + ThrowIntelligenceErr(env, INNER_ERROR, "napi_get_cb_info failed"); + return nullptr; + } + if (valueType == napi_string) { + StringType(env, args[ARG_0], promise, deferred); + } + if (valueType == napi_object) { + ArrayType(env, args[ARG_0], promise, deferred); + } + + return promise; +} + +napi_value TextEmbeddingNapi::StringType(napi_env env, napi_value args, napi_value promise, napi_deferred deferred) +{ + std::string strArg; + if (!AipNapiUtils::TransJsToStr(env, args, strArg)) { + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "TransJsToStr failed"); + return nullptr; + } + + AIP_HILOGI("string Arg: %{public}s", strArg.c_str()); + if (!GetEmbeddingStringAsyncExecution(env, deferred, strArg)) { + ThrowIntelligenceErr(env, INNER_ERROR, "GetEmbeddingStringAsyncExecution failed"); + return nullptr; + } + AIP_HILOGD("Exit"); + return promise; +} + +bool TextEmbeddingNapi::GetEmbeddingStringAsyncExecution(napi_env env, napi_deferred deferred, std::string strArg) +{ + AIP_HILOGD("Enter"); + auto textStringCallbackData = new TextStringCallbackData{ + .asyncWork = nullptr, + .deferred = deferred, + .strArg = strArg, + }; + + napi_value resourceName; + napi_status status = napi_create_string_utf8(env, "textStringEmbedding", NAPI_AUTO_LENGTH, &resourceName); + if (status != napi_ok) { + AIP_HILOGE("napi_create_string_utf8 failed"); + delete textStringCallbackData; + return false; + } + + status = napi_create_async_work(env, nullptr, resourceName, GetEmbeddingStringExecuteCB, + GetEmbeddingStringCompleteCB, static_cast<void *>(textStringCallbackData), &textStringCallbackData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_create_async_work failed"); + delete textStringCallbackData; + return false; + } + + status = napi_queue_async_work_with_qos(env, textStringCallbackData->asyncWork, napi_qos_default); + if (status != napi_ok) { + AIP_HILOGE("napi_queue_async_work_with_qos failed"); + napi_delete_async_work(env, textStringCallbackData->asyncWork); + delete textStringCallbackData; + return false; + } + return true; +} + +void TextEmbeddingNapi::GetEmbeddingStringExecuteCB(napi_env env, void *data) +{ + AIP_HILOGD("Enter"); + TextStringCallbackData *textStringCallbackData = static_cast<TextStringCallbackData *>(data); + std::string strArg = textStringCallbackData->strArg; + std::vector<float> result; + int32_t ret = textAipCoreManager_->GetTextEmbedding(strArg, result); + textStringCallbackData->ret = result; + textStringCallbackData->dataRet = ret; + AIP_HILOGD("Exit"); +} + +void TextEmbeddingNapi::GetEmbeddingStringCompleteCB(napi_env env, napi_status status, void *data) +{ + AIP_HILOGD("Enter"); + TextStringCallbackData *textStringCallbackData = static_cast<TextStringCallbackData *>(data); + napi_value value; + auto ret = textStringCallbackData->ret; + auto dataRet = textStringCallbackData->dataRet; + if (dataRet != ERR_OK) { + if (dataRet == DEVICE_EXCEPTION) { + ThrowIntelligenceErrByPromise(env, DEVICE_EXCEPTION, "GetEmbeddingStringCompleteCB failed", value); + } else { + ThrowIntelligenceErrByPromise(env, INNER_ERROR, "GetEmbeddingStringCompleteCB failed", value); + } + napi_reject_deferred(env, textStringCallbackData->deferred, value); + } else { + status = napi_create_array(env, &value); + if (status != napi_ok) { + AIP_HILOGE("napi_create_array failed"); + } else { + for (size_t i = 0; i < ret.size(); i++) { + napi_value jsDouble = nullptr; + AipNapiUtils::CreateDoubleData(env, static_cast<double>(ret[i]), &jsDouble); + napi_set_element(env, value, i, jsDouble); + } + status = napi_resolve_deferred(env, textStringCallbackData->deferred, value); + if (status != napi_ok) { + AIP_HILOGE(" napi_resolve_deferred failed"); + } + } + } + + status = napi_delete_async_work(env, textStringCallbackData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_delete_async_work failed"); + } + delete textStringCallbackData; +} + +bool TextEmbeddingNapi::ValidateAndDealArrayArgs(napi_env env, napi_value args, std::vector<std::string> &strArr) +{ + AIP_HILOGD("Enter"); + bool isArray = false; + napi_status status = napi_is_array(env, args, &isArray); + if (status != napi_ok) { + AIP_HILOGE("check napi is array failed"); + return false; + } + + if (!isArray) { + AIP_HILOGE("argument is not array"); + return false; + } + + uint32_t arrayLen = 0; + status = napi_get_array_length(env, args, &arrayLen); + if (status != napi_ok) { + AIP_HILOGE("argument is not array"); + return false; + } + if (arrayLen > MAX_STR_PARAM_LEN) { + AIP_HILOGE("argument size is too big"); + return false; + } + + for (uint32_t i = 0; i < arrayLen; ++i) { + napi_value element = nullptr; + status = napi_get_element(env, args, i, &element); + if (status != napi_ok) { + AIP_HILOGE("argument get array element failed"); + return false; + } + std::string text; + if (!AipNapiUtils::TransJsToStr(env, element, text)) { + AIP_HILOGE("napi get array element error"); + strArr.clear(); + return false; + } + strArr.push_back(text); + } + return true; +} + +napi_value TextEmbeddingNapi::ArrayType(napi_env env, napi_value args, napi_value promise, napi_deferred deferred) +{ + std::vector<std::string> text; + if (!ValidateAndDealArrayArgs(env, args, text)) { + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "Validate ArrayArgs error!"); + return nullptr; + } + if (!GetEmbeddingArrayAsyncExecution(env, deferred, text)) { + ThrowIntelligenceErr(env, INNER_ERROR, "GetEmbeddingArrayAsyncExecution failed!"); + return nullptr; + } + + AIP_HILOGD("exit"); + return promise; +} + +bool TextEmbeddingNapi::GetEmbeddingArrayAsyncExecution(napi_env env, napi_deferred deferred, + std::vector<std::string> text) +{ + AIP_HILOGD("Enter"); + auto textArrayCallbackData = new TextArrayCallbackData{ + .asyncWork = nullptr, + .deferred = deferred, + .text = text, + }; + + napi_value resourceName; + napi_status status = napi_create_string_utf8(env, "textArrayEmbedding", NAPI_AUTO_LENGTH, &resourceName); + if (status != napi_ok) { + AIP_HILOGE("napi_create_string_utf8 failed"); + delete textArrayCallbackData; + return false; + } + + status = napi_create_async_work(env, nullptr, resourceName, GetEmbeddingArrayExecuteCB, GetEmbeddingArrayCompleteCB, + static_cast<void *>(textArrayCallbackData), &textArrayCallbackData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_create_async_work failed"); + delete textArrayCallbackData; + return false; + } + + status = napi_queue_async_work_with_qos(env, textArrayCallbackData->asyncWork, napi_qos_default); + if (status != napi_ok) { + AIP_HILOGE("napi_queue_async_work_with_qos failed"); + napi_delete_async_work(env, textArrayCallbackData->asyncWork); + delete textArrayCallbackData; + return false; + } + return true; +} + + +void TextEmbeddingNapi::GetEmbeddingArrayExecuteCB(napi_env env, void *data) +{ + AIP_HILOGD("Enter"); + TextArrayCallbackData *textArrayCallbackData = static_cast<TextArrayCallbackData *>(data); + auto text = textArrayCallbackData->text; + std::vector<std::vector<float>> result; + int32_t ret = textAipCoreManager_->GetTextEmbedding(text, result); + textArrayCallbackData->ret = result; + textArrayCallbackData->dataRet = ret; +} + +void TextEmbeddingNapi::GetEmbeddingArrayCompleteCB(napi_env env, napi_status status, void *data) +{ + AIP_HILOGD("Enter"); + TextArrayCallbackData *textArrayCallbackData = static_cast<TextArrayCallbackData *>(data); + napi_value value = nullptr; + std::vector<std::vector<float>> ret = textArrayCallbackData->ret; + auto dataRet = textArrayCallbackData->dataRet; + if (dataRet != ERR_OK) { + if (dataRet == DEVICE_EXCEPTION) { + ThrowIntelligenceErrByPromise(env, DEVICE_EXCEPTION, "GetEmbeddingArrayCompleteCB failed", value); + } else { + ThrowIntelligenceErrByPromise(env, INNER_ERROR, "GetEmbeddingArrayCompleteCB failed", value); + } + napi_reject_deferred(env, textArrayCallbackData->deferred, value); + status = napi_delete_async_work(env, textArrayCallbackData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_delete_async_work failed"); + } + delete textArrayCallbackData; + return; + } + + status = napi_create_array(env, &value); + if (status != napi_ok) { + AIP_HILOGE("napi_create_array failed"); + } else { + for (size_t i = 0; i < ret.size(); ++i) { + napi_value res = nullptr; + napi_create_array(env, &res); + for (size_t j = 0; j < ret[i].size(); ++j) { + napi_value jsDouble = nullptr; + napi_create_double(env, static_cast<double>(ret[i][j]), &jsDouble); + napi_set_element(env, res, j, jsDouble); + } + napi_set_element(env, value, i, res); + } + status = napi_resolve_deferred(env, textArrayCallbackData->deferred, value); + if (status != napi_ok) { + AIP_HILOGE(" napi_resolve_deferred failed"); + } + } + + status = napi_delete_async_work(env, textArrayCallbackData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_delete_async_work failed"); + } + delete textArrayCallbackData; +} + + +napi_value TextEmbeddingNapi::LoadModel(napi_env env, napi_callback_info info) +{ + AIP_HILOGD("Enter"); + size_t argc = ARG_0; + napi_value args[ARG_1] = { nullptr }; + napi_value jsThis = nullptr; + + napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr); + if (status != napi_ok) { + AIP_HILOGE("napi_get_cb_info failed"); + ThrowIntelligenceErr(env, INNER_ERROR, "napi_get_cb_info failed"); + return nullptr; + } + + if (argc != ARG_0) { + AIP_HILOGE("param size error"); + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "param size error"); + return nullptr; + } + + napi_value promise = nullptr; + napi_deferred deferred = nullptr; + status = napi_create_promise(env, &deferred, &promise); + if (status != napi_ok) { + ThrowIntelligenceErr(env, INNER_ERROR, "create promise failed"); + return nullptr; + } + + if (!LoadAsyncExecution(env, deferred)) { + ThrowIntelligenceErr(env, INNER_ERROR, "create promise failed"); + return nullptr; + } + AIP_HILOGD("Exit"); + return promise; +} + +bool TextEmbeddingNapi::LoadAsyncExecution(napi_env env, napi_deferred deferred) +{ + AIP_HILOGD("Enter"); + auto loadCallbackData = new LoadCallbackData{ + .asyncWork = nullptr, + .deferred = deferred, + }; + + napi_value resourceName; + napi_status status = napi_create_string_utf8(env, "textLoad", NAPI_AUTO_LENGTH, &resourceName); + if (status != napi_ok) { + AIP_HILOGE("napi_create_string_utf8 failed"); + delete loadCallbackData; + return false; + } + + status = napi_create_async_work(env, nullptr, resourceName, LoadExecuteCB, LoadCompleteCB, + static_cast<void *>(loadCallbackData), &loadCallbackData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_create_async_work failed"); + delete loadCallbackData; + return false; + } + + status = napi_queue_async_work_with_qos(env, loadCallbackData->asyncWork, napi_qos_default); + if (status != napi_ok) { + AIP_HILOGE("napi_queue_async_work_with_qos failed"); + napi_delete_async_work(env, loadCallbackData->asyncWork); + delete loadCallbackData; + return false; + } + return true; +} + +void TextEmbeddingNapi::LoadExecuteCB(napi_env env, void *data) +{ + AIP_HILOGD("Enter"); + LoadCallbackData *loadCallbackData = static_cast<LoadCallbackData *>(data); + auto ret = textAipCoreManager_->LoadTextModel(); + loadCallbackData->ret = ret; + AIP_HILOGD("Exit"); +} + +void TextEmbeddingNapi::LoadCompleteCB(napi_env env, napi_status status, void *data) +{ + AIP_HILOGD("Enter"); + LoadCallbackData *loadCallbackData = static_cast<LoadCallbackData *>(data); + napi_value value = nullptr; + auto ret = loadCallbackData->ret; + if (ret != ERR_OK) { + if (ret == DEVICE_EXCEPTION) { + ThrowIntelligenceErrByPromise(env, DEVICE_EXCEPTION, "loadCallbackData failed", value); + } else { + ThrowIntelligenceErrByPromise(env, INNER_ERROR, "loadCallbackData failed", value); + } + napi_reject_deferred(env, loadCallbackData->deferred, value); + } else { + status = napi_get_undefined(env, &value); + if (status != napi_ok) { + AIP_HILOGE(" napi_get_undefined failed"); + } + status = napi_resolve_deferred(env, loadCallbackData->deferred, value); + if (status != napi_ok) { + AIP_HILOGE(" napi_resolve_deferred failed"); + } + } + + status = napi_delete_async_work(env, loadCallbackData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_delete_async_work failed"); + } + delete loadCallbackData; +} + + +napi_value TextEmbeddingNapi::ReleaseModel(napi_env env, napi_callback_info info) +{ + AIP_HILOGD("Enter"); + size_t argc = ARG_0; + napi_value args[ARG_1] = { nullptr }; + napi_value jsThis = nullptr; + + napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr); + if (status != napi_ok) { + AIP_HILOGE("napi_get_cb_info failed"); + ThrowIntelligenceErr(env, INNER_ERROR, "napi_get_cb_info failed"); + return nullptr; + } + + if (argc != ARG_0) { + ThrowIntelligenceErr(env, PARAM_EXCEPTION, "param size error"); + return nullptr; + } + + napi_value promise = nullptr; + napi_deferred deferred = nullptr; + status = napi_create_promise(env, &deferred, &promise); + if (status != napi_ok) { + ThrowIntelligenceErr(env, INNER_ERROR, "create promise failed"); + return nullptr; + } + + if (!ReleaseAsyncExecution(env, deferred)) { + ThrowIntelligenceErr(env, INNER_ERROR, "releaseAsyncExecution failed"); + return nullptr; + } + + AIP_HILOGD("Exit"); + return promise; +} + +bool TextEmbeddingNapi::ReleaseAsyncExecution(napi_env env, napi_deferred deferred) +{ + AIP_HILOGD("Enter"); + auto releaseCallbackData = new ReleaseCallbackData{ + .asyncWork = nullptr, + .deferred = deferred, + }; + + napi_value resourceName; + napi_status status = napi_create_string_utf8(env, "textLoad", NAPI_AUTO_LENGTH, &resourceName); + if (status != napi_ok) { + AIP_HILOGE("napi_create_string_utf8 failed"); + delete releaseCallbackData; + return false; + } + + status = napi_create_async_work(env, nullptr, resourceName, ReleaseExecuteCB, ReleaseCompleteCB, + static_cast<void *>(releaseCallbackData), &releaseCallbackData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_create_async_work failed"); + delete releaseCallbackData; + return false; + } + + status = napi_queue_async_work_with_qos(env, releaseCallbackData->asyncWork, napi_qos_default); + if (status != napi_ok) { + AIP_HILOGE("napi_queue_async_work_with_qos failed"); + napi_delete_async_work(env, releaseCallbackData->asyncWork); + delete releaseCallbackData; + return false; + } + return true; +} +void TextEmbeddingNapi::ReleaseExecuteCB(napi_env env, void *data) +{ + AIP_HILOGD("Enter"); + ReleaseCallbackData *releaseCallbackData = static_cast<ReleaseCallbackData *>(data); + auto ret = textAipCoreManager_->ReleaseTextModel(); + releaseCallbackData->ret = ret; + AIP_HILOGD("Exit"); +} + +void TextEmbeddingNapi::ReleaseCompleteCB(napi_env env, napi_status status, void *data) +{ + AIP_HILOGD("Enter"); + ReleaseCallbackData *releaseCallbackData = static_cast<ReleaseCallbackData *>(data); + napi_value value = nullptr; + auto ret = releaseCallbackData->ret; + if (ret != ERR_OK) { + if (ret == DEVICE_EXCEPTION) { + ThrowIntelligenceErrByPromise(env, DEVICE_EXCEPTION, "ReleaseCompleteCB failed", value); + } else { + ThrowIntelligenceErrByPromise(env, INNER_ERROR, "ReleaseCompleteCB failed", value); + } + napi_reject_deferred(env, releaseCallbackData->deferred, value); + } else { + status = napi_get_undefined(env, &value); + if (status != napi_ok) { + AIP_HILOGE(" napi_get_undefined failed"); + } + status = napi_resolve_deferred(env, releaseCallbackData->deferred, value); + if (status != napi_ok) { + AIP_HILOGE(" napi_resolve_deferred failed"); + } + } + + status = napi_delete_async_work(env, releaseCallbackData->asyncWork); + if (status != napi_ok) { + AIP_HILOGE("napi_delete_async_work failed"); + } + delete releaseCallbackData; +} +} // namespace DataIntelligence +} // namespace OHOS diff --git a/udmf/framework/jskitsimpl/unittest/UdmfJsTest.js b/udmf/framework/jskitsimpl/unittest/UdmfJsTest.js index 9999cf81b384b48c86de3fdd0a973416a375fa35..3ae48d28ff47e52711a249ad20026243a9ee5ba7 100644 --- a/udmf/framework/jskitsimpl/unittest/UdmfJsTest.js +++ b/udmf/framework/jskitsimpl/unittest/UdmfJsTest.js @@ -30,6 +30,8 @@ const LONG_TEST2M = 'a'.repeat(NUM_2M); const LONG_TESTOVER2M = 'a'.repeat((NUM_2M + 1)); let U8_ARRAY = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); +const ERROR_PARAMETER = '401'; +const NO_PERMISSION = '201'; describe('UdmfJSTest', function () { @@ -1094,13 +1096,20 @@ describe('UdmfJSTest', function () { const htmlType = 'general.html'; let text = new UDC.Text(); + let systemDefinedValue = 'systemDefinedValue'; + let hyperlinkValue = 'hyperlinkValue'; + text.addEntry(UTD.UniformDataType.HYPERLINK, hyperlinkValue); + text.addEntry('openharmony.app-item', systemDefinedValue); let unifiedData = new UDC.UnifiedData(text); expect(unifiedData.hasType(textType)).assertEqual(true); expect(unifiedData.hasType(htmlType)).assertEqual(false); - expect(unifiedData.hasType(plaintextType)).assertEqual(false); + expect(unifiedData.hasType(UTD.UniformDataType.HYPERLINK)).assertEqual(true); + expect(unifiedData.hasType('openharmony.app-item')).assertEqual(true); let types = unifiedData.getTypes(); - expect(types.length).assertEqual(1); - expect(types[0]).assertEqual(textType); + expect(types.length).assertEqual(3); + expect(types.includes(textType)).assertTrue(); + expect(types.includes(UTD.UniformDataType.HYPERLINK)).assertTrue(); + expect(types.includes('openharmony.app-item')).assertTrue(); let html = new UDC.HTML(); unifiedData.addRecord(html); @@ -1108,9 +1117,12 @@ describe('UdmfJSTest', function () { expect(unifiedData.hasType(htmlType)).assertEqual(true); expect(unifiedData.hasType(plaintextType)).assertEqual(false); types = unifiedData.getTypes(); - expect(types.length).assertEqual(2); - expect(types[0]).assertEqual(textType); - expect(types[1]).assertEqual(htmlType); + expect(types.length).assertEqual(4); + expect(types.includes(textType)).assertTrue(); + expect(types.includes(htmlType)).assertTrue(); + expect(types.includes(textType)).assertTrue(); + expect(types.includes(UTD.UniformDataType.HYPERLINK)).assertTrue(); + expect(types.includes('openharmony.app-item')).assertTrue(); }); /** @@ -1691,4 +1703,381 @@ describe('UdmfJSTest', function () { done(); } }); + + /** + * @tc.name UdmfSetAppShareOptionsTest001 + * @tc.desc Test Js Api setAppShareOptions, error intention + * @tc.type: FUNC + * @tc.require: + */ + it('UdmfSetAppShareOptionsTest001', 0, function () { + const TAG = 'UdmfSetAppShareOptionsTest001:'; + console.info(TAG, 'start'); + try { + UDC.setAppShareOptions(UDC.Intention.DATA_HUB, UDC.ShareOptions.IN_APP); + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + } catch (e) { + console.error(TAG, `get e. code is ${e.code},message is ${e.message} `); + expect(e.code === ERROR_PARAMETER).assertTrue(); + } + console.info(TAG, 'end'); + }); + + /** + * @tc.name UdmfRemoveAppShareOptionsTest001 + * @tc.desc Test Js Api removeAppShareOptions, error intention + * @tc.type: FUNC + * @tc.require: + */ + it('UdmfRemoveAppShareOptionsTest001', 0, function () { + const TAG = 'UdmfRemoveAppShareOptionsTest001:'; + console.info(TAG, 'start'); + try { + UDC.removeAppShareOptions(UDC.Intention.DATA_HUB); + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + } catch (e) { + console.error(TAG, `get e. code is ${e.code},message is ${e.message} `); + expect(e.code === ERROR_PARAMETER).assertTrue(); + } + console.info(TAG, 'end'); + }); + + /** + * @tc.name MultiEntryTest001 + * @tc.desc + * @tc.type: FUNC + * @tc.require: + */ + it('MultiEntryTest001', 0, async function (done) { + const TAG = 'MultiEntryTest001'; + console.info(TAG, 'start'); + let hyperLinkDetails = { + 'key1': 'value1', + 'key2': 'value2', + }; + let hyperLink = { + uniformDataType: UTD.UniformDataType.HYPERLINK, + url: 'www.xxx', + description: 'hyperlinkDescription', + details: hyperLinkDetails + }; + let systemDefinedDetails = { + 'key1': 'value1', + 'key2': 'value2', + }; + let systemDefined = { + uniformDataType: 'openharmony.app-item', + appId: 'app-itemAppId', + appName: 'app-itemAppName', + appIconId: 'app-itemAppIconId', + appLabelId: 'app-itemAppLabelId', + bundleName: 'app-itemBundleName', + abilityName: 'app-itemAbilityName', + details: systemDefinedDetails + }; + + let plainTextDetails = { + 'key1': 'value1', + 'key2': 'value2', + }; + let plainText = { + uniformDataType: UTD.UniformDataType.PLAIN_TEXT, + textContent: 'This is plainText textContent example', + abstract: 'this is abstract', + details: plainTextDetails + }; + let record1 = new UDC.UnifiedRecord(UTD.UniformDataType.PLAIN_TEXT, plainText); + record1.addEntry(UTD.UniformDataType.HYPERLINK, hyperLink); + record1.addEntry('openharmony.app-item', systemDefined); + + let entries = record1.getEntries(); + + let unifiedData = new UDC.UnifiedData(record1); + let records = unifiedData.getRecords(); + expect(records.length).assertEqual(1); + const value1 = records[0].getValue(); + let types = records[0].getTypes(); + let systemDefined1 = records[0].getEntry('openharmony.app-item'); + let hyperlink1 = records[0].getEntry(UTD.UniformDataType.HYPERLINK); + + expect(value1.uniformDataType).assertEqual(plainText.uniformDataType); + expect(value1.textContent).assertEqual(plainText.textContent); + expect(value1.abstract).assertEqual(plainText.abstract); + expect(value1.details.key1).assertEqual(plainText.details.key1); + expect(value1.details.key2).assertEqual(plainText.details.key2); + expect(hyperlink1.url).assertEqual('www.xxx'); + expect(hyperlink1.details.key1).assertEqual('value1'); + expect(systemDefined1.appId).assertEqual('app-itemAppId'); + expect(systemDefined1.details.key1).assertEqual('value1'); + expect(types.length).assertEqual(3); + expect(types.includes(UTD.UniformDataType.PLAIN_TEXT)).assertTrue(); + expect(types.includes(UTD.UniformDataType.HYPERLINK)).assertTrue(); + expect(types.includes('openharmony.app-item')).assertTrue(); + expect(entries['openharmony.app-item'].appIconId).assertEqual('app-itemAppIconId'); + expect(entries['openharmony.app-item'].details.key1).assertEqual('value1'); + expect(entries['general.hyperlink'].url).assertEqual('www.xxx'); + expect(entries['general.hyperlink'].details.key1).assertEqual('value1'); + expect(entries['general.plain-text'].textContent).assertEqual('This is plainText textContent example'); + expect(entries['general.plain-text'].details.key1).assertEqual('value1'); + + try { + UDC.insertData(optionsValid, unifiedData).then((data) => { + console.info(TAG, `insert success. The key: ${data}`); + let options = { key: data }; + console.info(TAG, `query start. The options: ${JSON.stringify(options)}`); + UDC.queryData(options).then((data) => { + console.info(TAG, 'query success.'); + expect(data.length).assertEqual(1); + let records = data[0].getRecords(); + expect(records.length).assertEqual(1); + const valueQuery = records[0].getValue(); + const hyperlinkQuery = records[0].getEntry(UTD.UniformDataType.HYPERLINK); + const systemDefinedQuery = records[0].getEntry('openharmony.app-item'); + const entriesQuery = records[0].getEntries(); + const types1 = records[0].getTypes(); + expect(valueQuery.uniformDataType).assertEqual(plainText.uniformDataType); + expect(valueQuery.textContent).assertEqual(plainText.textContent); + expect(valueQuery.abstract).assertEqual(plainText.abstract); + expect(valueQuery.details.key1).assertEqual(plainText.details.key1); + expect(valueQuery.details.key2).assertEqual(plainText.details.key2); + expect(hyperlinkQuery.url).assertEqual('www.xxx'); + expect(hyperlinkQuery.details.key1).assertEqual('value1'); + expect(systemDefinedQuery.appId).assertEqual('app-itemAppId'); + expect(systemDefinedQuery.details.key1).assertEqual('value1'); + expect(types1.length).assertEqual(3); + expect(types1.includes(UTD.UniformDataType.PLAIN_TEXT)).assertTrue(); + expect(types1.includes(UTD.UniformDataType.HYPERLINK)).assertTrue(); + expect(types1.includes('openharmony.app-item')).assertTrue(); + + expect(entriesQuery['openharmony.app-item'].appIconId).assertEqual('app-itemAppIconId'); + expect(entriesQuery['openharmony.app-item'].details.key1).assertEqual('value1'); + expect(entriesQuery['general.hyperlink'].url).assertEqual('www.xxx'); + expect(entriesQuery['general.hyperlink'].details.key1).assertEqual('value1'); + expect(entriesQuery['general.plain-text'].textContent).assertEqual('This is plainText textContent example'); + expect(entriesQuery['general.plain-text'].details.key1).assertEqual('value1'); + + UDC.deleteData(options).then((data) => { + console.info(TAG, 'delete success.'); + expect(data.length).assertEqual(1); + done(); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + } catch (e) { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + } + }); + + /** + * @tc.name MultiEntryTest002 + * @tc.desc + * @tc.type: FUNC + * @tc.require: + */ + it('MultiEntryTest002', 0, async function (done) { + const TAG = 'MultiEntryTest002'; + console.info(TAG, 'start'); + let hyperLinkDetails = { + 'key1': 'value1', + 'key2': 'value2', + }; + let hyperLink = { + uniformDataType: UTD.UniformDataType.HYPERLINK, + url: 'www.xxx', + description: 'hyperlinkDescription', + details: hyperLinkDetails + }; + let plainTextDetails = { + 'key1': 'value1', + 'key2': 'value2', + }; + let plainText = new UDC.PlainText(); + plainText.textContent = 'This is plainText textContent example'; + plainText.abstract = 'this is abstract'; + plainText.details = plainTextDetails; + plainText.addEntry(UTD.UniformDataType.HYPERLINK, hyperLink); + + let unifiedData = new UDC.UnifiedData(plainText); + let records = unifiedData.getRecords(); + expect(records.length).assertEqual(1); + let entries = records[0].getEntries(); + let types = records[0].getTypes(); + let hyperlink1 = records[0].getEntry(UTD.UniformDataType.HYPERLINK); + expect(records[0].textContent).assertEqual(plainText.textContent); + expect(records[0].abstract).assertEqual(plainText.abstract); + expect(records[0].details.key1).assertEqual(plainText.details.key1); + expect(records[0].details.key2).assertEqual(plainText.details.key2); + expect(hyperlink1.url).assertEqual('www.xxx'); + expect(hyperlink1.details.key1).assertEqual('value1'); + expect(types.length).assertEqual(2); + expect(types.includes(UTD.UniformDataType.PLAIN_TEXT)).assertTrue(); + expect(types.includes(UTD.UniformDataType.HYPERLINK)).assertTrue(); + expect(entries['general.hyperlink'].url).assertEqual('www.xxx'); + expect(entries['general.hyperlink'].details.key1).assertEqual('value1'); + expect(entries['general.plain-text'].textContent).assertEqual('This is plainText textContent example'); + expect(entries['general.plain-text'].details.key1).assertEqual('value1'); + + try { + UDC.insertData(optionsValid, unifiedData).then((data) => { + console.info(TAG, `insert success. The key: ${data}`); + let options = { key: data }; + console.info(TAG, `query start. The options: ${JSON.stringify(options)}`); + UDC.queryData(options).then((data) => { + console.info(TAG, 'query success.'); + expect(data.length).assertEqual(1); + let records = data[0].getRecords(); + expect(records.length).assertEqual(1); + const hyperlinkQuery = records[0].getEntry(UTD.UniformDataType.HYPERLINK); + const systemDefinedQuery = records[0].getEntry('openharmony.app-item'); + const entriesQuery = records[0].getEntries(); + let types1 = records[0].getTypes(); + expect(records[0].textContent).assertEqual(plainText.textContent); + expect(records[0].abstract).assertEqual(plainText.abstract); + expect(records[0].details.key1).assertEqual(plainText.details.key1); + expect(records[0].details.key2).assertEqual(plainText.details.key2); + expect(systemDefinedQuery).assertEqual(undefined); + expect(hyperlinkQuery.url).assertEqual('www.xxx'); + expect(hyperlinkQuery.details.key1).assertEqual('value1'); + expect(types1.length).assertEqual(2); + expect(types1.includes(UTD.UniformDataType.PLAIN_TEXT)).assertTrue(); + expect(types1.includes(UTD.UniformDataType.HYPERLINK)).assertTrue(); + + expect(entriesQuery['general.hyperlink'].url).assertEqual('www.xxx'); + expect(entriesQuery['general.hyperlink'].details.key1).assertEqual('value1'); + expect(entriesQuery['general.plain-text'].textContent).assertEqual('This is plainText textContent example'); + expect(entriesQuery['general.plain-text'].details.key1).assertEqual('value1'); + + UDC.deleteData(options).then((data) => { + console.info(TAG, 'delete success.'); + expect(data.length).assertEqual(1); + done(); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + } catch (e) { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + } + }); + + /** + * @tc.name MultiEntryTest003 + * @tc.desc + * @tc.type: FUNC + * @tc.require: + */ + it('MultiEntryTest003', 0, async function (done) { + const TAG = 'MultiEntryTest003'; + console.info(TAG, 'start'); + + let plaintextValue = 'plaintextValue'; + let systemDefinedValue = 'systemDefinedValue'; + let hyperlinkValue = 'hyperlinkValue'; + let record1 = new UDC.UnifiedRecord(UTD.UniformDataType.PLAIN_TEXT, plaintextValue); + record1.addEntry(UTD.UniformDataType.HYPERLINK, hyperlinkValue); + record1.addEntry('openharmony.app-item', systemDefinedValue); + + let entries = record1.getEntries(); + + let unifiedData = new UDC.UnifiedData(record1); + let records = unifiedData.getRecords(); + expect(records.length).assertEqual(1); + const value1 = records[0].getValue(); + let types = records[0].getTypes(); + let systemDefined1 = records[0].getEntry('openharmony.app-item'); + let hyperlink1 = records[0].getEntry(UTD.UniformDataType.HYPERLINK); + expect(value1).assertEqual(plaintextValue); + expect(value1.textContent).assertEqual(undefined); + expect(hyperlink1).assertEqual(hyperlinkValue); + expect(hyperlink1.details).assertEqual(undefined); + expect(systemDefined1).assertEqual(systemDefinedValue); + expect(systemDefined1.details).assertEqual(undefined); + expect(types.length).assertEqual(3); + expect(types.includes(UTD.UniformDataType.PLAIN_TEXT)).assertTrue(); + expect(types.includes(UTD.UniformDataType.HYPERLINK)).assertTrue(); + expect(types.includes('openharmony.app-item')).assertTrue(); + expect(entries['openharmony.app-item']).assertEqual(systemDefinedValue); + expect(entries['general.hyperlink']).assertEqual(hyperlinkValue); + expect(entries['general.plain-text'].VALUE_TYPE).assertEqual(plaintextValue); + + try { + UDC.insertData(optionsValid, unifiedData).then((data) => { + console.info(TAG, `insert success. The key: ${data}`); + let options = { key: data }; + console.info(TAG, `query start. The options: ${JSON.stringify(options)}`); + UDC.queryData(options).then((data) => { + console.info(TAG, 'query success.'); + expect(data.length).assertEqual(1); + let records = data[0].getRecords(); + expect(records.length).assertEqual(1); + const valueQuery = records[0].getValue(); + const hyperlinkQuery = records[0].getEntry(UTD.UniformDataType.HYPERLINK); + const systemDefinedQuery = records[0].getEntry('openharmony.app-item'); + const entriesQuery = records[0].getEntries(); + const types1 = records[0].getTypes(); + expect(valueQuery).assertEqual(plaintextValue); + expect(hyperlinkQuery).assertEqual(hyperlinkValue); + expect(systemDefinedQuery).assertEqual(systemDefinedValue); + expect(types1.length).assertEqual(3); + expect(types1.includes(UTD.UniformDataType.PLAIN_TEXT)).assertTrue(); + expect(types1.includes(UTD.UniformDataType.HYPERLINK)).assertTrue(); + expect(types1.includes('openharmony.app-item')).assertTrue(); + expect(entriesQuery['openharmony.app-item']).assertEqual(systemDefinedValue); + expect(entriesQuery['general.hyperlink']).assertEqual(hyperlinkValue); + expect(entriesQuery['general.plain-text'].VALUE_TYPE).assertEqual(plaintextValue); + + UDC.deleteData(options).then((data) => { + console.info(TAG, 'delete success.'); + expect(data.length).assertEqual(1); + done(); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + }).catch(() => { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + }); + } catch (e) { + console.error(TAG, 'Unreachable code!'); + expect(null).assertFail(); + done(); + } + }); }); \ No newline at end of file diff --git a/udmf/framework/ndkimpl/data/udmf.cpp b/udmf/framework/ndkimpl/data/udmf.cpp index 4fa1197fb251ef3d48d64db94220514a342cb185..c3f3c8c41b23ee0136a6cf458cf74553f513b9b7 100644 --- a/udmf/framework/ndkimpl/data/udmf.cpp +++ b/udmf/framework/ndkimpl/data/udmf.cpp @@ -88,7 +88,8 @@ static char** StrVectorToTypesArray(const std::vector<std::string>& strVector) } char** typesArray = new (std::nothrow) char* [vectorSize]; if (typesArray == nullptr) { - LOG_ERROR(UDMF_CAPI, "create types array failed!"); + LOG_ERROR(UDMF_CAPI, "create types array failed!, vectorSize: %{public}d, MAX_RECORDS_COUNT: %{public}" PRIu64, + vectorSize, MAX_RECORDS_COUNT); return nullptr; } for (unsigned int i = 0; i < vectorSize; ++i) { @@ -896,3 +897,65 @@ int OH_UdmfRecord_SetProvider(OH_UdmfRecord* record, const char* const* types, u record->record_->SetEntryGetter(udTypes, providerBox); return UDMF_E_OK; } + +int OH_UdmfProgressInfo_GetProgress(OH_Udmf_ProgressInfo* progressInfo) +{ + return progressInfo->progress; +} + +int OH_UdmfProgressInfo_GetStatus(OH_Udmf_ProgressInfo* progressInfo) +{ + return progressInfo->status; +} + +OH_UdmfGetDataParams* OH_UdmfGetDataParams_Create() +{ + OH_UdmfGetDataParams *params = new (std::nothrow) OH_UdmfGetDataParams(); + if (params == nullptr) { + LOG_ERROR(UDMF_CAPI, "allocate OH_UdmfGetDataParams memory fail"); + return nullptr; + } + return params; +} + +void OH_UdmfGetDataParams_Destroy(OH_UdmfGetDataParams* pThis) +{ + if (pThis == nullptr) { + return; + } + delete pThis; +} + +void OH_UdmfGetDataParams_SetDestUri(OH_UdmfGetDataParams* params, const char* destUri) +{ + if (destUri == nullptr) { + return; + } + params->destUri = std::string(destUri); +} + +void OH_UdmfGetDataParams_SetFileConflictOptions(OH_UdmfGetDataParams* params, const Udmf_FileConflictOptions options) +{ + if (params == nullptr) { + return; + } + params->fileConflictOptions = options; +} + +void OH_UdmfGetDataParams_SetProgressIndicator(OH_UdmfGetDataParams* params, + const Udmf_ProgressIndicator progressIndicator) +{ + if (params == nullptr) { + return; + } + params->progressIndicator = progressIndicator; +} + +void OH_UdmfGetDataParams_SetDataProgressListener(OH_UdmfGetDataParams* params, + const OH_Udmf_DataProgressListener dataProgressListener) +{ + if (params == nullptr) { + return; + } + params->dataProgressListener = dataProgressListener; +} \ No newline at end of file diff --git a/udmf/framework/ndkimpl/data/udmf_capi_common.h b/udmf/framework/ndkimpl/data/udmf_capi_common.h index e91d41c973f92c137f409c6a1b6dfedf607e8d40..d22d2ccfd40598cbb53f29de6dee060dd9958634 100644 --- a/udmf/framework/ndkimpl/data/udmf_capi_common.h +++ b/udmf/framework/ndkimpl/data/udmf_capi_common.h @@ -18,6 +18,7 @@ #include "unified_record.h" #include "unified_data.h" +#include "udmf.h" #include <mutex> #include <cstdint> @@ -116,6 +117,19 @@ struct OH_UdmfProperty { std::string extraStr; }; +struct OH_Udmf_ProgressInfo { + int progress; + int status; +}; + + +struct OH_UdmfGetDataParams { + std::string destUri; + Udmf_FileConflictOptions fileConflictOptions; + Udmf_ProgressIndicator progressIndicator; + OH_Udmf_DataProgressListener dataProgressListener; +}; + bool IsInvalidUdsObjectPtr(const UdsObject* pThis, int cid); bool IsInvalidUdsObjectByType(const UdsObject* pThis, const OHOS::UDMF::UDType& type); diff --git a/udmf/framework/ndkimpl/unittest/BUILD.gn b/udmf/framework/ndkimpl/unittest/BUILD.gn index 22da82a79fe98d7d91e3e019e10b25b7f0c918bd..c393b4dd253b944f617fc44c9a43f2b34f7b51ba 100644 --- a/udmf/framework/ndkimpl/unittest/BUILD.gn +++ b/udmf/framework/ndkimpl/unittest/BUILD.gn @@ -80,11 +80,29 @@ ohos_unittest("UdmfTest") { external_deps = common_external_deps } +ohos_unittest("DataProviderImplTest") { + module_out_path = module_output_path + + sources = [ "data_provider_impl_test.cpp" ] + + configs = [ ":module_private_config" ] + + deps = common_deps + + external_deps = common_external_deps + + defines = [ + "private=public", + "protected=public", + ] +} + ############################################################################### group("unittest") { testonly = true deps = [ + ":DataProviderImplTest", ":UdmfTest", ":UdsTest", ":UtdTest", diff --git a/udmf/framework/ndkimpl/unittest/data_provider_impl_test.cpp b/udmf/framework/ndkimpl/unittest/data_provider_impl_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..83524dc3458cf55a805b7949c30334c97acb66fa --- /dev/null +++ b/udmf/framework/ndkimpl/unittest/data_provider_impl_test.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2024 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 "DataProviderImplTest" + +#include <unistd.h> +#include <gtest/gtest.h> +#include <string> + +#include "logger.h" +#include "data_provider_impl.h" + +using namespace testing::ext; +using namespace OHOS::UDMF; +using namespace OHOS; +namespace OHOS::Test { +using namespace std; + +class DataProviderImplTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; +}; + +void DataProviderImplTest::SetUpTestCase() +{ +} + +void DataProviderImplTest::TearDownTestCase() +{ +} + +void DataProviderImplTest::SetUp() +{ +} + +void DataProviderImplTest::TearDown() +{ +} + +/** +* @tc.name: GetInnerProvider001 +* @tc.desc: Normal testcase of GetInnerProvider +* @tc.type: FUNC +*/ +HWTEST_F(DataProviderImplTest, GetInnerProvider001, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "GetInnerProvider001 begin."); + DataProviderImpl dataProviderImpl; + dataProviderImpl.innerProvider_ = OH_UdmfRecordProvider_Create(); + OH_UdmfRecordProvider* ret = dataProviderImpl.GetInnerProvider(); + EXPECT_EQ(ret, dataProviderImpl.innerProvider_); + LOG_INFO(UDMF_TEST, "GetInnerProvider001 end."); +} + +/** +* @tc.name: GetValueByType001 +* @tc.desc: Normal testcase of GetValueByType +* @tc.type: FUNC +*/ +HWTEST_F(DataProviderImplTest, GetValueByType001, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "GetValueByType001 begin."); + const std::string utdId; + DataProviderImpl dataProviderImpl; + ValueType ret = dataProviderImpl.GetValueByType(utdId); + EXPECT_TRUE(std::holds_alternative<std::monostate>(ret)); + LOG_INFO(UDMF_TEST, "GetValueByType001 end."); +} +} // OHOS::Test \ No newline at end of file diff --git a/udmf/framework/ndkimpl/unittest/udmf_test.cpp b/udmf/framework/ndkimpl/unittest/udmf_test.cpp index 23ab655a14c001d9f8ee5d8347eb124f8b30c076..a1f9a601d21ddc347f5ff26b8a9db3fc2ed2f056 100644 --- a/udmf/framework/ndkimpl/unittest/udmf_test.cpp +++ b/udmf/framework/ndkimpl/unittest/udmf_test.cpp @@ -1248,6 +1248,61 @@ HWTEST_F(UDMFTest, OH_Udmf_MultiStyleRecord001, TestSize.Level1) OH_UdmfData_Destroy(data); } +/** + * @tc.name: OH_Udmf_MultiStyleRecord002 + * @tc.desc: Normal testcase of OH_UdmfProperty_SetExtrasStringParam + * @tc.type: FUNC + */ +HWTEST_F(UDMFTest, OH_Udmf_MultiStyleRecord002, TestSize.Level1) +{ + LOG_INFO(UDMF_TEST, "GetSummary005 begin."); + + CustomOption option1 = { .intention = Intention::UD_INTENTION_DRAG }; + UnifiedData data; + std::string key; + auto object = std::make_shared<Object>(); + object->value_[UNIFORM_DATA_TYPE] = UtdUtils::GetUtdIdFromUtdEnum(UDType::PLAIN_TEXT); + object->value_[CONTENT] = "content_"; + object->value_[ABSTRACT] = "abstract_"; + auto record = std::make_shared<UnifiedRecord>(UDType::PLAIN_TEXT, object); + + std::vector<uint8_t> raw = {1, 2, 3, 4, 5}; + std::shared_ptr<Object> obj = std::make_shared<Object>(); + obj->value_[UNIFORM_DATA_TYPE] = "general.content-form"; + obj->value_[THUMB_DATA] = raw; + obj->value_[THUMB_DATA_LENGTH] = 5; + obj->value_[DESCRIPTION] = "descritpion"; + obj->value_[TITLE] = "title"; + obj->value_[APP_ICON_LENGTH] = 5; + obj->value_[APP_NAME] = "appName"; + obj->value_[LINK_URL] = "linkUri"; + auto contentForm = UnifiedRecord(CONTENT_FORM, obj); + record->AddEntry(contentForm.GetUtdId(), contentForm.GetOriginValue()); + + data.AddRecord(record); + + auto status = UdmfClient::GetInstance().SetData(option1, data, key); + ASSERT_EQ(status, E_OK); + + ASSERT_EQ(status, E_OK); + OH_UdmfData *readUnifiedData = OH_UdmfData_Create(); + int getRes = OH_Udmf_GetUnifiedData(key.c_str(), UDMF_INTENTION_DRAG, readUnifiedData); + ASSERT_EQ(getRes, E_OK); + unsigned int count = 0; + OH_UdmfRecord** readRecords = OH_UdmfData_GetRecords(readUnifiedData, &count); + ASSERT_EQ(count, 1); + for (int i = 0; i < count; i++) { + OH_UdsContentForm *contentForm = OH_UdsContentForm_Create(); + OH_UdmfRecord_GetContentForm(readRecords[i], contentForm); + const char* desc = OH_UdsContentForm_GetDescription(contentForm); + EXPECT_EQ(std::string(desc), "descritpion"); + OH_UdsPlainText *plainText = OH_UdsPlainText_Create(); + OH_UdmfRecord_GetPlainText(readRecords[i], plainText); + const char* text = OH_UdsPlainText_GetContent(plainText); + EXPECT_EQ(std::string(text), "content_"); + } +} + /** * @tc.name: OH_UdmfRecordProvider_Create001 * @tc.desc: Normal testcase of OH_UdmfRecordProvider_Create @@ -2130,10 +2185,13 @@ HWTEST_F(UDMFTest, FileUriTest004, TestSize.Level1) HWTEST_F(UDMFTest, FileUriTest005, TestSize.Level1) { std::string uri = "https://xxx/xx/xx.jpg"; - std::shared_ptr<Folder> folder = std::make_shared<Folder>(); - folder->SetUri(uri); + std::shared_ptr<Object> obj = std::make_shared<Object>(); + obj->value_[UNIFORM_DATA_TYPE] = "general.file-uri"; + obj->value_[FILE_URI_PARAM] = uri; + obj->value_[FILE_TYPE] = "general.img"; + auto record = std::make_shared<UnifiedRecord>(UDType::FOLDER, obj); std::shared_ptr<UnifiedData> unifiedData = std::make_shared<UnifiedData>(); - unifiedData->AddRecord(folder); + unifiedData->AddRecord(record); std::string key; CustomOption option = { .intention = UD_INTENTION_DRAG @@ -2228,6 +2286,63 @@ HWTEST_F(UDMFTest, FileUriTest006, TestSize.Level1) } } +/** + * @tc.name: FileUriTest007 + * @tc.desc: test fileUri between js and capi + * @tc.type: FUNC + */ +HWTEST_F(UDMFTest, FileUriTest007, TestSize.Level1) +{ + std::string uri = "https://xxx/xx/xx.jpg"; + + std::shared_ptr<Object> obj = std::make_shared<Object>(); + obj->value_[UNIFORM_DATA_TYPE] = "general.file-uri"; + obj->value_[FILE_URI_PARAM] = uri; + obj->value_[FILE_TYPE] = "general.img"; + auto record = std::make_shared<UnifiedRecord>(UDType::VIDEO, obj); + std::shared_ptr<UnifiedData> unifiedData = std::make_shared<UnifiedData>(); + unifiedData->AddRecord(record); + std::string key; + CustomOption option = { + .intention = UD_INTENTION_DRAG + }; + int setRet = UdmfClient::GetInstance().SetData(option, *unifiedData, key); + EXPECT_EQ(setRet, E_OK); + + OH_UdmfData* udmfData = OH_UdmfData_Create(); + OH_Udmf_GetUnifiedData(key.c_str(), UDMF_INTENTION_DRAG, udmfData); + + unsigned int dataTypeCount; + char** dataTypes = OH_UdmfData_GetTypes(udmfData, &dataTypeCount); + EXPECT_EQ(dataTypeCount, 2); + EXPECT_NE(dataTypes, nullptr); + EXPECT_EQ(strcmp(dataTypes[0], UDMF_META_VIDEO), 0); + EXPECT_EQ(strcmp(dataTypes[1], UDMF_META_GENERAL_FILE_URI), 0); + + unsigned int recordCount; + OH_UdmfRecord** records = OH_UdmfData_GetRecords(udmfData, &recordCount); + EXPECT_EQ(recordCount, 1); + EXPECT_NE(records, nullptr); + + for (unsigned int idx = 0; idx < recordCount; ++idx) { + unsigned int recordTypeCount; + char** recordTypes = OH_UdmfRecord_GetTypes(records[idx], &recordTypeCount); + EXPECT_EQ(recordTypeCount, 2); + EXPECT_NE(recordTypes, nullptr); + EXPECT_EQ(strcmp(recordTypes[0], UDMF_META_VIDEO), 0); + EXPECT_EQ(strcmp(recordTypes[1], UDMF_META_GENERAL_FILE_URI), 0); + for (unsigned int recordIdx = 0; recordIdx < recordTypeCount; ++recordIdx) { + if (strcmp(recordTypes[recordIdx], UDMF_META_GENERAL_FILE_URI) == 0) { + OH_UdsFileUri* fileUri = OH_UdsFileUri_Create(); + int getFileUriRet = OH_UdmfRecord_GetFileUri(records[idx], fileUri); + EXPECT_EQ(getFileUriRet, UDMF_E_OK); + const char* getFileUri = OH_UdsFileUri_GetFileUri(fileUri); + EXPECT_EQ(strcmp(getFileUri, uri.c_str()), 0); + } + } + } +} + /** * @tc.name: OH_Udmf_SetAndGetUnifiedData003 * @tc.desc: OH_Udmf_SetUnifiedData and OH_Udmf_GetUnifiedData with file uri diff --git a/udmf/interfaces/cj/include/unified_record_impl.h b/udmf/interfaces/cj/include/unified_record_impl.h index 2ef5d23adf5fc8eeb0e5ce3e5b83217157a66971..d2bb331a2e0ede9b5087a0ca35c53531a8d5330e 100644 --- a/udmf/interfaces/cj/include/unified_record_impl.h +++ b/udmf/interfaces/cj/include/unified_record_impl.h @@ -61,7 +61,7 @@ namespace UDMF { private: std::shared_ptr<UDMF::UnifiedRecord> unifiedRecord_; - int64_t pixelMapId_; + int64_t pixelMapId_ = 0; }; } diff --git a/udmf/interfaces/innerkits/BUILD.gn b/udmf/interfaces/innerkits/BUILD.gn index ecf66dc55f0da2764a74f1498006d9267fc3a1ca..9eaa7da8668fa513fedad281bc63ba3de9246627 100644 --- a/udmf/interfaces/innerkits/BUILD.gn +++ b/udmf/interfaces/innerkits/BUILD.gn @@ -51,12 +51,14 @@ ohos_shared_library("udmf_client") { "${udmf_framework_path}/common/endian_converter.cpp", "${udmf_framework_path}/common/tlv_object.cpp", "${udmf_framework_path}/common/tlv_util.cpp", + "${udmf_framework_path}/common/udmf_copy_file.cpp", "${udmf_framework_path}/common/udmf_radar_reporter.cpp", "${udmf_framework_path}/common/udmf_types_util.cpp", "${udmf_framework_path}/common/udmf_utils.cpp", - "${udmf_framework_path}/innerkitsimpl/client/async_obtain_data.cpp", "${udmf_framework_path}/innerkitsimpl/client/getter_system.cpp", + "${udmf_framework_path}/innerkitsimpl/client/udmf_async_client.cpp", "${udmf_framework_path}/innerkitsimpl/client/udmf_client.cpp", + "${udmf_framework_path}/innerkitsimpl/common/progress_queue.cpp", "${udmf_framework_path}/innerkitsimpl/common/unified_key.cpp", "${udmf_framework_path}/innerkitsimpl/common/unified_meta.cpp", "${udmf_framework_path}/innerkitsimpl/convert/ndk_data_conversion.cpp", @@ -78,6 +80,7 @@ ohos_shared_library("udmf_client") { "${udmf_framework_path}/innerkitsimpl/data/unified_data_helper.cpp", "${udmf_framework_path}/innerkitsimpl/data/unified_record.cpp", "${udmf_framework_path}/innerkitsimpl/data/video.cpp", + "${udmf_framework_path}/innerkitsimpl/service/progress_callback.cpp", "${udmf_framework_path}/innerkitsimpl/service/udmf_service_client.cpp", "${udmf_framework_path}/innerkitsimpl/service/udmf_service_proxy.cpp", ] @@ -91,13 +94,13 @@ ohos_shared_library("udmf_client") { "bundle_framework:appexecfwk_core", "cJSON:cjson", "c_utils:utils", + "dfs_service:distributed_file_daemon_kit_inner", "hilog:libhilog", "hisysevent:libhisysevent", "hitrace:hitrace_meter", "hitrace:libhitracechain", "image_framework:image_native", "ipc:ipc_core", - "kv_store:distributeddata_inner", "kv_store:distributeddata_mgr", "samgr:samgr_proxy", ] @@ -113,7 +116,10 @@ ohos_shared_library("udmf_client") { part_name = "udmf" use_exceptions = true - cflags_cc = [ "-fvisibility=hidden" ] + cflags_cc = [ + "-fvisibility=hidden", + "-O2", + ] } config("utd_client_config") { @@ -166,9 +172,15 @@ ohos_shared_library("utd_client") { subsystem_name = "distributeddatamgr" part_name = "udmf" - cflags_cc = [ "-fvisibility=hidden" ] + cflags_cc = [ + "-fvisibility=hidden", + "-O2", + ] if (build_selinux) { - cflags = [ "-DWITH_SELINUX" ] + cflags = [ + "-DWITH_SELINUX", + "-O2", + ] external_deps += [ "selinux_adapter:librestorecon" ] } } diff --git a/udmf/interfaces/innerkits/client/udmf_async_client.h b/udmf/interfaces/innerkits/client/udmf_async_client.h new file mode 100644 index 0000000000000000000000000000000000000000..66137a66869126d71b52ca380d70a6fb17f986ae --- /dev/null +++ b/udmf/interfaces/innerkits/client/udmf_async_client.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025 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 UDMF_ASYNC_CLIENT_H +#define UDMF_ASYNC_CLIENT_H + +#include "async_task_params.h" + +namespace OHOS::UDMF { +class UdmfAsyncClient { +public: + friend class UdmfCopyFile; + static UdmfAsyncClient API_EXPORT &GetInstance(); + Status API_EXPORT StartAsyncDataRetrieval(const GetDataParams &params); + Status API_EXPORT Cancel(std::string businessUdKey); + Status CancelOnSingleTask(); +private: + UdmfAsyncClient(); + ~UdmfAsyncClient() = default; + UdmfAsyncClient(const UdmfAsyncClient &obj) = delete; + UdmfAsyncClient &operator = (const UdmfAsyncClient &obj) = delete; + + Status ProgressTask(const std::string &businessUdKey); + Status GetDataTask(const QueryOption &query); + Status InvokeHapTask(const std::string &businessUdKey); + + Status RegisterAsyncHelper(const GetDataParams &params); + Status CheckSync(std::unique_ptr<AsyncHelper> &asyncHelper, const QueryOption &query); + Status GetDataFromDB(std::unique_ptr<AsyncHelper> &asyncHelper, const QueryOption &query); + Status GetDataFromCache(std::unique_ptr<AsyncHelper> &asyncHelper, const QueryOption &query); + Status SetProgressData(const std::string &businessUdKey); + Status SetCancelData(const std::string &businessUdKey); + Status UpdateProgressData(const std::string &progressUdKey, const ProgressInfo &progressInfo); + Status CopyFile(std::unique_ptr<AsyncHelper> &asyncHelper); + void CallProgress(std::unique_ptr<AsyncHelper> &asyncHelper, ProgressInfo &progressInfo, + std::shared_ptr<UnifiedData> data); + Status Clear(const std::string &businessUdKey); + Status ProcessUnifiedData(std::unique_ptr<AsyncHelper> &asyncHelper); + bool IsParamValid(const GetDataParams &params); + + ExecutorPool executor_; + std::unordered_map<std::string, std::unique_ptr<AsyncHelper>> asyncHelperMap_; + std::mutex mutex_; +}; +} // namespace +#endif // UDMF_ASYNC_CLIENT_H diff --git a/udmf/interfaces/innerkits/client/udmf_client.h b/udmf/interfaces/innerkits/client/udmf_client.h index 1d2608cc82ac05f0c485624de99739e5e24754bc..90f0213bcc9bcc166a34ae2fd792243019c1c4d4 100644 --- a/udmf/interfaces/innerkits/client/udmf_client.h +++ b/udmf/interfaces/innerkits/client/udmf_client.h @@ -28,7 +28,6 @@ #include "unified_meta.h" #include "unified_types.h" #include "visibility.h" -#include "async_obtain_data.h" namespace OHOS { namespace UDMF { class API_EXPORT UdmfClient { @@ -37,7 +36,6 @@ public: Status SetData(CustomOption &option, UnifiedData &unifiedData, std::string &key); Status GetData(const QueryOption &query, UnifiedData &unifiedData); - Status GetDataAsync(const QueryOption &query, ObtainDataCallback callback); Status GetBatchData(const QueryOption &query, std::vector<UnifiedData> &unifiedDataSet); Status UpdateData(const QueryOption &query, UnifiedData &unifiedData); Status DeleteData(const QueryOption &query, std::vector<UnifiedData> &unifiedDataSet); @@ -48,6 +46,7 @@ public: Status SetAppShareOption(const std::string &intention, enum ShareOptions shareOption); Status RemoveAppShareOption(const std::string &intention); Status GetAppShareOption(const std::string &intention, enum ShareOptions &shareOption); + Status GetDataFromCache(const QueryOption &query, UnifiedData &unifiedData); private: UdmfClient() = default; @@ -57,7 +56,6 @@ private: std::string GetSelfBundleName(); ConcurrentMap<std::string, UnifiedData> dataCache_; - AsyncObtainData asyncObtainData_; }; } // namespace UDMF } // namespace OHOS diff --git a/udmf/interfaces/innerkits/client/utd_client.h b/udmf/interfaces/innerkits/client/utd_client.h index e94ef98309023bb7b6ecfc09c0875cfab9c22adf..9f267527181b5e75b9fde088038c8036a2cf4b2d 100644 --- a/udmf/interfaces/innerkits/client/utd_client.h +++ b/udmf/interfaces/innerkits/client/utd_client.h @@ -52,6 +52,7 @@ private: ~UtdClient(); UtdClient(const UtdClient &obj) = delete; UtdClient &operator=(const UtdClient &obj) = delete; + std::string Anonymous(const std::string &fileExtension); bool Init(); bool IsHapTokenType(); Status GetCurrentActiveUserId(int32_t& userId); diff --git a/udmf/interfaces/innerkits/common/async_task_params.h b/udmf/interfaces/innerkits/common/async_task_params.h new file mode 100644 index 0000000000000000000000000000000000000000..a83645c95665e3e16cab68098e0cbf66b32b9c4a --- /dev/null +++ b/udmf/interfaces/innerkits/common/async_task_params.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025 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 ASYNC_TASK_PARAMS_H +#define ASYNC_TASK_PARAMS_H + +#include <map> +#include <mutex> +#include <string> + +#include "executor_pool.h" +#include "progress_queue.h" +#include "unified_data.h" +#include "unified_types.h" + +namespace OHOS::UDMF { +enum class FileConflictOptions : uint32_t { + OVERWRITE = 0, + SKIP = 1 +}; + +enum class ProgressIndicator : uint32_t { + NONE = 0, + DEFAULT = 1 +}; + +using ProgressListener = std::function<void(ProgressInfo progressInfo, std::shared_ptr<UnifiedData> data)>; + +struct GetDataParams { +public: + FileConflictOptions fileConflictOptions; + ProgressIndicator progressIndicator; + ProgressListener progressListener; + std::string destUri; + QueryOption query; +}; + +struct AsyncHelper { + uint32_t sycnRetryTime = 0; + int32_t lastProgress = 0; + ProgressIndicator progressIndicator; + ExecutorPool::TaskId invokeHapTask = ExecutorPool::INVALID_TASK_ID; + ExecutorPool::TaskId getDataTask = ExecutorPool::INVALID_TASK_ID; + ExecutorPool::TaskId progressTask = ExecutorPool::INVALID_TASK_ID; + ProgressListener progressListener; + FileConflictOptions fileConflictOptions; + std::string businessUdKey; + std::string processKey; + std::string cancelKey; + std::string destUri; + std::shared_ptr<UnifiedData> data = std::make_shared<UnifiedData>(); + ProgressQueue progressQueue; +}; + +enum ListenerStatus : int32_t { + FINISHED = 0, + PROCESSING, + CANCEL, + INNER_ERROR = 200, + INVALID_PARAMETERS, + DATA_NOT_FOUND, + SYNC_FAILED, + COPY_FILE_FAILED, +}; + +enum ProgressStatus { + NORMAL_PASTE = 0, + CANCEL_PASTE = 1, + PASTE_TIME_OUT = 2, +}; + +} // namespace OHOS::UDMF +#endif // ASYNC_TASK_PARAMS_H \ No newline at end of file diff --git a/udmf/interfaces/innerkits/common/error_code.h b/udmf/interfaces/innerkits/common/error_code.h index 6fdc06ef11ecfe1f09fe12fdb85474c5fd0be065..6d2e9b0f0cb175d7209ae4ade5021a0892859368 100644 --- a/udmf/interfaces/innerkits/common/error_code.h +++ b/udmf/interfaces/innerkits/common/error_code.h @@ -44,6 +44,10 @@ enum Status : int32_t { E_NOT_FOUND, E_SETTINGS_EXISTED, E_NO_SYSTEM_PERMISSION, + E_SYNC_FAILED, + E_COPY_FILE_FAILED, + E_IDEMPOTENT_ERROR, + E_COPY_CANCELED, E_BUTT, }; diff --git a/udmf/interfaces/innerkits/common/progress_queue.h b/udmf/interfaces/innerkits/common/progress_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..cca54133af27b47ccd2a486c23d9797cdb4eeda1 --- /dev/null +++ b/udmf/interfaces/innerkits/common/progress_queue.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025 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 PROGRESS_QUEUE_H +#define PROGRESS_QUEUE_H + +#include <mutex> +#include <queue> + +#include "unified_types.h" + +namespace OHOS::UDMF { +class ProgressQueue { +public: + void PushBack(ProgressInfo &progress); + std::pair<bool, std::shared_ptr<ProgressInfo>> Poll(); + bool IsCancel() const; + void Cancel(); + void SetClearable(const bool clearableFlag); + bool Clear(); + + ProgressQueue() = default; + ~ProgressQueue() = default; + ProgressQueue(const ProgressQueue &other) = delete; + ProgressQueue &operator=(const ProgressQueue &other) = delete; + ProgressQueue(ProgressQueue &&other) = delete; + ProgressQueue &operator=(ProgressQueue &&other) = delete; + +private: + bool cancelFlag_ = false; + bool clearableFlag_ = true; + std::queue<ProgressInfo> queue_; + mutable std::mutex mutex_; +}; + +} // namespace OHOS::UDMF +#endif // PROGRESS_QUEUE_H \ No newline at end of file diff --git a/udmf/interfaces/innerkits/common/unified_meta.h b/udmf/interfaces/innerkits/common/unified_meta.h index 2926b499bafa4ec783353a4ce324d1888efb5235..2da9724feb593404b9d6da2750da310ca31d3adf 100644 --- a/udmf/interfaces/innerkits/common/unified_meta.h +++ b/udmf/interfaces/innerkits/common/unified_meta.h @@ -62,6 +62,7 @@ constexpr const char *TITLE = "title"; constexpr const char* APP_ICON = "appIcon"; constexpr const char* APP_ICON_LENGTH = "appIconLen"; constexpr const char* LINK_URL = "linkUrl"; +constexpr const char* APPLICATION_DEFINED_RECORD_MARK = "applicationDefinedRecordMark"; enum UDType : int32_t { ENTITY = 0, @@ -529,6 +530,10 @@ enum UDType : int32_t { AC3_AUDIO, OPENHARMONY_HSP, OPENHARMONY_HAR, + OPENHARMONY_GOPAINT, + OPENHARMONY_GOBRUSH, + OPENHARMONY_GOBRUSHES, + OPENHARMONY_GOCOLOR, UD_BUTT }; @@ -624,8 +629,12 @@ struct API_EXPORT Object { }; namespace ObjectUtils { - std::shared_ptr<Object> ConvertToObject(UDDetails &details); - UDDetails ConvertToUDDetails(std::shared_ptr<Object> object); + std::shared_ptr<Object> API_EXPORT ConvertToObject(UDDetails &details); + UDDetails API_EXPORT ConvertToUDDetails(std::shared_ptr<Object> object); + + int64_t GetValueSize(const ValueType &value, bool isCalValueType); + int64_t GetObjectValueSize(const std::shared_ptr<Object> object, bool isCalValueType); + int64_t GetAllObjectSize(const std::shared_ptr<Object> object); template<typename T, typename... Types> bool ConvertVariant(T &&input, std::variant<Types...> &output) diff --git a/udmf/interfaces/innerkits/common/unified_types.h b/udmf/interfaces/innerkits/common/unified_types.h index 2ff3af8f7cdf75382b34e217020d64d9a614fa39..baf632a5acad2ffb778d6b400ed165280f57079c 100644 --- a/udmf/interfaces/innerkits/common/unified_types.h +++ b/udmf/interfaces/innerkits/common/unified_types.h @@ -19,6 +19,7 @@ #include <map> #include <string> +#include "error_code.h" #include "unified_key.h" #include "unified_meta.h" @@ -89,21 +90,24 @@ enum AsyncTaskStatus : uint32_t { }; struct AsyncProcessInfo { - AsyncTaskStatus syncStatus; - AsyncTaskStatus permStatus; + AsyncTaskStatus syncStatus { ASYNC_IDLE }; + AsyncTaskStatus permStatus { ASYNC_IDLE }; std::string srcDevName; uint32_t syncFinished = 0; uint32_t syncTotal = 0; uint32_t syncId = 0; uint32_t permFnished = 0; uint32_t permTotal = 0; + std::string businessUdKey; }; struct ProgressInfo { + int32_t progress = 0; + int32_t progressStatus; + Status errorCode; std::string srcDevName; - AsyncTaskStatus status; - uint32_t progress = 0; }; + } // namespace UDMF } // namespace OHOS #endif // UDMF_UNIFIED_TYPES_H \ No newline at end of file diff --git a/udmf/interfaces/innerkits/convert/data_params_conversion.h b/udmf/interfaces/innerkits/convert/data_params_conversion.h new file mode 100644 index 0000000000000000000000000000000000000000..3427c07db636f1c401d4082b1c99e42744393858 --- /dev/null +++ b/udmf/interfaces/innerkits/convert/data_params_conversion.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 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 DATA_PARAMS_CONVERSION_H +#define DATA_PARAMS_CONVERSION_H + +#include "async_task_params.h" +#include "udmf_capi_common.h" + +namespace OHOS::UDMF { +class DataParamsConversion { +public: + static Status API_EXPORT GetInnerDataParams(OH_UdmfGetDataParams &ndkDataParams, QueryOption &query, + GetDataParams &dataParams); +}; +} + +#endif // DATA_PARAMS_CONVERSION_H \ No newline at end of file diff --git a/udmf/interfaces/innerkits/convert/udmf_conversion.h b/udmf/interfaces/innerkits/convert/udmf_conversion.h index 69f9fb4522bfc687e51c4dba213fe0a56d23a673..18e2f976ed885d4af0e4554df9c65ff0ee5e90a5 100644 --- a/udmf/interfaces/innerkits/convert/udmf_conversion.h +++ b/udmf/interfaces/innerkits/convert/udmf_conversion.h @@ -17,17 +17,16 @@ #define UDMF_UDMF_CONVERSION_H #include "unified_data.h" -#include "visibility.h" namespace OHOS::UDMF { class UdmfConversion { public: - static void API_EXPORT ConvertRecordToSubclass(std::shared_ptr<UnifiedRecord> &record); - static void API_EXPORT ConvertRecordToSubclass(UnifiedData &data); - static void API_EXPORT ConvertRecordToSubclass(std::vector<UnifiedData> &datas); + static void ConvertRecordToSubclass(std::shared_ptr<UnifiedRecord> &record); + static void ConvertRecordToSubclass(UnifiedData &data); + static void ConvertRecordToSubclass(std::vector<UnifiedData> &datas); - static void API_EXPORT InitValueObject(UnifiedData &data); - static void API_EXPORT InitValueObject(std::vector<UnifiedData> &datas); + static void InitValueObject(UnifiedData &data); + static void InitValueObject(std::vector<UnifiedData> &datas); private: static void SetValueWhenNotUds(std::shared_ptr<UnifiedRecord> record); diff --git a/udmf/interfaces/innerkits/data/unified_data.h b/udmf/interfaces/innerkits/data/unified_data.h index 9a28474b8584d3d34148713509606c69e4c43edf..2ac36f2a71f15340ab20941e952fc46a4e1cf93e 100644 --- a/udmf/interfaces/innerkits/data/unified_data.h +++ b/udmf/interfaces/innerkits/data/unified_data.h @@ -38,7 +38,6 @@ public: void SetRecords(std::vector<std::shared_ptr<UnifiedRecord>> records); std::vector<std::shared_ptr<UnifiedRecord>> GetRecords() const; - std::string GetTypes(); std::vector<std::string> GetTypesLabels() const; bool HasType(const std::string &type) const; std::vector<std::string> GetEntriesTypes() const; @@ -47,6 +46,7 @@ public: bool IsEmpty() const; bool IsValid(); bool IsComplete(); + bool HasFileType() const; void SetProperties(std::shared_ptr<UnifiedDataProperties> properties); std::shared_ptr<UnifiedDataProperties> GetProperties() const; @@ -54,10 +54,13 @@ public: void SetDataId(uint32_t dataId); uint32_t GetDataId() const; void SetChannelName(const std::string &name); + std::vector<std::string> GetFileUris() const; static constexpr int64_t MAX_DATA_SIZE = 200 * 1024 * 1024; private: + std::set<std::string> GetTypIds() const; + uint32_t dataId_ = 0; uint32_t recordId_ = 0; std::string channelName_; diff --git a/udmf/interfaces/innerkits/data/unified_data_helper.h b/udmf/interfaces/innerkits/data/unified_data_helper.h index e057df4d53841ae44e5495055d32cf8e29af78b7..0db8ae6848bafb318b13cf3be778404a996c306b 100644 --- a/udmf/interfaces/innerkits/data/unified_data_helper.h +++ b/udmf/interfaces/innerkits/data/unified_data_helper.h @@ -29,11 +29,12 @@ public: static bool Pack(UnifiedData &data); static bool Unpack(UnifiedData &data); static void GetSummary(const UnifiedData &data, Summary &summary); - + static int32_t ProcessBigData(UnifiedData &data, Intention intention, bool isSaInvoke); private: static void CreateDirIfNotExist(const std::string& dirPath, const mode_t& mode); static bool SaveUDataToFile(const std::string &dataFile, UnifiedData &data); static bool LoadUDataFromFile(const std::string &dataFile, UnifiedData &data); + static void CalRecordSummary(std::map<std::string, ValueType> &entries, Summary &summary); static std::string GetRootPath(); private: diff --git a/udmf/interfaces/innerkits/data/unified_record.h b/udmf/interfaces/innerkits/data/unified_record.h index 9806374775905723ed39d65faa32b9162faf3c98..af23aef91af3311a1ffc3c3ff520ebdd2ed74c1e 100644 --- a/udmf/interfaces/innerkits/data/unified_record.h +++ b/udmf/interfaces/innerkits/data/unified_record.h @@ -19,6 +19,7 @@ #include <memory> #include <string> #include <vector> +#include <mutex> #include "entry_getter.h" #include "visibility.h" #include "unified_types.h" @@ -32,7 +33,13 @@ public: UnifiedRecord(UDType type, ValueType value); virtual ~UnifiedRecord() = default; + UnifiedRecord(const UnifiedRecord& other) = delete; + UnifiedRecord& operator=(const UnifiedRecord& other) = delete; + UnifiedRecord(UnifiedRecord &&other) = delete; + UnifiedRecord& operator=(UnifiedRecord &&other) = delete; + UDType GetType() const; + std::vector<std::string> GetTypes() const; void SetType(const UDType &type); virtual int64_t GetSize(); @@ -49,7 +56,10 @@ public: bool HasType(const std::string &utdId) const; void AddEntry(const std::string &utdId, ValueType &&value); ValueType GetEntry(const std::string &utdId); - std::shared_ptr<std::map<std::string, ValueType>> GetEntries() const; + std::shared_ptr<std::map<std::string, ValueType>> GetEntries(); + std::shared_ptr<std::map<std::string, ValueType>> GetInnerEntries() const; + void SetInnerEntries(std::shared_ptr<std::map<std::string, ValueType>> entries); + int64_t GetInnerEntriesSize() const; void SetEntryGetter(const std::vector<std::string> &utdIds, const std::shared_ptr<EntryGetter> &entryGetter); std::shared_ptr<EntryGetter> GetEntryGetter(); @@ -61,6 +71,8 @@ public: virtual void InitObject(); bool HasObject(); + bool HasFileType(std::string &fileUri) const; + void SetFileUri(const std::string &fileUri); protected: UDType dataType_; ValueType value_; @@ -73,6 +85,7 @@ private: uint32_t recordId_ = 0; std::string channelName_; std::shared_ptr<EntryGetter> entryGetter_; + mutable std::recursive_mutex mutex_; }; } // namespace UDMF } // namespace OHOS diff --git a/udmf/interfaces/jskits/BUILD.gn b/udmf/interfaces/jskits/BUILD.gn index 433e68e8c2807ff536a10e98bec8bf0021c2131e..c9c64606d7d0c5d69c202f4933746ad775cf4dc2 100644 --- a/udmf/interfaces/jskits/BUILD.gn +++ b/udmf/interfaces/jskits/BUILD.gn @@ -36,6 +36,10 @@ config("udmf_napi_config") { ] } +config("aip_core_napi_config") { + include_dirs = [ "${udmf_interfaces_path}/jskits/intelligence" ] +} + ohos_shared_library("unifieddatachannel_napi") { branch_protector_ret = "pac_ret" sanitize = { @@ -50,6 +54,7 @@ ohos_shared_library("unifieddatachannel_napi") { "${udmf_framework_path}/jskitsimpl/data/audio_napi.cpp", "${udmf_framework_path}/jskitsimpl/data/file_napi.cpp", "${udmf_framework_path}/jskitsimpl/data/folder_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/get_data_params_napi.cpp", "${udmf_framework_path}/jskitsimpl/data/html_napi.cpp", "${udmf_framework_path}/jskitsimpl/data/image_napi.cpp", "${udmf_framework_path}/jskitsimpl/data/link_napi.cpp", @@ -90,7 +95,10 @@ ohos_shared_library("unifieddatachannel_napi") { ] public_external_deps = [ "image_framework:image" ] - cflags = [ "-fvisibility=hidden" ] + cflags = [ + "-fvisibility=hidden", + "-O2", + ] relative_install_dir = "module/data" subsystem_name = "distributeddatamgr" part_name = "udmf" @@ -130,7 +138,10 @@ ohos_shared_library("uniformtypedescriptor_napi") { ] public_external_deps = [ "image_framework:image" ] - cflags = [ "-fvisibility=hidden" ] + cflags = [ + "-fvisibility=hidden", + "-O2", + ] relative_install_dir = "module/data" subsystem_name = "distributeddatamgr" part_name = "udmf" @@ -150,6 +161,7 @@ ohos_shared_library("udmf_data_napi") { "${udmf_framework_path}/jskitsimpl/data/audio_napi.cpp", "${udmf_framework_path}/jskitsimpl/data/file_napi.cpp", "${udmf_framework_path}/jskitsimpl/data/folder_napi.cpp", + "${udmf_framework_path}/jskitsimpl/data/get_data_params_napi.cpp", "${udmf_framework_path}/jskitsimpl/data/html_napi.cpp", "${udmf_framework_path}/jskitsimpl/data/image_napi.cpp", "${udmf_framework_path}/jskitsimpl/data/link_napi.cpp", @@ -190,7 +202,10 @@ ohos_shared_library("udmf_data_napi") { ] public_external_deps = [ "image_framework:image" ] - cflags = [ "-fvisibility=hidden" ] + cflags = [ + "-fvisibility=hidden", + "-O2", + ] subsystem_name = "distributeddatamgr" part_name = "udmf" } @@ -211,7 +226,10 @@ ohos_static_library("udmf_js_common") { ] ldflags = [ "-Wl,--exclude-libs=ALL" ] - cflags = [ "-fvisibility=hidden" ] + cflags = [ + "-fvisibility=hidden", + "-O2", + ] include_dirs = [ "${udmf_interfaces_path}/jskits/common" ] public_configs = [ ":udmf_napi_config" ] @@ -224,3 +242,40 @@ ohos_static_library("udmf_js_common") { subsystem_name = "distributeddatamgr" part_name = "udmf" } + +ohos_shared_library("intelligence_napi") { + branch_protector_ret = "pac_ret" + + sanitize = { + integer_overflow = true + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + + sources = [ + "${udmf_framework_path}/jskitsimpl/intelligence/aip_napi_error.cpp", + "${udmf_framework_path}/jskitsimpl/intelligence/aip_napi_utils.cpp", + "${udmf_framework_path}/jskitsimpl/intelligence/i_aip_core_manager_impl.cpp", + "${udmf_framework_path}/jskitsimpl/intelligence/image_embedding_napi.cpp", + "${udmf_framework_path}/jskitsimpl/intelligence/native_module_intelligence.cpp", + "${udmf_framework_path}/jskitsimpl/intelligence/text_embedding_napi.cpp", + ] + + public_configs = [ ":aip_core_napi_config" ] + + deps = [] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "napi:ace_napi", + ] + + defines = [ "LOG_DOMAIN = 0xD001660" ] + relative_install_dir = "module/data" + subsystem_name = "distributeddatamgr" + part_name = "udmf" +} diff --git a/udmf/interfaces/jskits/common/napi_data_utils.h b/udmf/interfaces/jskits/common/napi_data_utils.h index 091336d145c17d9347dcb8a95319f60aa7e3be41..3dc9e8b669f5a7262a350be9765a6db42dba62a7 100644 --- a/udmf/interfaces/jskits/common/napi_data_utils.h +++ b/udmf/interfaces/jskits/common/napi_data_utils.h @@ -34,6 +34,7 @@ #include "type_descriptor.h" #include "type_descriptor_napi.h" #include "pixel_map_napi.h" +#include "unified_types.h" namespace OHOS { namespace UDMF { @@ -109,6 +110,9 @@ public: static napi_status GetValue(napi_env env, napi_value in, nullptr_t &out); static napi_status SetValue(napi_env env, const nullptr_t &in, napi_value &out); + /* napi_value <- ProgressInfo */ + static napi_status SetValue(napi_env env, const ProgressInfo &in, napi_value &out); + static bool IsTypeForNapiValue(napi_env env, napi_value param, napi_valuetype expectType); static bool IsNull(napi_env env, napi_value value); diff --git a/udmf/interfaces/jskits/data/get_data_params_napi.h b/udmf/interfaces/jskits/data/get_data_params_napi.h new file mode 100644 index 0000000000000000000000000000000000000000..c3d3679c179b1eed6164c05235413aa409f2b963 --- /dev/null +++ b/udmf/interfaces/jskits/data/get_data_params_napi.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025 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 UDMF_GET_DATA_PARAMS_NAPI_H +#define UDMF_GET_DATA_PARAMS_NAPI_H + +#include "async_task_params.h" +#include "concurrent_map.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "visibility.h" + +namespace OHOS { +namespace UDMF { + +class API_EXPORT GetDataParamsNapi { +public: + static bool Convert2NativeValue(napi_env env, napi_value in, GetDataParams &getDataParams, const std::string &key); + +private: + struct ListenerArgs { + ProgressInfo progressInfo; + UnifiedData *unifiedData; + constexpr static size_t ARGV_SIZE = 2; + }; + + static bool SetProgressListener(napi_env env, GetDataParams &getDataParam, + napi_value callback, const std::string &key); + static void CallProgressListener(napi_env env, napi_value callback, void *context, void *data); + static ListenerArgs* CreateListenerArgs(ProgressInfo progressInfo, std::shared_ptr<UnifiedData> data); + static void DeleteListenerArgs(ListenerArgs *listenerArgs); + + static ConcurrentMap<std::string, napi_threadsafe_function> tsfns; +}; + +} // namespace UDMF +} // namespace OHOS +#endif // UDMF_GET_DATA_PARAMS_NAPI_H \ No newline at end of file diff --git a/udmf/interfaces/jskits/data/unified_data_channel_napi.h b/udmf/interfaces/jskits/data/unified_data_channel_napi.h index 9077bacce4cd4230933f53f29784fc9c10b1772e..31575669ce607d4144e8c74d2bbbd86c1a9899d3 100644 --- a/udmf/interfaces/jskits/data/unified_data_channel_napi.h +++ b/udmf/interfaces/jskits/data/unified_data_channel_napi.h @@ -20,6 +20,7 @@ #include "napi/native_api.h" #include "napi/native_node_api.h" +#include "udmf_client.h" namespace OHOS { namespace UDMF { @@ -39,6 +40,11 @@ private: static napi_value CreateShareOptions(napi_env env, napi_callback_info info); static napi_value SetAppShareOptions(napi_env env, napi_callback_info info); static napi_value RemoveAppShareOptions(napi_env env, napi_callback_info info); + static napi_status ConvertUnifiedDataSetToNapi( + napi_env env, const std::vector<UnifiedData> &dataSet, napi_value &output); + static napi_value CreateFileConflictOptions(napi_env env, napi_callback_info info); + static napi_value CreateProgressIndicator(napi_env env, napi_callback_info info); + static napi_value CreateListenerStatus(napi_env env, napi_callback_info info); }; } // namespace UDMF } // namespace OHOS diff --git a/udmf/interfaces/jskits/data/unified_record_napi.h b/udmf/interfaces/jskits/data/unified_record_napi.h index e00ed3a97be465f31f0e54c65dec16ce0604df79..76d25bc117c4f3263ea5c3bd9b01865e307db9c1 100644 --- a/udmf/interfaces/jskits/data/unified_record_napi.h +++ b/udmf/interfaces/jskits/data/unified_record_napi.h @@ -33,7 +33,11 @@ public: static napi_value Constructor(napi_env env); static void NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out); static napi_value GetType(napi_env env, napi_callback_info info); + static napi_value GetTypes(napi_env env, napi_callback_info info); static napi_value GetValue(napi_env env, napi_callback_info info); + static napi_value AddEntry(napi_env env, napi_callback_info info); + static napi_value GetEntry(napi_env env, napi_callback_info info); + static napi_value GetEntries(napi_env env, napi_callback_info info); static std::shared_ptr<UnifiedRecord> GenerateNativeRecord(napi_env env, std::string type, napi_value valueNapi); std::shared_ptr<UnifiedRecord> value_; diff --git a/udmf/interfaces/jskits/intelligence/aip_log.h b/udmf/interfaces/jskits/intelligence/aip_log.h new file mode 100644 index 0000000000000000000000000000000000000000..3f4f1bfb1e5e9108720c3f5bf1aaacc76e0ba579 --- /dev/null +++ b/udmf/interfaces/jskits/intelligence/aip_log.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025 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 AIP_LOG_H +#define AIP_LOG_H + +#include <cstdint> +#include "hilog/log.h" + +#ifndef LOG_DOMAIN +#define LOG_DOMAIN 0xD001660 +#endif + +namespace OHOS { +namespace DataIntelligence { +#ifndef AIP_FUNC_FMT +#define AIP_FUNC_FMT "in %{public}s, " +#endif + +#ifndef AIP_FUNC_INFO +#define AIP_FUNC_INFO __FUNCTION__ +#endif + +#define AIP_HILOGD(fmt, ...) \ + do { \ + HILOG_DEBUG(LOG_CORE, AIP_FUNC_FMT fmt, AIP_FUNC_INFO, ##__VA_ARGS__); \ + } while (0) + +#define AIP_HILOGI(fmt, ...) \ + do { \ + HILOG_INFO(LOG_CORE, AIP_FUNC_FMT fmt, AIP_FUNC_INFO, ##__VA_ARGS__); \ + } while (0) + +#define AIP_HILOGW(fmt, ...) \ + do { \ + HILOG_WARN(LOG_CORE, AIP_FUNC_FMT fmt, AIP_FUNC_INFO, ##__VA_ARGS__); \ + } while (0) + +#define AIP_HILOGE(fmt, ...) \ + do { \ + HILOG_ERROR(LOG_CORE, AIP_FUNC_FMT fmt, AIP_FUNC_INFO, ##__VA_ARGS__); \ + } while (0) + +#define AIP_HILOGF(fmt, ...) \ + do { \ + HILOG_FATAL(LOG_CORE, AIP_FUNC_FMT fmt, AIP_FUNC_INFO, ##__VA_ARGS__); \ + } while (0) +} // namespace DataIntelligence +} // namespace OHOS +#endif // AIP_LOG_H diff --git a/udmf/interfaces/jskits/intelligence/aip_napi_error.h b/udmf/interfaces/jskits/intelligence/aip_napi_error.h new file mode 100644 index 0000000000000000000000000000000000000000..73ba38cd400eaf41b99beeea9cb0f7750661b325 --- /dev/null +++ b/udmf/interfaces/jskits/intelligence/aip_napi_error.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 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 AIP_NAPI_ERROR_H +#define AIP_NAPI_ERROR_H + +#include <map> +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace DataIntelligence { +constexpr int32_t PARAM_EXCEPTION{ 401 }; +constexpr int32_t DEVICE_EXCEPTION{ 801 }; +constexpr int32_t INNER_ERROR{ 31300000 }; +const std::map<int32_t, std::string> ERROR_MESSAGES = { + { PARAM_EXCEPTION, "Params check failed." }, + { DEVICE_EXCEPTION, "The device does not support this API." }, + { INNER_ERROR, "Inner error." }, +}; + +napi_value CreateIntelligenceError(const napi_env &env, int32_t errorCode, const std::string &errorMsg); +std::optional<std::string> GetIntelligenceErrMsg(int32_t errorCode); +void ThrowIntelligenceErr(const napi_env &env, int32_t errorCode, const std::string &printMsg); +void ThrowIntelligenceErrByPromise(const napi_env &env, int32_t errorCode, const std::string &printMsg, + napi_value &value); +} // namespace DataIntelligence +} // namespae OHOS +#endif // AIP_NAPI_ERROR_H \ No newline at end of file diff --git a/udmf/interfaces/jskits/intelligence/aip_napi_utils.h b/udmf/interfaces/jskits/intelligence/aip_napi_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..753ea418f1234a2b6b5c1bda5e380d2e3c14711c --- /dev/null +++ b/udmf/interfaces/jskits/intelligence/aip_napi_utils.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 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 AIP_NAPI_UTILS_H +#define AIP_NAPI_UTILS_H + +#include "i_aip_core_manager.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace DataIntelligence { +class AipNapiUtils { +public: + AipNapiUtils() = default; + ~AipNapiUtils() = default; + + static bool LoadAlgoLibrary(const std::string &algoPath, AipCoreManagerHandle &aipMgrHandler); + static bool UnLoadAlgoLibrary(AipCoreManagerHandle &aipMgrHandler); + static IAipCoreManager *GetAlgoObj(AipCoreManagerHandle &aipMgrHandler); + static bool ValidateArgsType(napi_env env, napi_value *args, size_t argc, + const std::vector<std::string> &expectedTypes); + static bool TransJsToStr(napi_env env, napi_value value, std::string &str); + static bool TransJsToStrUnlimited(napi_env env, napi_value value, std::string &str); + static bool TransJsToInt32(napi_env env, napi_value value, int32_t &res); + static bool TransJsToDouble(napi_env env, napi_value value, double &res); + static bool TransJsToBool(napi_env env, napi_value value, bool &res); + static void CreateStringData(napi_env env, napi_value aipServiceValue, napi_value result, const std::string name, + std::string &content); + static void CreateInt32Data(napi_env env, napi_value aipServiceValue, napi_value result, const std::string name, + int32_t value); + static void CreateDoubleData(napi_env env, double value, napi_value *result); +}; +} // namespace DataIntelligence +} // namespace OHOS +#endif // AIP_NAPI_UTILS_H diff --git a/udmf/interfaces/jskits/intelligence/i_aip_core_manager.h b/udmf/interfaces/jskits/intelligence/i_aip_core_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..d91e1e50b5ae6b2cd48745e09302a9d68f1dbed3 --- /dev/null +++ b/udmf/interfaces/jskits/intelligence/i_aip_core_manager.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025 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 I_AIP_CORE_MANAGER_H +#define I_AIP_CORE_MANAGER_H + +#include <string> +#include <vector> + +namespace OHOS { +namespace DataIntelligence { +struct ModelConfigData { + int32_t versionValue; + bool isNPUAvailableValue; + std::string cachePathValue; +}; + +class IAipCoreManager { +public: + IAipCoreManager() = default; + virtual ~IAipCoreManager() = default; + + virtual int32_t InitTextModel(const ModelConfigData &config) = 0; + virtual int32_t InitImageModel(const ModelConfigData &config) = 0; + virtual int32_t LoadTextModel() = 0; + virtual int32_t ReleaseTextModel() = 0; + virtual int32_t GetTextEmbedding(std::string file, std::vector<float> &results) = 0; + virtual int32_t GetTextEmbedding(const std::vector<std::string> &files, + std::vector<std::vector<float>> &results) = 0; + virtual int32_t LoadImageModel() = 0; + virtual int32_t ReleaseImageModel() = 0; + virtual int32_t GetImageEmbedding(std::string uri, std::vector<float> &results) = 0; + virtual int32_t SplitText(std::string text, int32_t size, float overlap, std::vector<std::string> &results) = 0; +}; + +struct AipCoreManagerHandle { + void *handle; + IAipCoreManager *(*create)(); + void (*destroy)(const IAipCoreManager *); + IAipCoreManager *pAipManager; + AipCoreManagerHandle() : handle(nullptr), create(nullptr), destroy(nullptr), pAipManager(nullptr) {} + ~AipCoreManagerHandle() {} + void Clear() + { + handle = nullptr; + create = nullptr; + destroy = nullptr; + pAipManager = nullptr; + } +}; +} // namespace DataIntelligence +} // namespace OHOS + +#endif // I_AIP_CORE_MANAGER_H \ No newline at end of file diff --git a/udmf/interfaces/jskits/intelligence/i_aip_core_manager_impl.h b/udmf/interfaces/jskits/intelligence/i_aip_core_manager_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..10955b1a1809c652975cada2d84521185718b9a3 --- /dev/null +++ b/udmf/interfaces/jskits/intelligence/i_aip_core_manager_impl.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 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 a + * + * 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 I_AIP_CORE_MANAGER_IMPL_H +#define I_AIP_CORE_MANAGER_IMPL_H + +#include <string> +#include <vector> + +#include "i_aip_core_manager.h" + +namespace OHOS { +namespace DataIntelligence { +class IAipCoreManagerImpl : public IAipCoreManager { +public: + IAipCoreManagerImpl() = default; + ~IAipCoreManagerImpl() = default; + int32_t InitTextModel(const ModelConfigData &config) override; + int32_t InitImageModel(const ModelConfigData &config) override; + int32_t LoadTextModel() override; + int32_t ReleaseTextModel() override; + int32_t GetTextEmbedding(std::string file, std::vector<float> &results) override; + int32_t GetTextEmbedding(const std::vector<std::string> &files, std::vector<std::vector<float>> &results) override; + int32_t LoadImageModel() override; + int32_t ReleaseImageModel() override; + int32_t GetImageEmbedding(std::string uri, std::vector<float> &results) override; + int32_t SplitText(std::string text, int32_t size, float overlap, std::vector<std::string> &results) override; +}; +} // namespace DataIntelligence +} // namespace OHOS +#endif // I_AIP_CORE_MANAGER_IMPL_H diff --git a/udmf/interfaces/jskits/intelligence/image_embedding_napi.h b/udmf/interfaces/jskits/intelligence/image_embedding_napi.h new file mode 100644 index 0000000000000000000000000000000000000000..9d4eefcb7b347a0fd436b1c25eed4f585d7df7ee --- /dev/null +++ b/udmf/interfaces/jskits/intelligence/image_embedding_napi.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025 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 IMAGE_EMBEDDING_NAPI_H +#define IMAGE_EMBEDDING_NAPI_H + +#include <uv.h> +#include <refbase.h> + +#include "i_aip_core_manager.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace DataIntelligence { +class ImageEmbeddingNapi { +public: + ImageEmbeddingNapi(); + ~ImageEmbeddingNapi(); + + static napi_value Init(napi_env env, napi_value exports); + static napi_value LoadModel(napi_env env, napi_callback_info info); + static napi_value ReleaseModel(napi_env env, napi_callback_info info); + static napi_value GetEmbedding(napi_env env, napi_callback_info info); + static napi_value GetImageEmbeddingModel(napi_env env, napi_callback_info info); + static napi_value Constructor(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *nativeObject, void *finalize); + + struct AsyncGetImageEmbeddingModelData { + napi_async_work asyncWork; + napi_deferred deferred; + ModelConfigData config; + napi_value res; + int32_t ret; + }; + +private: + static bool LoadAsyncExecution(napi_env env, napi_deferred deferred); + static bool ReleaseAsyncExecution(napi_env env, napi_deferred deferred); + static bool GetEmbeddingAsyncExecution(napi_env env, napi_deferred deferred, std::string str); + static bool CreateAsyncImgModelExecution(napi_env env, AsyncGetImageEmbeddingModelData *asyncModelData); + static void GetImgEmbeddingModelExecutionCB(napi_env env, void *data); + static void GetImgEmbeddingModelCompleteCB(napi_env env, napi_status status, void *data); + static bool ParseModelConfig(napi_env env, napi_value *args, size_t argc, ModelConfigData *textModelConfig); + static void LoadExecuteCB(napi_env env, void *data); + static void LoadCompleteCB(napi_env env, napi_status status, void *data); + static void ReleaseExecuteCB(napi_env env, void *data); + static void ReleaseCompleteCB(napi_env env, napi_status status, void *data); + static void GetEmbeddingExecuteCB(napi_env env, void *data); + static void GetEmbeddingCompleteCB(napi_env env, napi_status status, void *data); + napi_env env_; + static thread_local napi_ref sConstructor_; + static AipCoreManagerHandle imgAipCoreMgrHandle_; + static IAipCoreManager *imageAipCoreManager_; +}; +} // namespace DataIntelligence +} // namespace OHOS +#endif // IMAGE_EMBEDDING_NAPI_H diff --git a/udmf/interfaces/jskits/intelligence/native_module_intelligence.h b/udmf/interfaces/jskits/intelligence/native_module_intelligence.h new file mode 100644 index 0000000000000000000000000000000000000000..747a6306210f22a6f48f9513bfc520a51ea84d5f --- /dev/null +++ b/udmf/interfaces/jskits/intelligence/native_module_intelligence.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 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 NATIVE_MODULE_INTELLIGENCE_H +#define NATIVE_MODULE_INTELLIGENCE_H + +#include "image_embedding_napi.h" +#include "napi/native_node_api.h" +#include "text_embedding_napi.h" + +#endif // NATIVE_MODULE_INTELLIGENCE_H \ No newline at end of file diff --git a/udmf/interfaces/jskits/intelligence/text_embedding_napi.h b/udmf/interfaces/jskits/intelligence/text_embedding_napi.h new file mode 100644 index 0000000000000000000000000000000000000000..b017dd4aca32407df9eff5ba6a7a36d8985b72d1 --- /dev/null +++ b/udmf/interfaces/jskits/intelligence/text_embedding_napi.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025 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 TEXT_EMBEDDING_NAPI_H +#define TEXT_EMBEDDING_NAPI_H + +#include <uv.h> +#include <refbase.h> + +#include "i_aip_core_manager.h" +#include "i_aip_core_manager_impl.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" +namespace OHOS { +namespace DataIntelligence { +class TextEmbeddingNapi { +public: + TextEmbeddingNapi(); + ~TextEmbeddingNapi(); + + static napi_value Init(napi_env env, napi_value exports); + static napi_value LoadModel(napi_env env, napi_callback_info info); + static napi_value ReleaseModel(napi_env env, napi_callback_info info); + static napi_value GetEmbedding(napi_env env, napi_callback_info info); + static napi_value SplitText(napi_env env, napi_callback_info info); + static napi_value GetTextEmbeddingModel(napi_env env, napi_callback_info info); + static napi_value TextConstructor(napi_env env, napi_callback_info info); + static void Destructor(napi_env env, void *nativeObject, void *finalize); + struct AsyncGetTextEmbeddingModelData { + napi_async_work asyncWork; + napi_deferred deferred; + ModelConfigData config; + napi_value res; + int32_t ret; + }; + +private: + static bool LoadAsyncExecution(napi_env env, napi_deferred deferred); + static bool ReleaseAsyncExecution(napi_env env, napi_deferred deferred); + static bool GetEmbeddingStringAsyncExecution(napi_env env, napi_deferred deferred, std::string str); + static bool GetEmbeddingArrayAsyncExecution(napi_env env, napi_deferred deferred, std::vector<std::string> text); + static bool SplitTextAsyncExecution(napi_env env, napi_deferred deferred, std::string strArg, int32_t configSize, + double configOverlap); + static napi_value StringType(napi_env env, napi_value args, napi_value promise, napi_deferred deferred); + static napi_value ArrayType(napi_env env, napi_value args, napi_value promise, napi_deferred deferred); + static bool ValidateAndDealArrayArgs(napi_env env, napi_value args, std::vector<std::string> &strArr); + static bool GetProperties(napi_env env, napi_value args, napi_value &cfgSize, napi_value &cfgOverlap); + static void LoadExecuteCB(napi_env env, void *data); + static void LoadCompleteCB(napi_env env, napi_status status, void *data); + static void ReleaseExecuteCB(napi_env env, void *data); + static void ReleaseCompleteCB(napi_env env, napi_status status, void *data); + static void GetEmbeddingStringExecuteCB(napi_env env, void *data); + static void GetEmbeddingStringCompleteCB(napi_env env, napi_status status, void *data); + static void GetEmbeddingArrayExecuteCB(napi_env env, void *data); + static void GetEmbeddingArrayCompleteCB(napi_env env, napi_status status, void *data); + static void SplitTextExecuteCB(napi_env env, void *data); + static void SplitTextCompleteCB(napi_env env, napi_status status, void *data); + static bool CreateAsyncTextModelExecution(napi_env env, AsyncGetTextEmbeddingModelData *asyncModelData); + static void GetTextEmbeddingModelExecutionCB(napi_env env, void *data); + static void GetTextEmbeddingModelCompleteCB(napi_env env, napi_status status, void *data); + static bool ParseModelConfig(napi_env env, napi_value *args, size_t argc, ModelConfigData *textModelConfig); + + static thread_local napi_ref sConstructor_; + static AipCoreManagerHandle textAipCoreMgrHandle_; + napi_env env_; + static IAipCoreManager *textAipCoreManager_; +}; +} // namespace DataIntelligence +} // namespace OHOS +#endif // TEXT_EMBEDDING_NAPI_H \ No newline at end of file diff --git a/udmf/interfaces/ndk/BUILD.gn b/udmf/interfaces/ndk/BUILD.gn index 2db39f273db6cc86523f9ac6ab23f061df624956..130c3eca5a024eac29ea0b8035611297aa7efad4 100644 --- a/udmf/interfaces/ndk/BUILD.gn +++ b/udmf/interfaces/ndk/BUILD.gn @@ -27,9 +27,11 @@ ohos_shared_library("libudmf") { "${udmf_interfaces_path}/innerkits/common", "${udmf_interfaces_path}/innerkits/data", "${udmf_framework_path}/common", + "${udmf_framework_path}/innerkitsimpl/convert", ] sources = [ "${udmf_framework_path}/innerkitsimpl/common/unified_meta.cpp", + "${udmf_framework_path}/innerkitsimpl/convert/data_params_conversion.cpp", "${udmf_framework_path}/ndkimpl/data/data_provider_impl.cpp", "${udmf_framework_path}/ndkimpl/data/udmf.cpp", "${udmf_framework_path}/ndkimpl/data/uds.cpp", diff --git a/udmf/interfaces/ndk/data/udmf.h b/udmf/interfaces/ndk/data/udmf.h index ffc1fe268d153247de44768da94fbf631238730b..84638d3aec5d6ad766d6167788aa9022f126ecbf 100644 --- a/udmf/interfaces/ndk/data/udmf.h +++ b/udmf/interfaces/ndk/data/udmf.h @@ -90,6 +90,38 @@ typedef enum Udmf_ShareOption { SHARE_OPTIONS_CROSS_APP } Udmf_ShareOption; +/** + * @brief Describe the types of file conflict options when getting data from the udmf. + * + * @since 15 + */ +typedef enum Udmf_FileConflictOptions { + /** + * @brief Overwrite when dest uri has file with same name. + */ + UDMF_OVERWRITE = 0, + /** + * @brief Skip when dest uri has file with same name. + */ + UDMF_SKIP = 1, +} Udmf_FileConflictOptions; + +/** + * @brief Describe the types of progress indicator when getting data from the udmf. + * + * @since 15 +*/ +typedef enum Udmf_ProgressIndicator { + /** + * @brief Getting data without system default progress indicator. + */ + UDMF_NONE = 0, + /** + * @brief Getting data with system default progress indicator. + */ + UDMF_DEFAULT = 1 +} Udmf_ProgressIndicator; + /** * @brief Describes the unified data type. * @@ -118,6 +150,30 @@ typedef struct OH_UdmfRecordProvider OH_UdmfRecordProvider; */ typedef struct OH_UdmfProperty OH_UdmfProperty; +/** + * @brief Represents the udmf progress information. + * + * @since 15 +*/ +typedef struct OH_Udmf_ProgressInfo OH_Udmf_ProgressInfo; + +/** + * @brief Represents the parameters of udmf get data with progress info. + * + * @since 15 +*/ +typedef struct OH_UdmfGetDataParams OH_UdmfGetDataParams; + +/** + * @brief Defines the callback function used to return the progress information and data. + * + * @param progressInfo The progress information notified to Application. + * @param data Represents the unified data. + * @since 15 +*/ +typedef void (*OH_Udmf_DataProgressListener)(OH_Udmf_ProgressInfo* progressInfo, OH_UdmfData* data); + + /** * @brief Creation a pointer to the instance of the {@link OH_UdmfData}. * @@ -749,6 +805,87 @@ int OH_Udmf_GetUnifiedData(const char* key, Udmf_Intention intention, OH_UdmfDat int OH_Udmf_SetUnifiedData(Udmf_Intention intention, OH_UdmfData* unifiedData, char* key, unsigned int keyLen); +/** + * @brief Gets the progress from the {@OH_Udmf_ProgressInfo}. + * + * @param progressInfo Represents a pointer to an instance of {@link OH_Udmf_ProgressInfo}. + * @return Returns the progress. + * @see OH_Udmf_ProgressInfo + * @since 15 + */ +int OH_UdmfProgressInfo_GetProgress(OH_Udmf_ProgressInfo* progressInfo); + +/** + * @brief Gets the status from the {@OH_Udmf_ProgressInfo}. + * + * @param progressInfo Represents a pointer to an instance of {@link OH_Udmf_ProgressInfo}. + * @return Returns the status code. See {@link Udmf_ListenerStatus}. + * @see OH_Udmf_ProgressInfo Udmf_ListenerStatus + * @since 15 + */ +int OH_UdmfProgressInfo_GetStatus(OH_Udmf_ProgressInfo* progressInfo); + +/** + * @brief Creation a pointer to the instance of the {@link OH_UdmfGetDataParams}. + * + * @return If the operation is successful, a pointer to the instance of the {@link OH_UdmfGetDataParams} + * structure is returned. If the operation is failed, nullptr is returned. + * @see OH_UdmfGetDataParams + * @since 15 + */ +OH_UdmfGetDataParams* OH_UdmfGetDataParams_Create(); + +/** + * @brief Destroy a pointer that points to an instance of {@link OH_UdmfGetDataParams}. + * + * @param pThis Represents a pointer to an instance of {@link OH_UdmfGetDataParams}. + * @see OH_UdmfGetDataParams + * @since 15 + */ +void OH_UdmfGetDataParams_Destroy(OH_UdmfGetDataParams* pThis); + +/** + * @brief Sets the destination uri to the {@OH_UdmfGetDataParams}. + * + * @param params Represents a pointer to an instance of {@link OH_UdmfGetDataParams}. + * @param destUri Pointer to a destination uri. + * @see OH_UdmfGetDataParams + * @since 15 + */ +void OH_UdmfGetDataParams_SetDestUri(OH_UdmfGetDataParams* params, const char* destUri); + +/** + * @brief Sets the file conflict options to the {@OH_UdmfGetDataParams}. + * + * @param params Represents a pointer to an instance of {@link OH_UdmfGetDataParams}. + * @param options Represents to the file conflict options. + * @see OH_UdmfGetDataParams Udmf_FileConflictOptions + * @since 15 + */ +void OH_UdmfGetDataParams_SetFileConflictOptions(OH_UdmfGetDataParams* params, const Udmf_FileConflictOptions options); + +/** + * @brief Sets the progress indicator to the {@OH_UdmfGetDataParams}. + * + * @param params Represents a pointer to an instance of {@link OH_UdmfGetDataParams}. + * @param options Represents to the progress indicator. + * @see OH_UdmfGetDataParams Udmf_ProgressIndicator + * @since 15 + */ +void OH_UdmfGetDataParams_SetProgressIndicator(OH_UdmfGetDataParams* params, + const Udmf_ProgressIndicator progressIndicator); + +/** + * @brief Sets the progress indicator to the {@OH_UdmfGetDataParams}. + * + * @param params Represents a pointer to an instance of {@link OH_UdmfGetDataParams}. + * @param options Represents to the data progress listener. + * @see OH_UdmfGetDataParams OH_Udmf_DataProgressListener + * @since 15 + */ +void OH_UdmfGetDataParams_SetDataProgressListener(OH_UdmfGetDataParams* params, + const OH_Udmf_DataProgressListener dataProgressListener); + #ifdef __cplusplus }; #endif diff --git a/udmf/interfaces/ndk/data/udmf_err_code.h b/udmf/interfaces/ndk/data/udmf_err_code.h index 105191c7c040db176267497551b13ee668468dd6..15fb0e0182c24b51eff81b2d52e1667b6e4ecf59 100644 --- a/udmf/interfaces/ndk/data/udmf_err_code.h +++ b/udmf/interfaces/ndk/data/udmf_err_code.h @@ -66,6 +66,42 @@ typedef enum Udmf_ErrCode { UDMF_E_INVALID_PARAM = (UDMF_ERR + 1), } Udmf_ErrCode; +/** + * @brief Indicates the error code information. + * + * @since 15 + */ +typedef enum Udmf_ListenerStatus { + /** + * brief Indicates the finished status. + */ + UDMF_FINISHED, + /** + * @brief Indicates that processing is still in progress. + */ + UDMF_PROCESSING, + /** + * @brief Indicates that an internal error has occurred. + */ + UDMF_INNER_ERROR, + /** + * @brief Indicates that the GetDataParams contains invalid parameters. + */ + UDMF_INVALID_PARAMETERS, + /** + * @brief Indicates that no data is obtained. + */ + UDMF_DATA_NOT_FOUND, + /** + * @brief Indicates that an error occurred in the synchronization process. + */ + UDMF_SYNC_FAILED, + /** + * @brief that an error occurred during file copying. + */ + UDMF_COPY_FILE_FAILED, +} Udmf_ListenerStatus; + #ifdef __cplusplus }; #endif