diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000000000000000000000000000000000..286ddac767c081781e0939fea7020e4786a3242d --- /dev/null +++ b/.clang-format @@ -0,0 +1,162 @@ +Language: Cpp +# BasedOnStyle: LLVM +# 访问说明符(public、private等)的偏移 +AccessModifierOffset: -4 +# 开括号(开圆括号、开尖括号、开方括号)后的对齐 +AlignAfterOpenBracket: Align +# 连续赋值时,等号对齐 +AlignConsecutiveAssignments: false +# 连续赋值时,变量名对齐 +AlignConsecutiveDeclarations: false +# 左对齐逃脱换行(使用反斜杠换行)的反斜杠 +AlignEscapedNewlinesLeft: true +# 水平对齐二元和三元表达式的操作数 +AlignOperands: true +# 对齐连续的尾随的注释 +AlignTrailingComments: true +# 允许函数声明的所有参数在放在下一行 +AllowAllParametersOfDeclarationOnNextLine: false +# 允许短的块放在同一行 +AllowShortBlocksOnASingleLine: false +# 允许短的case标签放在同一行 +AllowShortCaseLabelsOnASingleLine: false +# 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中,空函数), All +AllowShortFunctionsOnASingleLine: Empty +# 允许短的if语句保持在同一行 +AllowShortIfStatementsOnASingleLine: false +# 允许短的循环保持在同一行 +AllowShortLoopsOnASingleLine: false +# 总是在定义返回类型后换行(deprecated) +AlwaysBreakAfterDefinitionReturnType: None +# 总是在返回类型后换行: None, All, TopLevel(顶级函数,不包括在类中的函数), +# AllDefinitions(所有的定义,不包括声明), TopLevelDefinitions(所有的顶级函数的定义) +AlwaysBreakAfterReturnType: None +# 总是在多行string字面量前换行 +AlwaysBreakBeforeMultilineStrings: true +# 总是在template声明后换行 +AlwaysBreakTemplateDeclarations: true +# false表示函数实参要么都在同一行,要么都各自一行 +BinPackArguments: true +# false表示所有形参要么都在同一行,要么都各自一行 +BinPackParameters: false +# 大括号换行,只有当BreakBeforeBraces设置为Custom时才有效 +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false +# 在二元运算符前换行: None(在操作符后换行), NonAssignment(在非赋值的操作符前换行), All(在操作符前换行) +BreakBeforeBinaryOperators: None +# 在大括号前换行: Attach(始终将大括号附加到周围的上下文), Linux(除函数、命名空间和类定义,与Attach类似), +# Mozilla(除枚举、函数、记录定义,与Attach类似), Stroustrup(除函数定义、catch、else,与Attach类似), +# Allman(总是在大括号前换行), GNU(总是在大括号前换行,并对于控制语句的大括号增加额外的缩进), WebKit(在函数前换行), Custom +# 注:这里认为语句块也属于函数 +BreakBeforeBraces: Custom +# 在三元运算符前换行 +BreakBeforeTernaryOperators: true +# 在构造函数的初始化列表的逗号前换行 +BreakConstructorInitializersBeforeComma: false +# 每行字符的限制,0表示没有限制 +ColumnLimit: 120 +# 描述具有特殊意义的注释的正则表达式,它不应该被分割为多行或以其它方式改变 +CommentPragmas: "^ IWYU pragma:" +# 构造函数的初始化列表要么都在同一行,要么都各自一行 +ConstructorInitializerAllOnOneLineOrOnePerLine: true +# 构造函数的初始化列表的缩进宽度 +ConstructorInitializerIndentWidth: 4 +# 延续的行的缩进宽度 +ContinuationIndentWidth: 4 +# 去除C++11的列表初始化的大括号{后和}前的空格 +Cpp11BracedListStyle: true +# 继承最常用的指针和引用的对齐方式 +DerivePointerAlignment: false +# 关闭格式化 +DisableFormat: false +# 自动检测函数的调用和定义是否被格式为每行一个参数(Experimental) +ExperimentalAutoDetectBinPacking: false +# 需要被解读为foreach循环而不是函数调用的宏 +ForEachMacros: [foreach, Q_FOREACH, BOOST_FOREACH] +# 对#include进行排序,匹配了某正则表达式的#include拥有对应的优先级,匹配不到的则默认优先级为INT_MAX(优先级越小排序越靠前), +# 可以定义负数优先级从而保证某些#include永远在最前面 +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|isl|json)/)' + Priority: 3 + - Regex: ".*" + Priority: 1 +# 缩进case标签 +IndentCaseLabels: true +# 缩进宽度 +IndentWidth: 4 +# 函数返回类型换行时,缩进函数声明或函数定义的函数名 +IndentWrappedFunctionNames: true +# 保留在块开始处的空行 +KeepEmptyLinesAtTheStartOfBlocks: true +# 开始一个块的宏的正则表达式 +MacroBlockBegin: "" +# 结束一个块的宏的正则表达式 +MacroBlockEnd: "" +# 连续空行的最大数量 +MaxEmptyLinesToKeep: 1 +# 命名空间的缩进: None, Inner(缩进嵌套的命名空间中的内容), All +NamespaceIndentation: None +# 使用ObjC块时缩进宽度 +ObjCBlockIndentWidth: 4 +# 在ObjC的@property后添加一个空格 +ObjCSpaceAfterProperty: false +# 在ObjC的protocol列表前添加一个空格 +ObjCSpaceBeforeProtocolList: true +# 在call(后对函数调用换行的penalty +PenaltyBreakBeforeFirstCallParameter: 19 +# 在一个注释中引入换行的penalty +PenaltyBreakComment: 300 +# 第一次在<<前换行的penalty +PenaltyBreakFirstLessLess: 120 +# 在一个字符串字面量中引入换行的penalty +PenaltyBreakString: 1000 +# 对于每个在行字符数限制之外的字符的penalty +PenaltyExcessCharacter: 1000000 +# 将函数的返回类型放到它自己的行的penalty +PenaltyReturnTypeOnItsOwnLine: 120 +# 指针和引用的对齐: Left, Right, Middle +PointerAlignment: Right +# 允许重新排版注释 +ReflowComments: true +# 允许排序#include +SortIncludes: true +# 在C风格类型转换后添加空格 +SpaceAfterCStyleCast: false +# 在赋值运算符之前添加空格 +SpaceBeforeAssignmentOperators: true +# 开圆括号之前添加一个空格: Never, ControlStatements, Always +SpaceBeforeParens: ControlStatements +# 在空的圆括号中添加空格 +SpaceInEmptyParentheses: false +# 在尾随的评论前添加的空格数(只适用于//) +SpacesBeforeTrailingComments: 1 +# 在尖括号的<后和>前添加空格 +SpacesInAngles: false +# 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格 +SpacesInContainerLiterals: true +# 在C风格类型转换的括号中添加空格 +SpacesInCStyleCastParentheses: false +# 在圆括号的(后和)前添加空格 +SpacesInParentheses: false +# 在方括号的[后和]前添加空格,lamda表达式和未指明大小的数组的声明不受影响 +SpacesInSquareBrackets: false +# 在C++11的列表初始化的大括号之前添加空格 +SpaceBeforeCpp11BracedList: true +# 标准: c++03,c++11,c++14,c++17,c++20,Latest,Auto +Standard: c++17 +# tab宽度 +TabWidth: 4 +# 使用tab字符: Never, ForIndentation, ForContinuationAndIndentation, Always +UseTab: Never \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..600d2d33badf45cc068e01d2e3c837e11c417bc4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vscode \ No newline at end of file diff --git a/BUILD.gn b/BUILD.gn index af0c7ab4989f36f146f596b51f92249b98c5dbd5..44bf745721fd01f28153251a002e27cf0ca27838 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2021 Huawei Device Co., Ltd. +# 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 @@ -14,5 +14,41 @@ import("//build/ohos.gni") group("libremotefileshare") { - deps = [ "//foundation/filemanagement/app_file_service/interfaces/kits/js:remotefileshare" ] + deps = [ + "//foundation/filemanagement/app_file_service/interfaces/innerkits/remote_file_share/native:remote_file_share_native", + "//foundation/filemanagement/app_file_service/interfaces/kits/js:remotefileshare", + ] +} + +group("tgt_backup_extension") { + deps = [ + "frameworks/native/backup_ext:backup_extension_ability_native", + "interfaces/api/js/napi/backup_ext:backupextensionability_napi", + ] +} + +group("tgt_backup_kit_inner") { + deps = [ "interfaces/inner_api/native/backup_kit_inner" ] +} + +group("tgt_backup_sa") { + deps = [ + "services:backup_para_etc", + "services:backup_sa_etc", + "services:backup_sa_profile", + "services/backup_sa", + ] +} + +group("tgt_backup_tool") { + deps = [ "tools/backup_tool" ] +} + +group("tgt_backup_tests") { + testonly = true + + deps = [ + "tests/moduletests", + "tests/unittests", + ] } \ No newline at end of file diff --git a/OAT.xml b/OAT.xml index b736383c31b96f2c098e45a0ae74575006f4a95d..fd08f5d9ae490b3f796188d9f9022f3e3586b8f3 100644 --- a/OAT.xml +++ b/OAT.xml @@ -1,6 +1,5 @@ + + backup_sa + + libbackup_sa.z.so + + + 5203 + libbackup_sa.z.so + + + false + false + 1 + + diff --git a/services/BUILD.gn b/services/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..ae1fb99b67c69fb405470d957458741cfdf98194 --- /dev/null +++ b/services/BUILD.gn @@ -0,0 +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. + +import("//build/ohos.gni") +import("//build/ohos/sa_profile/sa_profile.gni") + +group("backup_para_etc") { + deps = [ ":backup.para" ] +} + +ohos_sa_profile("backup_sa_profile") { + sources = [ "5203.xml" ] + part_name = "app_file_service" +} + +ohos_prebuilt_etc("backup_sa_etc") { + source = "backup.cfg" + relative_install_dir = "init" + part_name = "app_file_service" + subsystem_name = "filemanagement" +} + +ohos_prebuilt_etc("backup.para") { + source = "backup.para" + install_images = [ "system" ] + part_name = "app_file_service" + subsystem_name = "filemanagement" + relative_install_dir = "param" +} \ No newline at end of file diff --git a/services/backup.cfg b/services/backup.cfg new file mode 100644 index 0000000000000000000000000000000000000000..84d391ce619ed8f98cf2852ca25b7b349902923a --- /dev/null +++ b/services/backup.cfg @@ -0,0 +1,11 @@ +{ + "services" : [{ + "name" : "backup_sa", + "path" : ["/system/bin/sa_main", "/system/profile/backup_sa.xml"], + "ondemand" : true, + "uid" : "backup", + "gid" : ["backup"], + "secon" : "u:r:backup_sa:s0" + } + ] +} \ No newline at end of file diff --git a/services/backup.para b/services/backup.para new file mode 100644 index 0000000000000000000000000000000000000000..9878f6ca2839204bf60e62bd09c6e9bb6d898ccd --- /dev/null +++ b/services/backup.para @@ -0,0 +1,14 @@ +# 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. + +backup.debug.overrideExtensionConfig=false \ No newline at end of file diff --git a/services/backup_sa/BUILD.gn b/services/backup_sa/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..0499ac1d6c1ecda977aa30ab507cbf5e07d6f425 --- /dev/null +++ b/services/backup_sa/BUILD.gn @@ -0,0 +1,55 @@ +# 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. + +import("//build/ohos.gni") +import("//foundation/filemanagement/app_file_service/backup.gni") + +ohos_shared_library("backup_sa") { + sources = [ + "src/module_ipc/service.cpp", + "src/module_ipc/service_reverse_proxy.cpp", + "src/module_ipc/service_stub.cpp", + "src/module_ipc/svc_backup_connection.cpp", + "src/module_ipc/svc_extension_proxy.cpp", + "src/module_ipc/svc_session_manager.cpp", + "src/module_sched/sched_scheduler.cpp", + ] + + defines = [ + "LOG_DOMAIN=0xD004303", + "LOG_TAG=\"BackupSA\"", + ] + + include_dirs = [ "include" ] + + deps = [ + "${path_ability_runtime}/interfaces/inner_api/ability_manager:ability_manager", + "${path_access_token}/interfaces/innerkits/accesstoken:libaccesstoken_sdk", + "${path_backup}/utils:backup_utils", + ] + + external_deps = [ + "ability_base:want", + "app_file_service:backup_kit_inner", + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + "init:libbegetutil", + ] + + use_exceptions = true + part_name = "app_file_service" + subsystem_name = "filemanagement" +} diff --git a/services/backup_sa/include/module_ipc/service.h b/services/backup_sa/include/module_ipc/service.h new file mode 100644 index 0000000000000000000000000000000000000000..b8d37b08dba3b0e557a34c275480c35e60392eae --- /dev/null +++ b/services/backup_sa/include/module_ipc/service.h @@ -0,0 +1,123 @@ +/* + * 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_FILEMGMT_BACKUP_SERVICE_H +#define OHOS_FILEMGMT_BACKUP_SERVICE_H + +#include +#include + +#include "i_service_reverse.h" +#include "iremote_stub.h" +#include "module_sched/sched_scheduler.h" +#include "service_stub.h" +#include "svc_session_manager.h" +#include "system_ability.h" + +namespace OHOS::FileManagement::Backup { +class Service : public SystemAbility, public ServiceStub, protected NoCopyable { + DECLARE_SYSTEM_ABILITY(Service); + + // 以下都是IPC接口 +public: + ErrCode InitRestoreSession(sptr remote, const std::vector &bundleNames) override; + ErrCode InitBackupSession(sptr remote, + UniqueFd fd, + const std::vector &bundleNames) override; + ErrCode Start() override; + UniqueFd GetLocalCapabilities() override; + ErrCode PublishFile(const BFileInfo &fileInfo) override; + ErrCode AppFileReady(const std::string &fileName, UniqueFd fd) override; + ErrCode AppDone(ErrCode errCode) override; + ErrCode GetExtFileName(std::string &bundleName, std::string &fileName) override; + + // 以下都是非IPC接口 +public: + void OnStart() override; + void OnStop() override; + void StopAll(const wptr &obj, bool force = false); + int Dump(int fd, const std::vector &args) override; + + /** + * @brief 执行启动 backup extension + * + * @param bundleName + * @return ErrCode + */ + virtual ErrCode LaunchBackupExtension(const BundleName &bundleName); + + /** + * @brief backup extension died + * + * @param bundleName 应用名称 + */ + void OnBackupExtensionDied(const std::string &&bundleName, ErrCode ret); + + /** + * @brief extension启动连接成功 + * + * @param bundleName 应用名称 + */ + void ExtConnectDone(std::string bundleName); + + /** + * @brief extension启动连接失败 + * + * @param bundleName 应用名称 + */ + void ExtConnectFailed(const std::string &bundleName, ErrCode ret); + + /** + * @brief 执行backup extension 备份恢复流程 + * + * @param bundleName 应用名称 + */ + virtual void ExtStart(const std::string &bundleName); + +public: + explicit Service(int32_t saID, bool runOnCreate = false) : SystemAbility(saID, runOnCreate) + { + session_ = sptr(new SvcSessionManager(wptr(this))); + }; + ~Service() override = default; + +private: + /** + * @brief 验证调用者并返回名称 + * + * @return std::string + */ + std::string VerifyCallerAndGetCallerName(); + + /** + * @brief 清除Session Sched相关资源 + * + * @param bundleName 应用名称 + */ + void ClearSessionAndSchedInfo(const std::string &bundleName); + +private: + static sptr instance_; + static std::mutex instanceLock_; + static inline std::atomic seed {1}; + + sptr session_; + sptr sched_; + + friend class ServiceTest; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_SERVICE_H \ No newline at end of file diff --git a/services/backup_sa/include/module_ipc/service_reverse_proxy.h b/services/backup_sa/include/module_ipc/service_reverse_proxy.h new file mode 100644 index 0000000000000000000000000000000000000000..2ab8a6aa6f809da68abae28dd64a4c39f26933c7 --- /dev/null +++ b/services/backup_sa/include/module_ipc/service_reverse_proxy.h @@ -0,0 +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 OHOS_FILEMGMT_BACKUP_SERVICE_REVERSE_PROXY_H +#define OHOS_FILEMGMT_BACKUP_SERVICE_REVERSE_PROXY_H + +#include "i_service_reverse.h" +#include "iremote_proxy.h" + +namespace OHOS::FileManagement::Backup { +class ServiceReverseProxy final : public IRemoteProxy, protected NoCopyable { +public: + void BackupOnFileReady(std::string bundleName, std::string fileName, int fd) override; + void BackupOnBundleStarted(int32_t errCode, std::string bundleName) override; + void BackupOnBundleFinished(int32_t errCode, std::string bundleName) override; + void BackupOnAllBundlesFinished(int32_t errCode) override; + + void RestoreOnBundleStarted(int32_t errCode, std::string bundleName) override; + void RestoreOnBundleFinished(int32_t errCode, std::string bundleName) override; + void RestoreOnAllBundlesFinished(int32_t errCode) override; + void RestoreOnFileReady(std::string bundleName, std::string fileName, int fd) override; + +public: + explicit ServiceReverseProxy(const sptr &impl) : IRemoteProxy(impl) {} + ~ServiceReverseProxy() override = default; + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_SERVICE_REVERSE_PROXY_H \ No newline at end of file diff --git a/services/backup_sa/include/module_ipc/service_stub.h b/services/backup_sa/include/module_ipc/service_stub.h new file mode 100644 index 0000000000000000000000000000000000000000..6b44e3de41dd710949a0f552b669cd9bbbea0758 --- /dev/null +++ b/services/backup_sa/include/module_ipc/service_stub.h @@ -0,0 +1,48 @@ +/* + * 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_FILEMGMT_BACKUP_SERVICE_STUB_H +#define OHOS_FILEMGMT_BACKUP_SERVICE_STUB_H + +#include + +#include "i_service.h" +#include "iremote_stub.h" + +namespace OHOS::FileManagement::Backup { +class ServiceStub : public IRemoteStub { +public: + int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +public: + ServiceStub(); + ~ServiceStub() override = default; + +private: + using ServiceInterface = int32_t (ServiceStub::*)(MessageParcel &data, MessageParcel &reply); + std::map opToInterfaceMap_; + + int32_t CmdInitRestoreSession(MessageParcel &data, MessageParcel &reply); + int32_t CmdInitBackupSession(MessageParcel &data, MessageParcel &reply); + int32_t CmdStart(MessageParcel &data, MessageParcel &reply); + int32_t CmdGetLocalCapabilities(MessageParcel &data, MessageParcel &reply); + int32_t CmdPublishFile(MessageParcel &data, MessageParcel &reply); + int32_t CmdAppFileReady(MessageParcel &data, MessageParcel &reply); + int32_t CmdAppDone(MessageParcel &data, MessageParcel &reply); + int32_t CmdGetExtFileName(MessageParcel &data, MessageParcel &reply); +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_SERVICE_STUB_H \ No newline at end of file diff --git a/services/backup_sa/include/module_ipc/svc_backup_connection.h b/services/backup_sa/include/module_ipc/svc_backup_connection.h new file mode 100644 index 0000000000000000000000000000000000000000..fa0b86c2ba653bdc7dfd6d669084047d65d2bbf8 --- /dev/null +++ b/services/backup_sa/include/module_ipc/svc_backup_connection.h @@ -0,0 +1,93 @@ +/* + * 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_FILEMGMT_BACKUP_SVC_BACKUP_CONNECTION_H +#define OHOS_FILEMGMT_BACKUP_SVC_BACKUP_CONNECTION_H + +#include "ability_connect_callback_stub.h" +#include "i_extension.h" + +namespace OHOS::FileManagement::Backup { +class SvcBackupConnection : public AAFwk::AbilityConnectionStub { +public: + /** + * @brief This method is called back to receive the connection result after an ability calls the + * ConnectAbility method to connect it to an extension ability. + * + * @param element: Indicates information about the connected extension ability. + * @param remote: Indicates the remote proxy object of the extension ability. + * @param resultCode: Indicates the connection result code. The value 0 indicates a successful connection, and any + * other value indicates a connection failure. + */ + void OnAbilityConnectDone(const AppExecFwk::ElementName &element, + const sptr &remoteObject, + int resultCode) override; + + /** + * @brief This method is called back to receive the disconnection result after the connected extension ability + * crashes or is killed. If the extension ability exits unexpectedly, all its connections are disconnected, and + * each ability previously connected to it will call onAbilityDisconnectDone. + * + * @param element: Indicates information about the disconnected extension ability. + * @param resultCode: Indicates the disconnection result code. The value 0 indicates a successful disconnection, + * and any other value indicates a disconnection failure. + */ + void OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) override; + + /** + * @brief connect remote ability of ExtBackup. + */ + ErrCode ConnectBackupExtAbility(AAFwk::Want &want); + + /** + * @brief disconnect remote ability of ExtBackup. + */ + ErrCode DisconnectBackupExtAbility(); + + /** + * @brief check whether connected to remote extension ability. + * + * @return bool true if connected, otherwise false. + */ + bool IsExtAbilityConnected(); + + /** + * @brief get the proxy of backup extension ability. + * + * @return the proxy of backup extension ability. + */ + sptr GetBackupExtProxy(); + +public: + SvcBackupConnection(std::function callDied, + std::function callConnDone) + : callDied_(callDied), callConnDone_(callConnDone) + { + } + ~SvcBackupConnection() override {}; + +private: + std::mutex mutex_; + std::condition_variable condition_; + std::atomic isConnected_ = {false}; + std::atomic isConnectedDone_ = {false}; + sptr backupProxy_; + + std::function callDied_; + std::function callConnDone_; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_SVC_BACKUP_CONNECTION_H \ No newline at end of file diff --git a/services/backup_sa/include/module_ipc/svc_extension_proxy.h b/services/backup_sa/include/module_ipc/svc_extension_proxy.h new file mode 100644 index 0000000000000000000000000000000000000000..720c6972218a6dfd7d2bded8bfec70bc7ce08ac6 --- /dev/null +++ b/services/backup_sa/include/module_ipc/svc_extension_proxy.h @@ -0,0 +1,38 @@ +/* + * 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_FILEMGMT_BACKUP_SVC_EXTENSION_PROXY_H +#define OHOS_FILEMGMT_BACKUP_SVC_EXTENSION_PROXY_H + +#include "i_extension.h" +#include "iremote_proxy.h" + +namespace OHOS::FileManagement::Backup { +class SvcExtensionProxy : public IRemoteProxy { +public: + UniqueFd GetFileHandle(const std::string &fileName) override; + ErrCode HandleClear() override; + ErrCode HandleBackup() override; + ErrCode PublishFile(const std::string &fileName) override; + +public: + explicit SvcExtensionProxy(const sptr &remote) : IRemoteProxy(remote) {} + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_SVC_EXTENSION_PROXY_H \ No newline at end of file diff --git a/services/backup_sa/include/module_ipc/svc_session_manager.h b/services/backup_sa/include/module_ipc/svc_session_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..1251da52e94197764634a4f7c06c24899a0d6372 --- /dev/null +++ b/services/backup_sa/include/module_ipc/svc_session_manager.h @@ -0,0 +1,252 @@ +/* + * 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_FILEMGMT_BACKUP_SVC_SESSION_MANAGER_H +#define OHOS_FILEMGMT_BACKUP_SVC_SESSION_MANAGER_H + +#include +#include +#include +#include +#include + +#include "b_file_info.h" +#include "b_resources/b_constants.h" +#include "bundlemgr/bundle_mgr_interface.h" +#include "i_service_reverse.h" +#include "module_ipc/svc_backup_connection.h" +#include "svc_death_recipient.h" + +namespace OHOS::FileManagement::Backup { +struct BackupExtInfo { + bool receExtManageJson {false}; + bool receExtAppDone {false}; + std::string backupExtName; + sptr backUpConnection; + std::set fileNameInfo; + BConstants::ServiceSchedAction schedAction {BConstants::ServiceSchedAction::WAIT}; +}; + +class Service; +class SvcSessionManager : public virtual RefBase { +public: + struct Impl { + uint32_t clientToken {0}; + IServiceReverse::Scenario scenario {IServiceReverse::Scenario::UNDEFINED}; + std::map backupExtNameMap; + sptr clientProxy; + }; + +public: + /** + * @brief 检验调用者是否是会话所有者,且当前命令是否与当前场景相匹配 + * + * @param clientToken 调用者TOKEN + * @param scenario 给定场景 + * @throw BError::Codes::SA_REFUSED_ACT 调用者不是会话所有者 + * @throw BError::Codes::SDK_MIXED_SCENARIO 调用者在备份/恢复场景使用了不匹配的函数 + */ + void VerifyCallerAndScenario(uint32_t clientToken, IServiceReverse::Scenario scenario) const; + + /** + * @brief 激活会话 + * + * @param impl 客户端信息 + */ + void Active(Impl newImpl); + + /** + * @brief 关闭会话 + * + * @param remoteInAction 尝试关闭会话的客户端代理。只有激活会话的客户端代理有权关闭会话 + * @param force 强制关闭 + */ + void Deactive(const wptr &remoteInAction, bool force = false); + + /** + * @brief 检验调用者给定的bundleName是否是有效的 + * + * @param bundleName 调用者名称 + * @throw BError::Codes::SA_REFUSED_ACT 调用者不是会话所有者 + */ + void VerifyBundleName(std::string &bundleName); + + /** + * @brief 获取IServiceReverse + * + * @return sptr 返回clientProxy + * @throw BError::Codes::SA_REFUSED_ACT 调用者不是会话所有者 + */ + sptr GetServiceReverseProxy(); + + /** + * @brief 获取Scenario + * + * @return IServiceReverse::Scenario 返回scenario + * @throw BError::Codes::SA_INVAL_ARG 获取异常 + */ + IServiceReverse::Scenario GetScenario(); + + /** + * @brief 更新backupExtNameMap并判断是否完成分发 + * + * @param bundleName 客户端信息 + * @param fileName 文件名称 + * @throw BError::Codes::SA_INVAL_ARG 获取异常 + * @return true 分发已完成 + * @return false 分发未完成 + */ + bool OnBunleFileReady(const std::string &bundleName, const std::string &fileName = ""); + + /** + * @brief 设置backup manage.json 信息 + * + * @param bundleName 客户端信息 + * @param fd manage.json 文件描述符 + * @return UniqueFd 返回manage.json 文件描述符 + * @throw BError::Codes::SA_INVAL_ARG 获取异常 + */ + UniqueFd OnBunleExtManageInfo(const std::string &bundleName, UniqueFd fd); + + /** + * @brief Remove backup extension info + * + * @param bundleName 应用名称 + */ + void RemoveExtInfo(const std::string &bundleName); + + /** + * @brief get extension connection info + * + * @param bundleName + * @return wptr + */ + wptr GetExtConnection(const BundleName &bundleName); + + /** + * @brief HiDumper dump info + * + * @param fd 对端dump句柄 + * @param args 服务参数 + */ + void DumpInfo(const int fd, const std::vector &args); + + /** + * @brief 暂存restore流程真实文件请求 + * + * @param bundleName 应用名称 + * @param fileName 文件名称 + */ + void SetExtFileNameRequest(const std::string &bundleName, const std::string &fileName); + + /** + * @brief 获取restore流程真实文件请求 + * + * @param bundleName 应用名称 + * @return std::set 返回真实文件vec + */ + std::set GetExtFileNameRequest(const std::string &bundleName); + + /** + * @brief 获取ServiceSchedAction状态 + * + * @param bundleName 应用名称 + * @return BConstants::ServiceSchedAction + */ + BConstants::ServiceSchedAction GetServiceSchedAction(const std::string &bundleName); + + /** + * @brief 设置ServiceSchedAction状态 + * + * @param bundleName 应用名称 + * @param action 状态 + */ + void SetServiceSchedAction(const std::string &bundleName, BConstants::ServiceSchedAction action); + + /** + * @brief 获取所需要的调度信息 + * + * @return std::string 返回bundleName + */ + bool GetSchedBundleName(std::string &bundleName); + + /** + * @brief 获取backup extension name + * + * @param bundleName 应用名称 + * @return std::string + * @return std::string extension name + */ + std::string GetBackupExtName(const std::string &bundleName); + +private: + /** + * @brief 校验BundleName和ability type 并补全Impl.backupExtNameMap信息 + * + * @param backupExtNameMap 客户端信息 + * @throw BError::Codes::SA_INVAL_ARG 客户端信息异常 + * @throw BError::Codes::SA_BROKEN_IPC + */ + virtual void GetBundleExtNames(std::map &backupExtNameMap); + + /** + * @brief 初始化 extension backUpConnection + * + * @param backupExtNameMap + */ + virtual void InitExtConn(std::map &backupExtNameMap); + + /** + * @brief 初始化 clientProxy + * + * @param newImpl + */ + virtual void InitClient(Impl &newImpl); + + /** + * @brief 获取BackupExtNameMap iterator + * + * @param bundleName 应用名称 + * @return std::map::iterator + */ + std::map::iterator GetBackupExtNameMap(const std::string &bundleName); + +public: + /** + * @brief Construct a new Svc Session object + * + * @param reversePtr 指向Service的反向指针,使用wptr避免循环引用 + */ + explicit SvcSessionManager(wptr reversePtr) : reversePtr_(reversePtr) {} + ~SvcSessionManager() override = default; + +private: + sptr GetBundleManager(); + + mutable std::shared_mutex lock_; + wptr reversePtr_; + sptr deathRecipient_; + Impl impl_; + uint32_t extConnectNum_ {0}; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_SVC_SESSION_MANAGER_H diff --git a/services/backup_sa/include/module_sched/sched_scheduler.h b/services/backup_sa/include/module_sched/sched_scheduler.h new file mode 100644 index 0000000000000000000000000000000000000000..d50c28024e2165d261eb9f7ce72587a690fd2786 --- /dev/null +++ b/services/backup_sa/include/module_sched/sched_scheduler.h @@ -0,0 +1,89 @@ +/* + * 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_FILEMGMT_BACKUP_SCHED_SCHEDULER_H +#define OHOS_FILEMGMT_BACKUP_SCHED_SCHEDULER_H + +#include +#include +#include +#include +#include + +#include "b_resources/b_constants.h" +#include "iremote_broker.h" +#include "thread_pool.h" +#include "timer.h" + +namespace OHOS::FileManagement::Backup { +class Service; +class SvcSessionManager; + +class SchedScheduler final : public virtual RefBase { +public: + /** + * @brief 给threadPool下发任务 + * + */ + void Sched(std::string bundleName = ""); + + /** + * @brief 执行队列任务 + * + * @param bundleName + */ + void ExecutingQueueTasks(const std::string &bundleName); + + /** + * @brief 移除定时器信息 + * + * @param bundleName 应用名称 + */ + void RemoveExtConn(const std::string &bundleName); + + void StartTimer() + { + extTime_.Setup(); + } + +public: + explicit SchedScheduler(wptr reversePtr, wptr sessionPtr) + : reversePtr_(reversePtr), sessionPtr_(sessionPtr) + { + threadPool_.Start(BConstants::SA_THREAD_POOL_COUNT); + } + + ~SchedScheduler() override + { + extTime_.Shutdown(); + reversePtr_ = nullptr; + sessionPtr_ = nullptr; + bundleTimeVec_.clear(); + } + +private: + mutable std::shared_mutex lock_; + OHOS::ThreadPool threadPool_; + + // 注册心跳信息 + std::vector> bundleTimeVec_; + + wptr reversePtr_; + wptr sessionPtr_; + Utils::Timer extTime_ {"backupSchedTimer"}; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_SCHED_SCHEDULER_H diff --git a/services/backup_sa/src/module_ipc/service.cpp b/services/backup_sa/src/module_ipc/service.cpp new file mode 100644 index 0000000000000000000000000000000000000000..830685921a2afdea1070298c0fa72be5069d3a4a --- /dev/null +++ b/services/backup_sa/src/module_ipc/service.cpp @@ -0,0 +1,505 @@ +/* + * 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. + */ + +/* + * 注意: + * - 注意点1:本文件原则上只处理与IPC无关的业务逻辑 + * - 注意点2:This document, in principle, captures all exceptions. + * Prevent exceptions from spreading to insecure modules. + */ +#include "module_ipc/service.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ability_manager_client.h" +#include "accesstoken_kit.h" +#include "b_error/b_error.h" +#include "b_file_info.h" +#include "b_json/b_json_cached_entity.h" +#include "b_json/b_json_entity_caps.h" +#include "b_process/b_multiuser.h" +#include "b_process/b_process.h" +#include "b_resources/b_constants.h" +#include "bundle_mgr_client.h" +#include "directory_ex.h" +#include "filemgmt_libhilog.h" +#include "ipc_skeleton.h" +#include "module_ipc/svc_backup_connection.h" +#include "parameter.h" +#include "system_ability_definition.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +REGISTER_SYSTEM_ABILITY_BY_ID(Service, FILEMANAGEMENT_BACKUP_SERVICE_SA_ID, false); + +void Service::OnStart() +{ + bool res = SystemAbility::Publish(sptr(this)); + sched_ = sptr(new SchedScheduler(wptr(this), wptr(session_))); + sched_->StartTimer(); + HILOGI("End, res = %{public}d", res); +} + +void Service::OnStop() +{ + HILOGI("Called"); + sched_ = nullptr; + session_ = nullptr; +} + +UniqueFd Service::GetLocalCapabilities() +{ + try { + struct statfs fsInfo = {}; + if (statfs(BConstants::SA_BUNDLE_BACKUP_ROOT_DIR.data(), &fsInfo) == -1) { + throw BError(errno); + } + + BJsonCachedEntity cachedEntity( + UniqueFd(open(BConstants::SA_BUNDLE_BACKUP_ROOT_DIR.data(), O_TMPFILE | O_RDWR, 0600))); + auto cache = cachedEntity.Structuralize(); + cache.SetFreeDiskSpace(fsInfo.f_bfree); + cache.SetOSFullName(GetOSFullName()); + cache.SetDeviceType(GetDeviceType()); + cachedEntity.Persist(); + + return move(cachedEntity.GetFd()); + } catch (const BError &e) { + return UniqueFd(-e.GetCode()); + } catch (const exception &e) { + HILOGE("Catched an unexpected low-level exception %{public}s", e.what()); + return UniqueFd(-EPERM); + } catch (...) { + HILOGE("Unexpected exception"); + return UniqueFd(-EPERM); + } +} + +void Service::StopAll(const wptr &obj, bool force) +{ + session_->Deactive(obj, force); +} + +string Service::VerifyCallerAndGetCallerName() +{ + try { + uint32_t tokenCaller = IPCSkeleton::GetCallingTokenID(); + int tokenType = Security::AccessToken::AccessTokenKit::GetTokenType(tokenCaller); + if (tokenType == Security::AccessToken::ATokenTypeEnum::TOKEN_HAP) { + Security::AccessToken::HapTokenInfo hapTokenInfo; + if (Security::AccessToken::AccessTokenKit::GetHapTokenInfo(tokenCaller, hapTokenInfo) != 0) { + throw BError(BError::Codes::SA_INVAL_ARG, "Get hap token info failed"); + } + session_->VerifyBundleName(hapTokenInfo.bundleName); + return hapTokenInfo.bundleName; + } else { + throw BError(BError::Codes::SA_INVAL_ARG, string("Invalid token type ").append(to_string(tokenType))); + } + } catch (const BError &e) { + return ""; + } catch (const exception &e) { + HILOGE("Catched an unexpected low-level exception %{public}s", e.what()); + return ""; + } catch (...) { + HILOGE("Unexpected exception"); + return ""; + } +} + +ErrCode Service::InitRestoreSession(sptr remote, const vector &bundleNames) +{ + try { + map backupExtNameMap; + auto setbackupExtNameMap = [](const BundleName &bundleName) { + BackupExtInfo info {}; + return make_pair(bundleName, info); + }; + transform(bundleNames.begin(), bundleNames.end(), inserter(backupExtNameMap, backupExtNameMap.end()), + setbackupExtNameMap); + session_->Active({ + .clientToken = IPCSkeleton::GetCallingTokenID(), + .scenario = IServiceReverse::Scenario::RESTORE, + .backupExtNameMap = move(backupExtNameMap), + .clientProxy = remote, + }); + return BError(BError::Codes::OK); + } catch (const BError &e) { + StopAll(nullptr, true); + return e.GetCode(); + } catch (const exception &e) { + HILOGE("Catched an unexpected low-level exception %{public}s", e.what()); + return EPERM; + } catch (...) { + HILOGE("Unexpected exception"); + return EPERM; + } +} + +ErrCode Service::InitBackupSession(sptr remote, UniqueFd fd, const vector &bundleNames) +{ + try { + map backupExtNameMap; + auto setbackupExtNameMap = [](const BundleName &bundleName) { + BackupExtInfo info {}; + return make_pair(bundleName, info); + }; + transform(bundleNames.begin(), bundleNames.end(), inserter(backupExtNameMap, backupExtNameMap.end()), + setbackupExtNameMap); + session_->Active({ + .clientToken = IPCSkeleton::GetCallingTokenID(), + .scenario = IServiceReverse::Scenario::BACKUP, + .backupExtNameMap = move(backupExtNameMap), + .clientProxy = remote, + }); + + BJsonCachedEntity cachedEntity(move(fd)); + auto cache = cachedEntity.Structuralize(); + uint64_t size = cache.GetFreeDiskSpace(); + if (size == 0) { + throw BError(BError::Codes::SA_INVAL_ARG, "Invalid field FreeDiskSpace or unsufficient space"); + } + return BError(BError::Codes::OK); + } catch (const BError &e) { + StopAll(nullptr, true); + return e.GetCode(); + } +} + +ErrCode Service::Start() +{ + try { + HILOGE("begin"); + for (int num = 0; num < BConstants::EXT_CONNECT_MAX_COUNT; num++) { + sched_->Sched(); + } + return BError(BError::Codes::OK); + } catch (const BError &e) { + return e.GetCode(); + } catch (const exception &e) { + HILOGE("Catched an unexpected low-level exception %{public}s", e.what()); + return EPERM; + } catch (...) { + HILOGE("Unexpected exception"); + return EPERM; + } +} + +ErrCode Service::PublishFile(const BFileInfo &fileInfo) +{ + try { + HILOGE("begin"); + session_->VerifyCallerAndScenario(IPCSkeleton::GetCallingTokenID(), IServiceReverse::Scenario::RESTORE); + + if (!regex_match(fileInfo.fileName, regex("^[0-9a-zA-Z_.]+$"))) { + throw BError(BError::Codes::SA_INVAL_ARG, "Filename is not alphanumeric"); + } + + auto backUpConnection = session_->GetExtConnection(fileInfo.owner); + + auto proxy = backUpConnection->GetBackupExtProxy(); + if (!proxy) { + throw BError(BError::Codes::SA_INVAL_ARG, "Extension backup Proxy is empty"); + } + ErrCode res = proxy->PublishFile(fileInfo.fileName); + if (res) { + HILOGE("Failed to publish file for backup extension"); + } + + return BError(BError::Codes::OK); + } catch (const BError &e) { + return e.GetCode(); + } catch (const exception &e) { + HILOGE("Catched an unexpected low-level exception %{public}s", e.what()); + return EPERM; + } catch (...) { + HILOGE("Unexpected exception"); + return EPERM; + } +} + +ErrCode Service::AppFileReady(const string &fileName, UniqueFd fd) +{ + try { + HILOGE("begin %{public}s", fileName.data()); + string callerName = VerifyCallerAndGetCallerName(); + if (!regex_match(fileName, regex("^[0-9a-zA-Z_.]+$"))) { + throw BError(BError::Codes::SA_INVAL_ARG, "Filename is not alphanumeric"); + } + if (fileName == BConstants::EXT_BACKUP_MANAGE) { + fd = session_->OnBunleExtManageInfo(callerName, move(fd)); + } + + session_->GetServiceReverseProxy()->BackupOnFileReady(callerName, fileName, move(fd)); + + if (session_->OnBunleFileReady(callerName, fileName)) { + auto backUpConnection = session_->GetExtConnection(callerName); + auto proxy = backUpConnection->GetBackupExtProxy(); + if (!proxy) { + throw BError(BError::Codes::SA_INVAL_ARG, "Extension backup Proxy is empty"); + } + // 通知extension清空缓存 + proxy->HandleClear(); + // 通知TOOL 备份完成 + session_->GetServiceReverseProxy()->BackupOnBundleFinished(BError(BError::Codes::OK), callerName); + // 断开extension + backUpConnection->DisconnectBackupExtAbility(); + ClearSessionAndSchedInfo(callerName); + } + return BError(BError::Codes::OK); + } catch (const BError &e) { + return e.GetCode(); // 任意异常产生,终止监听该任务 + } catch (const exception &e) { + HILOGE("Catched an unexpected low-level exception %{public}s", e.what()); + return EPERM; + } catch (...) { + HILOGE("Unexpected exception"); + return EPERM; + } +} + +ErrCode Service::AppDone(ErrCode errCode) +{ + try { + HILOGE("begin"); + string callerName = VerifyCallerAndGetCallerName(); + if (session_->OnBunleFileReady(callerName)) { + auto backUpConnection = session_->GetExtConnection(callerName); + auto proxy = backUpConnection->GetBackupExtProxy(); + if (!proxy) { + throw BError(BError::Codes::SA_INVAL_ARG, "Extension backup Proxy is empty"); + } + proxy->HandleClear(); + IServiceReverse::Scenario scenario = session_->GetScenario(); + if (scenario == IServiceReverse::Scenario::BACKUP) { + session_->GetServiceReverseProxy()->BackupOnBundleFinished(errCode, callerName); + } else if (scenario == IServiceReverse::Scenario::RESTORE) { + session_->GetServiceReverseProxy()->RestoreOnBundleFinished(errCode, callerName); + } + backUpConnection->DisconnectBackupExtAbility(); + ClearSessionAndSchedInfo(callerName); + } + return BError(BError::Codes::OK); + } catch (const BError &e) { + return e.GetCode(); // 任意异常产生,终止监听该任务 + } catch (const exception &e) { + HILOGE("Catched an unexpected low-level exception %{public}s", e.what()); + return EPERM; + } catch (...) { + HILOGE("Unexpected exception"); + return EPERM; + } +} + +ErrCode Service::LaunchBackupExtension(const BundleName &bundleName) +{ + try { + HILOGE("begin %{public}s", bundleName.data()); + IServiceReverse::Scenario scenario = session_->GetScenario(); + BConstants::ExtensionAction action; + if (scenario == IServiceReverse::Scenario::BACKUP) { + action = BConstants::ExtensionAction::BACKUP; + } else if (scenario == IServiceReverse::Scenario::RESTORE) { + action = BConstants::ExtensionAction::RESTORE; + } else { + throw BError(BError::Codes::SA_INVAL_ARG, "Failed to scenario"); + } + + AAFwk::Want want; + string backupExtName = session_->GetBackupExtName(bundleName); + want.SetElementName(bundleName, backupExtName); + want.SetParam(BConstants::EXTENSION_ACTION_PARA, static_cast(action)); + + auto backUpConnection = session_->GetExtConnection(bundleName); + ErrCode ret = backUpConnection->ConnectBackupExtAbility(want); + return ret; + } catch (const BError &e) { + return e.GetCode(); + } catch (const exception &e) { + HILOGE("Catched an unexpected low-level exception %{public}s", e.what()); + return EPERM; + } catch (...) { + HILOGE("Unexpected exception"); + return EPERM; + } +} + +ErrCode Service::GetExtFileName(string &bundleName, string &fileName) +{ + try { + HILOGE("begin"); + session_->VerifyCallerAndScenario(IPCSkeleton::GetCallingTokenID(), IServiceReverse::Scenario::RESTORE); + session_->SetExtFileNameRequest(bundleName, fileName); + return BError(BError::Codes::OK); + } catch (const BError &e) { + return e.GetCode(); + } catch (const exception &e) { + HILOGE("Catched an unexpected low-level exception %{public}s", e.what()); + return EPERM; + } catch (...) { + HILOGE("Unexpected exception"); + return EPERM; + } +} + +void Service::OnBackupExtensionDied(const string &&bundleName, ErrCode ret) +{ + try { + HILOGI("extension died. Died bundleName = %{public}s", bundleName.data()); + string callName = move(bundleName); + session_->VerifyBundleName(callName); + auto scenario = session_->GetScenario(); + if (scenario == IServiceReverse::Scenario::BACKUP) { + session_->GetServiceReverseProxy()->BackupOnBundleFinished(ret, callName); + } else if (scenario == IServiceReverse::Scenario::RESTORE) { + session_->GetServiceReverseProxy()->RestoreOnBundleFinished(ret, callName); + } + auto backUpConnection = session_->GetExtConnection(callName); + if (backUpConnection->IsExtAbilityConnected()) { + backUpConnection->DisconnectBackupExtAbility(); + } + ClearSessionAndSchedInfo(bundleName); + } catch (const BError &e) { + return; + } catch (const exception &e) { + HILOGE("Catched an unexpected low-level exception %{public}s", e.what()); + return; + } catch (...) { + HILOGE("Unexpected exception"); + return; + } +} + +void Service::ExtStart(const string &bundleName) +{ + try { + HILOGE("begin %{public}s", bundleName.data()); + IServiceReverse::Scenario scenario = session_->GetScenario(); + auto backUpConnection = session_->GetExtConnection(bundleName); + auto proxy = backUpConnection->GetBackupExtProxy(); + if (!proxy) { + throw BError(BError::Codes::SA_INVAL_ARG, "Extension backup Proxy is empty"); + } + if (scenario == IServiceReverse::Scenario::BACKUP) { + auto ret = proxy->HandleBackup(); + session_->GetServiceReverseProxy()->BackupOnBundleStarted(ret, bundleName); + if (ret) { + ClearSessionAndSchedInfo(bundleName); + } + return; + } + if (scenario != IServiceReverse::Scenario::RESTORE) { + throw BError(BError::Codes::SA_INVAL_ARG, "Failed to scenario"); + } + session_->GetServiceReverseProxy()->RestoreOnBundleStarted(BError(BError::Codes::OK), bundleName); + auto fileNameVec = session_->GetExtFileNameRequest(bundleName); + for (auto &fileName : fileNameVec) { + UniqueFd fd = proxy->GetFileHandle(fileName); + if (fd < 0) { + HILOGE("Failed to extension file handle"); + OnBackupExtensionDied(move(bundleName), fd); + return; + } + session_->GetServiceReverseProxy()->RestoreOnFileReady(bundleName, fileName, move(fd)); + } + return; + } catch (const BError &e) { + return; + } catch (const exception &e) { + HILOGE("Catched an unexpected low-level exception %{public}s", e.what()); + return; + } catch (...) { + HILOGE("Unexpected exception"); + return; + } +} + +int Service::Dump(int fd, const vector &args) +{ + if (fd < 0) { + HILOGI("HiDumper handle invalid"); + return -1; + } + + session_->DumpInfo(fd, args); + return 0; +} + +void Service::ExtConnectFailed(const string &bundleName, ErrCode ret) +{ + try { + HILOGE("begin %{public}s", bundleName.data()); + IServiceReverse::Scenario scenario = session_->GetScenario(); + if (scenario == IServiceReverse::Scenario::BACKUP) { + session_->GetServiceReverseProxy()->BackupOnBundleStarted(ret, bundleName); + } else if (scenario == IServiceReverse::Scenario::RESTORE) { + session_->GetServiceReverseProxy()->RestoreOnBundleStarted(ret, bundleName); + } + ClearSessionAndSchedInfo(bundleName); + return; + } catch (const BError &e) { + return; + } catch (const exception &e) { + HILOGE("Catched an unexpected low-level exception %{public}s", e.what()); + return; + } catch (...) { + HILOGE("Unexpected exception"); + return; + } +} + +void Service::ExtConnectDone(string bundleName) +{ + try { + HILOGE("begin %{public}s", bundleName.data()); + session_->SetServiceSchedAction(bundleName, BConstants::ServiceSchedAction::RUNNING); + sched_->Sched(bundleName); + } catch (const BError &e) { + return; + } catch (const exception &e) { + HILOGE("Catched an unexpected low-level exception %{public}s", e.what()); + return; + } catch (...) { + HILOGE("Unexpected exception"); + return; + } +} + +void Service::ClearSessionAndSchedInfo(const string &bundleName) +{ + try { + session_->RemoveExtInfo(bundleName); + sched_->RemoveExtConn(bundleName); + sched_->Sched(); + } catch (const BError &e) { + return; + } catch (const exception &e) { + HILOGE("Catched an unexpected low-level exception %{public}s", e.what()); + return; + } catch (...) { + HILOGE("Unexpected exception"); + return; + } +} +} // namespace OHOS::FileManagement::Backup diff --git a/services/backup_sa/src/module_ipc/service_reverse_proxy.cpp b/services/backup_sa/src/module_ipc/service_reverse_proxy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e7563302c234cb72e223dce0902d09fc7704d0b6 --- /dev/null +++ b/services/backup_sa/src/module_ipc/service_reverse_proxy.cpp @@ -0,0 +1,153 @@ +/* + * 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 "module_ipc/service_reverse_proxy.h" + +#include "b_error/b_error.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +void ServiceReverseProxy::BackupOnFileReady(string bundleName, string fileName, int fd) +{ + HILOGI("Begin"); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor()) || !data.WriteString(bundleName) || !data.WriteString(fileName) || + !data.WriteFileDescriptor(fd)) { + throw BError(BError::Codes::SA_BROKEN_IPC); + } + + MessageParcel reply; + MessageOption option; + if (int err = Remote()->SendRequest(IServiceReverse::SERVICER_BACKUP_ON_FILE_READY, data, reply, option); + err != ERR_OK) { + throw BError(BError::Codes::SA_BROKEN_IPC, to_string(err)); + } +} + +void ServiceReverseProxy::BackupOnBundleStarted(int32_t errCode, string bundleName) +{ + HILOGI("Begin"); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor()) || !data.WriteInt32(errCode) || !data.WriteString(bundleName)) { + throw BError(BError::Codes::SA_BROKEN_IPC); + }; + + MessageParcel reply; + MessageOption option; + if (int err = Remote()->SendRequest(IServiceReverse::SERVICER_BACKUP_ON_SUB_TASK_STARTED, data, reply, option); + err != ERR_OK) { + throw BError(BError::Codes::SA_BROKEN_IPC, to_string(err)); + } +} + +void ServiceReverseProxy::BackupOnBundleFinished(int32_t errCode, string bundleName) +{ + HILOGI("Begin"); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor()) || !data.WriteInt32(errCode) || !data.WriteString(bundleName)) { + throw BError(BError::Codes::SA_BROKEN_IPC); + } + + MessageParcel reply; + MessageOption option; + if (int err = Remote()->SendRequest(IServiceReverse::SERVICER_BACKUP_ON_SUB_TASK_FINISHED, data, reply, option); + err != ERR_OK) { + throw BError(BError::Codes::SA_BROKEN_IPC, to_string(err)); + } +} + +void ServiceReverseProxy::BackupOnAllBundlesFinished(int32_t errCode) +{ + HILOGI("Begin"); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor()) || !data.WriteInt32(errCode)) { + throw BError(BError::Codes::SA_BROKEN_IPC); + } + + MessageParcel reply; + MessageOption option; + if (int err = Remote()->SendRequest(IServiceReverse::SERVICER_BACKUP_ON_TASK_FINISHED, data, reply, option); + err != ERR_OK) { + throw BError(BError::Codes::SA_BROKEN_IPC, to_string(err)); + } +} + +void ServiceReverseProxy::RestoreOnBundleStarted(int32_t errCode, string bundleName) +{ + HILOGI("Begin"); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor()) || !data.WriteInt32(errCode) || !data.WriteString(bundleName)) { + throw BError(BError::Codes::SA_BROKEN_IPC); + } + + MessageParcel reply; + MessageOption option; + if (int err = Remote()->SendRequest(IServiceReverse::SERVICER_RESTORE_ON_SUB_TASK_STARTED, data, reply, option); + err != ERR_OK) { + throw BError(BError::Codes::SA_BROKEN_IPC, to_string(err)); + } +} + +void ServiceReverseProxy::RestoreOnBundleFinished(int32_t errCode, string bundleName) +{ + HILOGI("Begin"); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor()) || !data.WriteInt32(errCode) || !data.WriteString(bundleName)) { + throw BError(BError::Codes::SA_BROKEN_IPC); + } + + MessageParcel reply; + MessageOption option; + if (int err = Remote()->SendRequest(IServiceReverse::SERVICER_RESTORE_ON_SUB_TASK_FINISHED, data, reply, option); + err != ERR_OK) { + throw BError(BError::Codes::SA_BROKEN_IPC, to_string(err)); + } +} + +void ServiceReverseProxy::RestoreOnAllBundlesFinished(int32_t errCode) +{ + HILOGI("Begin"); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor()) || !data.WriteInt32(errCode)) { + throw BError(BError::Codes::SA_BROKEN_IPC); + } + + MessageParcel reply; + MessageOption option; + if (int err = Remote()->SendRequest(IServiceReverse::SERVICER_RESTORE_ON_TASK_FINISHED, data, reply, option); + err != ERR_OK) { + throw BError(BError::Codes::SA_BROKEN_IPC, to_string(err)); + } +} + +void ServiceReverseProxy::RestoreOnFileReady(string bundleName, string fileName, int fd) +{ + HILOGI("Begin"); + MessageParcel data; + if (!data.WriteInterfaceToken(GetDescriptor()) || !data.WriteString(bundleName) || !data.WriteString(fileName) || + !data.WriteFileDescriptor(fd)) { + throw BError(BError::Codes::SA_BROKEN_IPC); + } + + MessageParcel reply; + MessageOption option; + if (int err = Remote()->SendRequest(IServiceReverse::SERVICER_RESTORE_ON_FILE_READY, data, reply, option); + err != ERR_OK) { + throw BError(BError::Codes::SA_BROKEN_IPC, to_string(err)); + } +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/services/backup_sa/src/module_ipc/service_stub.cpp b/services/backup_sa/src/module_ipc/service_stub.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bd9740d2faf03c924c9e4fa745ff002c5d2bdbba --- /dev/null +++ b/services/backup_sa/src/module_ipc/service_stub.cpp @@ -0,0 +1,209 @@ +/* + * 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. + */ + +/* + * 注意: + * - 注意点1:本文件原则上只处理与IPC模块的IO,具体业务逻辑实现在service.cpp中 + * - 注意点2:所有调用开头处打印 Begin 字样,通过BError返回正常结果/错误码,这是出于防抵赖的目的 + */ + +#include "module_ipc/service_stub.h" + +#include + +#include "b_error/b_error.h" +#include "filemgmt_libhilog.h" +#include "module_ipc/service_reverse_proxy.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +ServiceStub::ServiceStub() +{ + opToInterfaceMap_[SERVICE_CMD_INIT_RESTORE_SESSION] = &ServiceStub::CmdInitRestoreSession; + opToInterfaceMap_[SERVICE_CMD_INIT_BACKUP_SESSION] = &ServiceStub::CmdInitBackupSession; + opToInterfaceMap_[SERVICE_CMD_GET_LOCAL_CAPABILITIES] = &ServiceStub::CmdGetLocalCapabilities; + opToInterfaceMap_[SERVICE_CMD_PUBLISH_FILE] = &ServiceStub::CmdPublishFile; + opToInterfaceMap_[SERVICE_CMD_APP_FILE_READY] = &ServiceStub::CmdAppFileReady; + opToInterfaceMap_[SERVICE_CMD_APP_DONE] = &ServiceStub::CmdAppDone; + opToInterfaceMap_[SERVICE_CMD_START] = &ServiceStub::CmdStart; + opToInterfaceMap_[SERVICE_CMD_GET_EXT_FILE_NAME] = &ServiceStub::CmdGetExtFileName; +} + +int32_t ServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + HILOGI("Begin to call procedure indexed %{public}u", code); + auto interfaceIndex = opToInterfaceMap_.find(code); + if (interfaceIndex == opToInterfaceMap_.end() || !interfaceIndex->second) { + stringstream ss; + ss << "Cannot response request " << code << ": unknown procedure"; + return BError(BError::Codes::SA_INVAL_ARG, ss.str()); + } + + const std::u16string descriptor = ServiceStub::GetDescriptor(); + const std::u16string remoteDescriptor = data.ReadInterfaceToken(); + if (descriptor != remoteDescriptor) { + return BError(BError::Codes::SA_INVAL_ARG, "Invalid remote descriptor"); + } + + return (this->*(interfaceIndex->second))(data, reply); +} + +int32_t ServiceStub::CmdInitRestoreSession(MessageParcel &data, MessageParcel &reply) +{ + HILOGE("Begin"); + auto remote = data.ReadRemoteObject(); + if (!remote) { + return BError(BError::Codes::SA_INVAL_ARG, "Failed to receive the reverse stub"); + } + auto iremote = iface_cast(remote); + if (!iremote) { + return BError(BError::Codes::SA_INVAL_ARG, "Failed to receive the reverse stub"); + } + + std::vector bundleNames; + if (!data.ReadStringVector(&bundleNames)) { + return BError(BError::Codes::SA_INVAL_ARG, "Failed to receive bundleNames"); + } + + int32_t res = InitRestoreSession(iremote, bundleNames); + if (!reply.WriteInt32(res)) { + stringstream ss; + ss << "Failed to send the result " << res; + return BError(BError::Codes::SA_BROKEN_IPC, ss.str()); + } + return BError(BError::Codes::OK); +} + +int32_t ServiceStub::CmdInitBackupSession(MessageParcel &data, MessageParcel &reply) +{ + HILOGE("Begin"); + auto remote = data.ReadRemoteObject(); + if (!remote) { + return BError(BError::Codes::SA_INVAL_ARG, "Failed to receive the reverse stub"); + } + auto iremote = iface_cast(remote); + if (!remote) { + return BError(BError::Codes::SA_INVAL_ARG, "Failed to receive the reverse stub"); + } + + UniqueFd fd(data.ReadFileDescriptor()); + if (fd < 0) { + return BError(BError::Codes::SA_INVAL_ARG, "Failed to receive fd"); + } + + std::vector bundleNames; + if (!data.ReadStringVector(&bundleNames)) { + return BError(BError::Codes::SA_INVAL_ARG, "Failed to receive bundleNames"); + } + + int res = InitBackupSession(iremote, move(fd), bundleNames); + if (!reply.WriteInt32(res)) { + stringstream ss; + ss << "Failed to send the result " << res; + return BError(BError::Codes::SA_BROKEN_IPC, ss.str()); + } + return BError(BError::Codes::OK); +} + +int32_t ServiceStub::CmdStart(MessageParcel &data, MessageParcel &reply) +{ + int res = Start(); + if (!reply.WriteInt32(res)) { + stringstream ss; + ss << "Failed to send the result " << res; + return BError(BError::Codes::SA_BROKEN_IPC, ss.str()); + } + return BError(BError::Codes::OK); +} + +int32_t ServiceStub::CmdGetLocalCapabilities(MessageParcel &data, MessageParcel &reply) +{ + HILOGE("Begin"); + UniqueFd fd(GetLocalCapabilities()); + if (!reply.WriteFileDescriptor(fd)) { + return BError(BError::Codes::SA_BROKEN_IPC, "Failed to send out the file"); + } + return BError(BError::Codes::OK); +} + +int32_t ServiceStub::CmdPublishFile(MessageParcel &data, MessageParcel &reply) +{ + HILOGE("Begin"); + unique_ptr fileInfo(data.ReadParcelable()); + if (!fileInfo) { + return BError(BError::Codes::SA_BROKEN_IPC, "Failed to receive fileInfo"); + } + int res = PublishFile(*fileInfo); + if (!reply.WriteInt32(res)) { + stringstream ss; + ss << "Failed to send the result " << res; + return BError(BError::Codes::SA_BROKEN_IPC, ss.str()); + } + return BError(BError::Codes::OK); +} + +int32_t ServiceStub::CmdAppFileReady(MessageParcel &data, MessageParcel &reply) +{ + HILOGE("Begin"); + string fileName; + if (!data.ReadString(fileName)) { + return BError(BError::Codes::SA_INVAL_ARG, "Failed to receive fileName"); + } + UniqueFd fd(data.ReadFileDescriptor()); + if (fd < 0) { + return BError(BError::Codes::SA_INVAL_ARG, "Failed to receive fd"); + } + + int res = AppFileReady(fileName, move(fd)); + if (!reply.WriteInt32(res)) { + stringstream ss; + ss << "Failed to send the result " << res; + return BError(BError::Codes::SA_BROKEN_IPC, ss.str()); + } + return BError(BError::Codes::OK); +} + +int32_t ServiceStub::CmdAppDone(MessageParcel &data, MessageParcel &reply) +{ + HILOGE("Begin"); + bool success; + if (!data.ReadBool(success)) { + return BError(BError::Codes::SA_INVAL_ARG, "Failed to receive bool flag"); + } + int res = AppDone(success); + if (!reply.WriteInt32(res)) { + stringstream ss; + ss << "Failed to send the result " << res; + return BError(BError::Codes::SA_BROKEN_IPC, ss.str()); + } + return BError(BError::Codes::OK); +} + +int32_t ServiceStub::CmdGetExtFileName(MessageParcel &data, MessageParcel &reply) +{ + HILOGE("Begin"); + string bundleName; + if (!data.ReadString(bundleName)) { + return BError(BError::Codes::SA_INVAL_ARG, "Failed to receive bundleName").GetCode(); + } + string fileName; + if (!data.ReadString(fileName)) { + return BError(BError::Codes::SA_INVAL_ARG, "Failed to receive fileName").GetCode(); + } + + return GetExtFileName(bundleName, fileName); +} +} // namespace OHOS::FileManagement::Backup diff --git a/services/backup_sa/src/module_ipc/svc_backup_connection.cpp b/services/backup_sa/src/module_ipc/svc_backup_connection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3d3266e59074580cf007d1051e32141933e82821 --- /dev/null +++ b/services/backup_sa/src/module_ipc/svc_backup_connection.cpp @@ -0,0 +1,101 @@ +/* + * 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 "module_ipc/svc_backup_connection.h" + +#include "ability_manager_client.h" +#include "filemgmt_libhilog.h" +#include "module_ipc/svc_extension_proxy.h" +#include "module_ipc/svc_session_manager.h" + +namespace OHOS::FileManagement::Backup { +constexpr int WAIT_TIME = 3; +using namespace std; + +void SvcBackupConnection::OnAbilityConnectDone(const AppExecFwk::ElementName &element, + const sptr &remoteObject, + int resultCode) +{ + HILOGI("called begin"); + if (remoteObject == nullptr) { + HILOGE("Failed to ability connect done, remote is nullptr"); + return; + } + backupProxy_ = iface_cast(remoteObject); + if (backupProxy_ == nullptr) { + HILOGE("Failed to ability connect done, backupProxy_ is nullptr"); + return; + } + isConnected_.store(true); + string bundleName = element.GetBundleName(); + callConnDone_(move(bundleName)); + HILOGI("called end"); +} + +void SvcBackupConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) +{ + HILOGI("called begin"); + if (isConnectedDone_ == false) { + string bundleName = element.GetBundleName(); + HILOGE("It's error that the backup extension dies before the backup sa. name : %{public}s", bundleName.data()); + callDied_(move(bundleName)); + } + backupProxy_ = nullptr; + isConnected_.store(false); + condition_.notify_all(); + HILOGI("called end"); +} + +ErrCode SvcBackupConnection::ConnectBackupExtAbility(AAFwk::Want &want) +{ + HILOGI("called begin"); + std::unique_lock lock(mutex_); + ErrCode ret = + AAFwk::AbilityManagerClient::GetInstance()->ConnectAbility(want, this, AppExecFwk::Constants::START_USERID); + HILOGI("called end, ret=%{public}d", ret); + return ret; +} + +ErrCode SvcBackupConnection::DisconnectBackupExtAbility() +{ + HILOGI("called begin"); + isConnectedDone_.store(true); + std::unique_lock lock(mutex_); + ErrCode ret = AppExecFwk::AbilityManagerClient::GetInstance()->DisconnectAbility(this); + auto callback = [extConn {wptr(this)}] { + auto extPtr = extConn.promote(); + if (!extPtr) { + HILOGE("Dis connect failed"); + return false; + } + return extPtr->GetBackupExtProxy() == nullptr; + }; + if (condition_.wait_for(lock, std::chrono::seconds(WAIT_TIME), callback)) { + HILOGI("Wait until the connection ends"); + } + HILOGI("called end, ret=%{public}d", ret); + return ret; +} + +bool SvcBackupConnection::IsExtAbilityConnected() +{ + return isConnected_.load(); +} + +sptr SvcBackupConnection::GetBackupExtProxy() +{ + return backupProxy_; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/services/backup_sa/src/module_ipc/svc_extension_proxy.cpp b/services/backup_sa/src/module_ipc/svc_extension_proxy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ad2ab501154303458b5a506ee69fb7ff0cdc95d7 --- /dev/null +++ b/services/backup_sa/src/module_ipc/svc_extension_proxy.cpp @@ -0,0 +1,108 @@ +/* + * 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 "module_ipc/svc_extension_proxy.h" + +#include "b_error/b_error.h" +#include "filemgmt_libhilog.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +UniqueFd SvcExtensionProxy::GetFileHandle(const string &fileName) +{ + HILOGI("Start"); + MessageParcel data; + data.WriteInterfaceToken(GetDescriptor()); + + if (!data.WriteString(fileName)) { + BError(BError::Codes::SDK_INVAL_ARG, "Failed to send the fileName"); + return UniqueFd(-1); + } + + MessageParcel reply; + MessageOption option; + int32_t ret = Remote()->SendRequest(IExtension::CMD_GET_FILE_HANDLE, data, reply, option); + if (ret != NO_ERROR) { + HILOGE("Received error %{public}d when doing IPC", ret); + return UniqueFd(-ret); + } + + HILOGI("Successful"); + UniqueFd fd(reply.ReadFileDescriptor()); + return fd; +} + +ErrCode SvcExtensionProxy::HandleClear() +{ + HILOGI("Start"); + MessageParcel data; + data.WriteInterfaceToken(GetDescriptor()); + + MessageParcel reply; + MessageOption option; + int32_t ret = Remote()->SendRequest(IExtension::CMD_HANDLE_CLAER, data, reply, option); + if (ret != NO_ERROR) { + HILOGE("Received error %{public}d when doing IPC", ret); + return ErrCode(ret); + } + + HILOGI("Successful"); + return reply.ReadInt32(); +} + +ErrCode SvcExtensionProxy::HandleBackup() +{ + HILOGI("Start"); + MessageParcel data; + data.WriteInterfaceToken(GetDescriptor()); + + MessageParcel reply; + MessageOption option; + int32_t ret = Remote()->SendRequest(IExtension::CMD_HANDLE_BACKUP, data, reply, option); + if (ret != NO_ERROR) { + HILOGE("Received error %{public}d when doing IPC", ret); + return ErrCode(ret); + } + + HILOGI("Successful"); + return reply.ReadInt32(); +} + +ErrCode SvcExtensionProxy::PublishFile(const string &fileName) +{ + HILOGI("Start"); + MessageParcel data; + data.WriteInterfaceToken(GetDescriptor()); + + if (!data.WriteString(fileName)) { + BError(BError::Codes::SDK_INVAL_ARG, "Failed to send the fileName"); + return ErrCode(EPERM); + } + + MessageParcel reply; + MessageOption option; + int32_t ret = Remote()->SendRequest(IExtension::CMD_PUBLISH_FILE, data, reply, option); + if (ret != NO_ERROR) { + HILOGE("Received error %{public}d when doing IPC", ret); + return ErrCode(ret); + } + + HILOGI("Successful"); + return reply.ReadInt32(); +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/services/backup_sa/src/module_ipc/svc_session_manager.cpp b/services/backup_sa/src/module_ipc/svc_session_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c317c75ad13a501a692589c96828a689ad7b37fa --- /dev/null +++ b/services/backup_sa/src/module_ipc/svc_session_manager.cpp @@ -0,0 +1,432 @@ +/* + * 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 "module_ipc/svc_session_manager.h" + +#include +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "b_json/b_json_entity_ext_manage.h" +#include "b_json/b_json_entity_extension_config.h" +#include "b_resources/b_constants.h" +#include "bundle_mgr_client.h" +#include "filemgmt_libhilog.h" +#include "module_ipc/service.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + + +namespace OHOS::FileManagement::Backup { +using namespace std; + +void SvcSessionManager::VerifyCallerAndScenario(uint32_t clientToken, IServiceReverse::Scenario scenario) const +{ + shared_lock lock(lock_); + if (impl_.scenario != scenario) { + throw BError(BError::Codes::SDK_MIXED_SCENARIO); + } + if (impl_.clientToken != clientToken) { + throw BError(BError::Codes::SA_REFUSED_ACT, "Caller mismatched"); + } + HILOGE("Succeed to verify the caller"); +} + +void SvcSessionManager::Active(Impl newImpl) +{ + unique_lock lock(lock_); + Impl &oldImpl = impl_; + if (oldImpl.clientToken) { + throw BError(BError::Codes::SA_REFUSED_ACT, "Already have an active session"); + } + + if (!newImpl.clientToken) { + throw BError(BError::Codes::SA_INVAL_ARG, "No caller token was specified"); + } + if (newImpl.scenario == IServiceReverse::Scenario::UNDEFINED) { + throw BError(BError::Codes::SA_INVAL_ARG, "No scenario was specified"); + } + + GetBundleExtNames(newImpl.backupExtNameMap); + + InitExtConn(newImpl.backupExtNameMap); + + InitClient(newImpl); + impl_ = newImpl; +} + +void SvcSessionManager::Deactive(const wptr &remoteInAction, bool force) +{ + unique_lock lock(lock_); + if (!impl_.clientToken || !impl_.clientProxy) { + HILOGI("Empty session"); + return; + } + if (!force && (!impl_.clientToken || !impl_.clientProxy)) { + throw BError(BError::Codes::SA_REFUSED_ACT, "Try to deactive an empty session"); + } + auto remoteHeldByProxy = impl_.clientProxy->AsObject(); + if (!force && (remoteInAction != remoteHeldByProxy)) { + throw BError(BError::Codes::SA_INVAL_ARG, "Only the client actived the session can deactive it"); + } + + deathRecipient_ = nullptr; + HILOGI("Succeed to deactive a session. Client token = %{public}u, client proxy = 0x%{private}p", impl_.clientToken, + impl_.clientProxy.GetRefPtr()); + impl_ = {}; + extConnectNum_ = 0; +} + +void SvcSessionManager::VerifyBundleName(string &bundleName) +{ + shared_lock lock(lock_); + if (!impl_.clientToken) { + throw BError(BError::Codes::SA_INVAL_ARG, "No caller token was specified"); + } + auto asVerify = [&bundleName](const auto &it) { return it.first == bundleName; }; + if (none_of(impl_.backupExtNameMap.begin(), impl_.backupExtNameMap.end(), asVerify)) { + stringstream ss; + ss << "Could not find the " << bundleName << " from current session"; + throw BError(BError::Codes::SA_REFUSED_ACT, ss.str()); + } + HILOGE("Succeed to verify the bundleName"); +} + +sptr SvcSessionManager::GetServiceReverseProxy() +{ + unique_lock lock(lock_); + if (!impl_.clientProxy) { + throw BError(BError::Codes::SA_REFUSED_ACT, "Try to deactive an empty session"); + } + return impl_.clientProxy; +} + +IServiceReverse::Scenario SvcSessionManager::GetScenario() +{ + shared_lock lock(lock_); + if (!impl_.clientToken) { + throw BError(BError::Codes::SA_INVAL_ARG, "No caller token was specified"); + } + return impl_.scenario; +} + +void SvcSessionManager::GetBundleExtNames(map &backupExtNameMap) +{ + if (backupExtNameMap.empty()) { + throw BError(BError::Codes::SA_INVAL_ARG, "No app was selected"); + } + + auto bms = GetBundleManager(); + if (!bms) { + throw BError(BError::Codes::SA_BROKEN_IPC, "Bms is invalid"); + } + + for (auto &&it : backupExtNameMap) { + AppExecFwk::BundleInfo installedBundle; + if (!bms->GetBundleInfo(it.first, AppExecFwk::GET_BUNDLE_WITH_EXTENSION_INFO, installedBundle, + AppExecFwk::Constants::START_USERID)) { + throw BError(BError::Codes::SA_BROKEN_IPC, "Failed to get the info of bundle " + it.first); + } + for (auto &&ext : installedBundle.extensionInfos) { + if (ext.type == AppExecFwk::ExtensionAbilityType::BACKUP) { + if (ext.name.empty()) { + throw BError(BError::Codes::SA_INVAL_ARG, "Failed to get ext name of bundle " + it.first); + } + vector out; + AppExecFwk::BundleMgrClient client; + if (!client.GetResConfigFile(ext, "ohos.extension.backup", out) || out.size() == 0) { + throw BError(BError::Codes::SA_INVAL_ARG, "Failed to get resconfigfile of bundle " + it.first); + } + BJsonCachedEntity cachedEntity(out[0], it.first); + auto cache = cachedEntity.Structuralize(); + if (cache.GetAllowToBackupRestore()) { + it.second.backupExtName = ext.name; + } else { + throw BError(BError::Codes::SA_INVAL_ARG, + "Permission denied to get allowToBackupRestore of bundle " + it.first); + } + } + } + } +} + +bool SvcSessionManager::OnBunleFileReady(const string &bundleName, const string &fileName) +{ + unique_lock lock(lock_); + if (!impl_.clientToken) { + throw BError(BError::Codes::SA_INVAL_ARG, "No caller token was specified"); + } + + auto it = impl_.backupExtNameMap.find(bundleName); + if (it == impl_.backupExtNameMap.end()) { + stringstream ss; + ss << "Could not find the " << bundleName << " from current session"; + throw BError(BError::Codes::SA_REFUSED_ACT, ss.str()); + } + + // 判断是否结束 通知EXTENTION清理资源 TOOL应用完成备份 + if (impl_.scenario == IServiceReverse::Scenario::RESTORE) { + return true; + } else if (impl_.scenario == IServiceReverse::Scenario::BACKUP) { + if (!fileName.empty() && fileName != BConstants::EXT_BACKUP_MANAGE) { + auto ret = it->second.fileNameInfo.insert(fileName); + if (!ret.second) { + it->second.fileNameInfo.erase(fileName); + } + } else if (fileName.empty()) { + it->second.receExtAppDone = true; + } + if (it->second.receExtManageJson && it->second.fileNameInfo.empty() && it->second.receExtAppDone) { + return true; + } + } + return false; +} + +UniqueFd SvcSessionManager::OnBunleExtManageInfo(const string &bundleName, UniqueFd fd) +{ + if (!impl_.clientToken) { + throw BError(BError::Codes::SA_INVAL_ARG, "No caller token was specified"); + } + if (impl_.scenario != IServiceReverse::Scenario::BACKUP) { + throw BError(BError::Codes::SA_INVAL_ARG, "Invalid Scenario"); + } + + BJsonCachedEntity cachedEntity(move(fd)); + auto cache = cachedEntity.Structuralize(); + auto info = cache.GetExtManage(); + + for (auto &fileName : info) { + HILOGE("fileName %{public}s", fileName.data()); + OnBunleFileReady(bundleName, fileName); + } + + unique_lock lock(lock_); + auto it = GetBackupExtNameMap(bundleName); + it->second.receExtManageJson = true; + return move(cachedEntity.GetFd()); +} + +void SvcSessionManager::RemoveExtInfo(const string &bundleName) +{ + HILOGE("begin"); + unique_lock lock(lock_); + auto it = impl_.backupExtNameMap.find(bundleName); + if (it == impl_.backupExtNameMap.end()) { + return; + } + impl_.backupExtNameMap.erase(it); + extConnectNum_--; +} + +wptr SvcSessionManager::GetExtConnection(const BundleName &bundleName) +{ + HILOGE("begin"); + shared_lock lock(lock_); + if (!impl_.clientToken) { + throw BError(BError::Codes::SA_INVAL_ARG, "No caller token was specified"); + } + + auto it = GetBackupExtNameMap(bundleName); + if (!it->second.backUpConnection) { + throw BError(BError::Codes::SA_INVAL_ARG, "Svc backup connection is empty"); + } + + return wptr(it->second.backUpConnection); +} + +void SvcSessionManager::InitExtConn(std::map &backupExtNameMap) +{ + HILOGE("begin"); + if (backupExtNameMap.empty()) { + throw BError(BError::Codes::SA_INVAL_ARG, "No app was selected"); + } + + for (auto &&it : backupExtNameMap) { + auto callDied = [revPtr {reversePtr_}](const string &&bundleName) { + auto revPtrStrong = revPtr.promote(); + if (!revPtrStrong) { + // 服务先于客户端死亡是一种异常场景,但该场景对本流程来说也没什么影响,所以只是简单记录一下 + HILOGW("It's curious that the backup sa dies before the backup client"); + return; + } + revPtrStrong->OnBackupExtensionDied(move(bundleName), ESRCH); + }; + + auto callConnDone = [revPtr {reversePtr_}](const string &&bundleName) { + auto revPtrStrong = revPtr.promote(); + if (!revPtrStrong) { + // 服务先于客户端死亡是一种异常场景,但该场景对本流程来说也没什么影响,所以只是简单记录一下 + HILOGW("It's curious that the backup sa dies before the backup client"); + return; + } + revPtrStrong->ExtConnectDone(move(bundleName)); + }; + + auto backUpConnection = sptr(new SvcBackupConnection(callDied, callConnDone)); + it.second.backUpConnection = backUpConnection; + } +} + +void SvcSessionManager::DumpInfo(const int fd, const std::vector &args) +{ + dprintf(fd, "---------------------backup info--------------------\n"); + dprintf(fd, "Scenario: %d\n", impl_.scenario); +} + +void SvcSessionManager::InitClient(Impl &newImpl) +{ + if (!newImpl.clientProxy) { + throw BError(BError::Codes::SA_INVAL_ARG, "Invalid client"); + } + auto remoteObj = newImpl.clientProxy->AsObject(); + if (!remoteObj) { + throw BError(BError::Codes::SA_BROKEN_IPC, "Proxy's remote object can't be nullptr"); + } + + auto callback = [revPtr {reversePtr_}](const wptr &obj) { + HILOGI("Client died. Died remote obj = %{private}p", obj.GetRefPtr()); + + auto revPtrStrong = revPtr.promote(); + if (!revPtrStrong) { + // 服务先于客户端死亡是一种异常场景,但该场景对本流程来说也没什么影响,所以只是简单记录一下 + HILOGW("It's curious that the backup sa dies before the backup client"); + return; + } + (void)revPtrStrong->StopAll(obj); + }; + deathRecipient_ = sptr(new SvcDeathRecipient(callback)); + remoteObj->AddDeathRecipient(deathRecipient_); + HILOGI( + "Succeed to active a session." + "Client token = %{public}u, client proxy = 0x%{private}p, remote obj = 0x%{private}p", + impl_.clientToken, impl_.clientProxy.GetRefPtr(), remoteObj.GetRefPtr()); +} + +void SvcSessionManager::SetExtFileNameRequest(const string &bundleName, const string &fileName) +{ + HILOGE("begin"); + unique_lock lock(lock_); + if (!impl_.clientToken) { + throw BError(BError::Codes::SA_INVAL_ARG, "No caller token was specified"); + } + + auto it = GetBackupExtNameMap(bundleName); + it->second.fileNameInfo.insert(fileName); +} + +std::set SvcSessionManager::GetExtFileNameRequest(const std::string &bundleName) +{ + HILOGE("start"); + shared_lock lock(lock_); + if (!impl_.clientToken) { + throw BError(BError::Codes::SA_INVAL_ARG, "No caller token was specified"); + } + + if (impl_.scenario != IServiceReverse::Scenario::RESTORE) { + throw BError(BError::Codes::SA_INVAL_ARG, "Invalid Scenario"); + } + auto it = GetBackupExtNameMap(bundleName); + return it->second.fileNameInfo; +} + +map::iterator SvcSessionManager::GetBackupExtNameMap(const string &bundleName) +{ + auto it = impl_.backupExtNameMap.find(bundleName); + if (it == impl_.backupExtNameMap.end()) { + stringstream ss; + ss << "Could not find the " << bundleName << " from current session"; + throw BError(BError::Codes::SA_REFUSED_ACT, ss.str()); + } + return it; +} + +bool SvcSessionManager::GetSchedBundleName(string &bundleName) +{ + HILOGE("start"); + shared_lock lock(lock_); + if (extConnectNum_ >= BConstants::EXT_CONNECT_MAX_COUNT) { + return false; + } + HILOGE("extConnectNum_ %{public}d", extConnectNum_); + for (auto &&it : impl_.backupExtNameMap) { + HILOGE("schedAction %{public}d", it.second.schedAction); + if (it.second.schedAction == BConstants::ServiceSchedAction::WAIT) { + bundleName = it.first; + return true; + } + } + return false; +} + +BConstants::ServiceSchedAction SvcSessionManager::GetServiceSchedAction(const std::string &bundleName) +{ + HILOGE("start"); + shared_lock lock(lock_); + if (!impl_.clientToken) { + throw BError(BError::Codes::SA_INVAL_ARG, "No caller token was specified"); + } + auto it = GetBackupExtNameMap(bundleName); + return it->second.schedAction; +} + +void SvcSessionManager::SetServiceSchedAction(const string &bundleName, BConstants::ServiceSchedAction action) +{ + HILOGE("start"); + unique_lock lock(lock_); + if (!impl_.clientToken) { + throw BError(BError::Codes::SA_INVAL_ARG, "No caller token was specified"); + } + + auto it = GetBackupExtNameMap(bundleName); + it->second.schedAction = action; + if (it->second.schedAction == BConstants::ServiceSchedAction::START) { + extConnectNum_++; + } +} + +string SvcSessionManager::GetBackupExtName(const string &bundleName) +{ + HILOGE("start"); + shared_lock lock(lock_); + if (!impl_.clientToken) { + throw BError(BError::Codes::SA_INVAL_ARG, "No caller token was specified"); + } + auto it = GetBackupExtNameMap(bundleName); + return it->second.backupExtName; +} + +sptr SvcSessionManager::GetBundleManager() +{ + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if(saMgr == nullptr) + { + HILOGE("SystemAbilityManager is nullptr."); + return nullptr; + } + + auto bundleObj = saMgr->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID); + if(bundleObj == nullptr) + { + HILOGE("Failed to get bundle manager service."); + return nullptr; + } + + return iface_cast(bundleObj); +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/services/backup_sa/src/module_sched/sched_scheduler.cpp b/services/backup_sa/src/module_sched/sched_scheduler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b1c6721541bc1c4d88de0d3a4b6d7f162ca391a9 --- /dev/null +++ b/services/backup_sa/src/module_sched/sched_scheduler.cpp @@ -0,0 +1,109 @@ +/* + * 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 "module_sched/sched_scheduler.h" + +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "filemgmt_libhilog.h" +#include "module_ipc/service.h" +#include "module_ipc/svc_session_manager.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +void SchedScheduler::Sched(string bundleName) +{ + if (bundleName == "") { + if (!sessionPtr_->GetSchedBundleName(bundleName)) { + return; + } + BConstants::ServiceSchedAction action = sessionPtr_->GetServiceSchedAction(bundleName); + if (action == BConstants::ServiceSchedAction::WAIT) { + sessionPtr_->SetServiceSchedAction(bundleName, BConstants::ServiceSchedAction::START); + } + } + HILOGE("Sched bundleName %{public}s", bundleName.data()); + auto callStart = [schedPtr {wptr(this)}, bundleName]() { + try { + auto ptr = schedPtr.promote(); + ptr->ExecutingQueueTasks(bundleName); + } catch (const BError &e) { + HILOGE("%{public}s", e.what()); + } catch (const exception &e) { + HILOGE("%{public}s", e.what()); + } catch (...) { + HILOGE(""); + } + }; + threadPool_.AddTask(callStart); +} + +void SchedScheduler::ExecutingQueueTasks(const string &bundleName) +{ + HILOGE("start"); + BConstants::ServiceSchedAction action = sessionPtr_->GetServiceSchedAction(bundleName); + if (action == BConstants::ServiceSchedAction::START) { + // 注册启动定时器 + auto callStart = [reversePtr {reversePtr_}, bundleName]() { + HILOGE("Extension connect failed = %{public}s", bundleName.data()); + auto ptr = reversePtr.promote(); + if (ptr) { + ptr->ExtConnectFailed(bundleName, EPERM); + } + }; + auto iTime = extTime_.Register(callStart, BConstants::EXT_CONNECT_MAX_TIME); + unique_lock lock(lock_); + bundleTimeVec_.emplace_back(make_tuple(bundleName, iTime)); + lock.unlock(); + // 启动extension + reversePtr_->LaunchBackupExtension(bundleName); + } else if (action == BConstants::ServiceSchedAction::RUNNING) { + unique_lock lock(lock_); + auto iter = find_if(bundleTimeVec_.begin(), bundleTimeVec_.end(), [&bundleName](auto &obj) { + auto &[bName, iTime] = obj; + return bName == bundleName; + }); + if (iter == bundleTimeVec_.end()) { + throw BError(BError::Codes::SA_INVAL_ARG, "Failed to find timer"); + } + auto &[bName, iTime] = *iter; + // 移除启动定时器 当前逻辑无启动成功后的ext心跳检测 + extTime_.Unregister(iTime); + lock.unlock(); + // 开始执行备份恢复流程 + reversePtr_->ExtStart(bundleName); + } +} + +void SchedScheduler::RemoveExtConn(const string &bundleName) +{ + unique_lock lock(lock_); + auto iter = find_if(bundleTimeVec_.begin(), bundleTimeVec_.end(), [&bundleName](auto &obj) { + auto &[bName, iTime] = obj; + return bName == bundleName; + }); + if (iter != bundleTimeVec_.end()) { + auto &[bName, iTime] = *iter; + HILOGE("bundleName = %{public}s , iTime = %{public}d", bName.data(), iTime); + extTime_.Unregister(iTime); + bundleTimeVec_.erase(iter); + } +} +}; // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/services/remote_file_share/src/remote_file_share.cpp b/services/remote_file_share/src/remote_file_share.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c994779fbb49eaca0812f608d17b1d855aad48ea --- /dev/null +++ b/services/remote_file_share/src/remote_file_share.cpp @@ -0,0 +1,220 @@ +/* + * 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 "remote_file_share.h" +#include "remote_file_share_log.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "securec.h" + +namespace OHOS { +namespace AppFileService { +namespace ModuleRemoteFileShare { +namespace { + const int HMDFS_CID_SIZE = 64; + const int USER_ID_INIT = 100; + const unsigned HMDFS_IOC = 0xf2; + const std::string SHAER_PATH_HEAD = "/mnt/hmdfs/"; + const std::string SHAER_PATH_MID = "/account/merge_view/services/"; + const std::string LOWER_SHARE_PATH_HEAD = "/mnt/hmdfs/"; + const std::string LOWER_SHARE_PATH_MID = "/account/device_view/local/services/"; +} + +#define HMDFS_IOC_SET_SHARE_PATH _IOW(HMDFS_IOC, 1, struct HmdfsShareControl) + +struct HmdfsShareControl { + int fd; + char deviceId[HMDFS_CID_SIZE]; +}; + +static std::string GetProcessName() +{ + char pthreadName[PATH_MAX]; + int ret = pthread_getname_np(pthread_self(), pthreadName, sizeof(pthreadName)); + if (ret != 0) { + LOGE("RemoteFileShare::GetProcessName, pthread_getname_np failed with %{public}d", errno); + return ""; + } + std::string pthreadNameStr = pthreadName; + LOGI("RemoteFileShare::GetProcessName, thread name is %{public}s", pthreadNameStr.c_str()); + return pthreadNameStr; +} + +static std::string GetFileName(const int &fd) +{ + char buf[PATH_MAX] = {'\0'}; + char filePath[PATH_MAX] = {'\0'}; + + int ret = snprintf_s(buf, sizeof(buf), sizeof(buf), "/proc/self/fd/%d", fd); + if (ret < 0) { + LOGE("RemoteFileShare::GetFileName, snprintf failed with %{public}d", errno); + return ""; + } + + ret = readlink(buf, filePath, PATH_MAX - 1); + if (ret < 0) { + LOGE("RemoteFileShare::GetFileName, readlink failed with %{public}d", errno); + return ""; + } + + std::string fileName = filePath; + std::size_t firstSlash = fileName.rfind("/"); + if (firstSlash == fileName.npos) { + LOGE("RemoteFileShare::GetFileName, get error path with %{public}s", fileName.c_str()); + return ""; + } + fileName = fileName.substr(firstSlash + 1, fileName.size() - firstSlash); + return fileName; +} + +static int CreateShareDir(const std::string &path) +{ + if (access(path.c_str(), F_OK) != 0) { + int ret = mkdir(path.c_str(), S_IRWXU); + if (ret != 0) { + LOGE("RemoteFileShare::CreateShareDir, make dir failed with %{public}d", errno); + return errno; + } + } + return 0; +} + +static std::string GetSharePath(const int &userId, const std::string &packageName) +{ + return SHAER_PATH_HEAD + std::to_string(userId) + SHAER_PATH_MID + packageName; +} + +static std::string GetLowerSharePath(const int &userId, const std::string &packageName) +{ + return LOWER_SHARE_PATH_HEAD + std::to_string(userId) + LOWER_SHARE_PATH_MID + packageName; +} + +static bool DeleteShareDir(const std::string &PACKAGE_PATH, const std::string &SHARE_PATH) +{ + bool result = true; + if (access(SHARE_PATH.c_str(), F_OK) == 0) { + int ret = rmdir(SHARE_PATH.c_str()); + if (ret != 0) { + LOGE("RemoteFileShare::DeleteShareDir, delete dir failed with %{public}d", errno); + result = false; + } else { + LOGI("RemoteFileShare::DeleteShareDir, delete %{public}s path successfully", SHARE_PATH.c_str()); + } + } + if (access(PACKAGE_PATH.c_str(), F_OK) == 0) { + int ret = rmdir(PACKAGE_PATH.c_str()); + if (ret != 0) { + LOGE("RemoteFileShare::DeleteShareDir, delete dir failed with %{public}d", errno); + result = false; + } else { + LOGI("RemoteFileShare::DeleteShareDir, delete %{public}s path successfully", PACKAGE_PATH.c_str()); + } + } + return result; +} + +static int CreateShareFile(struct HmdfsShareControl &shareControl, const char* file, + const std::string &deviceId) +{ + int32_t dirFd = open(file, O_RDONLY); + if (dirFd < 0) { + LOGE("RemoteFileShare::CreateShareFile, open share path failed with %{public}d", errno); + return errno; + } + + memset_s(shareControl.deviceId, HMDFS_CID_SIZE, '\0', HMDFS_CID_SIZE); + if (memcpy_s(shareControl.deviceId, HMDFS_CID_SIZE, deviceId.c_str(), deviceId.size()) != 0) { + LOGE("RemoteFileShare::CreateShareFile, memcpy_s failed with %{public}d", errno); + close(dirFd); + return errno; + } + + if (ioctl(dirFd, HMDFS_IOC_SET_SHARE_PATH, &shareControl) < 0) { + LOGE("RemoteFileShare::CreateShareFile, ioctl failed with %{public}d", errno); + close(dirFd); + return errno; + } + close(dirFd); + return 0; +} + +static int CheckInputValidity(const int &fd, const int &userId, const std::string &deviceId) +{ + return (fd < 0) || (userId < USER_ID_INIT) || (deviceId != SHARE_ALL_DEVICE && + deviceId.size() != HMDFS_CID_SIZE); +} + +int RemoteFileShare::CreateSharePath(const int &fd, std::string &sharePath, + const int &userId, const std::string &deviceId) +{ + struct HmdfsShareControl shareControl; + shareControl.fd = fd; + + if (CheckInputValidity(fd, userId, deviceId) != 0) { + LOGE("RemoteFileShare::CreateSharePath, invalid argument with %{public}d", EINVAL); + return EINVAL; + } + + const std::string processName = GetProcessName(); + if (processName == "") { + LOGE("RemoteFileShare::CreateSharePath, GetProcessName failed with %{public}d", errno); + return errno; + } + + const std::string PACKAGE_PATH = GetLowerSharePath(userId, processName); + const std::string LOWER_SHARE_PATH = PACKAGE_PATH + "/.share"; + if (CreateShareDir(PACKAGE_PATH) != 0) + return errno; + if (CreateShareDir(LOWER_SHARE_PATH) != 0) { + DeleteShareDir(PACKAGE_PATH, LOWER_SHARE_PATH); + return errno; + } + + const std::string SHARE_PATH = GetSharePath(userId, processName) + "/.share"; + char realPath[PATH_MAX] = {'\0'}; + if (!realpath(SHARE_PATH.c_str(), realPath)) { + LOGE("RemoteFileShare::CreateSharePath, realpath failed with %{public}d", errno); + DeleteShareDir(PACKAGE_PATH, LOWER_SHARE_PATH); + return errno; + } + + if (CreateShareFile(shareControl, realPath, deviceId) != 0) { + LOGE("RemoteFileShare::CreateSharePath, create share file failed with %{public}d", errno); + /* When the file is exist, we should not delete the dictionary */ + if (errno != EEXIST) + DeleteShareDir(PACKAGE_PATH, LOWER_SHARE_PATH); + return errno; + } + + std::string file_name = GetFileName(shareControl.fd); + if (file_name == "") { + LOGE("RemoteFileShare::CreateSharePath, get error file name"); + DeleteShareDir(PACKAGE_PATH, LOWER_SHARE_PATH); + return EBADF; + } + sharePath = SHARE_PATH + "/" + file_name; + LOGI("RemoteFileShare::CreateSharePath, create %{public}s successfully", sharePath.c_str()); + return 0; +} +} // namespace ModuleRemoteFileShare +} // namespace AppFileService +} // namespace OHOS diff --git a/test/fuzztest/BUILD.gn b/test/fuzztest/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..dd4bc44e6660cef15cf1d2fdd82d6f119bb2debf --- /dev/null +++ b/test/fuzztest/BUILD.gn @@ -0,0 +1,22 @@ +# 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. + +group("fuzztest") { + testonly = true + deps = [] + + deps += [ + # deps file + "//foundation/filemanagement/app_file_service/test/fuzztest/remotefileshare_fuzzer:RemoteFileShareFuzzTest", + ] +} diff --git a/test/fuzztest/remotefileshare_fuzzer/BUILD.gn b/test/fuzztest/remotefileshare_fuzzer/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..e787b85ef2706c0a14c03b5eb3666dc943f456e6 --- /dev/null +++ b/test/fuzztest/remotefileshare_fuzzer/BUILD.gn @@ -0,0 +1,42 @@ +# 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. + +#####################hydra-fuzz################### +import("//build/config/features.gni") +import("//build/test.gni") + +##############################fuzztest########################################## +ohos_fuzztest("RemoteFileShareFuzzTest") { + module_out_path = "filemanagement/app_file_service" + fuzz_config_file = "//foundation/filemanagement/app_file_service/test/fuzztest/remotefileshare_fuzzer" + include_dirs = [] + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + sources = [ "remotefileshare_fuzzer.cpp" ] + deps = [ + "//foundation/distributeddatamgr/distributedfile/utils/filemgmt_libn", + "//third_party/bounds_checking_function:libsec_shared", + ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + defines = [ + "LOG_TAG=\"app_file_service\"", + "LOG_DOMAIN=0xD200000", + ] +} + +############################################################################### + diff --git a/test/fuzztest/remotefileshare_fuzzer/corpus/init b/test/fuzztest/remotefileshare_fuzzer/corpus/init new file mode 100644 index 0000000000000000000000000000000000000000..8eb5a7d6eb6b7d71f0c70c244e5768d62bee6ac5 --- /dev/null +++ b/test/fuzztest/remotefileshare_fuzzer/corpus/init @@ -0,0 +1,16 @@ +/* + * 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. + */ + +FUZZ \ No newline at end of file diff --git a/test/fuzztest/remotefileshare_fuzzer/project.xml b/test/fuzztest/remotefileshare_fuzzer/project.xml new file mode 100644 index 0000000000000000000000000000000000000000..85e7ef2c1cc6471e288306f6e3dcea5287a78b0e --- /dev/null +++ b/test/fuzztest/remotefileshare_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + diff --git a/test/fuzztest/remotefileshare_fuzzer/remotefileshare_fuzzer.cpp b/test/fuzztest/remotefileshare_fuzzer/remotefileshare_fuzzer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c47b367c473b69a2be68d55936ff1b345cd18ad4 --- /dev/null +++ b/test/fuzztest/remotefileshare_fuzzer/remotefileshare_fuzzer.cpp @@ -0,0 +1,193 @@ +/* + * 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 "remotefileshare_fuzzer.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "securec.h" + +namespace OHOS { +namespace AppFileService { +namespace ModuleRemoteFileShare { +namespace { + constexpr int HMDFS_CID_SIZE = 64; + constexpr unsigned HMDFS_IOC = 0xf2; + const char* SHARE_PATH = "/data/storage/el2/distributedfiles/.share"; +} + +#define HMDFS_IOC_SET_SHARE_PATH _IOW(HMDFS_IOC, 1, struct hmdfs_share_control) + +struct hmdfs_share_control { + int src_fd; + char cid[HMDFS_CID_SIZE]; +}; + +bool ShareFilePathIoctlFdAndCidFuzzTest(const uint8_t* data, size_t size) +{ + struct hmdfs_share_control sc; + int32_t ret = 0; + int32_t dirFd; + + if (size == 0) { + return false; + } + + if (access(SHARE_PATH, F_OK) != 0) { + ret = mkdir(SHARE_PATH, S_IRWXU | S_IRWXG | S_IXOTH); + if (ret < 0) { + return false; + } + } + + char realPath[PATH_MAX] = {0}; + if (!realpath(SHARE_PATH, realPath)) { + return false; + } + dirFd = open(realPath, O_RDONLY); + if (dirFd < 0) { + return false; + } + + const char* cid = reinterpret_cast(data); + sc.src_fd = size; + if (memcpy_s(sc.cid, HMDFS_CID_SIZE, cid, size) != 0) { + close(dirFd); + return false; + } + + ret = ioctl(dirFd, HMDFS_IOC_SET_SHARE_PATH, &sc); + if (ret < 0) { + close(dirFd); + return false; + } + + return true; +} + +bool ShareFilePathIoctlCidFuzzTest(const uint8_t* data, size_t size) +{ + struct hmdfs_share_control sc; + int32_t ret = 0; + int32_t dirFd; + int32_t srcFd; + + if (size == 0) { + return false; + } + + if (access(SHARE_PATH, F_OK) != 0) { + ret = mkdir(SHARE_PATH, S_IRWXU | S_IRWXG | S_IXOTH); + if (ret < 0) { + return false; + } + } + + char realPath[PATH_MAX] = {0}; + if (!realpath(SHARE_PATH, realPath)) { + return false; + } + dirFd = open(realPath, O_RDONLY); + if (dirFd < 0) { + return false; + } + + const char* srcPath = "/data/service/el2/100/hmdfs/non_account/data/com.ohos.camera"; + srcFd = open(srcPath, O_RDONLY); + if (srcFd < 0) { + close(dirFd); + return false; + } + sc.src_fd = size; + const char* cid = reinterpret_cast(data); + if (memcpy_s(sc.cid, HMDFS_CID_SIZE, cid, size) != 0) { + close(dirFd); + close(srcFd); + return false; + } + + ret = ioctl(dirFd, HMDFS_IOC_SET_SHARE_PATH, &sc); + if (ret < 0) { + close(dirFd); + close(srcFd); + return false; + } + + close(srcFd); + return true; +} + +bool ShareFilePathIoctlFdFuzzTest(const uint8_t* data, size_t size) +{ + struct hmdfs_share_control sc; + int32_t ret = 0; + int32_t dirFd; + + if (size == 0) { + return false; + } + + if (access(SHARE_PATH, F_OK) != 0) { + ret = mkdir(SHARE_PATH, S_IRWXU | S_IRWXG | S_IXOTH); + if (ret < 0) { + return false; + } + } + + char realPath[PATH_MAX] = {0}; + if (!realpath(SHARE_PATH, realPath)) { + return false; + } + + dirFd = open(realPath, O_RDONLY); + if (dirFd < 0) { + return false; + } + + const char* cid = "remoteShareFileFuzzTestCidxxx"; + if (memcpy_s(sc.cid, HMDFS_CID_SIZE, cid, strlen(cid)) != 0) { + close(dirFd); + return false; + } + sc.src_fd = size; + + ret = ioctl(dirFd, HMDFS_IOC_SET_SHARE_PATH, &sc); + if (ret < 0) { + close(dirFd); + return false; + } + + return true; +} +} // namespace ModuleRemoteFileShare +} // namespace AppFileService +} // namespace OHOS + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + /* Run your code on data */ + OHOS::AppFileService::ModuleRemoteFileShare::ShareFilePathIoctlFdFuzzTest(data, size); + OHOS::AppFileService::ModuleRemoteFileShare::ShareFilePathIoctlCidFuzzTest(data, size); + OHOS::AppFileService::ModuleRemoteFileShare::ShareFilePathIoctlFdAndCidFuzzTest(data, size); + return 0; +} diff --git a/test/fuzztest/remotefileshare_fuzzer/remotefileshare_fuzzer.h b/test/fuzztest/remotefileshare_fuzzer/remotefileshare_fuzzer.h new file mode 100644 index 0000000000000000000000000000000000000000..433624e715733b7830d8862325e1c4bd3848c6b9 --- /dev/null +++ b/test/fuzztest/remotefileshare_fuzzer/remotefileshare_fuzzer.h @@ -0,0 +1,21 @@ +/* + * 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 REMOTEFILESHARE_FUZZER_H +#define REMOTEFILESHARE_FUZZER_H + +#define FUZZ_PROJECT_NAME "remotefileshare_fuzzer" + +#endif \ No newline at end of file diff --git a/test/unittest/BUILD.gn b/test/unittest/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..d81880b40dc7bac6fbbf07567b4158fb81ce316b --- /dev/null +++ b/test/unittest/BUILD.gn @@ -0,0 +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. + +group("unittest") { + testonly = true + deps = [ "remote_file_share:remote_file_share_test" ] +} diff --git a/test/unittest/remote_file_share/BUILD.gn b/test/unittest/remote_file_share/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..a9c46ef1dbf2125968bc61c1a2661dc896cefd30 --- /dev/null +++ b/test/unittest/remote_file_share/BUILD.gn @@ -0,0 +1,34 @@ +# 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. + +import("//build/test.gni") + +ohos_unittest("remote_file_share_test") { + module_out_path = "filemanagement/app_file_service" + + resource_config_file = "../resource/ohos_test.xml" + + sources = [ "remote_file_share_test.cpp" ] + + include_dirs = [ + "include", + "../../../interfaces/innerkits/remote_file_share/native", + "//utils/system/safwk/native/include", + "//commonlibrary/c_utils/base/include", + ] + + deps = [ + "../../../interfaces/innerkits/remote_file_share/native:remote_file_share_native", + "//third_party/googletest:gtest_main", + ] +} diff --git a/test/unittest/remote_file_share/remote_file_share_test.cpp b/test/unittest/remote_file_share/remote_file_share_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..34c67d07e3d48d3c5faa68bf4f9274ffc5a6de9e --- /dev/null +++ b/test/unittest/remote_file_share/remote_file_share_test.cpp @@ -0,0 +1,141 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include "remote_file_share.h" + +namespace { + using namespace std; + using namespace OHOS::AppFileService::ModuleRemoteFileShare; + + const int E_INVALID_ARGUMENT = 22; + const int E_OK = 0; + + class RemoteFileShareTest : public testing::Test { + public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() {}; + void TearDown() {}; + }; + + /** + * @tc.name: remote_file_share_test_0000 + * @tc.desc: Test function of RemoteFileShare() interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H63TL + */ + HWTEST_F(RemoteFileShareTest, Remote_file_share_RemoteFileShare_0000, testing::ext::TestSize.Level1) + { + GTEST_LOG_(INFO) << "RemoteFileShareTest-begin Remote_file_share_RemoteFileShare_0000"; + RemoteFileShare* test = new RemoteFileShare; + ASSERT_TRUE(test != nullptr) << "RemoteFileShare Construct Failed!"; + delete test; + GTEST_LOG_(INFO) << "RemoteFileShareTest-end Remote_file_share_RemoteFileShare_0000"; + } + + /** + * @tc.name: remote_file_share_test_0001 + * @tc.desc: Test function of CreateSharePath() interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H63TL + */ + HWTEST_F(RemoteFileShareTest, Remote_file_share_CreateSharePath_0001, testing::ext::TestSize.Level1) + { + GTEST_LOG_(INFO) << "RemoteFileShareTest-begin Remote_file_share_CreateSharePath_0001"; + const int fd = -1; + const int userId = 100; + const string deviceId = "0"; + string sharePath = ""; + int ret = RemoteFileShare::CreateSharePath(fd, sharePath, userId, deviceId); + EXPECT_EQ(ret, E_INVALID_ARGUMENT); + GTEST_LOG_(INFO) << "RemoteFileShareTest-end Remote_file_share_CreateSharePath_0001"; + } + + /** + * @tc.name: remote_file_share_test_0002 + * @tc.desc: Test function of CreateSharePath() interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H63TL + */ + HWTEST_F(RemoteFileShareTest, Remote_file_share_CreateSharePath_0002, testing::ext::TestSize.Level1) + { + GTEST_LOG_(INFO) << "RemoteFileShareTest-begin Remote_file_share_CreateSharePath_0002"; + const int fd = 10; + const int userId = 90; + const string deviceId = "0"; + string sharePath = ""; + int ret = RemoteFileShare::CreateSharePath(fd, sharePath, userId, deviceId); + EXPECT_EQ(ret, E_INVALID_ARGUMENT); + GTEST_LOG_(INFO) << "RemoteFileShareTest-end Remote_file_share_CreateSharePath_0002"; + } + + /** + * @tc.name: remote_file_share_test_0003 + * @tc.desc: Test function of CreateSharePath() interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H63TL + */ + HWTEST_F(RemoteFileShareTest, Remote_file_share_CreateSharePath_0003, testing::ext::TestSize.Level1) + { + GTEST_LOG_(INFO) << "RemoteFileShareTest-begin Remote_file_share_CreateSharePath_0003"; + const int fd = 10; + const int userId = 100; + const string deviceId = "00"; + string sharePath = ""; + int ret = RemoteFileShare::CreateSharePath(fd, sharePath, userId, deviceId); + EXPECT_EQ(ret, E_INVALID_ARGUMENT); + GTEST_LOG_(INFO) << "RemoteFileShareTest-end Remote_file_share_CreateSharePath_0003"; + } + + /** + * @tc.name: remote_file_share_test_0004 + * @tc.desc: Test function of CreateSharePath() interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H63TL + */ + HWTEST_F(RemoteFileShareTest, Remote_file_share_CreateSharePath_0004, testing::ext::TestSize.Level1) + { + GTEST_LOG_(INFO) << "RemoteFileShareTest-begin Remote_file_share_CreateSharePath_0004"; + const string fileStr = "/data/test/remote_file_share_test.txt"; + int fd = open(fileStr.c_str(), O_RDWR); + ASSERT_TRUE(fd != -1) << "RemoteFileShareTest Create File Failed!"; + const int userId = 100; + const string deviceId = "0"; + string sharePath = ""; + int ret = RemoteFileShare::CreateSharePath(fd, sharePath, userId, deviceId); + close(fd); + EXPECT_EQ(ret, E_OK); + GTEST_LOG_(INFO) << "RemoteFileShareTest Create Share Path " << sharePath; + GTEST_LOG_(INFO) << "RemoteFileShareTest-end Remote_file_share_CreateSharePath_0004"; + } +} diff --git a/test/unittest/resource/ohos_test.xml b/test/unittest/resource/ohos_test.xml new file mode 100644 index 0000000000000000000000000000000000000000..966c8ea6fe8417224b00e767934a6637eddf5157 --- /dev/null +++ b/test/unittest/resource/ohos_test.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/test/unittest/resource/remote_file_share_test.txt b/test/unittest/resource/remote_file_share_test.txt new file mode 100644 index 0000000000000000000000000000000000000000..c658b9b65d5f8b5f3a7e5c3c3e7caf5caa8f7672 --- /dev/null +++ b/test/unittest/resource/remote_file_share_test.txt @@ -0,0 +1,13 @@ +# 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. +remote_file_share_test diff --git a/tests/mock/accesstoken/accesstoken_kit_mock.cpp b/tests/mock/accesstoken/accesstoken_kit_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7292f48b7b8deccea6e41e38719b4afdafc43edf --- /dev/null +++ b/tests/mock/accesstoken/accesstoken_kit_mock.cpp @@ -0,0 +1,29 @@ +/* + * 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 "accesstoken_kit.h" + +namespace OHOS::Security::AccessToken { +ATokenTypeEnum AccessTokenKit::GetTokenType(AccessTokenID tokenID) +{ + return TOKEN_HAP; +} + +int AccessTokenKit::GetHapTokenInfo(AccessTokenID callerToken, HapTokenInfo &hapTokenInfoRes) +{ + hapTokenInfoRes.bundleName = "com.example.app2backup"; + return 0; +} +} // namespace OHOS::Security::AccessToken diff --git a/tests/mock/affwk/service_registry_mock.cpp b/tests/mock/affwk/service_registry_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9ec473467d968d4ce9ce6fa79752e2ae5a3d66b2 --- /dev/null +++ b/tests/mock/affwk/service_registry_mock.cpp @@ -0,0 +1,65 @@ +/* + * 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 "iservice_registry.h" +#include "mock_bundle_manager.h" +#include "system_ability_definition.h" +#include "system_ability_manager_proxy.h" + +namespace OHOS { +static sptr g_appMgrService = nullptr; + +SystemAbilityManagerClient &SystemAbilityManagerClient::GetInstance() +{ + static auto instance = new SystemAbilityManagerClient(); + return *instance; +} + +sptr SystemAbilityManagerProxy::GetSystemAbility(int32_t systemAbilityId) +{ + sptr remote = nullptr; + switch (systemAbilityId) { + case BUNDLE_MGR_SERVICE_SYS_ABILITY_ID: + if (!g_appMgrService) { + GTEST_LOG_(INFO) << "GetSystemAbility(" << systemAbilityId << "): return Mock"; + g_appMgrService = new AppExecFwk::BundleMgrStub(); + } + remote = g_appMgrService; + break; + default: + GTEST_LOG_(INFO) << "This service is not dummy!!!!" << systemAbilityId; + break; + } + return remote; +} + +sptr SystemAbilityManagerClient::GetSystemAbilityManager() +{ + std::lock_guard lock(systemAbilityManagerLock_); + if (systemAbilityManager_ != nullptr) { + return systemAbilityManager_; + } + + systemAbilityManager_ = new SystemAbilityManagerProxy(nullptr); + return systemAbilityManager_; +} + +sptr SystemAbilityManagerProxy::GetSystemAbility(int32_t systemAbilityId, const std::string &deviceId) +{ + return GetSystemAbility(systemAbilityId); +} +} // namespace OHOS \ No newline at end of file diff --git a/tests/mock/b_filesystem/b_file_mock.cpp b/tests/mock/b_filesystem/b_file_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..17f1cb6460e8bdbf9154837a633f28436a59a111 --- /dev/null +++ b/tests/mock/b_filesystem/b_file_mock.cpp @@ -0,0 +1,86 @@ +/* + * 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 "b_filesystem/b_file.h" + +#include + +#include +#include +#include + +namespace OHOS::FileManagement::Backup { +using namespace std; + +unique_ptr BFile::ReadFile(const UniqueFd &fd) +{ + if (lseek(fd, 0, SEEK_SET) == -1) { + GTEST_LOG_(INFO) << "BFile::ReadFile lseek error " << errno; + return make_unique(1); + } + + struct stat stat = {}; + if (fstat(fd, &stat) == -1) { + GTEST_LOG_(INFO) << "BFile::ReadFile fstat error " << errno; + return make_unique(1); + } + off_t fileSize = stat.st_size; + if (fileSize == 0) { + GTEST_LOG_(INFO) << "BFile::ReadFile fileSize error " << fileSize; + return make_unique(1); + } + + auto buf = make_unique(fileSize + 1); + if (read(fd, buf.get(), fileSize) == -1) { + GTEST_LOG_(INFO) << "BFile::ReadFile read error " << errno; + } + return buf; +} + +void BFile::SendFile(int outFd, int inFd) +{ + if (outFd <= 0 || inFd <= 0) { + return; + } + off_t offset = 0; + long ret = 0; + if (lseek(outFd, 0, SEEK_SET) == -1) { + GTEST_LOG_(INFO) << "BFile::SendFile lseek1 error " << errno; + return; + } + if (lseek(inFd, 0, SEEK_SET) == -1) { + GTEST_LOG_(INFO) << "BFile::SendFile lseek2 error " << errno; + return; + } + struct stat stat = {}; + if (fstat(inFd, &stat) == -1) { + GTEST_LOG_(INFO) << "BFile::SendFile fstat error " << errno; + return; + } + while ((ret = sendfile(outFd, inFd, &offset, stat.st_size)) > 0) { + }; + + if (ret == -1) { + GTEST_LOG_(INFO) << "BFile::SendFile ret error " << ret; + } +} + +void BFile::Write(const UniqueFd &fd, const string &str) {} + +bool BFile::CopyFile(const string &from, const string &to) +{ + return true; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/mock/b_process/b_process_mock.cpp b/tests/mock/b_process/b_process_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2d8d7b0fee46ae3af28fab94a867906f8ef2c440 --- /dev/null +++ b/tests/mock/b_process/b_process_mock.cpp @@ -0,0 +1,32 @@ +/* + * 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 "b_process/b_process.h" + +#include +#include + +namespace OHOS::FileManagement::Backup { +using namespace std; + +tuple BProcess::ExecuteCmd(vector argvSv, function DetectFatalLog) +{ + GTEST_LOG_(INFO) << "BProcess ExecuteCmd Begin"; + DetectFatalLog("test"); + DetectFatalLog("EOF"); + GTEST_LOG_(INFO) << "BProcess ExecuteCmd End"; + return {false, 0}; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/mock/b_tarball/b_tarball_cmdline_mock.cpp b/tests/mock/b_tarball/b_tarball_cmdline_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c6b9de7ae417b932f236e324587d411b6a92eedf --- /dev/null +++ b/tests/mock/b_tarball/b_tarball_cmdline_mock.cpp @@ -0,0 +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. + */ + +#include "b_tarball/b_tarball_cmdline.h" + +#include +#include + +#include + +#include +#include + +namespace OHOS::FileManagement::Backup { +using namespace std; + +void BTarballCmdline::Tar(string_view root, vector includes, vector excludes) +{ + GTEST_LOG_(INFO) << "BTarballCmdline Tar " << root; +} + +void BTarballCmdline::Untar(string_view root) +{ + GTEST_LOG_(INFO) << "BTarballCmdline Untar " << root; +} + +BTarballCmdline::BTarballCmdline(string_view tarballDir, string_view tarballName) + : tarballDir_(tarballDir), tarballName_(tarballName) +{ + tarballPath_ = tarballDir_ + "/" + tarballName_; +} +} // namespace OHOS::FileManagement::Backup diff --git a/tests/mock/backup_kit_inner/b_session_backup_mock.cpp b/tests/mock/backup_kit_inner/b_session_backup_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2ad3b7216f99a6ddaf402df23affefc3dfbb00dd --- /dev/null +++ b/tests/mock/backup_kit_inner/b_session_backup_mock.cpp @@ -0,0 +1,86 @@ +/* + * 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 "b_session_backup.h" + +#include +#include +#include + +#include +#include + +#include "b_error/b_error.h" +#include "test_manager.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +namespace { +static BSessionBackup::Callbacks callbacks_ = {}; +} // namespace + +BSessionBackup::~BSessionBackup() {} + +unique_ptr BSessionBackup::Init(UniqueFd remoteCap, + vector bundlesToBackup, + Callbacks callbacks) +{ + try { + callbacks_ = callbacks; + auto backup = make_unique(); + return backup; + } catch (const exception &e) { + return nullptr; + } + return nullptr; +} + +void BSessionBackup::RegisterBackupServiceDied(function functor) {} + +ErrCode BSessionBackup::Start() +{ + callbacks_.onBundleStarted(0, "com.example.app2backup"); + + BFileInfo bFileInfo("com.example.app2backup", "manage.json", 0); + TestManager tm("BSessionBackupMock_GetFd_0100"); + string fileManagePath = tm.GetRootDirCurTest().append("manage.json"); + SaveStringToFile(fileManagePath, R"([{"fileName": "1.tar"}])"); + UniqueFd fd(open(fileManagePath.data(), O_RDWR, S_IRWXU)); + GTEST_LOG_(INFO) << "callbacks_::onFileReady manage.json"; + callbacks_.onFileReady(bFileInfo, move(fd)); + + string filePath = tm.GetRootDirCurTest().append("1.tar"); + UniqueFd fdTar(open(filePath.data(), O_RDONLY | O_CREAT, S_IRWXU)); + bFileInfo.fileName = "1.tar"; + GTEST_LOG_(INFO) << "callbacks_::onFileReady 1.tar"; + callbacks_.onFileReady(bFileInfo, move(fdTar)); + + callbacks_.onBundleFinished(0, "com.example.app2backup"); + + callbacks_.onAllBundlesFinished(0); + callbacks_.onBundleStarted(1, "com.example.app2backup"); + callbacks_.onBundleFinished(1, "com.example.app2backup"); + callbacks_.onAllBundlesFinished(1); + + string filePathTwo = tm.GetRootDirCurTest().append("1.tar"); + UniqueFd fdFile(open(filePathTwo.data(), O_RDONLY | O_CREAT, S_IRWXU)); + GTEST_LOG_(INFO) << "callbacks_::onFileReady 1.tar"; + callbacks_.onFileReady(bFileInfo, move(fdFile)); + + callbacks_.onBackupServiceDied(); + return BError(BError::Codes::OK); +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/mock/backup_kit_inner/b_session_restore_mock.cpp b/tests/mock/backup_kit_inner/b_session_restore_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1bee017caa3f25b83d5e5e52c9bc66481d1f7f9 --- /dev/null +++ b/tests/mock/backup_kit_inner/b_session_restore_mock.cpp @@ -0,0 +1,106 @@ +/* + * 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 "b_session_restore.h" + +#include +#include +#include + +#include +#include + +#include "b_error/b_error.h" +#include "test_manager.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +namespace { +static BSessionRestore::Callbacks callbacks_ = {}; +static vector bundlesToRestore_ = {}; +} // namespace + +BSessionRestore::~BSessionRestore() {} + +unique_ptr BSessionRestore::Init(vector bundlesToRestore, Callbacks callbacks) +{ + try { + callbacks_ = move(callbacks); + bundlesToRestore_ = move(bundlesToRestore); + auto restore = make_unique(); + return restore; + } catch (const exception &e) { + return nullptr; + } + return nullptr; +} + +UniqueFd BSessionRestore::GetLocalCapabilities() +{ + string bundleName = "test"; + auto iter = find_if(bundlesToRestore_.begin(), bundlesToRestore_.end(), [&bundleName](auto &obj) { + const auto &bName = obj; + return bName == bundleName; + }); + if (iter != bundlesToRestore_.end()) { + return UniqueFd(-1); + } + TestManager tm("BSessionRestoreMock_GetFd_0100"); + string filePath = tm.GetRootDirCurTest().append("tmp"); + UniqueFd fd(open(filePath.data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + return fd; +} + +ErrCode BSessionRestore::PublishFile(BFileInfo fileInfo) +{ + return BError(BError::Codes::OK); +} + +ErrCode BSessionRestore::Start() +{ + callbacks_.onBundleStarted(0, "com.example.app2backup"); + + BFileInfo bFileInfo("com.example.app2backup", "1.tar", 0); + TestManager tm("BSessionRestoreMock_GetFd_0100"); + string filePath = tm.GetRootDirCurTest().append("1.tar"); + UniqueFd fd(open(filePath.data(), O_RDWR | O_CREAT, S_IRWXU)); + GTEST_LOG_(INFO) << "callbacks_::onFileReady 1.tar"; + callbacks_.onFileReady(bFileInfo, move(fd)); + + string fileManagePath = tm.GetRootDirCurTest().append("manage.json"); + UniqueFd fdManage(open(fileManagePath.data(), O_RDWR | O_CREAT, S_IRWXU)); + bFileInfo.fileName = "manage.json"; + GTEST_LOG_(INFO) << "callbacks_::onFileReady manage.json"; + callbacks_.onFileReady(bFileInfo, move(fdManage)); + + callbacks_.onBundleFinished(0, "com.example.app2backup"); + + callbacks_.onAllBundlesFinished(0); + callbacks_.onBundleStarted(1, "com.example.app2backup"); + callbacks_.onBundleFinished(1, "com.example.app2backup"); + callbacks_.onAllBundlesFinished(1); + + callbacks_.onBackupServiceDied(); + return BError(BError::Codes::OK); +} + +ErrCode BSessionRestore::GetExtFileName(string &bundleName, string &fileName) +{ + return BError(BError::Codes::OK); +} + +void BSessionRestore::RegisterBackupServiceDied(function functor) {} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/mock/backup_kit_inner/service_proxy_mock.cpp b/tests/mock/backup_kit_inner/service_proxy_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f99108ec7d6d15733a8af64b77b8c6977b55fced --- /dev/null +++ b/tests/mock/backup_kit_inner/service_proxy_mock.cpp @@ -0,0 +1,110 @@ +/* + * 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 "service_proxy.h" + +#include +#include +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "b_resources/b_constants.h" +#include "iremote_object_mock.h" +#include "test_manager.h" +#include "utils_mock_global_variable.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +int32_t ServiceProxy::InitRestoreSession(sptr remote, const vector &bundleNames) +{ + if (!GetMockInitBackupOrRestoreSession()) { + return 1; + } + return 0; +} + +int32_t ServiceProxy::InitBackupSession(sptr remote, + UniqueFd fd, + const vector &bundleNames) +{ + if (!GetMockInitBackupOrRestoreSession()) { + return 1; + } + return 0; +} + +ErrCode ServiceProxy::Start() +{ + return BError(BError::Codes::OK); +} + +UniqueFd ServiceProxy::GetLocalCapabilities() +{ + TestManager tm("ServiceProxyMock_GetFd_0100"); + string filePath = tm.GetRootDirCurTest().append("tmp"); + UniqueFd fd(open(filePath.data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + return fd; +} + +ErrCode ServiceProxy::PublishFile(const BFileInfo &fileInfo) +{ + return BError(BError::Codes::OK); +} + +ErrCode ServiceProxy::AppFileReady(const string &fileName, UniqueFd fd) +{ + return BError(BError::Codes::OK); +} + +ErrCode ServiceProxy::AppDone(ErrCode errCode) +{ + return BError(BError::Codes::OK); +} + +ErrCode ServiceProxy::GetExtFileName(string &bundleName, string &fileName) +{ + return BError(BError::Codes::OK); +} + +sptr ServiceProxy::GetInstance() +{ + if (!GetMockGetInstance()) { + return nullptr; + } + + if (!GetMockLoadSystemAbility()) { + serviceProxy_ = sptr(new ServiceProxy(nullptr)); + } else { + sptr object = new MockIRemoteObject(); + serviceProxy_ = sptr(new ServiceProxy(object)); + } + return serviceProxy_; +} + +void ServiceProxy::ServiceProxyLoadCallback::OnLoadSystemAbilitySuccess(int32_t systemAbilityId, + const OHOS::sptr &remoteObject) +{ + return; +} + +void ServiceProxy::ServiceProxyLoadCallback::OnLoadSystemAbilityFail(int32_t systemAbilityId) +{ + return; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/mock/bundle_manager/include/mock_bundle_manager.h b/tests/mock/bundle_manager/include/mock_bundle_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..de44d56dded92de8069ad29f7abc137f306f969d --- /dev/null +++ b/tests/mock/bundle_manager/include/mock_bundle_manager.h @@ -0,0 +1,62 @@ +/* + * 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 MOCK_BUNDLE_MANAGER_H +#define MOCK_BUNDLE_MANAGER_H + +#include +#include + +#include "ability_info.h" +#include "application_info.h" +#include "bundlemgr/bundle_mgr_interface.h" +#include "iremote_proxy.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace AppExecFwk { +class BundleMgrProxy : public IRemoteProxy { +public: + explicit BundleMgrProxy(const sptr &impl) : IRemoteProxy(impl) {} + virtual ~BundleMgrProxy() {} + + bool GetBundleInfo(const std::string &bundleName, + const BundleFlag flag, + BundleInfo &bundleInfo, + int32_t userId) override; +}; + +class BundleMgrStub : public IRemoteStub { +public: + BundleMgrStub() {}; + virtual ~BundleMgrStub() {} + virtual int OnRemoteRequest(uint32_t code, + MessageParcel &data, + MessageParcel &reply, + MessageOption &option) override; + + virtual bool GetBundleInfo(const std::string &bundleName, + const BundleFlag flag, + BundleInfo &bundleInfo, + int32_t userId = Constants::UNSPECIFIED_USERID) override; + + virtual bool GetBundleInfo(const std::string &bundleName, + int32_t flags, + BundleInfo &bundleInfo, + int32_t userId = Constants::UNSPECIFIED_USERID) override; +}; +} // namespace AppExecFwk +} // namespace OHOS +#endif // MOCK_BUNDLE_MANAGER_H \ No newline at end of file diff --git a/tests/mock/bundle_manager/src/mock_bundle_manager.cpp b/tests/mock/bundle_manager/src/mock_bundle_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65cc02664c6be9ec967a9f8147872d34bb84dfa9 --- /dev/null +++ b/tests/mock/bundle_manager/src/mock_bundle_manager.cpp @@ -0,0 +1,87 @@ +/* + * 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 "mock_bundle_manager.h" + +#include +#include +#include + +#include "ability_config.h" +#include "ability_info.h" +#include "application_info.h" +#include "bundle_mgr_client.h" + +namespace OHOS { +namespace AppExecFwk { +using namespace std; +using namespace OHOS::AAFwk; + +bool BundleMgrProxy::GetBundleInfo(const string &bundleName, + const BundleFlag flag, + BundleInfo &bundleInfo, + int32_t userId) +{ + GTEST_LOG_(INFO) << "GetBundleInfo is ok"; + ExtensionAbilityInfo info; + info.type = AppExecFwk::ExtensionAbilityType::BACKUP; + info.name = "com.example.app2backup"; + bundleInfo.extensionInfos.push_back(info); + return true; +} + +int BundleMgrStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + return 0; +} + +bool BundleMgrStub::GetBundleInfo(const string &bundleName, + const BundleFlag flag, + BundleInfo &bundleInfo, + int32_t userId) +{ + GTEST_LOG_(INFO) << "GetBundleInfo is ok"; + ExtensionAbilityInfo info; + info.type = AppExecFwk::ExtensionAbilityType::BACKUP; + info.name = "com.example.app2backup"; + bundleInfo.extensionInfos.push_back(info); + return true; +} + +bool BundleMgrStub::GetBundleInfo(const string &bundleName, int32_t flags, BundleInfo &bundleInfo, int32_t userId) +{ + GTEST_LOG_(INFO) << "GetBundleInfo is ok"; + ExtensionAbilityInfo info; + info.type = AppExecFwk::ExtensionAbilityType::BACKUP; + info.name = "com.example.app2backup"; + bundleInfo.extensionInfos.push_back(info); + return true; +} + +BundleMgrClient::BundleMgrClient() {} + +BundleMgrClient::~BundleMgrClient() {} + +bool BundleMgrClient::GetResConfigFile(const ExtensionAbilityInfo &extensionInfo, + const string &metadataName, + vector &profileInfos) const +{ + GTEST_LOG_(INFO) << "GetResConfigFile is ok"; + string str = "{\"allowToBackupRestore\":true}"; + profileInfos.push_back(str); + return true; +} +} // namespace AppExecFwk +} // namespace OHOS \ No newline at end of file diff --git a/tests/mock/module_ipc/service_mock.cpp b/tests/mock/module_ipc/service_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..05fe801c54fe6747839519535ac06b34a8ff361e --- /dev/null +++ b/tests/mock/module_ipc/service_mock.cpp @@ -0,0 +1,102 @@ +/* + * 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 "module_ipc/service.h" + +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "b_resources/b_constants.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +void Service::OnStart() {} + +void Service::OnStop() {} + +UniqueFd Service::GetLocalCapabilities() +{ + return UniqueFd(-1); +} + +void Service::StopAll(const wptr &obj, bool force) {} + +string Service::VerifyCallerAndGetCallerName() +{ + return ""; +} + +ErrCode Service::InitRestoreSession(sptr remote, const vector &bundleNames) +{ + return BError(BError::Codes::OK); +} + +ErrCode Service::InitBackupSession(sptr remote, UniqueFd fd, const vector &bundleNames) +{ + return BError(BError::Codes::OK); +} + +ErrCode Service::Start() +{ + return BError(BError::Codes::OK); +} + +ErrCode Service::PublishFile(const BFileInfo &fileInfo) +{ + return BError(BError::Codes::OK); +} + +ErrCode Service::AppFileReady(const string &fileName, UniqueFd fd) +{ + return BError(BError::Codes::OK); +} + +ErrCode Service::AppDone(ErrCode errCode) +{ + return BError(BError::Codes::OK); +} + +ErrCode Service::LaunchBackupExtension(const BundleName &bundleName) +{ + return BError(BError::Codes::OK); +} + +ErrCode Service::GetExtFileName(string &bundleName, string &fileName) +{ + return BError(BError::Codes::OK); +} + +void Service::OnBackupExtensionDied(const string &&bundleName, ErrCode ret) {} + +void Service::ExtStart(const string &bundleName) {} + +int Service::Dump(int fd, const vector &args) +{ + return 0; +} + +void Service::ExtConnectFailed(const string &bundleName, ErrCode ret) +{ + GTEST_LOG_(INFO) << "ExtConnectFailed is OK"; +} + +void Service::ExtConnectDone(string bundleName) {} + +void Service::ClearSessionAndSchedInfo(const string &bundleName) {} +} // namespace OHOS::FileManagement::Backup diff --git a/tests/mock/module_ipc/service_reverse_proxy_mock.cpp b/tests/mock/module_ipc/service_reverse_proxy_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d4ed2cc03f7b584fe49cd5fc44a6809a02d0dd5 --- /dev/null +++ b/tests/mock/module_ipc/service_reverse_proxy_mock.cpp @@ -0,0 +1,38 @@ +/* + * 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 "module_ipc/service_reverse_proxy.h" + +#include "b_error/b_error.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +void ServiceReverseProxy::BackupOnFileReady(string bundleName, string fileName, int fd) {} + +void ServiceReverseProxy::BackupOnBundleStarted(int32_t errCode, string bundleName) {} + +void ServiceReverseProxy::BackupOnBundleFinished(int32_t errCode, string bundleName) {} + +void ServiceReverseProxy::BackupOnAllBundlesFinished(int32_t errCode) {} + +void ServiceReverseProxy::RestoreOnBundleStarted(int32_t errCode, string bundleName) {} + +void ServiceReverseProxy::RestoreOnBundleFinished(int32_t errCode, string bundleName) {} + +void ServiceReverseProxy::RestoreOnAllBundlesFinished(int32_t errCode) {} + +void ServiceReverseProxy::RestoreOnFileReady(string bundleName, string fileName, int fd) {} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/mock/module_ipc/service_stub_mock.cpp b/tests/mock/module_ipc/service_stub_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3ad8067fdd4fa6f1904d6bf8b662dd4fe2ad942f --- /dev/null +++ b/tests/mock/module_ipc/service_stub_mock.cpp @@ -0,0 +1,130 @@ +/* + * 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 "module_ipc/service_stub.h" + +#include + +#include "b_error/b_error.h" +#include "module_ipc/service_reverse_proxy.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +ServiceStub::ServiceStub() +{ + opToInterfaceMap_[SERVICE_CMD_INIT_RESTORE_SESSION] = &ServiceStub::CmdInitRestoreSession; + opToInterfaceMap_[SERVICE_CMD_INIT_BACKUP_SESSION] = &ServiceStub::CmdInitBackupSession; + opToInterfaceMap_[SERVICE_CMD_GET_LOCAL_CAPABILITIES] = &ServiceStub::CmdGetLocalCapabilities; + opToInterfaceMap_[SERVICE_CMD_PUBLISH_FILE] = &ServiceStub::CmdPublishFile; + opToInterfaceMap_[SERVICE_CMD_APP_FILE_READY] = &ServiceStub::CmdAppFileReady; + opToInterfaceMap_[SERVICE_CMD_APP_DONE] = &ServiceStub::CmdAppDone; + opToInterfaceMap_[SERVICE_CMD_START] = &ServiceStub::CmdStart; + opToInterfaceMap_[SERVICE_CMD_GET_EXT_FILE_NAME] = &ServiceStub::CmdGetExtFileName; +} + +int32_t ServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + auto interfaceIndex = opToInterfaceMap_.find(code); + if (interfaceIndex == opToInterfaceMap_.end() || !interfaceIndex->second) { + return BError(BError::Codes::OK); + } + + const std::u16string descriptor = ServiceStub::GetDescriptor(); + const std::u16string remoteDescriptor = data.ReadInterfaceToken(); + if (descriptor != remoteDescriptor) { + return BError(BError::Codes::OK); + } + return (this->*(interfaceIndex->second))(data, reply); +} + +int32_t ServiceStub::CmdInitRestoreSession(MessageParcel &data, MessageParcel &reply) +{ + auto remote = data.ReadRemoteObject(); + auto iremote = iface_cast(remote); + + std::vector bundleNames; + data.ReadStringVector(&bundleNames); + int32_t res = InitRestoreSession(iremote, bundleNames); + reply.WriteInt32(res); + return BError(BError::Codes::OK); +} + +int32_t ServiceStub::CmdInitBackupSession(MessageParcel &data, MessageParcel &reply) +{ + auto remote = data.ReadRemoteObject(); + auto iremote = iface_cast(remote); + + UniqueFd fd(data.ReadFileDescriptor()); + + std::vector bundleNames; + data.ReadStringVector(&bundleNames); + + int res = InitBackupSession(iremote, move(fd), bundleNames); + reply.WriteInt32(res); + return BError(BError::Codes::OK); +} + +int32_t ServiceStub::CmdStart(MessageParcel &data, MessageParcel &reply) +{ + int res = Start(); + reply.WriteInt32(res); + return BError(BError::Codes::OK); +} + +int32_t ServiceStub::CmdGetLocalCapabilities(MessageParcel &data, MessageParcel &reply) +{ + UniqueFd fd(GetLocalCapabilities()); + reply.WriteFileDescriptor(fd); + return BError(BError::Codes::OK); +} + +int32_t ServiceStub::CmdPublishFile(MessageParcel &data, MessageParcel &reply) +{ + unique_ptr fileInfo(data.ReadParcelable()); + int res = PublishFile(*fileInfo); + reply.WriteInt32(res); + return BError(BError::Codes::OK); +} + +int32_t ServiceStub::CmdAppFileReady(MessageParcel &data, MessageParcel &reply) +{ + string fileName; + data.ReadString(fileName); + UniqueFd fd(data.ReadFileDescriptor()); + int res = AppFileReady(fileName, move(fd)); + reply.WriteInt32(res); + return BError(BError::Codes::OK); +} + +int32_t ServiceStub::CmdAppDone(MessageParcel &data, MessageParcel &reply) +{ + bool success; + data.ReadBool(success); + int res = AppDone(success); + reply.WriteInt32(res); + return BError(BError::Codes::OK); +} + +int32_t ServiceStub::CmdGetExtFileName(MessageParcel &data, MessageParcel &reply) +{ + string bundleName; + data.ReadString(bundleName); + string fileName; + data.ReadString(fileName); + + return GetExtFileName(bundleName, fileName); +} +} // namespace OHOS::FileManagement::Backup diff --git a/tests/mock/module_ipc/svc_backup_connection_mock.cpp b/tests/mock/module_ipc/svc_backup_connection_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd42b23140c069bd1dbad771b651498ace8f0f47 --- /dev/null +++ b/tests/mock/module_ipc/svc_backup_connection_mock.cpp @@ -0,0 +1,69 @@ +/* + * 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 "module_ipc/svc_backup_connection.h" + +#include + +#include "module_ipc/svc_extension_proxy.h" +#include "module_ipc/svc_session_manager.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +namespace { +static bool g_bExtAbilityConnected = false; +} + +void SvcBackupConnection::OnAbilityConnectDone(const AppExecFwk::ElementName &element, + const sptr &remoteObject, + int resultCode) +{ + isConnected_.store(true); + backupProxy_ = iface_cast(remoteObject); + string bundleName = ""; + callConnDone_(move(bundleName)); +} + +void SvcBackupConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) +{ + backupProxy_ = nullptr; + isConnected_.store(false); + string bundleName = ""; + callDied_(move(bundleName)); +} + +ErrCode SvcBackupConnection::ConnectBackupExtAbility(AAFwk::Want &want) +{ + return 0; +} + +ErrCode SvcBackupConnection::DisconnectBackupExtAbility() +{ + return 0; +} + +bool SvcBackupConnection::IsExtAbilityConnected() +{ + bool bFlag = g_bExtAbilityConnected; + g_bExtAbilityConnected = !bFlag; + return bFlag; +} + +sptr SvcBackupConnection::GetBackupExtProxy() +{ + return backupProxy_; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/mock/module_ipc/svc_extension_proxy_mock.cpp b/tests/mock/module_ipc/svc_extension_proxy_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6d0784c887aec41652dc88c0286706ca6fa7fa19 --- /dev/null +++ b/tests/mock/module_ipc/svc_extension_proxy_mock.cpp @@ -0,0 +1,40 @@ +/* + * 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 "module_ipc/svc_extension_proxy.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +UniqueFd SvcExtensionProxy::GetFileHandle(const string &fileName) +{ + return UniqueFd(-1); +} + +ErrCode SvcExtensionProxy::HandleClear() +{ + return 0; +} + +ErrCode SvcExtensionProxy::HandleBackup() +{ + return 0; +} + +ErrCode SvcExtensionProxy::PublishFile(const string &fileName) +{ + return 0; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/mock/module_ipc/svc_session_manager_mock.cpp b/tests/mock/module_ipc/svc_session_manager_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ef7e7692421d18d73a1f3d40e39d6bdbe39f6fa --- /dev/null +++ b/tests/mock/module_ipc/svc_session_manager_mock.cpp @@ -0,0 +1,199 @@ +/* + * 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 "module_ipc/svc_session_manager.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "b_resources/b_constants.h" +#include "ext_extension_mock.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +namespace { +constexpr int SCHED_NUM = 1; +constexpr int FILE_NUM = 2; +static int32_t g_nFileReadyNum = 0; +} // namespace + +void SvcSessionManager::VerifyCallerAndScenario(uint32_t clientToken, IServiceReverse::Scenario scenario) const +{ + GTEST_LOG_(INFO) << "VerifyCallerAndScenario"; +} + +void SvcSessionManager::Active(Impl newImpl) +{ + GTEST_LOG_(INFO) << "Active"; + extConnectNum_ = 0; + impl_ = newImpl; +} + +void SvcSessionManager::Deactive(const wptr &remoteInAction, bool force) +{ + GTEST_LOG_(INFO) << "Deactive"; +} + +void SvcSessionManager::VerifyBundleName(string &bundleName) +{ + GTEST_LOG_(INFO) << "VerifyBundleName " << bundleName; +} + +sptr SvcSessionManager::GetServiceReverseProxy() +{ + GTEST_LOG_(INFO) << "GetServiceReverseProxy"; + return impl_.clientProxy; +} + +IServiceReverse::Scenario SvcSessionManager::GetScenario() +{ + GTEST_LOG_(INFO) << "GetScenario"; + return impl_.scenario; +} + +void SvcSessionManager::GetBundleExtNames(map &backupExtNameMap) +{ + GTEST_LOG_(INFO) << "GetBundleExtNames"; +} + +bool SvcSessionManager::OnBunleFileReady(const string &bundleName, const string &fileName) +{ + GTEST_LOG_(INFO) << "OnBunleFileReady"; + g_nFileReadyNum++; + if (g_nFileReadyNum % FILE_NUM == SCHED_NUM) { + GTEST_LOG_(INFO) << "OnBunleFileReady is true"; + return true; + } + GTEST_LOG_(INFO) << "OnBunleFileReady is false"; + return false; +} + +UniqueFd SvcSessionManager::OnBunleExtManageInfo(const string &bundleName, UniqueFd fd) +{ + GTEST_LOG_(INFO) << "OnBunleExtManageInfo"; + return UniqueFd(-1); +} + +void SvcSessionManager::RemoveExtInfo(const string &bundleName) +{ + GTEST_LOG_(INFO) << "RemoveExtInfo"; +} + +wptr SvcSessionManager::GetExtConnection(const BundleName &bundleName) +{ + GTEST_LOG_(INFO) << "GetExtConnection"; + auto it = impl_.backupExtNameMap.find(bundleName); + if (it == impl_.backupExtNameMap.end()) { + return nullptr; + } + if (!it->second.backUpConnection) { + auto callDied = [](const string &&bundleName) {}; + auto callConnDone = [](const string &&bundleName) {}; + it->second.backUpConnection = sptr(new SvcBackupConnection(callDied, callConnDone)); + sptr mock = sptr(new BackupExtExtensionMock()); + it->second.backUpConnection->OnAbilityConnectDone({}, mock->AsObject(), 0); + } + return wptr(it->second.backUpConnection); +} + +void SvcSessionManager::InitExtConn(std::map &backupExtNameMap) +{ + GTEST_LOG_(INFO) << "InitExtConn"; +} + +void SvcSessionManager::DumpInfo(const int fd, const std::vector &args) +{ + GTEST_LOG_(INFO) << "DumpInfo"; +} + +void SvcSessionManager::InitClient(Impl &newImpl) +{ + GTEST_LOG_(INFO) << "InitClient"; +} + +void SvcSessionManager::SetExtFileNameRequest(const string &bundleName, const string &fileName) +{ + GTEST_LOG_(INFO) << "SetExtFileNameRequest"; +} + +std::set SvcSessionManager::GetExtFileNameRequest(const std::string &bundleName) +{ + GTEST_LOG_(INFO) << "GetExtFileNameRequest"; + std::set fileNameInfo; + fileNameInfo.insert("testName"); + fileNameInfo.insert("fileName"); + return fileNameInfo; +} + +map::iterator SvcSessionManager::GetBackupExtNameMap(const string &bundleName) +{ + GTEST_LOG_(INFO) << "GetBackupExtNameMap"; + auto it = impl_.backupExtNameMap.find(bundleName); + return it; +} + +bool SvcSessionManager::GetSchedBundleName(string &bundleName) +{ + if (extConnectNum_ == 0) { + GTEST_LOG_(INFO) << "GetSchedBundleName is zero"; + extConnectNum_++; + return false; + } else if (extConnectNum_ == SCHED_NUM || extConnectNum_ == (SCHED_NUM + 1)) { + GTEST_LOG_(INFO) << "GetSchedBundleName is one two"; + bundleName = "com.example.app2backup"; + extConnectNum_++; + return true; + } + + auto it = impl_.backupExtNameMap.find(bundleName); + if (it == impl_.backupExtNameMap.end()) { + return false; + } + it->second.backupExtName = bundleName; + GTEST_LOG_(INFO) << "GetSchedBundleName is " << it->second.backupExtName; + return true; +} + +BConstants::ServiceSchedAction SvcSessionManager::GetServiceSchedAction(const std::string &bundleName) +{ + auto it = impl_.backupExtNameMap.find(bundleName); + if (it == impl_.backupExtNameMap.end()) { + return BConstants::ServiceSchedAction::WAIT; + } + GTEST_LOG_(INFO) << "GetServiceSchedAction is " << it->second.schedAction; + return it->second.schedAction; +} + +void SvcSessionManager::SetServiceSchedAction(const string &bundleName, BConstants::ServiceSchedAction action) +{ + auto it = impl_.backupExtNameMap.find(bundleName); + if (it == impl_.backupExtNameMap.end()) { + return; + } + it->second.schedAction = action; +} + +string SvcSessionManager::GetBackupExtName(const string &bundleName) +{ + GTEST_LOG_(INFO) << "GetBackupExtName " << bundleName; + return ""; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/mock/module_sched/sched_scheduler_mock.cpp b/tests/mock/module_sched/sched_scheduler_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..09213b00f4d4bb35ee51984ef1b77fc703fd97df --- /dev/null +++ b/tests/mock/module_sched/sched_scheduler_mock.cpp @@ -0,0 +1,32 @@ +/* + * 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 "module_sched/sched_scheduler.h" + +#include "module_ipc/service.h" +#include "module_ipc/svc_session_manager.h" + +#include +#include + +namespace OHOS::FileManagement::Backup { +using namespace std; + +void SchedScheduler::Sched(string bundleName) {} + +void SchedScheduler::ExecutingQueueTasks(const string &bundleName) {} + +void SchedScheduler::RemoveExtConn(const string &bundleName) {} +}; // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/mock/parameter/include/parameter.h b/tests/mock/parameter/include/parameter.h new file mode 100644 index 0000000000000000000000000000000000000000..aec162176050520160f0fe27c87cdce35cd43ca9 --- /dev/null +++ b/tests/mock/parameter/include/parameter.h @@ -0,0 +1,40 @@ +/* + * 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 MOCK_OHOS_BACKUP_PARAMETER_H +#define MOCK_OHOS_BACKUP_PARAMETER_H + +#include +#include + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +void SetMockParameter(bool para); +bool GetMockParameter(void); + +uint32_t FindParameter(const char *key); +int GetParameterValue(uint32_t handle, char *value, uint32_t len); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif // MOCK_OHOS_BACKUP_PARAMETER_H \ No newline at end of file diff --git a/tests/mock/parameter/src/parameter.c b/tests/mock/parameter/src/parameter.c new file mode 100644 index 0000000000000000000000000000000000000000..4553975bdbf5098fceccb66eaa637d830a8fdc8f --- /dev/null +++ b/tests/mock/parameter/src/parameter.c @@ -0,0 +1,50 @@ +/* + * 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 "parameter.h" + +#include + +#include "securec.h" + +static int g_bMockParameter = 0; + +void SetMockParameter(bool para) +{ + g_bMockParameter = para; +} + +bool GetMockParameter(void) +{ + return g_bMockParameter; +} + +uint32_t FindParameter(const char *key) +{ + return 1; +} + +int GetParameterValue(uint32_t handle, char *value, uint32_t len) +{ + errno_t ret = EOK; + if (GetMockParameter()) { + char src[] = "true"; + ret = strncpy_s(value, len, src, strlen(src)); + } else { + char src[] = "false"; + ret = strncpy_s(value, len, src, strlen(src)); + } + return ret == EOK ? 1 : -1; +} \ No newline at end of file diff --git a/tests/mock/parcel/include/parcel.h b/tests/mock/parcel/include/parcel.h new file mode 100644 index 0000000000000000000000000000000000000000..816bbd5d6134dc57f6a1e0d81aad0ca155ec2cfd --- /dev/null +++ b/tests/mock/parcel/include/parcel.h @@ -0,0 +1,67 @@ +/* + * 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 MOCK_OHOS_BACKUP_PARCEL_H +#define MOCK_OHOS_BACKUP_PARCEL_H + +#include + +namespace OHOS::FileManagement::Backup { +void MockWriteUint32(bool state); + +void MockWriteString(bool state, uint8_t count); + +void MockWriteParcelable(bool state); + +void MockReadParcelable(bool state); + +void ResetParcelState(); + +bool GetMockReadParcelableState(); + +class Parcelable; +class Parcel { +public: + Parcel() {} + virtual ~Parcel() = default; + + bool WriteUint32(uint32_t); + + bool WriteString(const std::string &); + + bool WriteParcelable(const Parcelable *); + + bool ReadString(std::string &value); + + bool ReadUint32(uint32_t &value); + + template + T *ReadParcelable() + { + if (GetMockReadParcelableState()) { + return new T(); + } + return nullptr; + } +}; + +class Parcelable { +public: + Parcelable() = default; + virtual ~Parcelable() = default; + virtual bool Marshalling(Parcel &parcel) const = 0; +}; +} // namespace OHOS::FileManagement::Backup +#endif \ No newline at end of file diff --git a/tests/mock/parcel/src/parcel.cpp b/tests/mock/parcel/src/parcel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..104026433bfd663d591e0d79e2ad48718cebd9a4 --- /dev/null +++ b/tests/mock/parcel/src/parcel.cpp @@ -0,0 +1,97 @@ +/* + * 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 "parcel.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +namespace { +bool g_mockWriteUint32 = true; +bool g_mockWriteString = true; +bool g_mockWriteParcelable = true; +bool g_mockReadParcelable = true; +uint8_t g_mockWriteStringCount = 0; +uint8_t g_mockWriteStringMax = 0; +} // namespace + +void MockWriteUint32(bool state) +{ + g_mockWriteUint32 = state; +} + +void MockWriteString(bool state, uint8_t count) +{ + g_mockWriteString = state; + g_mockWriteStringMax = count; +} + +void MockWriteParcelable(bool state) +{ + g_mockWriteParcelable = state; +} + +void MockReadParcelable(bool state) +{ + g_mockReadParcelable = state; +} + +void ResetParcelState() +{ + g_mockWriteUint32 = true; + g_mockWriteString = true; + g_mockWriteParcelable = true; + g_mockReadParcelable = true; + g_mockWriteStringCount = 0; + g_mockWriteStringMax = 0; +} + +bool GetMockReadParcelableState() +{ + return g_mockReadParcelable; +} + +bool Parcel::WriteUint32(uint32_t) +{ + return g_mockWriteUint32; +} + +bool Parcel::WriteString(const string &) +{ + if (g_mockWriteStringCount < g_mockWriteStringMax) { + g_mockWriteStringCount++; + return !g_mockWriteString; + } + return g_mockWriteString; +} + +bool Parcel::WriteParcelable(const Parcelable *) +{ + return g_mockWriteParcelable; +} + +bool Parcel::ReadString(string &value) +{ + if (g_mockWriteStringCount < g_mockWriteStringMax) { + g_mockWriteStringCount++; + return !g_mockWriteString; + } + return g_mockWriteString; +} + +bool Parcel::ReadUint32(uint32_t &value) +{ + return g_mockWriteUint32; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/mock/system_ability_manager/service_registry_mock.cpp b/tests/mock/system_ability_manager/service_registry_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..51e768d3f86123c65dba5c3a3f501a1d46152025 --- /dev/null +++ b/tests/mock/system_ability_manager/service_registry_mock.cpp @@ -0,0 +1,56 @@ +/* + * 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 "iservice_registry.h" + +#include +#include +#include + +#include "system_ability_definition.h" +#include "system_ability_manager_proxy.h" +#include "utils_mock_global_variable.h" + +namespace OHOS { +using namespace FileManagement::Backup; + +SystemAbilityManagerClient &SystemAbilityManagerClient::GetInstance() +{ + static auto instance = new SystemAbilityManagerClient(); + return *instance; +} + +sptr SystemAbilityManagerClient::GetSystemAbilityManager() +{ + GTEST_LOG_(INFO) << "GetSystemAbilityManager is ok"; + std::lock_guard lock(systemAbilityManagerLock_); + if (systemAbilityManager_ != nullptr) { + return systemAbilityManager_; + } + + systemAbilityManager_ = new SystemAbilityManagerProxy(nullptr); + return systemAbilityManager_; +} + +int32_t SystemAbilityManagerProxy::LoadSystemAbility(int32_t systemAbilityId, + const sptr &callback) +{ + GTEST_LOG_(INFO) << "LoadSystemAbility is ok"; + if (!GetMockLoadSystemAbility()) { + return -1; + } + return ERR_OK; +} +} // namespace OHOS \ No newline at end of file diff --git a/tests/mock/timer/timer_mock.cpp b/tests/mock/timer/timer_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..12ff79236646522ff640fb9c863cb1b62857b8e1 --- /dev/null +++ b/tests/mock/timer/timer_mock.cpp @@ -0,0 +1,53 @@ +/* + * 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 "timer.h" + +#include +#include + +namespace OHOS { +namespace Utils { + +Timer::Timer(const std::string &name, int timeoutMs) +{ + GTEST_LOG_(INFO) << "Timer " << name << " ,timeoutMs " << timeoutMs; + name_ = name; +} + +uint32_t Timer::Setup() +{ + GTEST_LOG_(INFO) << "Timer Setup"; + return 1; +} + +uint32_t Timer::Register(const TimerCallback &callback, uint32_t interval, bool once) +{ + GTEST_LOG_(INFO) << "Timer Register " << interval; + callback(); + return 1; +} + +void Timer::Shutdown(bool useJoin) +{ + GTEST_LOG_(INFO) << "Timer Shutdown " << useJoin; +} + +void Timer::Unregister(uint32_t timerId) +{ + GTEST_LOG_(INFO) << "Timer Unregister " << timerId; +} +} // namespace Utils +} // namespace OHOS diff --git a/tests/mock/utils_mock/include/iremote_object_mock.h b/tests/mock/utils_mock/include/iremote_object_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..3fbc0f07179bce13e4f8f4c59fd81a7e65201cf4 --- /dev/null +++ b/tests/mock/utils_mock/include/iremote_object_mock.h @@ -0,0 +1,86 @@ +/* + * 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_FILEMGMT_BACKUP_IREMOTE_OBJECT_MOCK_H +#define OHOS_FILEMGMT_BACKUP_IREMOTE_OBJECT_MOCK_H + +#include + +#include "iremote_object.h" + +namespace OHOS::FileManagement::Backup { +class MockIRemoteObject : public IRemoteObject { +public: + MockIRemoteObject() : IRemoteObject(u"mock_i_remote_object") + { + GTEST_LOG_(INFO) << "MockIRemoteObject is ok"; + } + + ~MockIRemoteObject() {} + + int SendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override + { + return 0; + } + + int32_t GetObjectRefCount() override + { + return 0; + } + + bool CheckObjectLegality() const override + { + return true; + } + + bool IsProxyObject() const override + { + return true; + } + + bool AddDeathRecipient(const sptr &recipient) override + { + GTEST_LOG_(INFO) << "AddDeathRecipient is ok"; + return true; + } + + bool RemoveDeathRecipient(const sptr &recipient) override + { + return true; + } + + sptr AsInterface() override + { + return nullptr; + } + + bool Marshalling(Parcel &parcel) const override + { + return true; + } + + std::u16string GetObjectDescriptor() const + { + std::u16string descriptor = std::u16string(); + return descriptor; + } + + int Dump(int fd, const std::vector &args) override + { + return 0; + } +}; +} // namespace OHOS::FileManagement::Backup +#endif \ No newline at end of file diff --git a/tests/mock/utils_mock/include/utils_mock_global_variable.h b/tests/mock/utils_mock/include/utils_mock_global_variable.h new file mode 100644 index 0000000000000000000000000000000000000000..8b4a7004d02f2c09c7638dbe2d1aab308bb8720b --- /dev/null +++ b/tests/mock/utils_mock/include/utils_mock_global_variable.h @@ -0,0 +1,27 @@ +/* + * 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 MOCK_OHOS_BACKUP_UTILS_MOCK_GLOBAL_VARIABLE_H +#define MOCK_OHOS_BACKUP_UTILS_MOCK_GLOBAL_VARIABLE_H + +namespace OHOS::FileManagement::Backup { +void SetMockGetInstance(bool state); +void SetMockInitBackupOrRestoreSession(bool state); +bool GetMockGetInstance(); +bool GetMockInitBackupOrRestoreSession(); +void SetMockLoadSystemAbility(bool state); +bool GetMockLoadSystemAbility(); +} // namespace OHOS::FileManagement::Backup +#endif \ No newline at end of file diff --git a/tests/mock/utils_mock/src/utils_mock_global_variable.cpp b/tests/mock/utils_mock/src/utils_mock_global_variable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d0bc84e61601d6e892ddccec518de41075a6e24d --- /dev/null +++ b/tests/mock/utils_mock/src/utils_mock_global_variable.cpp @@ -0,0 +1,54 @@ +/* + * 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 "utils_mock_global_variable.h" + +namespace OHOS::FileManagement::Backup { +namespace { +static bool g_bMockGetInstance = true; +static bool g_bMockInitBackupOrRestoreSession = true; +static bool g_bMockLoadSystemAbility = true; +} // namespace + +void SetMockGetInstance(bool state) +{ + g_bMockGetInstance = state; +} + +void SetMockInitBackupOrRestoreSession(bool state) +{ + g_bMockInitBackupOrRestoreSession = state; +} + +bool GetMockGetInstance() +{ + return g_bMockGetInstance; +} + +bool GetMockInitBackupOrRestoreSession() +{ + return g_bMockInitBackupOrRestoreSession; +} + +void SetMockLoadSystemAbility(bool state) +{ + g_bMockLoadSystemAbility = state; +} + +bool GetMockLoadSystemAbility() +{ + return g_bMockLoadSystemAbility; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/moduletests/BUILD.gn b/tests/moduletests/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..041af97361903b168f5f3b27a00bbdc01dd9a043 --- /dev/null +++ b/tests/moduletests/BUILD.gn @@ -0,0 +1,24 @@ +# 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. + +import("//build/ohos.gni") +import("//foundation/filemanagement/app_file_service/backup.gni") + +group("moduletests") { + testonly = true + + deps = [ + "backup_kit_inner:session_test", + "backup_tool:tools_test", + ] +} diff --git a/tests/moduletests/backup_kit_inner/BUILD.gn b/tests/moduletests/backup_kit_inner/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..46794135c34ef368fea551e8a1fdd7c0d102c995 --- /dev/null +++ b/tests/moduletests/backup_kit_inner/BUILD.gn @@ -0,0 +1,51 @@ +# 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. + +import("//build/test.gni") +import("//foundation/filemanagement/app_file_service/backup.gni") + +ohos_unittest("b_session_test") { + module_out_path = path_module_out_tests + + sources = [ + "${path_backup}/frameworks/native/backup_kit_inner/src/b_session_backup.cpp", + "${path_backup}/frameworks/native/backup_kit_inner/src/b_session_restore.cpp", + "${path_backup}/frameworks/native/backup_kit_inner/src/service_reverse.cpp", + "${path_backup}/frameworks/native/backup_kit_inner/src/service_reverse_stub.cpp", + "b_session_backup_test.cpp", + "b_session_restore_test.cpp", + ] + sources += backup_mock_proxy_src + + include_dirs = [ + "${path_backup}/interfaces/inner_api/native/backup_kit_inner/", + "${path_backup}/interfaces/inner_api/native/backup_kit_inner/impl", + "${path_backup}/frameworks/native/backup_kit_inner/include", + ] + include_dirs += backup_mock_utils_include + + deps = [ + "${path_backup}/tests/utils:backup_test_utils", + "${path_backup}/utils:backup_utils", + "${path_ipc}/interfaces/innerkits/ipc_core:ipc_core", + "${path_samgr}/interfaces/innerkits/samgr_proxy:samgr_proxy", + ] + + use_exceptions = true +} + +group("session_test") { + testonly = true + + deps = [ ":b_session_test" ] +} diff --git a/tests/moduletests/backup_kit_inner/b_session_backup_test.cpp b/tests/moduletests/backup_kit_inner/b_session_backup_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f958ca76f4558b6779e493c4665e71c6fe5887db --- /dev/null +++ b/tests/moduletests/backup_kit_inner/b_session_backup_test.cpp @@ -0,0 +1,241 @@ +/* + * 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 + +#include "b_error/b_error.h" +#include "b_file_info.h" +#include "backup_kit_inner.h" +#include "unique_fd.h" +#include "utils_mock_global_variable.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +static void OnFileReady(const BFileInfo &fileInfo, UniqueFd fd) +{ + GTEST_LOG_(INFO) << "BSessionBackupTest OnFileReady OK"; +} + +static void OnBundleStarted(ErrCode err, const BundleName name) +{ + GTEST_LOG_(INFO) << "BSessionBackupTest OnBundleStarted OK"; +} + +static void OnBundleFinished(ErrCode err, const BundleName name) +{ + GTEST_LOG_(INFO) << "BSessionBackupTest OnBundleFinished OK"; +} + +static void OnAllBundlesFinished(ErrCode err) +{ + GTEST_LOG_(INFO) << "BSessionBackupTest OnAllBundlesFinished OK"; +} + +static void OnBackupServiceDied() +{ + GTEST_LOG_(INFO) << "BSessionBackupTest OnBackupServiceDied OK"; +} + +class BSessionBackupTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() override; + void TearDown() override; + + void Init(); + + unique_ptr backupPtr_; + BSessionBackup::Callbacks callbacks_; +}; + +void BSessionBackupTest::SetUp() +{ + SetMockInitBackupOrRestoreSession(true); + SetMockGetInstance(true); + SetMockLoadSystemAbility(true); + backupPtr_ = make_unique(); +} + +void BSessionBackupTest::TearDown() +{ + backupPtr_ = nullptr; +} + +void BSessionBackupTest::Init() +{ + callbacks_.onFileReady = OnFileReady; + callbacks_.onBundleStarted = OnBundleStarted; + callbacks_.onBundleFinished = OnBundleFinished; + callbacks_.onAllBundlesFinished = OnAllBundlesFinished; + callbacks_.onBackupServiceDied = OnBackupServiceDied; +} + +/** + * @tc.number: SUB_backup_b_session_backup_0100 + * @tc.name: SUB_backup_b_session_backup_0100 + * @tc.desc: 测试Start接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(BSessionBackupTest, SUB_backup_b_session_backup_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BSessionBackupTest-begin SUB_backup_b_session_backup_0100"; + try { + GTEST_LOG_(INFO) << "GetInstance is true"; + auto ret = backupPtr_->Start(); + EXPECT_EQ(ret, ErrCode(BError::Codes::OK)); + GTEST_LOG_(INFO) << "GetInstance is false"; + SetMockGetInstance(false); + ret = backupPtr_->Start(); + EXPECT_NE(ret, ErrCode(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BSessionBackupTest-an exception occurred by Start."; + } + GTEST_LOG_(INFO) << "BSessionBackupTest-end SUB_backup_b_session_backup_0100"; +} + +/** + * @tc.number: SUB_backup_b_session_backup_0200 + * @tc.name: SUB_backup_b_session_backup_0200 + * @tc.desc: 测试Callbacks接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(BSessionBackupTest, SUB_backup_b_session_backup_0200, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BSessionBackupTest-begin SUB_backup_b_session_backup_0200"; + try { + Init(); + BFileInfo bFileInfo("", "", 0); + callbacks_.onFileReady(bFileInfo, UniqueFd(-1)); + callbacks_.onBundleStarted(ErrCode(BError::Codes::OK), ""); + callbacks_.onBundleFinished(ErrCode(BError::Codes::OK), ""); + callbacks_.onAllBundlesFinished(ErrCode(BError::Codes::OK)); + callbacks_.onBackupServiceDied(); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BSessionBackupTest-an exception occurred by Callbacks."; + } + GTEST_LOG_(INFO) << "BSessionBackupTest-end SUB_backup_b_session_backup_0200"; +} + +/** + * @tc.number: SUB_backup_b_session_backup_0300 + * @tc.name: SUB_backup_b_session_backup_0300 + * @tc.desc: 测试Init接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(BSessionBackupTest, SUB_backup_b_session_backup_0300, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BSessionBackupTest-begin SUB_backup_b_session_backup_0300"; + try { + GTEST_LOG_(INFO) << "GetInstance is false"; + SetMockGetInstance(false); + vector bundlesToBackup; + auto backupPtr = BSessionBackup::Init(UniqueFd(-1), bundlesToBackup, BSessionBackup::Callbacks {}); + EXPECT_EQ(backupPtr, nullptr); + GTEST_LOG_(INFO) << "GetInstance is true"; + GTEST_LOG_(INFO) << "InitBackupSession is false"; + SetMockGetInstance(true); + SetMockInitBackupOrRestoreSession(false); + backupPtr = BSessionBackup::Init(UniqueFd(-1), bundlesToBackup, BSessionBackup::Callbacks {}); + EXPECT_EQ(backupPtr, nullptr); + GTEST_LOG_(INFO) << "InitBackupSession is true"; + SetMockInitBackupOrRestoreSession(true); + Init(); + backupPtr = BSessionBackup::Init(UniqueFd(-1), bundlesToBackup, callbacks_); + EXPECT_NE(backupPtr, nullptr); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BSessionBackupTest-an exception occurred by Init."; + } + GTEST_LOG_(INFO) << "BSessionBackupTest-end SUB_backup_b_session_backup_0300"; +} + +/** + * @tc.number: SUB_backup_b_session_backup_0400 + * @tc.name: SUB_backup_b_session_backup_0400 + * @tc.desc: 测试RegisterBackupServiceDied接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(BSessionBackupTest, SUB_backup_b_session_backup_0400, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BSessionBackupTest-begin SUB_backup_b_session_backup_0400"; + try { + GTEST_LOG_(INFO) << "GetInstance is false"; + SetMockGetInstance(false); + backupPtr_->RegisterBackupServiceDied(nullptr); + GTEST_LOG_(INFO) << "GetInstance is true"; + SetMockGetInstance(true); + backupPtr_->RegisterBackupServiceDied(nullptr); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BSessionBackupTest-an exception occurred by RegisterBackupServiceDied."; + } + GTEST_LOG_(INFO) << "BSessionBackupTest-end SUB_backup_b_session_backup_0400"; +} + +/** + * @tc.number: SUB_backup_b_session_backup_0500 + * @tc.name: SUB_backup_b_session_backup_0500 + * @tc.desc: 测试析构流程接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(BSessionBackupTest, SUB_backup_b_session_backup_0500, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BSessionBackupTest-begin SUB_backup_b_session_backup_0500"; + try { + SetMockGetInstance(true); + SetMockLoadSystemAbility(true); + vector bundlesToBackup; + Init(); + auto backupPtr = BSessionBackup::Init(UniqueFd(-1), bundlesToBackup, callbacks_); + EXPECT_NE(backupPtr, nullptr); + + GTEST_LOG_(INFO) << "GetInstance is false"; + SetMockGetInstance(false); + backupPtr = nullptr; + + SetMockGetInstance(true); + SetMockLoadSystemAbility(true); + backupPtr = BSessionBackup::Init(UniqueFd(-1), bundlesToBackup, callbacks_); + EXPECT_NE(backupPtr, nullptr); + + GTEST_LOG_(INFO) << "LoadSystemAbility is false"; + SetMockLoadSystemAbility(false); + backupPtr = nullptr; + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BSessionBackupTest-an exception occurred by ~BSessionBackup."; + } + GTEST_LOG_(INFO) << "BSessionBackupTest-end SUB_backup_b_session_backup_0500"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/moduletests/backup_kit_inner/b_session_restore_test.cpp b/tests/moduletests/backup_kit_inner/b_session_restore_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f0749e165576dc928cdd09b4488724082be75c10 --- /dev/null +++ b/tests/moduletests/backup_kit_inner/b_session_restore_test.cpp @@ -0,0 +1,329 @@ +/* + * 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 +#include + +#include "b_error/b_error.h" +#include "b_file_info.h" +#include "backup_kit_inner.h" +#include "unique_fd.h" +#include "utils_mock_global_variable.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +static void OnFileReady(const BFileInfo &fileInfo, UniqueFd fd) +{ + GTEST_LOG_(INFO) << "BSessionRestoreTest OnFileReady OK"; +} + +static void OnBundleStarted(ErrCode err, const BundleName name) +{ + GTEST_LOG_(INFO) << "BSessionRestoreTest OnBundleStarted OK"; +} + +static void OnBundleFinished(ErrCode err, const BundleName name) +{ + GTEST_LOG_(INFO) << "BSessionRestoreTest OnBundleFinished OK"; +} + +static void OnAllBundlesFinished(ErrCode err) +{ + GTEST_LOG_(INFO) << "BSessionRestoreTest OnAllBundlesFinished OK"; +} + +static void OnBackupServiceDied() +{ + GTEST_LOG_(INFO) << "BSessionRestoreTest OnBackupServiceDied OK"; +} + +class BSessionRestoreTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() override; + void TearDown() override; + + void Init(); + + unique_ptr restorePtr_; + BSessionRestore::Callbacks callbacks_; +}; + +void BSessionRestoreTest::SetUp() +{ + SetMockInitBackupOrRestoreSession(true); + SetMockGetInstance(true); + SetMockLoadSystemAbility(true); + restorePtr_ = unique_ptr(); +} + +void BSessionRestoreTest::TearDown() +{ + restorePtr_ = nullptr; +} + +void BSessionRestoreTest::Init() +{ + callbacks_.onFileReady = OnFileReady; + callbacks_.onBundleStarted = OnBundleStarted; + callbacks_.onBundleFinished = OnBundleFinished; + callbacks_.onAllBundlesFinished = OnAllBundlesFinished; + callbacks_.onBackupServiceDied = OnBackupServiceDied; +} + +/** + * @tc.number: SUB_backup_b_session_restore_0100 + * @tc.name: SUB_backup_b_session_restore_0100 + * @tc.desc: 测试Start接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(BSessionRestoreTest, SUB_backup_b_session_restore_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BSessionRestoreTest-begin SUB_backup_b_session_restore_0100"; + try { + GTEST_LOG_(INFO) << "GetInstance is true"; + auto ret = restorePtr_->Start(); + EXPECT_EQ(ret, ErrCode(BError::Codes::OK)); + GTEST_LOG_(INFO) << "GetInstance is false"; + SetMockGetInstance(false); + ret = restorePtr_->Start(); + EXPECT_NE(ret, ErrCode(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BSessionRestoreTest-an exception occurred by Start."; + } + GTEST_LOG_(INFO) << "BSessionRestoreTest-end SUB_backup_b_session_restore_0100"; +} + +/** + * @tc.number: SUB_backup_b_session_restore_0200 + * @tc.name: SUB_backup_b_session_restore_0200 + * @tc.desc: 测试Callbacks接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(BSessionRestoreTest, SUB_backup_b_session_restore_0200, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BSessionRestoreTest-begin SUB_backup_b_session_restore_0200"; + try { + Init(); + BFileInfo bFileInfo("", "", 0); + callbacks_.onFileReady(bFileInfo, UniqueFd(-1)); + callbacks_.onBundleStarted(ErrCode(BError::Codes::OK), ""); + callbacks_.onBundleFinished(ErrCode(BError::Codes::OK), ""); + callbacks_.onAllBundlesFinished(ErrCode(BError::Codes::OK)); + callbacks_.onBackupServiceDied(); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BSessionRestoreTest-an exception occurred by Callbacks."; + } + GTEST_LOG_(INFO) << "BSessionRestoreTest-end SUB_backup_b_session_restore_0200"; +} + +/** + * @tc.number: SUB_backup_b_session_restore_0300 + * @tc.name: SUB_backup_b_session_restore_0300 + * @tc.desc: 测试Init接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(BSessionRestoreTest, SUB_backup_b_session_restore_0300, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BSessionRestoreTest-begin SUB_backup_b_session_restore_0300"; + try { + GTEST_LOG_(INFO) << "GetInstance is false"; + SetMockGetInstance(false); + vector bundlesToBackup; + auto restorePtr = BSessionRestore::Init(bundlesToBackup, {}); + EXPECT_EQ(restorePtr, nullptr); + GTEST_LOG_(INFO) << "GetInstance is true"; + GTEST_LOG_(INFO) << "InitBackupSession is false"; + SetMockGetInstance(true); + SetMockInitBackupOrRestoreSession(false); + restorePtr = BSessionRestore::Init(bundlesToBackup, {}); + EXPECT_EQ(restorePtr, nullptr); + GTEST_LOG_(INFO) << "InitBackupSession is true"; + SetMockInitBackupOrRestoreSession(true); + Init(); + restorePtr = BSessionRestore::Init(bundlesToBackup, callbacks_); + EXPECT_NE(restorePtr, nullptr); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BSessionRestoreTest-an exception occurred by Init."; + } + GTEST_LOG_(INFO) << "BSessionRestoreTest-end SUB_backup_b_session_restore_0300"; +} + +/** + * @tc.number: SUB_backup_b_session_restore_0400 + * @tc.name: SUB_backup_b_session_restore_0400 + * @tc.desc: 测试GetLocalCapabilities接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0377 + */ +HWTEST_F(BSessionRestoreTest, SUB_backup_b_session_restore_0400, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BSessionRestoreTest-begin SUB_backup_b_session_restore_0400"; + try { + GTEST_LOG_(INFO) << "GetInstance is false"; + SetMockGetInstance(false); + auto fd = restorePtr_->GetLocalCapabilities(); + EXPECT_NE(fd, 0); + GTEST_LOG_(INFO) << "GetInstance is true"; + SetMockGetInstance(true); + fd = restorePtr_->GetLocalCapabilities(); + EXPECT_NE(fd, 0); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BSessionRestoreTest-an exception occurred by GetLocalCapabilities."; + } + GTEST_LOG_(INFO) << "BSessionRestoreTest-end SUB_backup_b_session_restore_0400"; +} + +/** + * @tc.number: SUB_backup_b_session_restore_0500 + * @tc.name: SUB_backup_b_session_restore_0500 + * @tc.desc: 测试PublishFile接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(BSessionRestoreTest, SUB_backup_b_session_restore_0500, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BSessionRestoreTest-begin SUB_backup_b_session_restore_0500"; + try { + GTEST_LOG_(INFO) << "GetInstance is false"; + SetMockGetInstance(false); + BFileInfo bFileInfo("", "", 0); + auto ret = restorePtr_->PublishFile(bFileInfo); + EXPECT_NE(ret, ErrCode(BError::Codes::OK)); + GTEST_LOG_(INFO) << "GetInstance is true"; + SetMockGetInstance(true); + ret = restorePtr_->PublishFile(bFileInfo); + EXPECT_EQ(ret, ErrCode(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BSessionRestoreTest-an exception occurred by PublishFile."; + } + GTEST_LOG_(INFO) << "BSessionRestoreTest-end SUB_backup_b_session_restore_0500"; +} + +/** + * @tc.number: SUB_backup_b_session_restore_0600 + * @tc.name: SUB_backup_b_session_restore_0600 + * @tc.desc: 测试GetExtFileName接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(BSessionRestoreTest, SUB_backup_b_session_restore_0600, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BSessionRestoreTest-begin SUB_backup_b_session_restore_0600"; + try { + GTEST_LOG_(INFO) << "GetInstance is false"; + SetMockGetInstance(false); + string bundleName = ""; + string fileName = ""; + auto ret = restorePtr_->GetExtFileName(bundleName, fileName); + EXPECT_NE(ret, ErrCode(BError::Codes::OK)); + GTEST_LOG_(INFO) << "GetInstance is true"; + SetMockGetInstance(true); + ret = restorePtr_->GetExtFileName(bundleName, fileName); + EXPECT_EQ(ret, ErrCode(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BSessionRestoreTest-an exception occurred by GetExtFileName."; + } + GTEST_LOG_(INFO) << "BSessionRestoreTest-end SUB_backup_b_session_restore_0600"; +} + +/** + * @tc.number: SUB_backup_b_session_restore_0700 + * @tc.name: SUB_backup_b_session_restore_0700 + * @tc.desc: 测试RegisterBackupServiceDied接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(BSessionRestoreTest, SUB_backup_b_session_restore_0700, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BSessionRestoreTest-begin SUB_backup_b_session_restore_0700"; + try { + GTEST_LOG_(INFO) << "GetInstance is false"; + SetMockGetInstance(false); + restorePtr_->RegisterBackupServiceDied(nullptr); + GTEST_LOG_(INFO) << "GetInstance is true"; + SetMockGetInstance(true); + restorePtr_->RegisterBackupServiceDied(nullptr); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BSessionRestoreTest-an exception occurred by RegisterBackupServiceDied."; + } + GTEST_LOG_(INFO) << "BSessionRestoreTest-end SUB_backup_b_session_restore_0700"; +} + +/** + * @tc.number: SUB_backup_b_session_restore_0800 + * @tc.name: SUB_backup_b_session_restore_0800 + * @tc.desc: 测试析构流程接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(BSessionRestoreTest, SUB_backup_b_session_restore_0800, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BSessionRestoreTest-begin SUB_backup_b_session_restore_0800"; + try { + vector bundlesToBackup; + SetMockGetInstance(true); + SetMockLoadSystemAbility(true); + Init(); + auto restorePtr = BSessionRestore::Init(bundlesToBackup, callbacks_); + EXPECT_NE(restorePtr, nullptr); + + GTEST_LOG_(INFO) << "GetInstance is false"; + SetMockGetInstance(false); + restorePtr = nullptr; + + SetMockGetInstance(true); + SetMockLoadSystemAbility(true); + restorePtr = BSessionRestore::Init(bundlesToBackup, callbacks_); + EXPECT_NE(restorePtr, nullptr); + + GTEST_LOG_(INFO) << "LoadSystemAbility is false"; + SetMockLoadSystemAbility(false); + restorePtr = nullptr; + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BSessionRestoreTest-an exception occurred by ~BSessionRestore."; + } + GTEST_LOG_(INFO) << "BSessionRestoreTest-end SUB_backup_b_session_restore_0800"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/moduletests/backup_tool/BUILD.gn b/tests/moduletests/backup_tool/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..c9bfb0168a7e47a693ee4bbe7134f93c19e3cd0c --- /dev/null +++ b/tests/moduletests/backup_tool/BUILD.gn @@ -0,0 +1,37 @@ +# 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. + +import("//build/test.gni") +import("//foundation/filemanagement/app_file_service/backup.gni") + +ohos_unittest("tools_op_test") { + module_out_path = path_module_out_tests + + sources = [ + "tool_backup_restore_test.cpp", + "tool_help_test.cpp", + ] + + deps = [ + "${path_backup}/tests/utils:backup_test_utils", + "${path_backup}/utils/:backup_utils", + ] + + use_exceptions = true +} + +group("tools_test") { + testonly = true + + deps = [ ":tools_op_test" ] +} diff --git a/tests/moduletests/backup_tool/tool_backup_restore_test.cpp b/tests/moduletests/backup_tool/tool_backup_restore_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3aa896201fe749ff1ae7be9d71e0257f81efe7ae --- /dev/null +++ b/tests/moduletests/backup_tool/tool_backup_restore_test.cpp @@ -0,0 +1,31 @@ +/* + * 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 + +#include "b_process/b_process.h" +#include "test_manager.h" +#include "gtest/gtest.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +class ToolsTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() {}; + void TearDown() {}; +}; +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/moduletests/backup_tool/tool_help_test.cpp b/tests/moduletests/backup_tool/tool_help_test.cpp new file mode 100755 index 0000000000000000000000000000000000000000..08552813f3c65f76f451c41dc359a460d8d0ce49 --- /dev/null +++ b/tests/moduletests/backup_tool/tool_help_test.cpp @@ -0,0 +1,78 @@ +/* + * 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 "b_process/b_process.h" +#include "test_manager.h" +#include "gtest/gtest.h" + +namespace OHOS::FileManagement::Backup { +class ToolsTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() {}; + void TearDown() {}; +}; + +/** + * @tc.number: SUB_backup_tool_help_0100 + * @tc.name: tool_help_0100 + * @tc.desc: 测试help命令常规用法 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0377 + */ +HWTEST_F(ToolsTest, tool_help_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "ToolsTest-begin tool_help_0100"; + try { + auto [bFatalError, ret] = BProcess::ExecuteCmd({ + "/system/bin/backup_tool", + "help", + }); + EXPECT_EQ(ret, 0); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ToolsTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "ToolsTest-end tool_help_0100"; +} + +/** + * @tc.number: SUB_backup_tool_help_0200 + * @tc.name: tool_help_0200 + * @tc.desc: 测试help命令错误使用 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0377 + */ +HWTEST_F(ToolsTest, tool_help_0200, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "ToolsTest-begin tool_help_0200"; + try { + auto [bFatalError, ret] = BProcess::ExecuteCmd({ + "/system/bin/backup_tool", + "xxxx", + }); + EXPECT_NE(ret, 0); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ToolsTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "ToolsTest-end tool_help_0200"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/BUILD.gn b/tests/unittests/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..5902c09e5318b008fd9fec826f2d976b221fcb6d --- /dev/null +++ b/tests/unittests/BUILD.gn @@ -0,0 +1,26 @@ +# 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. + +import("//build/ohos.gni") +import("//foundation/filemanagement/app_file_service/backup.gni") + +group("unittests") { + testonly = true + + deps = [ + "backup_api:backup_api_test", + "backup_sa:backup_sa_test", + "backup_tools:backup_test", + "backup_utils:backup_test", + ] +} diff --git a/tests/unittests/backup_api/BUILD.gn b/tests/unittests/backup_api/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..4b93a25826521f81a9e1b5ef59a8b2a7deb5ab09 --- /dev/null +++ b/tests/unittests/backup_api/BUILD.gn @@ -0,0 +1,21 @@ +# 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. + +import("//build/ohos.gni") +import("//foundation/filemanagement/app_file_service/backup.gni") + +group("backup_api_test") { + testonly = true + + deps = [ "backup_impl:backup_impl_test" ] +} diff --git a/tests/unittests/backup_api/backup_impl/BUILD.gn b/tests/unittests/backup_api/backup_impl/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..df60a1062795bc0ec17d719d41f2ad0d7d1ec223 --- /dev/null +++ b/tests/unittests/backup_api/backup_impl/BUILD.gn @@ -0,0 +1,79 @@ +# 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. + +import("//build/test.gni") +import("//foundation/filemanagement/app_file_service/backup.gni") + +ohos_unittest("b_file_info_test") { + module_out_path = path_module_out_tests + + sources = [ + "${path_backup}/frameworks/native/backup_kit_inner/src/b_file_info.cpp", + "b_file_info_test.cpp", + ] + sources += backup_mock_parcel_src + + include_dirs = + [ "${path_backup}/interfaces/inner_api/native/backup_kit_inner/impl" ] + include_dirs += backup_mock_parcel_include_dirs + + deps = [ + "${path_backup}/tests/utils:backup_test_utils", + "${path_backup}/utils:backup_utils", + ] + + use_exceptions = true +} + +ohos_unittest("backup_sa_impl_test") { + module_out_path = "filemanagement/backup" + + sources = [ + "${path_backup_mock}/system_ability_manager/service_registry_mock.cpp", + "${path_backup_mock}/utils_mock/src/utils_mock_global_variable.cpp", + "service_proxy_test.cpp", + "service_reverse_stub_test.cpp", + "service_reverse_test.cpp", + "svc_death_recipient_test.cpp", + ] + + include_dirs = [ + "${path_backup}/services/backup_sa/include", + "${path_backup}/frameworks/native/backup_kit_inner/include", + "${path_backup}/tests/unittests/backup_api/backup_impl/include", + "${path_backup}/interfaces/inner_api/native/backup_kit_inner/impl", + ] + include_dirs += backup_mock_utils_include + + deps = [ + "${path_backup}/tests/utils:backup_test_utils", + "${path_backup}/utils:backup_utils", + "${path_googletest}:gmock_main", + ] + + external_deps = [ + "app_file_service:backup_kit_inner", + "ipc:ipc_core", + ] + + use_exceptions = true +} + +group("backup_impl_test") { + testonly = true + + deps = [ + ":b_file_info_test", + ":backup_sa_impl_test", + ] +} diff --git a/tests/unittests/backup_api/backup_impl/b_file_info_test.cpp b/tests/unittests/backup_api/backup_impl/b_file_info_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ae5859ffee6299f9448dceb8cdba774af2c561c4 --- /dev/null +++ b/tests/unittests/backup_api/backup_impl/b_file_info_test.cpp @@ -0,0 +1,141 @@ +/* + * 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 + +#include "b_file_info.h" +#include "parcel.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +using namespace testing; + +namespace { +const string BUNDLE_NAME = "com.example.app2backup"; +const string FILE_NAME = "1.tar"; +} // namespace + +class BFileInfoTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() override {}; + void TearDown() override {}; +}; + +/** + * @tc.number: SUB_BFile_Info_Marshalling_0100 + * @tc.name: SUB_BFile_Info_Marshalling_0100 + * @tc.desc: Test function of Marshalling interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(BFileInfoTest, SUB_BFile_Info_Marshalling_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BFileInfoTest-begin SUB_BFile_Info_Marshalling_0100"; + BFileInfo bFileInfo(BUNDLE_NAME, FILE_NAME, -1); + Parcel parcel; + // marshalling + EXPECT_EQ(bFileInfo.Marshalling(parcel), true); + // unmarshalling + auto infoPtr = bFileInfo.Unmarshalling(parcel); + EXPECT_NE(infoPtr, nullptr); + GTEST_LOG_(INFO) << "BFileInfoTest-end SUB_BFile_Info_Marshalling_0100"; +} + +/** + * @tc.number: SUB_BFile_Info_ReadFromParcel_0100 + * @tc.name: SUB_BFile_Info_ReadFromParcel_0100 + * @tc.desc: Test function of ReadFromParcel interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(BFileInfoTest, SUB_BFile_Info_ReadFromParcel_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BFileInfoTest-begin SUB_BFile_Info_ReadFromParcel_0100"; + BFileInfo bFileInfo(BUNDLE_NAME, FILE_NAME, -1); + Parcel parcel; + // marshalling + EXPECT_EQ(bFileInfo.Marshalling(parcel), true); + + // ReadFromParcel + BFileInfo bFileInfoTemp {"", "", -1}; + bFileInfoTemp.ReadFromParcel(parcel); + GTEST_LOG_(INFO) << "BFileInfoTest-end SUB_BFile_Info_ReadFromParcel_0100"; +} + +/** + * @tc.number: SUB_BFile_Info_Unmarshalling_0100 + * @tc.name: SUB_BFile_Info_Unmarshalling_0100 + * @tc.desc: Test function of Unmarshalling interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(BFileInfoTest, SUB_BFile_Info_Unmarshalling_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BFileInfoTest-begin SUB_BFile_Info_Unmarshalling_0100"; + BFileInfo bFileInfo(BUNDLE_NAME, FILE_NAME, -1); + Parcel parcel; + // marshalling + EXPECT_EQ(bFileInfo.Marshalling(parcel), true); + // unmarshalling + BFileInfo bFileInfoTemp {"", "", -1}; + auto infoPtr = bFileInfoTemp.Unmarshalling(parcel); + EXPECT_NE(infoPtr, nullptr); + GTEST_LOG_(INFO) << "BFileInfoTest-end SUB_BFile_Info_Unmarshalling_0100"; +} + +/** + * @tc.number: SUB_BFile_Info_0200 + * @tc.name: SUB_BFile_Info_0200 + * @tc.desc: 分支测试 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(BFileInfoTest, SUB_BFile_Info_0200, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BFileInfoTest-begin SUB_BFile_Info_0200"; + BFileInfo bFileInfo(BUNDLE_NAME, FILE_NAME, -1); + Parcel parcel; + ResetParcelState(); + MockWriteUint32(false); + EXPECT_EQ(bFileInfo.Marshalling(parcel), false); + MockWriteUint32(true); + MockWriteString(false, 1); + EXPECT_EQ(bFileInfo.Marshalling(parcel), false); + EXPECT_EQ(bFileInfo.Marshalling(parcel), false); + + ResetParcelState(); + MockWriteUint32(false); + EXPECT_EQ(bFileInfo.ReadFromParcel(parcel), false); + MockWriteUint32(true); + MockWriteString(false, 1); + EXPECT_EQ(bFileInfo.ReadFromParcel(parcel), false); + EXPECT_EQ(bFileInfo.ReadFromParcel(parcel), false); + + auto infoPtr = bFileInfo.Unmarshalling(parcel); + EXPECT_EQ(infoPtr, nullptr); + + GTEST_LOG_(INFO) << "BFileInfoTest-end SUB_BFile_Info_0200"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_api/backup_impl/include/ext_extension_mock.h b/tests/unittests/backup_api/backup_impl/include/ext_extension_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..6be2c2ae987bdfe7fc2fc6bd0ba00544ca0853f8 --- /dev/null +++ b/tests/unittests/backup_api/backup_impl/include/ext_extension_mock.h @@ -0,0 +1,99 @@ +/* + * 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 MOCK_EXTENSION_MOCK_H +#define MOCK_EXTENSION_MOCK_H + +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "i_extension.h" +#include "iremote_stub.h" +#include "test_manager.h" + +namespace OHOS::FileManagement::Backup { +class BackupExtExtensionMock : public IRemoteStub { +public: + int code_ = 0; + BackupExtExtensionMock() : code_(0) {} + virtual ~BackupExtExtensionMock() {} + + MOCK_METHOD4(SendRequest, int(uint32_t, MessageParcel &, MessageParcel &, MessageOption &)); + + int32_t InvokeSendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) + { + reply.WriteInt32(BError(BError::Codes::OK)); + return BError(BError::Codes::OK); + } + + int32_t InvokeGetFileHandleRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) + { + std::string fileName = "1.tar"; + TestManager tm("GetFileHand_GetFd_0100"); + std::string filePath = tm.GetRootDirCurTest().append(fileName); + UniqueFd fd(open(filePath.data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + reply.WriteFileDescriptor(fd); + return BError(BError::Codes::OK); + } + + UniqueFd GetFileHandle(const std::string &fileName) override + { + GTEST_LOG_(INFO) << "GetFileHandle" << fileName; + if (fileName == "testName") { + return UniqueFd(-1); + } + + if (fileName.empty()) { + return UniqueFd(-1); + } + TestManager tm("GetFileHand_GetFd_0200"); + std::string filePath = tm.GetRootDirCurTest().append(fileName); + UniqueFd fd(open(filePath.data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + return fd; + }; + + ErrCode HandleClear() override + { + return BError(BError::Codes::OK); + }; + + ErrCode HandleBackup() override + { + GTEST_LOG_(INFO) << "HandleBackup"; + if (nHandleBackupNum_ == 1) { + GTEST_LOG_(INFO) << "HandleBackup is false"; + return 1; + } + nHandleBackupNum_++; + return BError(BError::Codes::OK); + }; + + ErrCode PublishFile(const std::string &fileName) override + { + GTEST_LOG_(INFO) << "PublishFile " << fileName; + if (fileName == "test") { + return 1; + } + return BError(BError::Codes::OK); + }; + +private: + int32_t nHandleBackupNum_ = 0; +}; +} // namespace OHOS::FileManagement::Backup +#endif // MOCK_EXTENSION_MOCK_H \ No newline at end of file diff --git a/tests/unittests/backup_api/backup_impl/include/i_service_mock.h b/tests/unittests/backup_api/backup_impl/include/i_service_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..e6c3720d968cef13f4b1c6fd527433bf7df67058 --- /dev/null +++ b/tests/unittests/backup_api/backup_impl/include/i_service_mock.h @@ -0,0 +1,99 @@ +/* + * 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 MOCK_I_SERVICE_MOCK_H +#define MOCK_I_SERVICE_MOCK_H + +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "i_service.h" +#include "iremote_stub.h" +#include "test_manager.h" + +namespace OHOS::FileManagement::Backup { +class IServiceMock : public IRemoteStub { +public: + int code_ = 0; + IServiceMock() : code_(0) {} + virtual ~IServiceMock() {} + + MOCK_METHOD4(SendRequest, int(uint32_t, MessageParcel &, MessageParcel &, MessageOption &)); + + int32_t InvokeSendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) + { + code_ = code; + reply.WriteInt32(BError(BError::Codes::OK)); + return BError(BError::Codes::OK); + } + + int32_t InvokeGetLocalSendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) + { + code_ = code; + std::string fileName = "1.tar"; + TestManager tm("GetLocalCap_GetFd_0100"); + std::string filePath = tm.GetRootDirCurTest().append(fileName); + UniqueFd fd(open(filePath.data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + reply.WriteFileDescriptor(fd); + return BError(BError::Codes::OK); + } + + ErrCode InitRestoreSession(sptr remote, const std::vector &bundleNames) override + { + return BError(BError::Codes::OK); + } + + ErrCode InitBackupSession(sptr remote, + UniqueFd fd, + const std::vector &bundleNames) override + { + return BError(BError::Codes::OK); + } + + ErrCode Start() override + { + return BError(BError::Codes::OK); + } + + UniqueFd GetLocalCapabilities() override + { + return UniqueFd(-1); + } + + ErrCode PublishFile(const BFileInfo &fileInfo) override + { + return BError(BError::Codes::OK); + } + + ErrCode AppFileReady(const std::string &fileName, UniqueFd fd) override + { + return BError(BError::Codes::OK); + } + + ErrCode AppDone(ErrCode errCode) override + { + return BError(BError::Codes::OK); + } + + ErrCode GetExtFileName(std::string &bundleName, std::string &fileName) override + { + return BError(BError::Codes::OK); + } +}; +} // namespace OHOS::FileManagement::Backup +#endif // MOCK_I_SERVICE_MOCK_H \ No newline at end of file diff --git a/tests/unittests/backup_api/backup_impl/include/service_reverse_mock.h b/tests/unittests/backup_api/backup_impl/include/service_reverse_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..ac83aab4b77e7bf2cc35d8278fae9e13dce8a6b7 --- /dev/null +++ b/tests/unittests/backup_api/backup_impl/include/service_reverse_mock.h @@ -0,0 +1,50 @@ +/* + * 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 MOCK_SERVICE_REVERSE_MOCK_H +#define MOCK_SERVICE_REVERSE_MOCK_H + +#include + +#include "b_error/b_error.h" +#include "i_service_reverse.h" +#include "iremote_stub.h" + +namespace OHOS::FileManagement::Backup { +class ServiceReverseMock : public IRemoteStub { +public: + int code_ = 0; + ServiceReverseMock() : code_(0) {} + virtual ~ServiceReverseMock() {} + + MOCK_METHOD4(SendRequest, int(uint32_t, MessageParcel &, MessageParcel &, MessageOption &)); + + int32_t InvokeSendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) + { + code_ = code; + return BError(BError::Codes::OK); + } + void BackupOnFileReady(std::string bundleName, std::string fileName, int fd) override {} + void BackupOnBundleStarted(int32_t errCode, std::string bundleName) override {} + void BackupOnBundleFinished(int32_t errCode, std::string bundleName) override {} + void BackupOnAllBundlesFinished(int32_t errCode) override {} + + void RestoreOnBundleStarted(int32_t errCode, std::string bundleName) override {} + void RestoreOnBundleFinished(int32_t errCode, std::string bundleName) override {} + void RestoreOnAllBundlesFinished(int32_t errCode) override {} + void RestoreOnFileReady(std::string bundleName, std::string fileName, int fd) override {} +}; +} // namespace OHOS::FileManagement::Backup +#endif // MOCK_SERVICE_REVERSE_MOCK_H \ No newline at end of file diff --git a/tests/unittests/backup_api/backup_impl/service_proxy_test.cpp b/tests/unittests/backup_api/backup_impl/service_proxy_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a74966e32f7e3f335e09d76aa18778dc6d45d690 --- /dev/null +++ b/tests/unittests/backup_api/backup_impl/service_proxy_test.cpp @@ -0,0 +1,350 @@ +/* + * 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 +#include +#include +#include + +#include "b_file_info.h" +#include "i_service_mock.h" +#include "iremote_object_mock.h" +#include "iservice_registry.h" +#include "service_proxy.h" +#include "service_reverse_mock.h" +#include "unique_fd.h" +#include "utils_mock_global_variable.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +using namespace testing; + +namespace { +const string FILE_NAME = "1.tar"; +constexpr int32_t SERVICE_ID = 5203; +} // namespace + +class ServiceProxyTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() override; + void TearDown() override; + + shared_ptr proxy_ = nullptr; + sptr mock_ = nullptr; + sptr remote_ = nullptr; +}; + +void ServiceProxyTest::SetUp() +{ + mock_ = sptr(new IServiceMock()); + proxy_ = make_shared(mock_); + remote_ = sptr(new ServiceReverseMock()); +} + +void ServiceProxyTest::TearDown() +{ + proxy_ = nullptr; + mock_ = nullptr; + remote_ = nullptr; +} + +/** + * @tc.number: SUB_Service_proxy_InitRestoreSession_0100 + * @tc.name: SUB_Service_proxy_InitRestoreSession_0100 + * @tc.desc: 测试 InitRestoreSession 注册restore Session接口调用成功和失败 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(ServiceProxyTest, SUB_Service_proxy_InitRestoreSession_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceProxyTest-begin SUB_Service_proxy_InitRestoreSession_0100"; + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(2) + .WillOnce(Invoke(mock_.GetRefPtr(), &IServiceMock::InvokeSendRequest)) + .WillOnce(Return(EPERM)); + std::vector bundleNames; + int32_t result = proxy_->InitRestoreSession(remote_, bundleNames); + EXPECT_EQ(result, BError(BError::Codes::OK)); + + result = proxy_->InitRestoreSession(remote_, bundleNames); + EXPECT_NE(result, BError(BError::Codes::OK)); + result = proxy_->InitRestoreSession(nullptr, bundleNames); + EXPECT_NE(result, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "ServiceProxyTest-end SUB_Service_proxy_InitRestoreSession_0100"; +} + +/** + * @tc.number: SUB_Service_proxy_InitBackupSession_0100 + * @tc.name: SUB_Service_proxy_InitBackupSession_0100 + * @tc.desc: 测试 InitBackupSession 注册backup Session接口调用成功和失败 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceProxyTest, SUB_Service_proxy_InitBackupSession_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceProxyTest-begin SUB_Service_proxy_InitBackupSession_0100"; + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(2) + .WillOnce(Invoke(mock_.GetRefPtr(), &IServiceMock::InvokeSendRequest)) + .WillOnce(Return(EPERM)); + std::vector bundleNames; + + TestManager tm("BackupSession_GetFd_0100"); + std::string filePath = tm.GetRootDirCurTest().append(FILE_NAME); + UniqueFd fd(open(filePath.data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + int32_t result = proxy_->InitBackupSession(remote_, move(fd), bundleNames); + EXPECT_EQ(result, BError(BError::Codes::OK)); + + result = proxy_->InitRestoreSession(remote_, bundleNames); + EXPECT_NE(result, BError(BError::Codes::OK)); + result = proxy_->InitBackupSession(nullptr, move(fd), bundleNames); + EXPECT_NE(result, BError(BError::Codes::OK)); + result = proxy_->InitBackupSession(remote_, UniqueFd(-1), bundleNames); + EXPECT_NE(result, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "ServiceProxyTest-end SUB_Service_proxy_InitBackupSession_0100"; +} + +/** + * @tc.number: SUB_Service_proxy_Start_0100 + * @tc.name: SUB_Service_proxy_Start_0100 + * @tc.desc: 测试 Start 启动备份恢复流程接口调用成功和失败 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceProxyTest, SUB_Service_proxy_Start_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceProxyTest-begin SUB_Service_proxy_Start_0100"; + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(2) + .WillOnce(Invoke(mock_.GetRefPtr(), &IServiceMock::InvokeSendRequest)) + .WillOnce(Return(EPERM)); + int32_t result = proxy_->Start(); + EXPECT_EQ(result, BError(BError::Codes::OK)); + + result = proxy_->Start(); + EXPECT_NE(result, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "ServiceProxyTest-end SUB_Service_proxy_Start_0100"; +} + +/** + * @tc.number: SUB_Service_proxy_GetLocalCapabilities_0100 + * @tc.name: SUB_Service_proxy_GetLocalCapabilities_0100 + * @tc.desc: 测试 GetLocalCapabilities 获取能力文件接口调用成功和失败 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0377 + */ +HWTEST_F(ServiceProxyTest, SUB_Service_proxy_GetLocalCapabilities_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceProxyTest-begin SUB_Service_proxy_GetLocalCapabilities_0100"; + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(2) + .WillOnce(Invoke(mock_.GetRefPtr(), &IServiceMock::InvokeGetLocalSendRequest)) + .WillOnce(Return(EPERM)); + UniqueFd fd = proxy_->GetLocalCapabilities(); + EXPECT_GT(fd, BError(BError::Codes::OK)); + + UniqueFd fdErr = proxy_->GetLocalCapabilities(); + EXPECT_LT(fdErr, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "ServiceProxyTest-end SUB_Service_proxy_GetLocalCapabilities_0100"; +} + +/** + * @tc.number: SUB_Service_proxy_PublishFile_0100 + * @tc.name: SUB_Service_proxy_PublishFile_0100 + * @tc.desc: 测试 PublishFile 推送接口调用成功和失败 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceProxyTest, SUB_Service_proxy_PublishFile_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceProxyTest-begin SUB_Service_proxy_PublishFile_0100"; + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(2) + .WillOnce(Invoke(mock_.GetRefPtr(), &IServiceMock::InvokeSendRequest)) + .WillOnce(Return(EPERM)); + string bundleName = "com.example.app2backup"; + string fileName = "1.tar"; + BFileInfo fileInfo(bundleName, fileName, -1); + int32_t result = proxy_->PublishFile(fileInfo); + EXPECT_EQ(result, BError(BError::Codes::OK)); + + result = proxy_->PublishFile(fileInfo); + EXPECT_NE(result, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "ServiceProxyTest-end SUB_Service_proxy_PublishFile_0100"; +} + +/** + * @tc.number: SUB_Service_proxy_AppFileReady_0100 + * @tc.name: SUB_Service_proxy_AppFileReady_0100 + * @tc.desc: 测试 AppFileReady 文件就绪调用成功和失败 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0380 + */ +HWTEST_F(ServiceProxyTest, SUB_Service_proxy_AppFileReady_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceProxyTest-begin SUB_Service_proxy_AppFileReady_0100"; + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(2) + .WillOnce(Invoke(mock_.GetRefPtr(), &IServiceMock::InvokeSendRequest)) + .WillOnce(Return(EPERM)); + + string bundleName = "com.example.app2backup"; + TestManager tm("AppFileReady_GetFd_0100"); + std::string filePath = tm.GetRootDirCurTest().append(FILE_NAME); + UniqueFd fd(open(filePath.data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + + int32_t result = proxy_->AppFileReady(bundleName, move(fd)); + EXPECT_EQ(result, BError(BError::Codes::OK)); + + TestManager tmErr("AppFileReady_GetFd_0200"); + UniqueFd fdErr(open(tmErr.GetRootDirCurTest().append(FILE_NAME).data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + result = proxy_->AppFileReady(bundleName, move(fdErr)); + EXPECT_NE(result, BError(BError::Codes::OK)); + result = proxy_->AppFileReady(bundleName, UniqueFd(-1)); + EXPECT_NE(result, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "ServiceProxyTest-end SUB_Service_proxy_AppFileReady_0100"; +} + +/** + * @tc.number: SUB_Service_proxy_AppDone_0100 + * @tc.name: SUB_Service_proxy_AppDone_0100 + * @tc.desc: 测试 AppDone ext备份恢复流程结束调用成功和失败 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0380 + */ +HWTEST_F(ServiceProxyTest, SUB_Service_proxy_AppDone_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceProxyTest-begin SUB_Service_proxy_AppDone_0100"; + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(2) + .WillOnce(Invoke(mock_.GetRefPtr(), &IServiceMock::InvokeSendRequest)) + .WillOnce(Return(EPERM)); + int32_t result = proxy_->AppDone(BError(BError::Codes::OK)); + EXPECT_EQ(result, BError(BError::Codes::OK)); + + result = proxy_->AppDone(BError(BError::Codes::OK)); + EXPECT_NE(result, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "ServiceProxyTest-end SUB_Service_proxy_AppDone_0100"; +} + +/** + * @tc.number: SUB_Service_proxy_GetExtFileName_0100 + * @tc.name: SUB_Service_proxy_GetExtFileName_0100 + * @tc.desc: 测试 GetExtFileName 获取真实文件调用成功和失败 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0379 + */ +HWTEST_F(ServiceProxyTest, SUB_Service_proxy_GetExtFileName_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceProxyTest-begin SUB_Service_proxy_GetExtFileName_0100"; + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(2) + .WillOnce(Invoke(mock_.GetRefPtr(), &IServiceMock::InvokeSendRequest)) + .WillOnce(Return(EPERM)); + string bundleName = "com.example.app2backup"; + string fileName = "1.tar"; + int32_t result = proxy_->GetExtFileName(bundleName, fileName); + EXPECT_EQ(result, BError(BError::Codes::OK)); + + result = proxy_->GetExtFileName(bundleName, fileName); + EXPECT_NE(result, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "ServiceProxyTest-end SUB_Service_proxy_GetExtFileName_0100"; +} + +/** + * @tc.number: SUB_Service_proxy_OnLoadSystemAbilitySuccess_0100 + * @tc.name: SUB_Service_proxy_OnLoadSystemAbilitySuccess_0100 + * @tc.desc: 测试 OnLoadSystemAbilitySuccess 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0379 + */ +HWTEST_F(ServiceProxyTest, SUB_Service_proxy_OnLoadSystemAbilitySuccess_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceProxyTest-begin SUB_Service_proxy_OnLoadSystemAbilitySuccess_0100"; + sptr loadCallback = new ServiceProxy::ServiceProxyLoadCallback(); + EXPECT_NE(loadCallback, nullptr); + loadCallback->OnLoadSystemAbilitySuccess(SERVICE_ID, nullptr); + loadCallback = nullptr; + GTEST_LOG_(INFO) << "ServiceProxyTest-end SUB_Service_proxy_OnLoadSystemAbilitySuccess_0100"; +} + +/** + * @tc.number: SUB_Service_proxy_OnLoadSystemAbilityFail_0100 + * @tc.name: SUB_Service_proxy_OnLoadSystemAbilityFail_0100 + * @tc.desc: 测试 OnLoadSystemAbilityFail 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0379 + */ +HWTEST_F(ServiceProxyTest, SUB_Service_proxy_OnLoadSystemAbilityFail_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceProxyTest-begin SUB_Service_proxy_OnLoadSystemAbilityFail_0100"; + sptr loadCallback = new ServiceProxy::ServiceProxyLoadCallback(); + EXPECT_NE(loadCallback, nullptr); + loadCallback->OnLoadSystemAbilityFail(SERVICE_ID); + loadCallback = nullptr; + GTEST_LOG_(INFO) << "ServiceProxyTest-end SUB_Service_proxy_OnLoadSystemAbilityFail_0100"; +} + +/** + * @tc.number: SUB_Service_proxy_GetInstance_0100 + * @tc.name: SUB_Service_proxy_GetInstance_0100 + * @tc.desc: 测试 GetInstance 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceProxyTest, SUB_Service_proxy_GetInstance_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceProxyTest-begin SUB_Service_proxy_GetInstance_0100"; + GTEST_LOG_(INFO) << "MockLoadSystemAbility is false"; + SetMockLoadSystemAbility(false); + auto proxy = ServiceProxy::GetInstance(); + EXPECT_EQ(proxy, nullptr); + GTEST_LOG_(INFO) << "MockLoadSystemAbility is true"; + SetMockLoadSystemAbility(true); + proxy = ServiceProxy::GetInstance(); + EXPECT_EQ(proxy, nullptr); + sptr loadCallback = new ServiceProxy::ServiceProxyLoadCallback(); + sptr object = new MockIRemoteObject(); + loadCallback->OnLoadSystemAbilitySuccess(SERVICE_ID, object); + GTEST_LOG_(INFO) << "GetInstance is ok"; + proxy = ServiceProxy::GetInstance(); + EXPECT_NE(proxy, nullptr); + GTEST_LOG_(INFO) << "ServiceProxyTest-end SUB_Service_proxy_GetInstance_0100"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_api/backup_impl/service_reverse_stub_test.cpp b/tests/unittests/backup_api/backup_impl/service_reverse_stub_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ce59c6e0759ada983c47d7d56b5a1c25ab87afc5 --- /dev/null +++ b/tests/unittests/backup_api/backup_impl/service_reverse_stub_test.cpp @@ -0,0 +1,363 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "i_service_reverse.h" +#include "service_reverse_stub.h" +#include "test_manager.h" +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +using namespace testing; + +namespace { +const string BUNDLE_NAME = "com.example.app2backup"; +const string FILE_NAME = "1.tar"; +} // namespace + +class MockServiceReverse final : public ServiceReverseStub { +public: + MOCK_METHOD3(BackupOnFileReady, void(string bundleName, string fileName, int fd)); + MOCK_METHOD2(BackupOnBundleStarted, void(int32_t errCode, string bundleName)); + MOCK_METHOD2(BackupOnBundleFinished, void(int32_t errCode, string bundleName)); + MOCK_METHOD1(BackupOnAllBundlesFinished, void(int32_t errCode)); + MOCK_METHOD2(RestoreOnBundleStarted, void(int32_t errCode, std::string bundleName)); + MOCK_METHOD2(RestoreOnBundleFinished, void(int32_t errCode, string bundleName)); + MOCK_METHOD1(RestoreOnAllBundlesFinished, void(int32_t errCode)); + MOCK_METHOD3(RestoreOnFileReady, void(string bundleName, string fileName, int fd)); +}; + +class ServiceReverseStubTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() override {}; + void TearDown() override {}; +}; + +/** + * @tc.number: SUB_backup_ServiceReverseStub_BackupOnFileReady_0100 + * @tc.name: SUB_backup_ServiceReverseStub_BackupOnFileReady_0100 + * @tc.desc: Test function of BackupOnFileReady interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseStubTest, SUB_backup_ServiceReverseStub_BackupOnFileReady_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseStubTest-begin SUB_backup_ServiceReverseStub_BackupOnFileReady_0100"; + try { + MockServiceReverse service; + EXPECT_CALL(service, BackupOnFileReady(_, _, _)).WillOnce(Return()); + MessageParcel data; + MessageParcel reply; + MessageOption option; + + EXPECT_TRUE(data.WriteInterfaceToken(IServiceReverse::GetDescriptor())); + EXPECT_TRUE(data.WriteString(BUNDLE_NAME)); + EXPECT_TRUE(data.WriteString(FILE_NAME)); + TestManager tm("ServiceReverseStub_0100"); + string filePath = tm.GetRootDirCurTest().append(FILE_NAME); + UniqueFd fd(open(filePath.data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + data.WriteFileDescriptor(fd); + + EXPECT_EQ(BError(BError::Codes::OK), + service.OnRemoteRequest(IServiceReverse::SERVICER_BACKUP_ON_FILE_READY, data, reply, option)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseStubTest-an exception occurred by BackupOnFileReady."; + } + GTEST_LOG_(INFO) << "ServiceReverseStubTest-end SUB_backup_ServiceReverseStub_BackupOnFileReady_0100"; +} + +/** + * @tc.number: SUB_backup_ServiceReverseStub_BackupOnBundleStarted_0100 + * @tc.name: SUB_backup_ServiceReverseStub_BackupOnBundleStarted_0100 + * @tc.desc: Test function of BackupOnBundleStarted interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseStubTest, + SUB_backup_ServiceReverseStub_BackupOnBundleStarted_0100, + testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseStubTest-begin SUB_backup_ServiceReverseStub_BackupOnBundleStarted_0100"; + try { + MockServiceReverse service; + EXPECT_CALL(service, BackupOnBundleStarted(_, _)).WillOnce(Return()); + MessageParcel data; + MessageParcel reply; + MessageOption option; + + EXPECT_TRUE(data.WriteInterfaceToken(IServiceReverse::GetDescriptor())); + EXPECT_TRUE(data.WriteInt32(BError(BError::Codes::OK))); + EXPECT_TRUE(data.WriteString(BUNDLE_NAME)); + + EXPECT_EQ(BError(BError::Codes::OK), + service.OnRemoteRequest(IServiceReverse::SERVICER_BACKUP_ON_SUB_TASK_STARTED, data, reply, option)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseStubTest-an exception occurred by BackupOnBundleStarted."; + } + GTEST_LOG_(INFO) << "ServiceReverseStubTest-end SUB_backup_ServiceReverseStub_BackupOnBundleStarted_0100"; +} + +/** + * @tc.number: SUB_backup_ServiceReverseStub_BackupOnBundleFinished_0100 + * @tc.name: SUB_backup_ServiceReverseStub_BackupOnBundleFinished_0100 + * @tc.desc: Test function of BackupOnBundleFinished interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseStubTest, + SUB_backup_ServiceReverseStub_BackupOnBundleFinished_0100, + testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseStubTest-begin SUB_backup_ServiceReverseStub_BackupOnBundleFinished_0100"; + try { + MockServiceReverse service; + EXPECT_CALL(service, BackupOnBundleFinished(_, _)).WillOnce(Return()); + MessageParcel data; + MessageParcel reply; + MessageOption option; + + EXPECT_TRUE(data.WriteInterfaceToken(IServiceReverse::GetDescriptor())); + EXPECT_TRUE(data.WriteInt32(BError(BError::Codes::OK))); + EXPECT_TRUE(data.WriteString(BUNDLE_NAME)); + + EXPECT_EQ(BError(BError::Codes::OK), + service.OnRemoteRequest(IServiceReverse::SERVICER_BACKUP_ON_SUB_TASK_FINISHED, data, reply, option)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseStubTest-an exception occurred by BackupOnBundleFinished."; + } + GTEST_LOG_(INFO) << "ServiceReverseStubTest-end SUB_backup_ServiceReverseStub_BackupOnBundleFinished_0100"; +} + +/** + * @tc.number: SUB_backup_ServiceReverseStub_BackupOnAllBundlesFinished_0100 + * @tc.name: SUB_backup_ServiceReverseStub_BackupOnAllBundlesFinished_0100 + * @tc.desc: Test function of BackupOnAllBundlesFinished interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseStubTest, + SUB_backup_ServiceReverseStub_BackupOnAllBundlesFinished_0100, + testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseStubTest-begin SUB_backup_ServiceReverseStub_BackupOnAllBundlesFinished_0100"; + try { + MockServiceReverse service; + EXPECT_CALL(service, BackupOnAllBundlesFinished(_)).WillOnce(Return()); + MessageParcel data; + MessageParcel reply; + MessageOption option; + + EXPECT_TRUE(data.WriteInterfaceToken(IServiceReverse::GetDescriptor())); + EXPECT_TRUE(data.WriteInt32(BError(BError::Codes::OK))); + + EXPECT_EQ(BError(BError::Codes::OK), + service.OnRemoteRequest(IServiceReverse::SERVICER_BACKUP_ON_TASK_FINISHED, data, reply, option)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseStubTest-an exception occurred by BackupOnAllBundlesFinished."; + } + GTEST_LOG_(INFO) << "ServiceReverseStubTest-end SUB_backup_ServiceReverseStub_BackupOnAllBundlesFinished_0100"; +} + +/** + * @tc.number: SUB_backup_ServiceReverseStub_RestoreOnBundleStarted_0100 + * @tc.name: SUB_backup_ServiceReverseStub_RestoreOnBundleStarted_0100 + * @tc.desc: Test function of RestoreOnBundleStarted interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(ServiceReverseStubTest, + SUB_backup_ServiceReverseStub_RestoreOnBundleStarted_0100, + testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseStubTest-begin SUB_backup_ServiceReverseStub_RestoreOnBundleStarted_0100"; + try { + MockServiceReverse service; + EXPECT_CALL(service, RestoreOnBundleStarted(_, _)).WillOnce(Return()); + MessageParcel data; + MessageParcel reply; + MessageOption option; + + EXPECT_TRUE(data.WriteInterfaceToken(IServiceReverse::GetDescriptor())); + EXPECT_TRUE(data.WriteInt32(BError(BError::Codes::OK))); + EXPECT_TRUE(data.WriteString(BUNDLE_NAME)); + + EXPECT_EQ(BError(BError::Codes::OK), + service.OnRemoteRequest(IServiceReverse::SERVICER_RESTORE_ON_SUB_TASK_STARTED, data, reply, option)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseStubTest-an exception occurred by RestoreOnBundleStarted."; + } + GTEST_LOG_(INFO) << "ServiceReverseStubTest-end SUB_backup_ServiceReverseStub_RestoreOnBundleStarted_0100"; +} + +/** + * @tc.number: SUB_backup_ServiceReverseStub_RestoreOnBundleFinished_0100 + * @tc.name: SUB_backup_ServiceReverseStub_RestoreOnBundleFinished_0100 + * @tc.desc: Test function of RestoreOnBundleFinished interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(ServiceReverseStubTest, + SUB_backup_ServiceReverseStub_RestoreOnBundleFinished_0100, + testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseStubTest-begin SUB_backup_ServiceReverseStub_RestoreOnBundleFinished_0100"; + try { + MockServiceReverse service; + EXPECT_CALL(service, RestoreOnBundleFinished(_, _)).WillOnce(Return()); + MessageParcel data; + MessageParcel reply; + MessageOption option; + + EXPECT_TRUE(data.WriteInterfaceToken(IServiceReverse::GetDescriptor())); + EXPECT_TRUE(data.WriteInt32(BError(BError::Codes::OK))); + EXPECT_TRUE(data.WriteString(BUNDLE_NAME)); + + EXPECT_EQ(BError(BError::Codes::OK), + service.OnRemoteRequest(IServiceReverse::SERVICER_RESTORE_ON_SUB_TASK_FINISHED, data, reply, option)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseStubTest-an exception occurred by RestoreOnBundleFinished."; + } + GTEST_LOG_(INFO) << "ServiceReverseStubTest-end SUB_backup_ServiceReverseStub_RestoreOnBundleFinished_0100"; +} + +/** + * @tc.number: SUB_backup_ServiceReverseStub_RestoreOnAllBundlesFinished_0100 + * @tc.name: SUB_backup_ServiceReverseStub_RestoreOnAllBundlesFinished_0100 + * @tc.desc: Test function of RestoreOnBundleStarted interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(ServiceReverseStubTest, + SUB_backup_ServiceReverseStub_RestoreOnAllBundlesFinished_0100, + testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseStubTest-begin SUB_backup_ServiceReverseStub_RestoreOnAllBundlesFinished_0100"; + try { + MockServiceReverse service; + EXPECT_CALL(service, RestoreOnAllBundlesFinished(_)).WillOnce(Return()); + MessageParcel data; + MessageParcel reply; + MessageOption option; + + EXPECT_TRUE(data.WriteInterfaceToken(IServiceReverse::GetDescriptor())); + EXPECT_TRUE(data.WriteInt32(BError(BError::Codes::OK))); + + EXPECT_EQ(BError(BError::Codes::OK), + service.OnRemoteRequest(IServiceReverse::SERVICER_RESTORE_ON_TASK_FINISHED, data, reply, option)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseStubTest-an exception occurred by RestoreOnAllBundlesFinished."; + } + GTEST_LOG_(INFO) << "ServiceReverseStubTest-end SUB_backup_ServiceReverseStub_RestoreOnAllBundlesFinished_0100"; +} + +/** + * @tc.number: SUB_backup_ServiceReverseStub_RestoreOnFileReady_0100 + * @tc.name: SUB_backup_ServiceReverseStub_RestoreOnFileReady_0100 + * @tc.desc: Test function of RestoreOnFileReady interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(ServiceReverseStubTest, SUB_backup_ServiceReverseStub_RestoreOnFileReady_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseStubTest-begin SUB_backup_ServiceReverseStub_RestoreOnFileReady_0100"; + try { + MockServiceReverse service; + EXPECT_CALL(service, RestoreOnFileReady(_, _, _)).WillOnce(Return()); + MessageParcel data; + MessageParcel reply; + MessageOption option; + + EXPECT_TRUE(data.WriteInterfaceToken(IServiceReverse::GetDescriptor())); + EXPECT_TRUE(data.WriteString(BUNDLE_NAME)); + EXPECT_TRUE(data.WriteString(FILE_NAME)); + + TestManager tm("ServiceReverseStub_0200"); + string filePath = tm.GetRootDirCurTest().append(FILE_NAME); + UniqueFd fd(open(filePath.data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + data.WriteFileDescriptor(fd); + + EXPECT_EQ(BError(BError::Codes::OK), + service.OnRemoteRequest(IServiceReverse::SERVICER_RESTORE_ON_FILE_READY, data, reply, option)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseStubTest-an exception occurred by RestoreOnFileReady."; + } + GTEST_LOG_(INFO) << "ServiceReverseStubTest-end SUB_backup_ServiceReverseStub_RestoreOnFileReady_0100"; +} + +/** + * @tc.number: SUB_backup_ServiceReverseStub_error_0100 + * @tc.name: SUB_backup_ServiceReverseStub_error_0100 + * @tc.desc: Test function of RestoreOnFileReady interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(ServiceReverseStubTest, SUB_backup_ServiceReverseStub_error_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseStubTest-begin SUB_backup_ServiceReverseStub_error_0100"; + try { + MockServiceReverse service; + MessageParcel data; + MessageParcel reply; + MessageOption option; + EXPECT_TRUE(data.WriteInterfaceToken(Str8ToStr16("test"))); + + EXPECT_NE(BError(BError::Codes::OK), service.OnRemoteRequest(3333, data, reply, option)); + EXPECT_NE(BError(BError::Codes::OK), + service.OnRemoteRequest(IServiceReverse::SERVICER_RESTORE_ON_FILE_READY, data, reply, option)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseStubTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "ServiceReverseStubTest-end SUB_backup_ServiceReverseStub_error_0100"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_api/backup_impl/service_reverse_test.cpp b/tests/unittests/backup_api/backup_impl/service_reverse_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..46ff14ca8562625acecb2876a4f5ac5e01c77cd1 --- /dev/null +++ b/tests/unittests/backup_api/backup_impl/service_reverse_test.cpp @@ -0,0 +1,352 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "b_session_restore.h" +#include "refbase.h" +#include "service_reverse.h" +#include "test_manager.h" +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +using namespace testing; + +namespace { +const string BUNDLE_NAME = "com.example.app2backup"; +const string FILE_NAME = "1.tar"; +} // namespace + +class ServiceReverseTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() override {}; + void TearDown() override; + + void Init(IServiceReverse::Scenario scenario, int nType = 0); + sptr service_ = nullptr; +}; + +static void OnFileReadyTest(const BFileInfo &fileInfo, UniqueFd fd) +{ + EXPECT_EQ(fileInfo.owner, BUNDLE_NAME); + EXPECT_EQ(fileInfo.fileName, FILE_NAME); + GTEST_LOG_(INFO) << "ServiceReverseTest-OnFileReadyTest SUCCESS"; +} + +static void OnBundleStartedTest(ErrCode err, const BundleName name) +{ + EXPECT_EQ(name, BUNDLE_NAME); + GTEST_LOG_(INFO) << "ServiceReverseTest-OnBundleStartedTest SUCCESS"; +} + +static void OnBundleFinishedTest(ErrCode err, const BundleName name) +{ + EXPECT_EQ(name, BUNDLE_NAME); + GTEST_LOG_(INFO) << "ServiceReverseTest-OnBundleFinishedTest SUCCESS"; +} + +static void OnAllBundlesFinishedTest(ErrCode err) +{ + EXPECT_EQ(err, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "ServiceReverseTest-OnAllBundlesFinishedTest SUCCESS"; +} + +static void OnBackupServiceDiedTest() {} + +void ServiceReverseTest::TearDown() +{ + service_ = nullptr; +} + +void ServiceReverseTest::Init(IServiceReverse::Scenario scenario, int nType) +{ + if (scenario == IServiceReverse::Scenario::BACKUP) { + if (nType) { + service_ = new ServiceReverse(BSessionBackup::Callbacks {.onFileReady = nullptr, + .onBundleStarted = nullptr, + .onBundleFinished = nullptr, + .onAllBundlesFinished = nullptr, + .onBackupServiceDied = nullptr}); + } else { + service_ = new ServiceReverse(BSessionBackup::Callbacks { + .onFileReady = bind(OnFileReadyTest, placeholders::_1, placeholders::_2), + .onBundleStarted = bind(OnBundleStartedTest, placeholders::_1, placeholders::_2), + .onBundleFinished = bind(OnBundleFinishedTest, placeholders::_1, placeholders::_2), + .onAllBundlesFinished = bind(OnAllBundlesFinishedTest, placeholders::_1), + .onBackupServiceDied = bind(OnBackupServiceDiedTest)}); + } + } else { + if (nType) { + service_ = new ServiceReverse(BSessionRestore::Callbacks {.onFileReady = nullptr, + .onBundleStarted = nullptr, + .onBundleFinished = nullptr, + .onAllBundlesFinished = nullptr, + .onBackupServiceDied = nullptr}); + } else { + service_ = new ServiceReverse(BSessionRestore::Callbacks { + .onFileReady = bind(OnFileReadyTest, placeholders::_1, placeholders::_2), + .onBundleStarted = bind(OnBundleStartedTest, placeholders::_1, placeholders::_2), + .onBundleFinished = bind(OnBundleFinishedTest, placeholders::_1, placeholders::_2), + .onAllBundlesFinished = bind(OnAllBundlesFinishedTest, placeholders::_1), + .onBackupServiceDied = bind(OnBackupServiceDiedTest)}); + } + } +} + +/** + * @tc.number: SUB_backup_ServiceReverse_BackupOnFileReady_0100 + * @tc.name: SUB_backup_ServiceReverse_BackupOnFileReady_0100 + * @tc.desc: 测试 BackupOnFileReady 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseTest, SUB_backup_ServiceReverse_BackupOnFileReady_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseTest-begin SUB_backup_ServiceReverse_BackupOnFileReady_0100"; + try { + Init(IServiceReverse::Scenario::BACKUP); + service_->BackupOnFileReady(BUNDLE_NAME, FILE_NAME, -1); + service_->RestoreOnFileReady(BUNDLE_NAME, FILE_NAME, -1); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseTest-an exception occurred by BackupOnFileReady."; + } + GTEST_LOG_(INFO) << "ServiceReverseTest-end SUB_backup_ServiceReverse_BackupOnFileReady_0100"; +} + +/** + * @tc.number: SUB_backup_ServiceReverse_BackupOnBundleStarted_0100 + * @tc.name: SUB_backup_ServiceReverse_BackupOnBundleStarted_0100 + * @tc.desc: 测试 BackupOnBundleStarted 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseTest, SUB_backup_ServiceReverse_BackupOnBundleStarted_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseTest-begin SUB_backup_ServiceReverse_BackupOnBundleStarted_0100"; + try { + Init(IServiceReverse::Scenario::BACKUP); + service_->BackupOnBundleStarted(BError(BError::Codes::OK), BUNDLE_NAME); + service_->RestoreOnBundleStarted(BError(BError::Codes::OK), BUNDLE_NAME); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseTest-an exception occurred by BackupOnBundleStarted."; + } + GTEST_LOG_(INFO) << "ServiceReverseTest-end SUB_backup_ServiceReverse_BackupOnBundleStarted_0100"; +} + +/** + * @tc.number: SUB_backup_ServiceReverse_BackupOnBundleFinished_0100 + * @tc.name: SUB_backup_ServiceReverse_BackupOnBundleFinished_0100 + * @tc.desc: 测试 BackupOnBundleFinished 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseTest, SUB_backup_ServiceReverse_BackupOnBundleFinished_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseTest-begin SUB_backup_ServiceReverse_BackupOnBundleFinished_0100"; + try { + Init(IServiceReverse::Scenario::BACKUP); + service_->BackupOnBundleFinished(BError(BError::Codes::OK), BUNDLE_NAME); + service_->RestoreOnBundleFinished(BError(BError::Codes::OK), BUNDLE_NAME); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseTest-an exception occurred by BackupOnBundleFinished."; + } + GTEST_LOG_(INFO) << "ServiceReverseTest-end SUB_backup_ServiceReverse_BackupOnBundleFinished_0100"; +} + +/** + * @tc.number: SUB_backup_ServiceReverse_BackupOnAllBundlesFinished_0100 + * @tc.name: SUB_backup_ServiceReverse_BackupOnAllBundlesFinished_0100 + * @tc.desc: 测试 BackupOnAllBundlesFinished 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseTest, SUB_backup_ServiceReverse_BackupOnAllBundlesFinished_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseTest-begin SUB_backup_ServiceReverse_BackupOnAllBundlesFinished_0100"; + try { + Init(IServiceReverse::Scenario::BACKUP); + service_->BackupOnAllBundlesFinished(BError(BError::Codes::OK)); + service_->RestoreOnAllBundlesFinished(BError(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseTest-an exception occurred by BackupOnAllBundlesFinished."; + } + GTEST_LOG_(INFO) << "ServiceReverseTest-end SUB_backup_ServiceReverse_BackupOnAllBundlesFinished_0100"; +} + +/** + * @tc.number: SUB_backup_ServiceReverse_RestoreOnFileReady_0100 + * @tc.name: SUB_backup_ServiceReverse_RestoreOnFileReady_0100 + * @tc.desc: 测试 RestoreOnFileReady 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseTest, SUB_backup_ServiceReverse_RestoreOnFileReady_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseTest-begin SUB_backup_ServiceReverse_RestoreOnFileReady_0100"; + try { + Init(IServiceReverse::Scenario::RESTORE); + service_->RestoreOnFileReady(BUNDLE_NAME, FILE_NAME, -1); + service_->BackupOnFileReady(BUNDLE_NAME, FILE_NAME, -1); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseTest-an exception occurred by RestoreOnFileReady."; + } + GTEST_LOG_(INFO) << "ServiceReverseTest-end SUB_backup_ServiceReverse_RestoreOnFileReady_0100"; +} + +/** + * @tc.number: SUB_backup_ServiceReverse_RestoreOnBundleStarted_0100 + * @tc.name: SUB_backup_ServiceReverse_RestoreOnBundleStarted_0100 + * @tc.desc: 测试 RestoreOnBundleStarted 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseTest, SUB_backup_ServiceReverse_RestoreOnBundleStarted_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseTest-begin SUB_backup_ServiceReverse_RestoreOnBundleStarted_0100"; + try { + Init(IServiceReverse::Scenario::RESTORE); + service_->RestoreOnBundleStarted(BError(BError::Codes::OK), BUNDLE_NAME); + service_->BackupOnBundleStarted(BError(BError::Codes::OK), BUNDLE_NAME); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseTest-an exception occurred by RestoreOnBundleStarted."; + } + GTEST_LOG_(INFO) << "ServiceReverseTest-end SUB_backup_ServiceReverse_RestoreOnBundleStarted_0100"; +} + +/** + * @tc.number: SUB_backup_ServiceReverse_RestoreOnBundleFinished_0100 + * @tc.name: SUB_backup_ServiceReverse_RestoreOnBundleFinished_0100 + * @tc.desc: 测试 RestoreOnBundleFinished 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseTest, SUB_backup_ServiceReverse_RestoreOnBundleFinished_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseTest-begin SUB_backup_ServiceReverse_RestoreOnBundleFinished_0100"; + try { + Init(IServiceReverse::Scenario::RESTORE); + service_->RestoreOnBundleFinished(BError(BError::Codes::OK), BUNDLE_NAME); + service_->BackupOnBundleFinished(BError(BError::Codes::OK), BUNDLE_NAME); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseTest-an exception occurred by RestoreOnBundleFinished."; + } + GTEST_LOG_(INFO) << "ServiceReverseTest-end SUB_backup_ServiceReverse_RestoreOnBundleFinished_0100"; +} + +/** + * @tc.number: SUB_backup_ServiceReverse_RestoreOnAllBundlesFinished_0100 + * @tc.name: SUB_backup_ServiceReverse_RestoreOnAllBundlesFinished_0100 + * @tc.desc: 测试 RestoreOnAllBundlesFinished 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseTest, SUB_backup_ServiceReverse_RestoreOnAllBundlesFinished_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseTest-begin SUB_backup_ServiceReverse_RestoreOnAllBundlesFinished_0100"; + try { + Init(IServiceReverse::Scenario::RESTORE); + service_->RestoreOnAllBundlesFinished(BError(BError::Codes::OK)); + service_->BackupOnAllBundlesFinished(BError(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseTest-an exception occurred by RestoreOnAllBundlesFinished."; + } + GTEST_LOG_(INFO) << "ServiceReverseTest-end SUB_backup_ServiceReverse_RestoreOnAllBundlesFinished_0100"; +} + +/** + * @tc.number: SUB_backup_ServiceReverse_0200 + * @tc.name: SUB_backup_ServiceReverse_0200 + * @tc.desc: 测试分支 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseTest, SUB_backup_ServiceReverse_0200, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseTest-begin SUB_backup_ServiceReverse_0200"; + try { + Init(IServiceReverse::Scenario::RESTORE, 1); + service_->RestoreOnFileReady(BUNDLE_NAME, FILE_NAME, -1); + service_->RestoreOnBundleStarted(BError(BError::Codes::OK), BUNDLE_NAME); + service_->RestoreOnBundleFinished(BError(BError::Codes::OK), BUNDLE_NAME); + service_->RestoreOnAllBundlesFinished(BError(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "ServiceReverseTest-end SUB_backup_ServiceReverse_0200"; +} + +/** + * @tc.number: SUB_backup_ServiceReverse_0300 + * @tc.name: SUB_backup_ServiceReverse_0300 + * @tc.desc: 测试分支 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseTest, SUB_backup_ServiceReverse_0300, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseTest-begin SUB_backup_ServiceReverse_0300"; + try { + Init(IServiceReverse::Scenario::BACKUP, 1); + service_->BackupOnFileReady(BUNDLE_NAME, FILE_NAME, -1); + service_->BackupOnBundleStarted(BError(BError::Codes::OK), BUNDLE_NAME); + service_->BackupOnBundleFinished(BError(BError::Codes::OK), BUNDLE_NAME); + service_->BackupOnAllBundlesFinished(BError(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "ServiceReverseTest-end SUB_backup_ServiceReverse_0300"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_api/backup_impl/svc_death_recipient_test.cpp b/tests/unittests/backup_api/backup_impl/svc_death_recipient_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e195e85432b41fa79ff2875c16a48554a7c11f36 --- /dev/null +++ b/tests/unittests/backup_api/backup_impl/svc_death_recipient_test.cpp @@ -0,0 +1,62 @@ +/* + * 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 +#include + +#include "iservice_registry.h" +#include "service_reverse_mock.h" +#include "svc_death_recipient.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +using namespace testing; + +const string FILE_NAME = "temp.json"; + +class SvcDeathRecipientTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() override {}; + void TearDown() override {}; +}; + +static void CallBack(const wptr &obj) +{ + GTEST_LOG_(INFO) << "SvcSessionManagerTest-CallBack success"; +} + +/** + * @tc.number: SUB_backup_sa_deathecipient_OnRemoteDied_0100 + * @tc.name: SUB_backup_sa_deathecipient_OnRemoteDied_0100 + * @tc.desc: 测试 OnRemoteDied 接口调用成功 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcDeathRecipientTest, SUB_backup_sa_deathecipient_OnRemoteDied_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcSessionManagerTest-begin SUB_backup_sa_deathecipient_OnRemoteDied_0100"; + sptr remote = sptr(new ServiceReverseMock()); + sptr deathRecipient = sptr(new SvcDeathRecipient(CallBack)); + remote->AddDeathRecipient(deathRecipient); + deathRecipient->OnRemoteDied(remote); + remote = nullptr; + deathRecipient = nullptr; + GTEST_LOG_(INFO) << "SvcSessionManagerTest-end SUB_backup_sa_deathecipient_OnRemoteDied_0100"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_sa/BUILD.gn b/tests/unittests/backup_sa/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..a1dc27b669488e20dee1aaf707b6f850ca158154 --- /dev/null +++ b/tests/unittests/backup_sa/BUILD.gn @@ -0,0 +1,21 @@ +# 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. + +import("//build/ohos.gni") +import("//foundation/filemanagement/app_file_service/backup.gni") + +group("backup_sa_test") { + testonly = true + + deps = [ "module_ipc:backup_sa_ipc_test" ] +} diff --git a/tests/unittests/backup_sa/module_ipc/BUILD.gn b/tests/unittests/backup_sa/module_ipc/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..7fd6435b566f8b192a81dfe238f18cd64ebc3165 --- /dev/null +++ b/tests/unittests/backup_sa/module_ipc/BUILD.gn @@ -0,0 +1,174 @@ +# 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. + +import("//build/test.gni") +import("//foundation/filemanagement/app_file_service/backup.gni") + +ohos_unittest("module_ipc_test") { + module_out_path = path_module_out_tests + + sources = [ + "service_reverse_proxy_test.cpp", + "service_stub_test.cpp", + "svc_backup_connection_test.cpp", + "svc_extension_proxy_test.cpp", + ] + + include_dirs = [ + "${path_backup}/services/backup_sa/include", + "${path_base}/include", + "${path_backup}/tests/unittests/backup_api/backup_impl/include", + "${path_backup}/interfaces/inner_api/native/backup_kit_inner/impl", + ] + + deps = [ + "${path_ability_runtime}/interfaces/inner_api/ability_manager:ability_manager", + "${path_backup}/services/backup_sa:backup_sa", + "${path_backup}/tests/utils:backup_test_utils", + "${path_backup}/utils:backup_utils", + "${path_base}:utils", + "//third_party/googletest:gmock_main", + ] + + external_deps = [ + "ability_base:want", + "app_file_service:backup_kit_inner", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + ] + + use_exceptions = true +} + +ohos_unittest("backup_service_test") { + module_out_path = path_module_out_tests + + sources = [ + "${path_backup_mock}/accesstoken/accesstoken_kit_mock.cpp", + "${path_backup}/services/backup_sa/src/module_ipc/service.cpp", + "service_test.cpp", + ] + sources += backup_mock_src + sources += backup_mock_session_manager_src + sources += backup_mock_scheduler_src + + include_dirs = [ + "${path_backup}/services/backup_sa/include", + "${path_backup}/interfaces/inner_api/native/backup_kit_inner/impl", + "${path_backup}/tests/unittests/backup_api/backup_impl/include", + "${path_access_token}/interfaces/innerkits/accesstoken/include", + ] + + deps = [ + "${path_ability_runtime}/interfaces/inner_api/ability_manager:ability_manager", + "${path_backup}/tests/utils:backup_test_utils", + "${path_backup}/utils:backup_utils", + "${path_googletest}:gmock_main", + ] + + external_deps = [ + "ability_base:want", + "app_file_service:backup_kit_inner", + "init:libbegetutil", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + ] + + use_exceptions = true +} + +ohos_unittest("backup_service_session_test") { + module_out_path = path_module_out_tests + + sources = [ + "${path_backup_mock}/affwk/service_registry_mock.cpp", + "${path_backup_mock}/bundle_manager/src/mock_bundle_manager.cpp", + "${path_backup}/services/backup_sa/src/module_ipc/svc_session_manager.cpp", + "svc_session_manager_test.cpp", + ] + sources += backup_mock_src + sources += backup_mock_scheduler_src + sources += backup_mock_service_src + + include_dirs = [ + "${path_backup}/services/backup_sa/include", + "${path_backup}/interfaces/inner_api/native/backup_kit_inner/impl", + "${path_backup}/tests/unittests/backup_api/backup_impl/include", + "${path_base}/include", + "${path_backup_mock}/bundle_manager/include", + ] + + deps = [ + "${path_ability_runtime}/interfaces/inner_api/ability_manager:ability_manager", + "${path_backup}/tests/utils:backup_test_utils", + "${path_backup}/utils:backup_utils", + "${path_base}:utils", + "${path_googletest}:gmock_main", + ] + + external_deps = [ + "ability_base:want", + "app_file_service:backup_kit_inner", + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + ] + + use_exceptions = true +} + +ohos_unittest("backup_service_scheduler_test") { + module_out_path = path_module_out_tests + + sources = [ + "${path_backup_mock}/timer/timer_mock.cpp", + "${path_backup}/services/backup_sa/src/module_sched/sched_scheduler.cpp", + "sched_scheduler_test.cpp", + ] + sources += backup_mock_src + sources += backup_mock_service_src + sources += backup_mock_session_manager_src + + include_dirs = [ + "${path_backup}/services/backup_sa/include", + "${path_backup}/interfaces/inner_api/native/backup_kit_inner/impl", + "${path_backup}/tests/unittests/backup_api/backup_impl/include", + ] + + deps = [ + "${path_ability_runtime}/interfaces/inner_api/ability_manager:ability_manager", + "${path_backup}/tests/utils:backup_test_utils", + "${path_backup}/utils:backup_utils", + "${path_googletest}:gmock_main", + ] + + external_deps = [ + "ability_base:want", + "app_file_service:backup_kit_inner", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + ] + + use_exceptions = true +} + +group("backup_sa_ipc_test") { + testonly = true + deps = [ + ":backup_service_scheduler_test", + ":backup_service_session_test", + ":backup_service_test", + ":module_ipc_test", + ] +} diff --git a/tests/unittests/backup_sa/module_ipc/sched_scheduler_test.cpp b/tests/unittests/backup_sa/module_ipc/sched_scheduler_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..959d400c9551a7464b6f5513ec91612c5e9a9a00 --- /dev/null +++ b/tests/unittests/backup_sa/module_ipc/sched_scheduler_test.cpp @@ -0,0 +1,166 @@ +/* + * 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 +#include + +#include + +#include + +#include "b_error/b_error.h" +#include "module_ipc/service.h" +#include "module_ipc/svc_session_manager.h" +#include "module_sched/sched_scheduler.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +using namespace testing; + +namespace { +const string BUNDLE_NAME = "com.example.app2backup"; +constexpr int32_t CLIENT_TOKEN_ID = 100; +constexpr int32_t SERVICE_ID = 5203; +constexpr int32_t WAIT_TIME = 3; +} // namespace + +class SchedSchedulerTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(); + void SetUp() override {}; + void TearDown() override {}; + void Init(IServiceReverse::Scenario scenario); + + static inline sptr schedPtr_ = nullptr; + static inline sptr sessionManagerPtr_ = nullptr; + static inline sptr servicePtr_ = nullptr; +}; + +void SchedSchedulerTest::SetUpTestCase() +{ + servicePtr_ = sptr(new Service(SERVICE_ID)); + sessionManagerPtr_ = sptr(new SvcSessionManager(wptr(servicePtr_))); + schedPtr_ = sptr(new SchedScheduler(wptr(servicePtr_), wptr(sessionManagerPtr_))); +} + +void SchedSchedulerTest::TearDownTestCase() +{ + schedPtr_ = nullptr; + servicePtr_ = nullptr; + sessionManagerPtr_ = nullptr; +} + +void SchedSchedulerTest::Init(IServiceReverse::Scenario scenario) +{ + vector bundleNames; + map backupExtNameMap; + bundleNames.emplace_back(BUNDLE_NAME); + auto setBackupExtNameMap = [](const string &bundleName) { + BackupExtInfo info {}; + info.backupExtName = BUNDLE_NAME; + info.receExtManageJson = true; + info.receExtAppDone = true; + return make_pair(bundleName, info); + }; + transform(bundleNames.begin(), bundleNames.end(), inserter(backupExtNameMap, backupExtNameMap.end()), + setBackupExtNameMap); + + sessionManagerPtr_->Active({ + .clientToken = CLIENT_TOKEN_ID, + .scenario = scenario, + .backupExtNameMap = move(backupExtNameMap), + }); +} + +/** + * @tc.number: SUB_Service_Sched_0100 + * @tc.name: SUB_Service_Sched_0100 + * @tc.desc: 测试 Sched接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SchedSchedulerTest, SUB_Service_Sched_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SchedSchedulerTest-begin SUB_Service_Sched_0100"; + try { + Init(IServiceReverse::Scenario::BACKUP); + schedPtr_->Sched(); + GTEST_LOG_(INFO) << "SchedSchedulerTest-Sched Branches"; + sessionManagerPtr_->SetServiceSchedAction(BUNDLE_NAME, BConstants::ServiceSchedAction::FINISH); + schedPtr_->Sched(); + sessionManagerPtr_->SetServiceSchedAction(BUNDLE_NAME, BConstants::ServiceSchedAction::WAIT); + schedPtr_->Sched(); + GTEST_LOG_(INFO) << "SchedSchedulerTest-ExecutingQueueTasks time callback"; + schedPtr_->RemoveExtConn(BUNDLE_NAME); + schedPtr_->Sched("test"); + // SchedScheduler在析构时释放OHOS::ThreadPool若此时没有完成的任务,ThreadPool在析构调用stop时会出现异常,目前暂时sleep处理,后续更改ThreadPool方案 + // 原因是sleep等待ThreadPool任务完成后,任务不再额外持有SchedScheduler的引用计数 + // 于是本函数执行结束后SchedScheduler引用计数清空,得以在另外的线程上析构SchedScheduler对象及其中的线程池。 + sleep(WAIT_TIME); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SchedSchedulerTest-an exception occurred by Sched."; + } + GTEST_LOG_(INFO) << "SchedSchedulerTest-end SUB_Service_Sched_0100"; +} + +/** + * @tc.number: SUB_Service_ExecutingQueueTasks_0100 + * @tc.name: SUB_Service_ExecutingQueueTasks_0100 + * @tc.desc: 测试 ExecutingQueueTasks 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SchedSchedulerTest, SUB_Service_ExecutingQueueTasks_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SchedSchedulerTest-begin SUB_Service_ExecutingQueueTasks_0100"; + try { + sessionManagerPtr_->SetServiceSchedAction(BUNDLE_NAME, BConstants::ServiceSchedAction::START); + schedPtr_->ExecutingQueueTasks(BUNDLE_NAME); + sessionManagerPtr_->SetServiceSchedAction(BUNDLE_NAME, BConstants::ServiceSchedAction::RUNNING); + schedPtr_->ExecutingQueueTasks(BUNDLE_NAME); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SchedSchedulerTest-an exception occurred by ExecutingQueueTasks."; + } + GTEST_LOG_(INFO) << "SchedSchedulerTest-end SUB_Service_ExecutingQueueTasks_0100"; +} + +/** + * @tc.number: SUB_Service_RemoveExtConn_0100 + * @tc.name: SUB_Service_RemoveExtConn_0100 + * @tc.desc: 测试 RemoveExtConn 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SchedSchedulerTest, SUB_Service_RemoveExtConn_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SchedSchedulerTest-begin SUB_Service_RemoveExtConn_0100"; + try { + schedPtr_->RemoveExtConn("test"); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SchedSchedulerTest-an exception occurred by RemoveExtConn."; + } + GTEST_LOG_(INFO) << "SchedSchedulerTest-end SUB_Service_RemoveExtConn_0100"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_sa/module_ipc/service_reverse_proxy_test.cpp b/tests/unittests/backup_sa/module_ipc/service_reverse_proxy_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..709264b60133efc48053edb5372d84e76f5ef755 --- /dev/null +++ b/tests/unittests/backup_sa/module_ipc/service_reverse_proxy_test.cpp @@ -0,0 +1,263 @@ +/* + * 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 +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "b_file_info.h" +#include "iservice_registry.h" +#include "module_ipc/service_reverse_proxy.h" +#include "service_reverse_mock.h" +#include "test_manager.h" +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +using namespace testing; + +namespace { +const string BUNDLE_NAME = "com.example.app2backup"; +const string FILE_NAME = "1.tar"; +} // namespace + +class ServiceReverseProxyTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() override; + void TearDown() override; + shared_ptr proxy_ = nullptr; + sptr mock_ = nullptr; +}; + +void ServiceReverseProxyTest::SetUp() +{ + mock_ = sptr(new ServiceReverseMock()); + proxy_ = make_shared(mock_); +} +void ServiceReverseProxyTest::TearDown() +{ + mock_ = nullptr; + proxy_ = nullptr; +} + +/** + * @tc.number: SUB_ServiceReverse_proxy_BackupOnFileReady_0100 + * @tc.name: SUB_ServiceReverse_proxy_BackupOnFileReady_0100 + * @tc.desc: Test function of BackupOnFileReady interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseProxyTest, SUB_ServiceReverse_proxy_BackupOnFileReady_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-begin SUB_ServiceReverse_proxy_BackupOnFileReady_0100"; + try { + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(1) + .WillOnce(Invoke(mock_.GetRefPtr(), &ServiceReverseMock::InvokeSendRequest)); + + TestManager tm("ServiceReverseProxyTest_GetFd_0100"); + std::string filePath = tm.GetRootDirCurTest().append(FILE_NAME); + UniqueFd fd(open(filePath.data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + proxy_->BackupOnFileReady(BUNDLE_NAME, FILE_NAME, fd); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-an exception occurred by BackupOnFileReady."; + } + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-end SUB_ServiceReverse_proxy_BackupOnFileReady_0100"; +} + +/** + * @tc.number: SUB_ServiceReverse_proxy_BackupOnBundleStarted_0100 + * @tc.name: SUB_ServiceReverse_proxy_BackupOnBundleStarted_0100 + * @tc.desc: Test function of BackupOnBundleStarted interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseProxyTest, SUB_ServiceReverse_proxy_BackupOnBundleStarted_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-begin SUB_ServiceReverse_proxy_BackupOnBundleStarted_0100"; + try { + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(1) + .WillOnce(Invoke(mock_.GetRefPtr(), &ServiceReverseMock::InvokeSendRequest)); + proxy_->BackupOnBundleStarted(BError(BError::Codes::OK), BUNDLE_NAME); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-an exception occurred by BackupOnBundleStarted."; + } + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-end SUB_ServiceReverse_proxy_BackupOnBundleStarted_0100"; +} + +/** + * @tc.number: SUB_ServiceReverse_proxy_BackupOnBundleFinished_0100 + * @tc.name: SUB_ServiceReverse_proxy_BackupOnBundleFinished_0100 + * @tc.desc: Test function of BackupOnBundleFinished interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseProxyTest, SUB_ServiceReverse_proxy_BackupOnBundleFinished_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-begin SUB_ServiceReverse_proxy_BackupOnBundleFinished_0100"; + try { + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(1) + .WillOnce(Invoke(mock_.GetRefPtr(), &ServiceReverseMock::InvokeSendRequest)); + proxy_->BackupOnBundleFinished(BError(BError::Codes::OK), BUNDLE_NAME); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-an exception occurred by BackupOnBundleFinished."; + } + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-end SUB_ServiceReverse_proxy_BackupOnBundleFinished_0100"; +} + +/** + * @tc.number: SUB_ServiceReverse_proxy_BackupOnAllBundlesFinished_0100 + * @tc.name: SUB_ServiceReverse_proxy_BackupOnAllBundlesFinished_0100 + * @tc.desc: Test function of BackupOnAllBundlesFinished interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseProxyTest, + SUB_ServiceReverse_proxy_BackupOnAllBundlesFinished_0100, + testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-begin SUB_ServiceReverse_proxy_BackupOnAllBundlesFinished_0100"; + try { + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(1) + .WillOnce(Invoke(mock_.GetRefPtr(), &ServiceReverseMock::InvokeSendRequest)); + proxy_->BackupOnAllBundlesFinished(BError(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-an exception occurred by BackupOnAllBundlesFinished."; + } + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-end SUB_ServiceReverse_proxy_BackupOnAllBundlesFinished_0100"; +} + +/** + * @tc.number: SUB_ServiceReverse_proxy_RestoreOnBundleStarted_0100 + * @tc.name: SUB_ServiceReverse_proxy_RestoreOnBundleStarted_0100 + * @tc.desc: Test function of RestoreOnBundleStarted interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseProxyTest, SUB_ServiceReverse_proxy_RestoreOnBundleStarted_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-begin SUB_ServiceReverse_proxy_RestoreOnBundleStarted_0100"; + try { + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(1) + .WillOnce(Invoke(mock_.GetRefPtr(), &ServiceReverseMock::InvokeSendRequest)); + proxy_->RestoreOnBundleStarted(BError(BError::Codes::OK), BUNDLE_NAME); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-an exception occurred by RestoreOnBundleStarted."; + } + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-end SUB_ServiceReverse_proxy_RestoreOnBundleStarted_0100"; +} + +/** + * @tc.number: SUB_ServiceReverse_proxy_RestoreOnBundleFinished_0100 + * @tc.name: SUB_ServiceReverse_proxy_RestoreOnBundleFinished_0100 + * @tc.desc: Test function of RestoreOnBundleFinished interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseProxyTest, SUB_ServiceReverse_proxy_RestoreOnBundleFinished_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-begin SUB_ServiceReverse_proxy_RestoreOnBundleFinished_0100"; + try { + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(1) + .WillOnce(Invoke(mock_.GetRefPtr(), &ServiceReverseMock::InvokeSendRequest)); + proxy_->RestoreOnBundleFinished(BError(BError::Codes::OK), BUNDLE_NAME); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-an exception occurred by RestoreOnBundleFinished."; + } + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-end SUB_ServiceReverse_proxy_RestoreOnBundleFinished_0100"; +} + +/** + * @tc.number: SUB_ServiceReverse_proxy_RestoreOnAllBundlesFinished_0100 + * @tc.name: SUB_ServiceReverse_proxy_RestoreOnAllBundlesFinished_0100 + * @tc.desc: Test function of RestoreOnAllBundlesFinished interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseProxyTest, + SUB_ServiceReverse_proxy_RestoreOnAllBundlesFinished_0100, + testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-begin SUB_ServiceReverse_proxy_RestoreOnAllBundlesFinished_0100"; + try { + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(1) + .WillOnce(Invoke(mock_.GetRefPtr(), &ServiceReverseMock::InvokeSendRequest)); + proxy_->RestoreOnAllBundlesFinished(BError(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-an exception occurred by RestoreOnAllBundlesFinished."; + } + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-end SUB_ServiceReverse_proxy_RestoreOnAllBundlesFinished_0100"; +} + +/** + * @tc.number: SUB_ServiceReverse_proxy_RestoreOnFileReady_0100 + * @tc.name: SUB_ServiceReverse_proxy_RestoreOnFileReady_0100 + * @tc.desc: Test function of RestoreOnFileReady interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceReverseProxyTest, SUB_ServiceReverse_proxy_RestoreOnFileReady_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-begin SUB_ServiceReverse_proxy_RestoreOnFileReady_0100"; + try { + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(1) + .WillOnce(Invoke(mock_.GetRefPtr(), &ServiceReverseMock::InvokeSendRequest)); + + TestManager tm("ServiceReverseProxyTest_GetFd_0200"); + std::string filePath = tm.GetRootDirCurTest().append(FILE_NAME); + UniqueFd fd(open(filePath.data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + proxy_->RestoreOnFileReady(BUNDLE_NAME, FILE_NAME, fd); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-an exception occurred by RestoreOnFileReady."; + } + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-end SUB_ServiceReverse_proxy_RestoreOnFileReady_0100"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_sa/module_ipc/service_stub_test.cpp b/tests/unittests/backup_sa/module_ipc/service_stub_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e7aef2e891b1049d67f306c37179bff2158c0188 --- /dev/null +++ b/tests/unittests/backup_sa/module_ipc/service_stub_test.cpp @@ -0,0 +1,362 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "i_service.h" +#include "module_ipc/service_stub.h" +#include "service_reverse_mock.h" +#include "test_manager.h" +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +using namespace testing; + +namespace { +const string BUNDLE_NAME = "com.example.app2backup"; +const string FILE_NAME = "1.tar"; +} // namespace + +class MockService final : public ServiceStub { +public: + MOCK_METHOD2(InitRestoreSession, ErrCode(sptr remote, const vector &bundleNames)); + MOCK_METHOD3(InitBackupSession, + ErrCode(sptr remote, UniqueFd fd, const vector &bundleNames)); + MOCK_METHOD0(Start, ErrCode()); + MOCK_METHOD0(GetLocalCapabilities, UniqueFd()); + MOCK_METHOD1(PublishFile, ErrCode(const BFileInfo &fileInfo)); + MOCK_METHOD2(AppFileReady, ErrCode(const string &fileName, UniqueFd fd)); + MOCK_METHOD1(AppDone, ErrCode(ErrCode errCode)); + MOCK_METHOD2(GetExtFileName, ErrCode(string &bundleName, string &fileName)); + UniqueFd InvokeGetLocalCapabilities() + { + if (bCapabilities_) { + return UniqueFd(-1); + } + TestManager tm("MockService_GetFd_0100"); + std::string filePath = tm.GetRootDirCurTest().append(FILE_NAME); + UniqueFd fd(open(filePath.data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + bCapabilities_ = true; + return fd; + } + +private: + bool bCapabilities_ = {false}; +}; + +class ServiceStubTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() override {}; + void TearDown() override {}; +}; + +/** + * @tc.number: SUB_backup_sa_ServiceStub_InitRestoreSession_0100 + * @tc.name: SUB_backup_sa_ServiceStub_InitRestoreSession_0100 + * @tc.desc: Test function of InitRestoreSession interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(ServiceStubTest, SUB_backup_sa_ServiceStub_InitRestoreSession_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "ServiceStubTest-begin SUB_backup_sa_ServiceStub_InitRestoreSession_0100"; + try { + MockService service; + EXPECT_CALL(service, InitRestoreSession(_, _)).WillOnce(Return(BError(BError::Codes::OK))); + MessageParcel data; + MessageParcel reply; + MessageOption option; + + EXPECT_TRUE(data.WriteInterfaceToken(IService::GetDescriptor())); + sptr remote = sptr(new ServiceReverseMock()); + EXPECT_TRUE(data.WriteRemoteObject(remote->AsObject().GetRefPtr())); + vector bundleNames; + bundleNames.push_back(BUNDLE_NAME); + EXPECT_TRUE(data.WriteStringVector(bundleNames)); + + EXPECT_EQ(BError(BError::Codes::OK), + service.OnRemoteRequest(IService::SERVICE_CMD_INIT_RESTORE_SESSION, data, reply, option)); + remote = nullptr; + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceStubTest-an exception occurred by InitRestoreSession."; + } + GTEST_LOG_(INFO) << "ServiceStubTest-end SUB_backup_sa_ServiceStub_InitRestoreSession_0100"; +} + +/** + * @tc.number: SUB_backup_sa_ServiceStub_InitBackupSession_0100 + * @tc.name: SUB_backup_sa_ServiceStub_InitBackupSession_0100 + * @tc.desc: Test function of InitBackupSession interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceStubTest, SUB_backup_sa_ServiceStub_InitBackupSession_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "ServiceStubTest-begin SUB_backup_sa_ServiceStub_InitBackupSession_0100"; + try { + MockService service; + EXPECT_CALL(service, InitBackupSession(_, _, _)).WillOnce(Return(BError(BError::Codes::OK))); + MessageParcel data; + MessageParcel reply; + MessageOption option; + + vector bundleNames; + bundleNames.push_back(BUNDLE_NAME); + sptr remote = sptr(new ServiceReverseMock()); + TestManager tm("ServiceStub_GetFd_0100"); + std::string filePath = tm.GetRootDirCurTest().append(FILE_NAME); + UniqueFd fd(open(filePath.data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + + EXPECT_TRUE(data.WriteInterfaceToken(IService::GetDescriptor())); + EXPECT_TRUE(data.WriteRemoteObject(remote->AsObject().GetRefPtr())); + EXPECT_TRUE(data.WriteFileDescriptor(fd)); + EXPECT_TRUE(data.WriteStringVector(bundleNames)); + + EXPECT_EQ(BError(BError::Codes::OK), + service.OnRemoteRequest(IService::SERVICE_CMD_INIT_BACKUP_SESSION, data, reply, option)); + GTEST_LOG_(INFO) << "ServiceStubTest-CmdInitBackupSession Brances"; + MessageParcel brances; + EXPECT_TRUE(data.WriteInterfaceToken(IService::GetDescriptor())); + EXPECT_TRUE(data.WriteRemoteObject(remote->AsObject().GetRefPtr())); + EXPECT_NE(BError(BError::Codes::OK), + service.OnRemoteRequest(IService::SERVICE_CMD_INIT_BACKUP_SESSION, brances, reply, option)); + remote = nullptr; + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceStubTest-an exception occurred by InitBackupSession."; + } + GTEST_LOG_(INFO) << "ServiceStubTest-end SUB_backup_sa_ServiceStub_InitBackupSession_0100"; +} + +/** + * @tc.number: SUB_backup_sa_ServiceStub_Start_0100 + * @tc.name: SUB_backup_sa_ServiceStub_Start_0100 + * @tc.desc: Test function of Start interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceStubTest, SUB_backup_sa_ServiceStub_Start_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "ServiceStubTest-begin SUB_backup_sa_ServiceStub_Start_0100"; + try { + MockService service; + EXPECT_CALL(service, Start()).WillOnce(Return(BError(BError::Codes::OK))); + MessageParcel data; + MessageParcel reply; + MessageOption option; + + EXPECT_TRUE(data.WriteInterfaceToken(IService::GetDescriptor())); + EXPECT_EQ(BError(BError::Codes::OK), service.OnRemoteRequest(IService::SERVICE_CMD_START, data, reply, option)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceStubTest-an exception occurred by Start."; + } + GTEST_LOG_(INFO) << "ServiceStubTest-end SUB_backup_sa_ServiceStub_Start_0100"; +} + +/** + * @tc.number: SUB_backup_sa_ServiceStub_GetLocalCapabilities_0100 + * @tc.name: SUB_backup_sa_ServiceStub_GetLocalCapabilities_0100 + * @tc.desc: Test function of GetLocalCapabilities interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0377 + */ +HWTEST_F(ServiceStubTest, SUB_backup_sa_ServiceStub_GetLocalCapabilities_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "ServiceStubTest-begin SUB_backup_sa_ServiceStub_GetLocalCapabilities_0100"; + try { + sptr serviceSptr = sptr(new MockService()); + EXPECT_CALL(*serviceSptr, GetLocalCapabilities()) + .Times(2) + .WillOnce(Invoke(serviceSptr.GetRefPtr(), &MockService::InvokeGetLocalCapabilities)) + .WillOnce(Invoke(serviceSptr.GetRefPtr(), &MockService::InvokeGetLocalCapabilities)); + MessageParcel data; + MessageParcel reply; + MessageOption option; + + EXPECT_TRUE(data.WriteInterfaceToken(IService::GetDescriptor())); + + EXPECT_EQ(BError(BError::Codes::OK), + serviceSptr->OnRemoteRequest(IService::SERVICE_CMD_GET_LOCAL_CAPABILITIES, data, reply, option)); + UniqueFd fd(reply.ReadFileDescriptor()); + EXPECT_GT(fd, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "ServiceStubTest-CmdGetLocalCapabilities Brances"; + MessageParcel brances; + EXPECT_TRUE(brances.WriteInterfaceToken(IService::GetDescriptor())); + EXPECT_NE(BError(BError::Codes::OK), + serviceSptr->OnRemoteRequest(IService::SERVICE_CMD_GET_LOCAL_CAPABILITIES, brances, reply, option)); + serviceSptr = nullptr; + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceStubTest-an exception occurred by GetLocalCapabilities."; + } + GTEST_LOG_(INFO) << "ServiceStubTest-end SUB_backup_sa_ServiceStub_GetLocalCapabilities_0100"; +} + +/** + * @tc.number: SUB_backup_sa_ServiceStub_PublishFile_0100 + * @tc.name: SUB_backup_sa_ServiceStub_PublishFile_0100 + * @tc.desc: Test function of PublishFile interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceStubTest, SUB_backup_sa_ServiceStub_PublishFile_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "ServiceStubTest-begin SUB_backup_sa_ServiceStub_PublishFile_0100"; + try { + MockService service; + EXPECT_CALL(service, PublishFile(_)).WillOnce(Return(BError(BError::Codes::OK))); + MessageParcel data; + MessageParcel reply; + MessageOption option; + + BFileInfo fileInfo {BUNDLE_NAME, FILE_NAME, -1}; + EXPECT_TRUE(data.WriteInterfaceToken(IService::GetDescriptor())); + EXPECT_TRUE(data.WriteParcelable(&fileInfo)); + EXPECT_EQ(BError(BError::Codes::OK), + service.OnRemoteRequest(IService::SERVICE_CMD_PUBLISH_FILE, data, reply, option)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceStubTest-an exception occurred by PublishFile."; + } + GTEST_LOG_(INFO) << "ServiceStubTest-end SUB_backup_sa_ServiceStub_PublishFile_0100"; +} + +/** + * @tc.number: SUB_backup_sa_ServiceStub_AppFileReady_0100 + * @tc.name: SUB_backup_sa_ServiceStub_AppFileReady_0100 + * @tc.desc: Test function of AppFileReady interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0380 + */ +HWTEST_F(ServiceStubTest, SUB_backup_sa_ServiceStub_AppFileReady_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "ServiceStubTest-begin SUB_backup_sa_ServiceStub_AppFileReady_0100"; + try { + MockService service; + EXPECT_CALL(service, AppFileReady(_, _)).WillOnce(Return(BError(BError::Codes::OK))); + MessageParcel data; + MessageParcel reply; + MessageOption option; + + TestManager tm("ServiceStub_GetFd_0200"); + std::string filePath = tm.GetRootDirCurTest().append(FILE_NAME); + UniqueFd fd(open(filePath.data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + + EXPECT_TRUE(data.WriteInterfaceToken(IService::GetDescriptor())); + EXPECT_TRUE(data.WriteString(FILE_NAME)); + EXPECT_TRUE(data.WriteFileDescriptor(fd)); + EXPECT_EQ(BError(BError::Codes::OK), + service.OnRemoteRequest(IService::SERVICE_CMD_APP_FILE_READY, data, reply, option)); + GTEST_LOG_(INFO) << "ServiceStubTest-begin-CmdAppFileReady Brances"; + MessageParcel brances; + EXPECT_TRUE(brances.WriteInterfaceToken(IService::GetDescriptor())); + EXPECT_TRUE(brances.WriteString(FILE_NAME)); + EXPECT_NE(BError(BError::Codes::OK), + service.OnRemoteRequest(IService::SERVICE_CMD_APP_FILE_READY, brances, reply, option)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceStubTest-an exception occurred by AppFileReady."; + } + GTEST_LOG_(INFO) << "ServiceStubTest-end SUB_backup_sa_ServiceStub_AppFileReady_0100"; +} + +/** + * @tc.number: SUB_backup_sa_ServiceStub_AppDone_0100 + * @tc.name: SUB_backup_sa_ServiceStub_AppDone_0100 + * @tc.desc: Test function of AppDone interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0380 + */ +HWTEST_F(ServiceStubTest, SUB_backup_sa_ServiceStub_AppDone_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "ServiceStubTest-begin SUB_backup_sa_ServiceStub_AppDone_0100"; + try { + MockService service; + EXPECT_CALL(service, AppDone(_)).WillOnce(Return(BError(BError::Codes::OK))); + MessageParcel data; + MessageParcel reply; + MessageOption option; + + EXPECT_TRUE(data.WriteInterfaceToken(IService::GetDescriptor())); + EXPECT_TRUE(data.WriteInt32(BError(BError::Codes::OK))); + EXPECT_EQ(BError(BError::Codes::OK), + service.OnRemoteRequest(IService::SERVICE_CMD_APP_DONE, data, reply, option)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceStubTest-an exception occurred by AppDone."; + } + GTEST_LOG_(INFO) << "ServiceStubTest-end SUB_backup_sa_ServiceStub_AppDone_0100"; +} + +/** + * @tc.number: SUB_backup_sa_ServiceStub_GetExtFileName_0100 + * @tc.name: SUB_backup_sa_ServiceStub_GetExtFileName_0100 + * @tc.desc: Test function of GetExtFileName interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0379 + */ +HWTEST_F(ServiceStubTest, SUB_backup_sa_ServiceStub_GetExtFileName_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "ServiceStubTest-begin SUB_backup_sa_ServiceStub_GetExtFileName_0100"; + try { + MockService service; + EXPECT_CALL(service, GetExtFileName(_, _)).WillOnce(Return(BError(BError::Codes::OK))); + MessageParcel data; + MessageParcel reply; + MessageOption option; + option.SetFlags(MessageOption::TF_ASYNC); + + EXPECT_TRUE(data.WriteInterfaceToken(IService::GetDescriptor())); + EXPECT_TRUE(data.WriteString(BUNDLE_NAME)); + EXPECT_TRUE(data.WriteString(FILE_NAME)); + EXPECT_EQ(BError(BError::Codes::OK), + service.OnRemoteRequest(IService::SERVICE_CMD_GET_EXT_FILE_NAME, data, reply, option)); + EXPECT_NE(BError(BError::Codes::OK), service.OnRemoteRequest(3333, data, reply, option)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceStubTest-an exception occurred by GetExtFileName."; + } + GTEST_LOG_(INFO) << "ServiceStubTest-end SUB_backup_sa_ServiceStub_GetExtFileName_0100"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_sa/module_ipc/service_test.cpp b/tests/unittests/backup_sa/module_ipc/service_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4c40cca230e99b286fc63ccfc7d67605c10e7600 --- /dev/null +++ b/tests/unittests/backup_sa/module_ipc/service_test.cpp @@ -0,0 +1,463 @@ +/* + * 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 +#include +#include +#include +#include + +#include "module_ipc/service.h" +#include "service_reverse_mock.h" +#include "test_manager.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +using namespace testing; + +namespace { +const string BUNDLE_NAME = "com.example.app2backup"; +const string MANAGE_JSON = "manage.json"; +const string FILE_NAME = "1.tar"; +constexpr int32_t SERVICE_ID = 5203; +} // namespace + +class ServiceTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(); + void SetUp() {}; + void TearDown() {}; + + ErrCode Init(IServiceReverse::Scenario scenario); + + static inline sptr servicePtr_ = nullptr; + static inline sptr remote_ = nullptr; +}; + +void ServiceTest::SetUpTestCase(void) +{ + GTEST_LOG_(INFO) << "SetUpTestCase enter"; + servicePtr_ = sptr(new Service(SERVICE_ID)); + remote_ = sptr(new ServiceReverseMock()); +} + +void ServiceTest::TearDownTestCase() +{ + GTEST_LOG_(INFO) << "TearDownTestCase enter"; + servicePtr_ = nullptr; + remote_ = nullptr; +} + +ErrCode ServiceTest::Init(IServiceReverse::Scenario scenario) +{ + vector bundleNames; + bundleNames.emplace_back(BUNDLE_NAME); + ErrCode ret = 0; + if (scenario == IServiceReverse::Scenario::RESTORE) { + ret = servicePtr_->InitRestoreSession(remote_, bundleNames); + } else if (scenario == IServiceReverse::Scenario::BACKUP) { + UniqueFd fd = servicePtr_->GetLocalCapabilities(); + EXPECT_GT(fd, BError(BError::Codes::OK)); + ret = servicePtr_->InitBackupSession(remote_, move(fd), bundleNames); + } + return ret; +} + +/** + * @tc.number: SUB_Service_GetLocalCapabilities_0100 + * @tc.name: SUB_Service_GetLocalCapabilities_0100 + * @tc.desc: 测试 GetLocalCapabilities 获取本地能力文件 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceTest, SUB_Service_GetLocalCapabilities_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceTest-begin SUB_Service_GetLocalCapabilities_0100"; + try { + UniqueFd fd = servicePtr_->GetLocalCapabilities(); + EXPECT_GT(fd, BError(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by GetLocalCapabilities."; + } + GTEST_LOG_(INFO) << "ServiceTest-end SUB_Service_GetLocalCapabilities_0100"; +} + +/** + * @tc.number: SUB_Service_OnStart_0100 + * @tc.name: SUB_Service_OnStart_0100 + * @tc.desc: 测试 OnStart 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceTest, SUB_Service_OnStart_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceTest-begin SUB_Service_OnStart_0100"; + try { + servicePtr_->OnStart(); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by OnStart."; + } + GTEST_LOG_(INFO) << "ServiceTest-end SUB_Service_OnStart_0100"; +} + +/** + * @tc.number: SUB_Service_Start_0100 + * @tc.name: SUB_Service_Start_0100 + * @tc.desc: 测试 Start 备份恢复启动 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceTest, SUB_Service_Start_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceTest-begin SUB_Service_Start_0100"; + try { + auto ret = servicePtr_->Start(); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by Start."; + } + GTEST_LOG_(INFO) << "ServiceTest-end SUB_Service_Start_0100"; +} + +/** + * @tc.number: SUB_Service_PublishFile_0100 + * @tc.name: SUB_Service_PublishFile_0100 + * @tc.desc: 测试 PublishFile 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceTest, SUB_Service_PublishFile_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceTest-begin SUB_Service_PublishFile_0100"; + try { + ErrCode ret = Init(IServiceReverse::Scenario::RESTORE); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + BFileInfo fileInfo {BUNDLE_NAME, FILE_NAME, 0}; + ret = servicePtr_->PublishFile(fileInfo); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "ServiceTest-PublishFile Branches"; + fileInfo.fileName = "test"; + ret = servicePtr_->PublishFile(fileInfo); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by PublishFile."; + } + GTEST_LOG_(INFO) << "ServiceTest-end SUB_Service_PublishFile_0100"; +} + +/** + * @tc.number: SUB_Service_AppFileReady_0100 + * @tc.name: SUB_Service_AppFileReady_0100 + * @tc.desc: 测试 AppFileReady 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceTest, SUB_Service_AppFileReady_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceTest-begin SUB_Service_AppFileReady_0100"; + try { + string fileName = MANAGE_JSON; + auto ret = servicePtr_->AppFileReady(fileName, UniqueFd(-1)); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "ServiceTest-AppFileReady Branches"; + fileName = "test"; + ret = servicePtr_->AppFileReady(fileName, UniqueFd(-1)); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by AppFileReady."; + } + GTEST_LOG_(INFO) << "ServiceTest-end SUB_Service_AppFileReady_0100"; +} + +/** + * @tc.number: SUB_Service_AppDone_0100 + * @tc.name: SUB_Service_AppDone_0100 + * @tc.desc: 测试 AppDone 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceTest, SUB_Service_AppDone_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceTest-begin SUB_Service_AppDone_0100"; + try { + GTEST_LOG_(INFO) << "SUB_Service_AppDone_0100 RESTORE"; + auto ret = servicePtr_->AppDone(BError(BError::Codes::OK)); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "SUB_Service_AppDone_0100 BACKUP"; + ret = Init(IServiceReverse::Scenario::BACKUP); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "ServiceTest-AppDone Branches"; + ret = servicePtr_->AppDone(1); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "ServiceTest-AppDone Branches End"; + ret = servicePtr_->AppDone(BError(BError::Codes::OK)); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by AppDone."; + } + GTEST_LOG_(INFO) << "ServiceTest-end SUB_Service_AppDone_0100"; +} + +/** + * @tc.number: SUB_Service_LaunchBackupExtension_0100 + * @tc.name: SUB_Service_LaunchBackupExtension_0100 + * @tc.desc: 测试 LaunchBackupExtension 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceTest, SUB_Service_LaunchBackupExtension_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceTest-begin SUB_Service_LaunchBackupExtension_0100"; + try { + GTEST_LOG_(INFO) << "SUB_Service_LaunchBackupExtension_0100 RESTORE"; + ErrCode ret = Init(IServiceReverse::Scenario::RESTORE); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + ret = servicePtr_->LaunchBackupExtension(BUNDLE_NAME); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "SUB_Service_LaunchBackupExtension_0100 BACKUP"; + ret = Init(IServiceReverse::Scenario::BACKUP); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + ret = servicePtr_->LaunchBackupExtension(BUNDLE_NAME); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by LaunchBackupExtension."; + } + GTEST_LOG_(INFO) << "ServiceTest-end SUB_Service_LaunchBackupExtension_0100"; +} + +/** + * @tc.number: SUB_Service_GetExtFileName_0100 + * @tc.name: SUB_Service_GetExtFileName_0100 + * @tc.desc: 测试 GetExtFileName 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceTest, SUB_Service_GetExtFileName_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceTest-begin SUB_Service_GetExtFileName_0100"; + try { + ErrCode ret = Init(IServiceReverse::Scenario::RESTORE); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + + string bundleName = BUNDLE_NAME; + string fileName = FILE_NAME; + ret = servicePtr_->GetExtFileName(bundleName, fileName); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by GetExtFileName."; + } + GTEST_LOG_(INFO) << "ServiceTest-end SUB_Service_GetExtFileName_0100"; +} + +/** + * @tc.number: SUB_Service_OnBackupExtensionDied_0100 + * @tc.name: SUB_Service_OnBackupExtensionDied_0100 + * @tc.desc: 测试 OnBackupExtensionDied 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceTest, SUB_Service_OnBackupExtensionDied_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceTest-begin SUB_Service_OnBackupExtensionDied_0100"; + try { + GTEST_LOG_(INFO) << "SUB_Service_OnBackupExtensionDied_0100 RESTORE"; + ErrCode ret = Init(IServiceReverse::Scenario::RESTORE); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + string bundleName = BUNDLE_NAME; + servicePtr_->OnBackupExtensionDied(move(bundleName), BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "SUB_Service_OnBackupExtensionDied_0100 BACKUP"; + ret = Init(IServiceReverse::Scenario::BACKUP); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + bundleName = BUNDLE_NAME; + servicePtr_->OnBackupExtensionDied(move(bundleName), BError(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by GetExtFileName."; + } + GTEST_LOG_(INFO) << "ServiceTest-end SUB_Service_OnBackupExtensionDied_0100"; +} + +/** + * @tc.number: SUB_Service_ExtStart_0100 + * @tc.name: SUB_Service_ExtStart_0100 + * @tc.desc: 测试 ExtStart 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceTest, SUB_Service_ExtStart_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceTest-begin SUB_Service_ExtStart_0100"; + try { + GTEST_LOG_(INFO) << "SUB_Service_ExtStart_0100 BACKUP"; + ErrCode ret = Init(IServiceReverse::Scenario::BACKUP); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + servicePtr_->ExtStart(BUNDLE_NAME); + GTEST_LOG_(INFO) << "ServiceTest-ExtStart BACKUP Branches"; + servicePtr_->ExtStart(BUNDLE_NAME); + GTEST_LOG_(INFO) << "SUB_Service_ExtStart_0100 RESTORE"; + ret = Init(IServiceReverse::Scenario::RESTORE); + servicePtr_->ExtStart(BUNDLE_NAME); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by ExtStart."; + } + GTEST_LOG_(INFO) << "ServiceTest-end SUB_Service_ExtStart_0100"; +} + +/** + * @tc.number: SUB_Service_Dump_0100 + * @tc.name: SUB_Service_Dump_0100 + * @tc.desc: 测试 Dump 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceTest, SUB_Service_Dump_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceTest-begin SUB_Service_Dump_0100"; + try { + servicePtr_->Dump(-1, {}); + TestManager tm("ServiceTest_GetFd_0100"); + string filePath = tm.GetRootDirCurTest().append(FILE_NAME); + UniqueFd fd(open(filePath.data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + servicePtr_->Dump(move(fd), {}); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by Dump."; + } + GTEST_LOG_(INFO) << "ServiceTest-end SUB_Service_Dump_0100"; +} + +/** + * @tc.number: SUB_Service_ExtConnectFailed_0100 + * @tc.name: SUB_Service_ExtConnectFailed_0100 + * @tc.desc: 测试 ExtConnectFailed 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceTest, SUB_Service_ExtConnectFailed_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceTest-begin SUB_Service_ExtConnectFailed_0100"; + try { + GTEST_LOG_(INFO) << "SUB_Service_ExtConnectFailed_0100 RESTORE"; + ErrCode ret = Init(IServiceReverse::Scenario::RESTORE); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + servicePtr_->ExtConnectFailed(BUNDLE_NAME, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "SUB_Service_ExtConnectFailed_0100 BACKUP"; + ret = Init(IServiceReverse::Scenario::BACKUP); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + servicePtr_->ExtConnectFailed(BUNDLE_NAME, BError(BError::Codes::OK)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by ExtConnectFailed."; + } + GTEST_LOG_(INFO) << "ServiceTest-end SUB_Service_ExtConnectFailed_0100"; +} + +/** + * @tc.number: SUB_Service_ExtConnectDone_0100 + * @tc.name: SUB_Service_ExtConnectDone_0100 + * @tc.desc: 测试 ExtConnectDone 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceTest, SUB_Service_ExtConnectDone_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceTest-begin SUB_Service_ExtConnectDone_0100"; + try { + servicePtr_->ExtConnectDone(BUNDLE_NAME); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by ExtConnectDone."; + } + GTEST_LOG_(INFO) << "ServiceTest-end SUB_Service_ExtConnectDone_0100"; +} + +/** + * @tc.number: SUB_Service_StopAll_0100 + * @tc.name: SUB_Service_StopAll_0100 + * @tc.desc: 测试 StopAll 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceTest, SUB_Service_StopAll_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceTest-begin SUB_Service_StopAll_0100"; + try { + servicePtr_->StopAll(nullptr, true); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by StopAll."; + } + GTEST_LOG_(INFO) << "ServiceTest-end SUB_Service_StopAll_0100"; +} + +/** + * @tc.number: SUB_Service_OnStop_0100 + * @tc.name: SUB_Service_OnStop_0100 + * @tc.desc: 测试 OnStop 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(ServiceTest, SUB_Service_OnStop_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ServiceTest-begin SUB_Service_OnStop_0100"; + try { + servicePtr_->OnStop(); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ServiceTest-an exception occurred by OnStop."; + } + GTEST_LOG_(INFO) << "ServiceTest-end SUB_Service_OnStop_0100"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_sa/module_ipc/svc_backup_connection_test.cpp b/tests/unittests/backup_sa/module_ipc/svc_backup_connection_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..34c01ff2fadeab4ae916a3b0bf00dcb325e29d5d --- /dev/null +++ b/tests/unittests/backup_sa/module_ipc/svc_backup_connection_test.cpp @@ -0,0 +1,178 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "element_name.h" +#include "ext_extension_mock.h" +#include "module_ipc/svc_backup_connection.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +using namespace testing; + +namespace { +constexpr int32_t WAIT_TIME = 1; +} // namespace + +class SvcBackupConnectionTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() override; + void TearDown() override; + sptr backupCon_ = nullptr; +}; + +static void CallDied(const std::string &&name) +{ + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-CallDied SUCCESS"; +} + +static void CallDone(const std::string &&name) +{ + GTEST_LOG_(INFO) << "ServiceReverseProxyTest-CallDone SUCCESS"; +} + +void SvcBackupConnectionTest::SetUp() +{ + backupCon_ = sptr(new SvcBackupConnection(CallDied, CallDone)); +} +void SvcBackupConnectionTest::TearDown() +{ + backupCon_ = nullptr; +} + +/** + * @tc.number: SUB_BackupConnection_OnAbilityConnectDone_0100 + * @tc.name: SUB_BackupConnection_OnAbilityConnectDone_0100 + * @tc.desc: 测试 OnAbilityConnectDone 链接回调接口调用成功 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcBackupConnectionTest, SUB_BackupConnection_OnAbilityConnectDone_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcBackupConnectionTest-begin SUB_BackupConnection_OnAbilityConnectDone_0100"; + AppExecFwk::ElementName element; + string bundleName = ""; + element.SetBundleName(bundleName); + int resultCode = 1; + sptr mock = sptr(new BackupExtExtensionMock()); + backupCon_->OnAbilityConnectDone(element, mock->AsObject(), resultCode); + bool ret = backupCon_->IsExtAbilityConnected(); + EXPECT_TRUE(ret); + mock = nullptr; + backupCon_->OnAbilityConnectDone(element, nullptr, resultCode); + GTEST_LOG_(INFO) << "SvcBackupConnectionTest-end SUB_BackupConnection_OnAbilityConnectDone_0100"; +} + +/** + * @tc.number: SUB_BackupConnection_OnAbilityDisconnectDone_0100 + * @tc.name: SUB_BackupConnection_OnAbilityDisconnectDone_0100 + * @tc.desc: 测试 OnAbilityDisconnectDone 链接回调接口调用成功 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcBackupConnectionTest, SUB_BackupConnection_OnAbilityDisconnectDone_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcBackupConnectionTest-begin SUB_BackupConnection_OnAbilityDisconnectDone_0100"; + AppExecFwk::ElementName element; + string bundleName = ""; + element.SetBundleName(bundleName); + int resultCode = 1; + backupCon_->OnAbilityDisconnectDone(element, resultCode); + bool ret = backupCon_->IsExtAbilityConnected(); + EXPECT_FALSE(ret); + GTEST_LOG_(INFO) << "SvcBackupConnectionTest-end SUB_BackupConnection_OnAbilityDisconnectDone_0100"; +} + +/** + * @tc.number: SUB_BackupConnection_GetBackupExtProxy_0100 + * @tc.name: SUB_BackupConnection_GetBackupExtProxy_0100 + * @tc.desc: 测试 GetBackupExtProxy 获取连接状态接口调用成功 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcBackupConnectionTest, SUB_BackupConnection_GetBackupExtProxy_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcBackupConnectionTest-begin SUB_BackupConnection_GetBackupExtProxy_0100"; + auto proxy = backupCon_->GetBackupExtProxy(); + EXPECT_EQ(proxy, nullptr); + GTEST_LOG_(INFO) << "SvcBackupConnectionTest-end SUB_BackupConnection_GetBackupExtProxy_0100"; +} + +/** + * @tc.number: SUB_BackupConnection_ConnectBackupExtAbility_0100 + * @tc.name: SUB_BackupConnection_ConnectBackupExtAbility_0100 + * @tc.desc: 测试 ConnectBackupExtAbility 拉起extension接口调用成功 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcBackupConnectionTest, SUB_BackupConnection_ConnectBackupExtAbility_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcBackupConnectionTest-begin SUB_BackupConnection_ConnectBackupExtAbility_0100"; + AAFwk::Want want; + ErrCode ret = backupCon_->ConnectBackupExtAbility(want); + EXPECT_NE(ret, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "SvcBackupConnectionTest-end SUB_BackupConnection_ConnectBackupExtAbility_0100"; +} + +static void CallBack(sptr backupCon) +{ + GTEST_LOG_(INFO) << "SvcBackupConnectionTest-CallBack Begin"; + sleep(WAIT_TIME); + backupCon->OnAbilityDisconnectDone({}, WAIT_TIME); + GTEST_LOG_(INFO) << "SvcBackupConnectionTest-CallBack End"; +} + +/** + * @tc.number: SUB_BackupConnection_DisconnectBackupExtAbility_0100 + * @tc.name: SUB_BackupConnection_DisconnectBackupExtAbility_0100 + * @tc.desc: 测试 DisconnectBackupExtAbility 拉起extension接口调用成功 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcBackupConnectionTest, SUB_BackupConnection_DisconnectBackupExtAbility_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcBackupConnectionTest-begin SUB_BackupConnection_DisconnectBackupExtAbility_0100"; + ErrCode ret = backupCon_->DisconnectBackupExtAbility(); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "SvcBackupConnectionTest-DisconnectBackupExtAbility async Begin"; + auto future = std::async(std::launch::async, CallBack, backupCon_); + sleep(WAIT_TIME); + GTEST_LOG_(INFO) << "SvcBackupConnectionTest-DisconnectBackupExtAbility Branches Begin"; + ret = backupCon_->DisconnectBackupExtAbility(); + EXPECT_EQ(ret, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "SvcBackupConnectionTest-DisconnectBackupExtAbility Branches End"; + future.get(); + GTEST_LOG_(INFO) << "SvcBackupConnectionTest-end SUB_BackupConnection_DisconnectBackupExtAbility_0100"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_sa/module_ipc/svc_extension_proxy_test.cpp b/tests/unittests/backup_sa/module_ipc/svc_extension_proxy_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d041d387a83b18d8e578b89f3d52a0a9761ac4dc --- /dev/null +++ b/tests/unittests/backup_sa/module_ipc/svc_extension_proxy_test.cpp @@ -0,0 +1,147 @@ +/* + * 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 +#include +#include + +#include "b_error/b_error.h" +#include "ext_extension_mock.h" +#include "module_ipc/svc_extension_proxy.h" +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +using namespace testing; + +class SvcExtensionProxyTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() override; + void TearDown() override; + sptr proxy_ = nullptr; + sptr mock_ = nullptr; +}; + +void SvcExtensionProxyTest::SetUp() +{ + mock_ = sptr(new BackupExtExtensionMock()); + proxy_ = sptr(new SvcExtensionProxy(mock_)); +} +void SvcExtensionProxyTest::TearDown() +{ + mock_ = nullptr; + proxy_ = nullptr; +} + +/** + * @tc.number: SUB_Ext_Extension_proxy_GetFileHandle_0100 + * @tc.name: SUB_Ext_Extension_proxy_GetFileHandle_0100 + * @tc.desc: 测试 GetFileHandle 获取真实文件接口调用成功和失败 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcExtensionProxyTest, SUB_Ext_Extension_proxy_GetFileHandle_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcExtensionProxyTest-begin SUB_Ext_Extension_proxy_GetFileHandle_0100"; + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(2) + .WillOnce(Invoke(mock_.GetRefPtr(), &BackupExtExtensionMock::InvokeGetFileHandleRequest)) + .WillOnce(Return(EPERM)); + string fileName = "1.tar"; + UniqueFd fd = proxy_->GetFileHandle(fileName); + EXPECT_GT(fd, BError(BError::Codes::OK)); + + UniqueFd fdErr = proxy_->GetFileHandle(fileName); + EXPECT_LT(fdErr, BError(BError::Codes::OK)); + GTEST_LOG_(INFO) << "SvcExtensionProxyTest-end SUB_Ext_Extension_proxy_GetFileHandle_0100"; +} + +/** + * @tc.number: SUB_Ext_Extension_proxy_HandleClear_0100 + * @tc.name: SUB_Ext_Extension_proxy_HandleClear_0100 + * @tc.desc: 测试 HandleClear 接口调用成功和失败 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcExtensionProxyTest, SUB_Ext_Extension_proxy_HandleClear_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcExtensionProxyTest-begin SUB_Ext_Extension_proxy_HandleClear_0100"; + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(2) + .WillOnce(Invoke(mock_.GetRefPtr(), &BackupExtExtensionMock::InvokeSendRequest)) + .WillOnce(Return(EPERM)); + ErrCode ret = proxy_->HandleClear(); + EXPECT_EQ(BError(BError::Codes::OK), ret); + + ret = proxy_->HandleClear(); + EXPECT_NE(BError(BError::Codes::OK), ret); + GTEST_LOG_(INFO) << "SvcExtensionProxyTest-end SUB_Ext_Extension_proxy_HandleClear_0100"; +} + +/** + * @tc.number: SUB_Ext_Extension_proxy_HandleBackup_0100 + * @tc.name: SUB_Ext_Extension_proxy_HandleBackup_0100 + * @tc.desc: 测试 HandleBackup 接口调用成功和失败 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcExtensionProxyTest, SUB_Ext_Extension_proxy_HandleBackup_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcExtensionProxyTest-begin SUB_Ext_Extension_proxy_HandleBackup_0100"; + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(2) + .WillOnce(Invoke(mock_.GetRefPtr(), &BackupExtExtensionMock::InvokeSendRequest)) + .WillOnce(Return(EPERM)); + ErrCode ret = proxy_->HandleBackup(); + EXPECT_EQ(BError(BError::Codes::OK), ret); + + ret = proxy_->HandleBackup(); + EXPECT_NE(BError(BError::Codes::OK), ret); + GTEST_LOG_(INFO) << "SvcExtensionProxyTest-end SUB_Ext_Extension_proxy_HandleBackup_0100"; +} + +/** + * @tc.number: SUB_Ext_Extension_proxy_PublishFile_0100 + * @tc.name: SUB_Ext_Extension_proxy_PublishFile_0100 + * @tc.desc: 测试 PublishFile 接口调用成功和失败 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcExtensionProxyTest, SUB_Ext_Extension_proxy_PublishFile_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcExtensionProxyTest-begin SUB_Ext_Extension_proxy_PublishFile_0100"; + EXPECT_CALL(*mock_, SendRequest(_, _, _, _)) + .Times(2) + .WillOnce(Invoke(mock_.GetRefPtr(), &BackupExtExtensionMock::InvokeSendRequest)) + .WillOnce(Return(EPERM)); + string fileName = "1.tar"; + ErrCode ret = proxy_->PublishFile(fileName); + EXPECT_EQ(BError(BError::Codes::OK), ret); + + ret = proxy_->PublishFile(fileName); + EXPECT_NE(BError(BError::Codes::OK), ret); + GTEST_LOG_(INFO) << "SvcExtensionProxyTest-end SUB_Ext_Extension_proxy_PublishFile_0100"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_sa/module_ipc/svc_session_manager_test.cpp b/tests/unittests/backup_sa/module_ipc/svc_session_manager_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..afe62a25d7c239539b5902d8520b0be64b2dddea --- /dev/null +++ b/tests/unittests/backup_sa/module_ipc/svc_session_manager_test.cpp @@ -0,0 +1,479 @@ +/* + * 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 +#include +#include + +#include "b_error/b_error.h" +#include "b_json/b_json_entity_ext_manage.h" +#include "ext_extension_mock.h" +#include "file_ex.h" +#include "module_ipc/service.h" +#include "module_ipc/svc_session_manager.h" +#include "service_reverse_mock.h" +#include "test_manager.h" + +namespace OHOS::FileManagement::Backup { +using namespace testing; +using namespace std; + +namespace { +const string BUNDLE_NAME = "com.example.app2backup"; +const string MANAGE_JSON = "manage.json"; +const string FILE_NAME = "1.tar"; +constexpr int32_t SERVICE_ID = 5203; +constexpr int32_t CLIENT_TOKEN_ID = 100; +} // namespace + +class SvcSessionManagerTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp() override {}; + void TearDown() override {}; + void Init(IServiceReverse::Scenario scenario); + + static inline sptr sessionManagerPtr_ = nullptr; + static inline sptr remote_ = nullptr; + static inline sptr servicePtr_ = nullptr; +}; + +void SvcSessionManagerTest::SetUpTestCase(void) +{ + GTEST_LOG_(INFO) << "SetUpTestCase enter"; + remote_ = sptr(new ServiceReverseMock()); + servicePtr_ = sptr(new Service(SERVICE_ID)); + sessionManagerPtr_ = sptr(new SvcSessionManager(wptr(servicePtr_))); +} + +void SvcSessionManagerTest::TearDownTestCase(void) +{ + GTEST_LOG_(INFO) << "TearDownTestCase enter"; + sessionManagerPtr_ = nullptr; + servicePtr_ = nullptr; + remote_ = nullptr; +} + +void SvcSessionManagerTest::Init(IServiceReverse::Scenario scenario) +{ + vector bundleNames; + map backupExtNameMap; + bundleNames.emplace_back(BUNDLE_NAME); + auto setBackupExtNameMap = [](const string &bundleName) { + BackupExtInfo info {}; + info.backupExtName = BUNDLE_NAME; + info.receExtManageJson = false; + info.receExtAppDone = false; + return make_pair(bundleName, info); + }; + transform(bundleNames.begin(), bundleNames.end(), inserter(backupExtNameMap, backupExtNameMap.end()), + setBackupExtNameMap); + sessionManagerPtr_->Active({.clientToken = CLIENT_TOKEN_ID, + .scenario = scenario, + .backupExtNameMap = move(backupExtNameMap), + .clientProxy = remote_}); +} + +/** + * @tc.number: SUB_backup_sa_session_VerifyCallerAndScenario_0100 + * @tc.name: SUB_backup_sa_session_VerifyCallerAndScenario_0100 + * @tc.desc: 测试 VerifyCallerAndScenario 是否是有效的 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_VerifyCallerAndScenario_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcSessionManagerTest-begin SUB_backup_sa_session_VerifyCallerAndScenario_0100"; + try { + Init(IServiceReverse::Scenario::RESTORE); + sessionManagerPtr_->VerifyCallerAndScenario(CLIENT_TOKEN_ID, IServiceReverse::Scenario::RESTORE); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-an exception occurred by VerifyCallerAndScenario."; + } + GTEST_LOG_(INFO) << "SvcSessionManagerTest-end SUB_backup_sa_session_VerifyCallerAndScenario_0100"; +} + +/** + * @tc.number: SUB_backup_sa_session_VerifyBundleName_0100 + * @tc.name: SUB_backup_sa_session_VerifyBundleName_0100 + * @tc.desc: 测试 VerifyBundleName 检验调用者给定的bundleName是否是有效的 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_VerifyBundleName_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcSessionManagerTest-begin SUB_backup_sa_session_VerifyBundleName_0100"; + try { + string bundleName = BUNDLE_NAME; + sessionManagerPtr_->VerifyBundleName(bundleName); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-an exception occurred by VerifyBundleName."; + } + GTEST_LOG_(INFO) << "SvcSessionManagerTest-end SUB_backup_sa_session_VerifyBundleName_0100"; +} + +/** + * @tc.number: SUB_backup_sa_session_GetServiceReverseProxy_0100 + * @tc.name: SUB_backup_sa_session_GetServiceReverseProxy_0100 + * @tc.desc: 测试 GetServiceReverseProxy + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_GetServiceReverseProxy_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcSessionManagerTest-begin SUB_backup_sa_session_GetServiceReverseProxy_0100"; + try { + auto proxy = sessionManagerPtr_->GetServiceReverseProxy(); + EXPECT_NE(proxy, nullptr); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-an exception occurred by GetServiceReverseProxy."; + } + GTEST_LOG_(INFO) << "SvcSessionManagerTest-end SUB_backup_sa_session_GetServiceReverseProxy_0100"; +} + +/** + * @tc.number: SUB_backup_sa_session_getscenario_0100 + * @tc.name: SUB_backup_sa_session_getscenario_0100 + * @tc.desc: 测试 GetScenario 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_getscenario_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcSessionManagerTest-begin SUB_backup_sa_session_getscenario_0100"; + try { + IServiceReverse::Scenario scenario = sessionManagerPtr_->GetScenario(); + EXPECT_EQ(scenario, IServiceReverse::Scenario::RESTORE); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-an exception occurred by getscenario."; + } + GTEST_LOG_(INFO) << "SvcSessionManagerTest-end SUB_backup_sa_session_getscenario_0100"; +} + +/** + * @tc.number: SUB_backup_sa_session_onbunlefileready_0100 + * @tc.name: SUB_backup_sa_session_onbunlefileready_0100 + * @tc.desc: 测试 OnBunleFileReady 接口 restroe流程 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_onbunlefileready_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcSessionManagerTest-begin SUB_backup_sa_session_onbunlefileready_0100"; + try { + bool condition = sessionManagerPtr_->OnBunleFileReady(BUNDLE_NAME); + EXPECT_TRUE(condition); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-an exception occurred by onbunlefileready."; + } + GTEST_LOG_(INFO) << "SvcSessionManagerTest-end SUB_backup_sa_session_onbunlefileready_0100"; +} + +/** + * @tc.number: SUB_backup_sa_session_GetExtFileNameRequest_0100 + * @tc.name: SUB_backup_sa_session_GetExtFileNameRequest_0100 + * @tc.desc: 测试 GetExtFileNameRequest 获取暂存真实文件请求 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_GetExtFileNameRequest_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcSessionManagerTest-begin SUB_backup_sa_session_GetExtFileNameRequest_0100"; + try { + sessionManagerPtr_->SetExtFileNameRequest(BUNDLE_NAME, FILE_NAME); + auto fileNameVec = sessionManagerPtr_->GetExtFileNameRequest(BUNDLE_NAME); + for (auto &fileName : fileNameVec) { + EXPECT_EQ(fileName, FILE_NAME); + } + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-an exception occurred by GetExtFileNameRequest."; + } + GTEST_LOG_(INFO) << "SvcSessionManagerTest-end SUB_backup_sa_session_GetExtFileNameRequest_0100"; +} + +/** + * @tc.number: SUB_backup_sa_session_GetExtConnection_0100 + * @tc.name: SUB_backup_sa_session_GetExtConnection_0100 + * @tc.desc: 测试 GetExtConnection 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_GetExtConnection_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcSessionManagerTest-begin SUB_backup_sa_session_GetExtConnection_0100"; + try { + auto backupCon = sessionManagerPtr_->GetExtConnection(BUNDLE_NAME); + EXPECT_NE(backupCon, nullptr); + sptr mock = sptr(new BackupExtExtensionMock()); + backupCon->OnAbilityConnectDone({}, mock->AsObject(), 0); + backupCon->OnAbilityDisconnectDone({}, 0); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-an exception occurred by GetExtConnection."; + } + GTEST_LOG_(INFO) << "SvcSessionManagerTest-end SUB_backup_sa_session_GetExtConnection_0100"; +} + +/** + * @tc.number: SUB_backup_sa_session_DumpInfo_0100 + * @tc.name: SUB_backup_sa_session_DumpInfo_0100 + * @tc.desc: 测试 DumpInfo 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_DumpInfo_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcSessionManagerTest-begin SUB_backup_sa_session_DumpInfo_0100"; + try { + TestManager tm("SvcSessionManagerTest_GetFd_0100"); + string filePath = tm.GetRootDirCurTest().append(FILE_NAME); + UniqueFd fd(open(filePath.data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + sessionManagerPtr_->DumpInfo(fd, {}); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-an exception occurred by DumpInfo."; + } + GTEST_LOG_(INFO) << "SvcSessionManagerTest-end SUB_backup_sa_session_DumpInfo_0100"; +} + +/** + * @tc.number: SUB_backup_sa_session_GetSchedBundleName_0100 + * @tc.name: SUB_backup_sa_session_GetSchedBundleName_0100 + * @tc.desc: 测试 GetSchedBundleName 调度器获取所需要的调度信息 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_GetSchedBundleName_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcSessionManagerTest-begin SUB_backup_sa_session_GetSchedBundleName_0100"; + try { + string bundleName; + bool condition = sessionManagerPtr_->GetSchedBundleName(bundleName); + EXPECT_EQ(bundleName, BUNDLE_NAME); + EXPECT_TRUE(condition); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-GetSchedBundleName Branches"; + sessionManagerPtr_->SetServiceSchedAction(BUNDLE_NAME, BConstants::ServiceSchedAction::START); + condition = sessionManagerPtr_->GetSchedBundleName(bundleName); + EXPECT_FALSE(condition); + sessionManagerPtr_->SetServiceSchedAction(BUNDLE_NAME, BConstants::ServiceSchedAction::START); + sessionManagerPtr_->SetServiceSchedAction(BUNDLE_NAME, BConstants::ServiceSchedAction::START); + sessionManagerPtr_->SetServiceSchedAction(BUNDLE_NAME, BConstants::ServiceSchedAction::START); + condition = sessionManagerPtr_->GetSchedBundleName(bundleName); + EXPECT_FALSE(condition); + sessionManagerPtr_->SetServiceSchedAction(BUNDLE_NAME, BConstants::ServiceSchedAction::WAIT); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-an exception occurred by GetSchedBundleName."; + } + GTEST_LOG_(INFO) << "SvcSessionManagerTest-end SUB_backup_sa_session_GetSchedBundleName_0100"; +} + +/** + * @tc.number: SUB_backup_sa_session_GetServiceSchedAction_0100 + * @tc.name: SUB_backup_sa_session_GetServiceSchedAction_0100 + * @tc.desc: 测试 GetServiceSchedAction 获取状态 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_GetServiceSchedAction_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcSessionManagerTest-begin SUB_backup_sa_session_GetServiceSchedAction_0100"; + try { + auto action = sessionManagerPtr_->GetServiceSchedAction(BUNDLE_NAME); + EXPECT_EQ(action, BConstants::ServiceSchedAction::WAIT); + + sessionManagerPtr_->SetServiceSchedAction(BUNDLE_NAME, BConstants::ServiceSchedAction::START); + action = sessionManagerPtr_->GetServiceSchedAction(BUNDLE_NAME); + EXPECT_EQ(action, BConstants::ServiceSchedAction::START); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-SetServiceSchedAction Branches"; + sessionManagerPtr_->SetServiceSchedAction(BUNDLE_NAME, BConstants::ServiceSchedAction::FINISH); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-an exception occurred by GetServiceSchedAction."; + } + GTEST_LOG_(INFO) << "SvcSessionManagerTest-end SUB_backup_sa_session_GetServiceSchedAction_0100"; +} + +/** + * @tc.number: SUB_backup_sa_session_GetBackupExtName_0100 + * @tc.name: SUB_backup_sa_session_GetBackupExtName_0100 + * @tc.desc: 测试 GetBackupExtName 接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_GetBackupExtName_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcSessionManagerTest-begin SUB_backup_sa_session_GetBackupExtName_0100"; + try { + string extName = sessionManagerPtr_->GetBackupExtName(BUNDLE_NAME); + EXPECT_EQ(extName, BUNDLE_NAME); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-an exception occurred by GetBackupExtName."; + } + GTEST_LOG_(INFO) << "SvcSessionManagerTest-end SUB_backup_sa_session_GetBackupExtName_0100"; +} + +/** + * @tc.number: SUB_backup_sa_session_removeextinfo_0100 + * @tc.name: SUB_backup_sa_session_removeextinfo_0100 + * @tc.desc: 测试 RemoveExtInfo 移除bundleName是否是有效的 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_removeextinfo_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcSessionManagerTest-begin SUB_backup_sa_session_removeextinfo_0100"; + try { + sessionManagerPtr_->RemoveExtInfo(BUNDLE_NAME); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-RemoveExtInfo Branches"; + sessionManagerPtr_->RemoveExtInfo(BUNDLE_NAME); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-an exception occurred by RemoveExtInfo."; + } + GTEST_LOG_(INFO) << "SvcSessionManagerTest-end SUB_backup_sa_session_removeextinfo_0100"; +} + +/** + * @tc.number: SUB_backup_sa_session_Deactive_0100 + * @tc.name: SUB_backup_sa_session_Deactive_0100 + * @tc.desc: 测试 Deactive + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_Deactive_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcSessionManagerTest-begin SUB_backup_sa_session_Deactive_0100"; + try { + sessionManagerPtr_->Deactive(nullptr, true); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-Deactive Branches One"; + sessionManagerPtr_->Deactive(nullptr, true); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-Deactive Branches Two"; + Init(IServiceReverse::Scenario::BACKUP); + sessionManagerPtr_->Deactive(remote_, false); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-Deactive Branches Three"; + Init(IServiceReverse::Scenario::BACKUP); + sessionManagerPtr_->Deactive(remote_, true); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-an exception occurred by Deactive."; + } + GTEST_LOG_(INFO) << "SvcSessionManagerTest-end SUB_backup_sa_session_Deactive_0100"; +} + +/** + * @tc.number: SUB_backup_sa_session_OnBunleExtManageInfo_0100 + * @tc.name: SUB_backup_sa_session_OnBunleExtManageInfo_0100 + * @tc.desc: 测试 OnBunleExtManageInfo + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_OnBunleExtManageInfo_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcSessionManagerTest-begin SUB_backup_sa_session_OnBunleExtManageInfo_0100"; + try { + Init(IServiceReverse::Scenario::BACKUP); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-OnBunleFileReady Branches"; + auto ret = sessionManagerPtr_->OnBunleFileReady(BUNDLE_NAME, FILE_NAME); + EXPECT_FALSE(ret); + ret = sessionManagerPtr_->OnBunleFileReady(BUNDLE_NAME, FILE_NAME); + EXPECT_FALSE(ret); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-OnBunleFileReady Branches End"; + TestManager tm("SvcSessionManagerTest_GetFd_0100"); + string filePath = tm.GetRootDirCurTest().append(MANAGE_JSON); + SaveStringToFile(filePath, R"({"fileName" : "1.tar"})"); + UniqueFd fd(open(filePath.data(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)); + sessionManagerPtr_->OnBunleExtManageInfo(BUNDLE_NAME, move(fd)); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-OnBunleFileReady Branches"; + ret = sessionManagerPtr_->OnBunleFileReady(BUNDLE_NAME, FILE_NAME); + EXPECT_FALSE(ret); + ret = sessionManagerPtr_->OnBunleFileReady(BUNDLE_NAME); + EXPECT_FALSE(ret); + ret = sessionManagerPtr_->OnBunleFileReady(BUNDLE_NAME, MANAGE_JSON); + EXPECT_FALSE(ret); + ret = sessionManagerPtr_->OnBunleFileReady(BUNDLE_NAME, FILE_NAME); + EXPECT_TRUE(ret); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-OnBunleFileReady Branches End"; + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-an exception occurred by OnBunleExtManageInfo."; + } + GTEST_LOG_(INFO) << "SvcSessionManagerTest-end SUB_backup_sa_session_OnBunleExtManageInfo_0100"; +} + +/** + * @tc.number: SUB_backup_sa_session_OnBunleFileReady_0200 + * @tc.name: SUB_backup_sa_session_OnBunleFileReady_0200 + * @tc.desc: 测试 OnBunleFileReady + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(SvcSessionManagerTest, SUB_backup_sa_session_OnBunleFileReady_0200, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "SvcSessionManagerTest-begin SUB_backup_sa_session_OnBunleFileReady_0200"; + try { + sessionManagerPtr_->Deactive(nullptr, true); + Init(IServiceReverse::Scenario::BACKUP); + auto ret = sessionManagerPtr_->OnBunleFileReady(BUNDLE_NAME, MANAGE_JSON); + EXPECT_FALSE(ret); + ret = sessionManagerPtr_->OnBunleFileReady(BUNDLE_NAME, FILE_NAME); + EXPECT_FALSE(ret); + ret = sessionManagerPtr_->OnBunleFileReady(BUNDLE_NAME, FILE_NAME); + EXPECT_FALSE(ret); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "SvcSessionManagerTest-an exception occurred by OnBunleFileReady."; + } + GTEST_LOG_(INFO) << "SvcSessionManagerTest-end SUB_backup_sa_session_OnBunleFileReady_0200"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_tools/BUILD.gn b/tests/unittests/backup_tools/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..3e079f9f3f9abf9ba1171eaf3672d715d0fbc91f --- /dev/null +++ b/tests/unittests/backup_tools/BUILD.gn @@ -0,0 +1,91 @@ +# 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. + +import("//build/test.gni") +import("//foundation/filemanagement/app_file_service/backup.gni") + +ohos_unittest("backup_tool_test") { + module_out_path = path_module_out_tests + + sources = [ + "${path_backup_mock}/b_filesystem/b_file_mock.cpp", + "${path_backup}/tests/mock/backup_kit_inner/b_session_backup_mock.cpp", + "${path_backup}/tools/backup_tool/src/tools_op.cpp", + "${path_backup}/tools/backup_tool/src/tools_op_backup.cpp", + "${path_backup}/tools/backup_tool/src/tools_op_check_sa.cpp", + "backup_tool/tools_op_backup_test.cpp", + "backup_tool/tools_op_check_sa_test.cpp", + "backup_tool/tools_op_test.cpp", + ] + sources += backup_mock_proxy_src + + include_dirs = [ + "${path_base}/include", + "${path_backup}/interfaces/inner_api/native/backup_kit_inner/impl", + "${path_backup}/interfaces/inner_api/native/backup_kit_inner", + "${path_backup}/tools/backup_tool/include", + ] + include_dirs += backup_mock_utils_include + + deps = [ + "${path_backup}/tests/utils:backup_test_utils", + "${path_backup}/utils:backup_utils", + "${path_base}:utils", + "${path_ipc}/interfaces/innerkits/ipc_core:ipc_core", + "${path_samgr}/interfaces/innerkits/samgr_proxy:samgr_proxy", + ] + + external_deps = [ "hitrace_native:hitrace_meter" ] + use_exceptions = true +} + +ohos_unittest("backup_tool_restore_test") { + module_out_path = path_module_out_tests + + sources = [ + "${path_backup_mock}/b_filesystem/b_file_mock.cpp", + "${path_backup}/tests/mock/backup_kit_inner/b_session_restore_mock.cpp", + "${path_backup}/tools/backup_tool/src/tools_op.cpp", + "${path_backup}/tools/backup_tool/src/tools_op_restore.cpp", + "backup_tool/tools_op_restore_test.cpp", + ] + sources += backup_mock_proxy_src + + include_dirs = [ + "${path_base}/include", + "${path_backup}/interfaces/inner_api/native/backup_kit_inner/impl", + "${path_backup}/interfaces/inner_api/native/backup_kit_inner", + "${path_backup}/tools/backup_tool/include", + ] + include_dirs += backup_mock_utils_include + + deps = [ + "${path_backup}/tests/utils:backup_test_utils", + "${path_backup}/utils:backup_utils", + "${path_base}:utils", + "${path_ipc}/interfaces/innerkits/ipc_core:ipc_core", + "${path_samgr}/interfaces/innerkits/samgr_proxy:samgr_proxy", + ] + + external_deps = [ "hitrace_native:hitrace_meter" ] + use_exceptions = true +} + +group("backup_test") { + testonly = true + + deps = [ + ":backup_tool_restore_test", + ":backup_tool_test", + ] +} diff --git a/tests/unittests/backup_tools/backup_tool/tools_op_backup_test.cpp b/tests/unittests/backup_tools/backup_tool/tools_op_backup_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fdee2367966ed4e71c21cbc06abf3e6e006e5d03 --- /dev/null +++ b/tests/unittests/backup_tools/backup_tool/tools_op_backup_test.cpp @@ -0,0 +1,189 @@ +/* + * 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 +#include +#include + +#include + +#include "tools_op.h" +#include "utils_mock_global_variable.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +class ToolsOpBackupTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() {}; + void TearDown() {}; +}; + +/** + * @tc.number: SUB_backup_tools_op_backup_0100 + * @tc.name: SUB_backup_tools_op_backup_0100 + * @tc.desc: 测试backup流程 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0382 + */ +HWTEST_F(ToolsOpBackupTest, SUB_backup_tools_op_backup_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ToolsOpBackupTest-begin SUB_backup_tools_op_backup_0100"; + try { + SetMockGetInstance(true); + GTEST_LOG_(INFO) << "ToolsOpBackupTest-info"; + map> mapArgToVal; + vector path = {"/data/backup/tmp"}; + mapArgToVal.insert(make_pair("pathCapFile", path)); + vector bundles = {"com.example.app2backup"}; + mapArgToVal.insert(make_pair("bundles", bundles)); + vector local = {"true"}; + mapArgToVal.insert(make_pair("isLocal", local)); + + // 创建测试路径 + string strPath = "/data/backup"; + mkdir(strPath.data(), S_IRWXU); + + // 尝试匹配当前命令,成功后执行 + GTEST_LOG_(INFO) << "ToolsOpBackupTest-backup"; + vector curOp; + curOp.emplace_back("backup"); + auto tryOpSucceed = [&curOp](const ToolsOp &op) { return op.TryMatch(curOp); }; + auto &&opeartions = ToolsOp::GetAllOperations(); + auto matchedOp = find_if(opeartions.begin(), opeartions.end(), tryOpSucceed); + if (matchedOp != opeartions.end()) { + auto ret = matchedOp->Execute(mapArgToVal); + EXPECT_EQ(ret, 0); + } + + GTEST_LOG_(INFO) << "GetInstance is false"; + SetMockGetInstance(false); + if (matchedOp != opeartions.end()) { + auto ret = matchedOp->Execute(mapArgToVal); + EXPECT_NE(ret, 0); + } + SetMockGetInstance(true); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ToolsOpBackupTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "ToolsOpBackupTest-end SUB_backup_tools_op_backup_0100"; +} + +/** + * @tc.number: SUB_backup_tools_op_backup_0200 + * @tc.name: SUB_backup_tools_op_backup_0200 + * @tc.desc: 测试Exec分支 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0382 + */ +HWTEST_F(ToolsOpBackupTest, SUB_backup_tools_op_backup_0200, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ToolsOpBackupTest-begin SUB_backup_tools_op_backup_0200"; + try { + GTEST_LOG_(INFO) << "ToolsOpBackupTest-The pathCapFile field is not contained."; + map> mapArgToVal; + vector bundles = {"com.example.app2backup"}; + vector path = {"/data/backup/tmp"}; + vector local = {"true"}; + mapArgToVal.insert(make_pair("bundles", bundles)); + mapArgToVal.insert(make_pair("isLocal", local)); + + vector curOp; + curOp.emplace_back("backup"); + auto tryOpSucceed = [&curOp](const ToolsOp &op) { return op.TryMatch(curOp); }; + auto &&opeartions = ToolsOp::GetAllOperations(); + auto matchedOp = find_if(opeartions.begin(), opeartions.end(), tryOpSucceed); + int ret = 0; + if (matchedOp != opeartions.end()) { + ret = matchedOp->Execute(mapArgToVal); + EXPECT_NE(ret, 0); + } + + GTEST_LOG_(INFO) << "ToolsOpBackupTest-The bundles field is noGt contained."; + mapArgToVal.clear(); + mapArgToVal.insert(make_pair("pathCapFile", path)); + mapArgToVal.insert(make_pair("isLocal", local)); + if (matchedOp != opeartions.end()) { + ret = matchedOp->Execute(mapArgToVal); + EXPECT_NE(ret, 0); + } + + GTEST_LOG_(INFO) << "ToolsOpBackupTest-The isLocal field is noGt contained."; + mapArgToVal.clear(); + mapArgToVal.insert(make_pair("pathCapFile", path)); + mapArgToVal.insert(make_pair("bundles", bundles)); + if (matchedOp != opeartions.end()) { + ret = matchedOp->Execute(mapArgToVal); + EXPECT_NE(ret, 0); + } + + mapArgToVal.clear(); + if (matchedOp != opeartions.end()) { + ret = matchedOp->Execute(mapArgToVal); + EXPECT_NE(ret, 0); + } + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ToolsOpBackupTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "ToolsOpBackupTest-end SUB_backup_tools_op_backup_0200"; +} + +/** + * @tc.number: SUB_backup_tools_op_backup_0300 + * @tc.name: SUB_backup_tools_op_backup_0300 + * @tc.desc: 测试Exec分支 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0382 + */ +HWTEST_F(ToolsOpBackupTest, SUB_backup_tools_op_backup_0300, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ToolsOpBackupTest-begin SUB_backup_tools_op_backup_0300"; + try { + GTEST_LOG_(INFO) << "ToolsOpBackupTest-info"; + map> mapArgToVal; + vector path = {"/data/backup/tmp"}; + mapArgToVal.insert(make_pair("pathCapFile", path)); + vector bundles = {"com.example.app2backup"}; + mapArgToVal.insert(make_pair("bundles", bundles)); + vector local = {"false"}; + mapArgToVal.insert(make_pair("isLocal", local)); + + // 尝试匹配当前命令,成功后执行 + GTEST_LOG_(INFO) << "ToolsOpBackupTest-backup"; + vector curOp; + curOp.emplace_back("backup"); + auto tryOpSucceed = [&curOp](const ToolsOp &op) { return op.TryMatch(curOp); }; + auto &&opeartions = ToolsOp::GetAllOperations(); + auto matchedOp = find_if(opeartions.begin(), opeartions.end(), tryOpSucceed); + if (matchedOp != opeartions.end()) { + auto ret = matchedOp->Execute(mapArgToVal); + EXPECT_EQ(ret, 0); + } + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ToolsOpBackupTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "ToolsOpBackupTest-end SUB_backup_tools_op_backup_0300"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_tools/backup_tool/tools_op_check_sa_test.cpp b/tests/unittests/backup_tools/backup_tool/tools_op_check_sa_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2f761b839faa763091c813c7bc4faac6525e7731 --- /dev/null +++ b/tests/unittests/backup_tools/backup_tool/tools_op_check_sa_test.cpp @@ -0,0 +1,72 @@ +/* + * 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 +#include +#include +#include + +#include "tools_op.h" +#include "utils_mock_global_variable.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +class ToolsOpCheckSaTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() {}; + void TearDown() {}; +}; + +/** + * @tc.number: SUB_backup_tools_op_check_sa_0100 + * @tc.name: SUB_backup_tools_op_check_sa_0100 + * @tc.desc: 测试 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0382 + */ +HWTEST_F(ToolsOpCheckSaTest, SUB_backup_tools_op_check_sa_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ToolsOpCheckSaTest-begin SUB_backup_tools_op_check_sa_0100"; + try { + GTEST_LOG_(INFO) << "ToolsOpCheckSaTest-info"; + map> mapArgToVal; + vector curOp; + curOp.emplace_back("check"); + curOp.emplace_back("sa"); + auto tryOpSucceed = [&curOp](const ToolsOp &op) { return op.TryMatch(curOp); }; + auto &&opeartions = ToolsOp::GetAllOperations(); + auto matchedOp = find_if(opeartions.begin(), opeartions.end(), tryOpSucceed); + int ret = 0; + if (matchedOp != opeartions.end()) { + ret = matchedOp->Execute(mapArgToVal); + EXPECT_EQ(ret, 0); + } + GTEST_LOG_(INFO) << "GetInstance is false"; + SetMockGetInstance(false); + if (matchedOp != opeartions.end()) { + ret = matchedOp->Execute(mapArgToVal); + EXPECT_NE(ret, 0); + } + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ToolsOpCheckSaTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "ToolsOpCheckSaTest-end SUB_backup_tools_op_check_sa_0100"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_tools/backup_tool/tools_op_restore_test.cpp b/tests/unittests/backup_tools/backup_tool/tools_op_restore_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..26e4b08308db9ee7b1a2680b46136eec13874cec --- /dev/null +++ b/tests/unittests/backup_tools/backup_tool/tools_op_restore_test.cpp @@ -0,0 +1,146 @@ +/* + * 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 +#include +#include + +#include + +#include "b_resources/b_constants.h" +#include "tools_op.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +namespace { +const string BUNDLE_NAME = "com.example.app2backup/"; +const string MANAGE_JSON = "manage.json"; +const string FILE_NAME = "1.tar"; +} // namespace + +class ToolsOpRestoreTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() {}; + void TearDown() {}; +}; + +/** + * @tc.number: SUB_backup_tools_op_restore_0100 + * @tc.name: SUB_backup_tools_op_restore_0100 + * @tc.desc: 测试 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0382 + */ +HWTEST_F(ToolsOpRestoreTest, SUB_backup_tools_op_restore_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ToolsOpRestoreTest-begin SUB_backup_tools_op_restore_0100"; + try { + GTEST_LOG_(INFO) << "ToolsOpRestoreTest-info"; + map> mapArgToVal; + vector path = {"/data/backup/tmp"}; + mapArgToVal.insert(make_pair("pathCapFile", path)); + vector bundles = {"com.example.app2backup"}; + mapArgToVal.insert(make_pair("bundles", bundles)); + + // 创建测试路径以及测试环境 + string cmdMkdir = string("mkdir -p ") + BConstants::BACKUP_TOOL_RECEIVE_DIR.data() + BUNDLE_NAME; + system(cmdMkdir.c_str()); + string touchTar = string("touch ") + BConstants::BACKUP_TOOL_RECEIVE_DIR.data() + BUNDLE_NAME + FILE_NAME; + system(touchTar.c_str()); + string touchManage = string("touch ") + BConstants::BACKUP_TOOL_RECEIVE_DIR.data() + BUNDLE_NAME + MANAGE_JSON; + system(touchManage.c_str()); + + // 尝试匹配当前命令,成功后执行 + GTEST_LOG_(INFO) << "ToolsOpRestoreTest-restore"; + vector curOp; + curOp.emplace_back("restore"); + auto tryOpSucceed = [&curOp](const ToolsOp &op) { return op.TryMatch(curOp); }; + auto &&opeartions = ToolsOp::GetAllOperations(); + auto matchedOp = find_if(opeartions.begin(), opeartions.end(), tryOpSucceed); + if (matchedOp != opeartions.end()) { + auto ret = matchedOp->Execute(mapArgToVal); + EXPECT_EQ(ret, 0); + } + + GTEST_LOG_(INFO) << "GetLocalCapabilities is false"; + mapArgToVal.clear(); + mapArgToVal.insert(make_pair("pathCapFile", path)); + vector bundleVec = {"test"}; + mapArgToVal.insert(make_pair("bundles", bundleVec)); + if (matchedOp != opeartions.end()) { + auto ret = matchedOp->Execute(mapArgToVal); + EXPECT_NE(ret, 0); + } + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ToolsOpRestoreTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "ToolsOpRestoreTest-end SUB_backup_tools_op_restore_0100"; +} + +/** + * @tc.number: SUB_backup_tools_op_restore_0200 + * @tc.name: SUB_backup_tools_op_restore_0200 + * @tc.desc: 测试 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0382 + */ +HWTEST_F(ToolsOpRestoreTest, SUB_backup_tools_op_restore_0200, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ToolsOpRestoreTest-begin SUB_backup_tools_op_restore_0200"; + try { + GTEST_LOG_(INFO) << "ToolsOpRestoreTest-The pathCapFile field is not contained."; + map> mapArgToVal; + vector bundles = {"com.example.app2backup"}; + vector path = {"/data/backup/tmp"}; + mapArgToVal.insert(make_pair("bundles", bundles)); + + vector curOp; + curOp.emplace_back("restore"); + auto tryOpSucceed = [&curOp](const ToolsOp &op) { return op.TryMatch(curOp); }; + auto &&opeartions = ToolsOp::GetAllOperations(); + auto matchedOp = find_if(opeartions.begin(), opeartions.end(), tryOpSucceed); + int ret = 0; + if (matchedOp != opeartions.end()) { + ret = matchedOp->Execute(mapArgToVal); + EXPECT_NE(ret, 0); + } + GTEST_LOG_(INFO) << "ToolsOpRestoreTest-The bundles field is not contained."; + mapArgToVal.clear(); + mapArgToVal.insert(make_pair("pathCapFile", path)); + if (matchedOp != opeartions.end()) { + ret = matchedOp->Execute(mapArgToVal); + EXPECT_NE(ret, 0); + } + + mapArgToVal.clear(); + if (matchedOp != opeartions.end()) { + ret = matchedOp->Execute(mapArgToVal); + EXPECT_NE(ret, 0); + } + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ToolsOpRestoreTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "ToolsOpRestoreTest-end SUB_backup_tools_op_restore_0200"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_tools/backup_tool/tools_op_test.cpp b/tests/unittests/backup_tools/backup_tool/tools_op_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fadbb53f8c8348d60a17b44b6bab0f95475ff267 --- /dev/null +++ b/tests/unittests/backup_tools/backup_tool/tools_op_test.cpp @@ -0,0 +1,96 @@ +/* + * 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 +#include +#include + +#include + +#include "tools_op.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +class ToolsOpTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() {}; + void TearDown() {}; +}; + +/** + * @tc.number: SUB_backup_tools_op_0100 + * @tc.name: SUB_backup_tools_op_0100 + * @tc.desc: 测试Execute分支 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0382 + */ +HWTEST_F(ToolsOpTest, SUB_backup_tools_op_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ToolsOpTest-begin SUB_backup_tools_op_0100"; + try { + GTEST_LOG_(INFO) << "ToolsOpTest-info"; + bool autoTest = ToolsOp::Register(ToolsOp {ToolsOp::Descriptor { + .opName = {"test"}, + .funcGenHelpMsg = nullptr, + .funcExec = nullptr, + }}); + EXPECT_TRUE(autoTest); + map> mapArgToVal; + vector curOp; + curOp.emplace_back("test"); + auto tryOpSucceed = [&curOp](const ToolsOp &op) { return op.TryMatch(curOp); }; + auto &&opeartions = ToolsOp::GetAllOperations(); + auto matchedOp = find_if(opeartions.begin(), opeartions.end(), tryOpSucceed); + if (matchedOp != opeartions.end()) { + matchedOp->Execute(mapArgToVal); + } + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ToolsOpTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "ToolsOpTest-end SUB_backup_tools_op_0100"; +} + +/** + * @tc.number: SUB_backup_tools_op_0200 + * @tc.name: SUB_backup_tools_op_0200 + * @tc.desc: 测试Register分支 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0382 + */ +HWTEST_F(ToolsOpTest, SUB_backup_tools_op_0200, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "ToolsOpTest-begin SUB_backup_tools_op_0200"; + try { + GTEST_LOG_(INFO) << "ToolsOpTest-info"; + bool autoTest = ToolsOp::Register(ToolsOp {ToolsOp::Descriptor { + .opName = {"???"}, + .funcGenHelpMsg = nullptr, + .funcExec = nullptr, + }}); + EXPECT_FALSE(autoTest); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "ToolsOpTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "ToolsOpTest-end SUB_backup_tools_op_0200"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_utils/BUILD.gn b/tests/unittests/backup_utils/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..c179e2a157364bfbf8cf63374a2b97b742bcb9dc --- /dev/null +++ b/tests/unittests/backup_utils/BUILD.gn @@ -0,0 +1,163 @@ +# 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. + +import("//build/test.gni") +import("//foundation/filemanagement/app_file_service/backup.gni") + +ohos_unittest("b_error_test") { + module_out_path = path_module_out_tests + + sources = [ "b_error/b_error_test.cpp" ] + + deps = [ + "${path_backup}/tests/utils:backup_test_utils", + "${path_backup}/utils/:backup_utils", + ] + + use_exceptions = true +} + +ohos_unittest("b_file_test") { + module_out_path = path_module_out_tests + + sources = [ + "b_filesystem/b_dir_test.cpp", + "b_filesystem/b_file_test.cpp", + ] + + deps = [ + "${path_backup}/tests/utils:backup_test_utils", + "${path_backup}/utils/:backup_utils", + ] + + use_exceptions = true +} + +ohos_unittest("b_json_test") { + module_out_path = path_module_out_tests + + sources = [ + "${path_backup}/utils/src/b_json/b_json_entity_extension_config.cpp", + "b_json/b_json_cached_entity_test.cpp", + "b_json/b_json_entity_ext_manage_test.cpp", + "b_json/b_json_entity_extension_config_test.cpp", + ] + sources += backup_mock_parameter_src + + include_dirs = [ "${path_base}/include" ] + include_dirs += backup_mock_parameter_include_dirs + + deps = [ + "${path_backup}/tests/utils:backup_test_utils", + "${path_backup}/utils/:backup_utils", + "${path_googletest}:gmock_main", + ] + + use_exceptions = true +} + +ohos_unittest("b_tarball_test") { + module_out_path = path_module_out_tests + + sources = [ "b_tarball/b_tarball_posix_tarball_test.cpp" ] + + include_dirs = [ + "${path_base}/include", + "${path_backup}/utils/include/b_error", + "${path_backup}/utils/include/b_process", + "${path_backup}/utils/include/b_tarball", + ] + + deps = [ + "${path_backup}/tests/utils:backup_test_utils", + "${path_backup}/utils/:backup_utils", + "${path_base}:utils", + ] + + use_exceptions = true +} + +ohos_unittest("b_tarball_cmdline_test") { + module_out_path = path_module_out_tests + + sources = [ + "${path_backup_mock}/b_process/b_process_mock.cpp", + "b_tarball/b_tarball_cmdline_test.cpp", + ] + + include_dirs = [ + "${path_base}/include", + "${path_backup}/utils/include", + ] + + deps = [ + "${path_backup}/tests/utils:backup_test_utils", + "${path_base}:utils", + ] + + use_exceptions = true +} + +ohos_unittest("b_tarball_factory_test") { + module_out_path = path_module_out_tests + + sources = [ + "${path_backup_mock}/b_tarball/b_tarball_cmdline_mock.cpp", + "b_tarball/b_tarball_factory_test.cpp", + ] + + include_dirs = [ + "${path_base}/include", + "${path_backup}/utils/include", + ] + + deps = [ + "${path_backup}/tests/utils:backup_test_utils", + "${path_base}:utils", + ] + + use_exceptions = true +} + +ohos_unittest("b_process_test") { + module_out_path = path_module_out_tests + + sources = [ "b_process/b_process_test.cpp" ] + + include_dirs = [ + "${path_base}/include", + "${path_backup}/utils/include", + ] + + deps = [ + "${path_backup}/tests/utils:backup_test_utils", + "${path_backup}/utils/:backup_utils", + "${path_base}:utils", + ] + + use_exceptions = true +} + +group("backup_test") { + testonly = true + + deps = [ + ":b_error_test", + ":b_file_test", + ":b_json_test", + ":b_process_test", + ":b_tarball_cmdline_test", + ":b_tarball_factory_test", + ":b_tarball_test", + ] +} diff --git a/tests/unittests/backup_utils/b_error/b_error_test.cpp b/tests/unittests/backup_utils/b_error/b_error_test.cpp new file mode 100755 index 0000000000000000000000000000000000000000..b4be768151906413b144af0a29504fd1b1186954 --- /dev/null +++ b/tests/unittests/backup_utils/b_error/b_error_test.cpp @@ -0,0 +1,182 @@ +/* + * 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 +#include + +#include "b_error/b_error.h" + +namespace OHOS::FileManagement::Backup { +class BErrorTest : public testing::Test { +public: + static void SetUpTestCase(void){}; + static void TearDownTestCase() {}; + void SetUp() {}; + void TearDown() {}; +}; + +/** + * @tc.number: SUB_backup_b_error_construction_0100 + * @tc.name: b_error_construction_0100 + * @tc.desc: Test function of construction interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(BErrorTest, b_error_construction_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BErrorTest-begin b_error_construction_0100"; + try { + BError be(BError::Codes::OK); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BErrorTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "BErrorTest-end b_error_construction_0100"; +} + +/** + * @tc.number: SUB_backup_b_error_construction_0300 + * @tc.name: b_error_construction_0300 + * @tc.desc: Test function of construction interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(BErrorTest, b_error_construction_0300, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BErrorTest-begin b_error_construction_0300"; + try { + std::string_view extraMsg; + BError be(BError::Codes::OK, extraMsg); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BErrorTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "BErrorTest-end b_error_construction_0300"; +} + +/** + * @tc.number: SUB_backup_b_error_construction_0500 + * @tc.name: b_error_construction_0500 + * @tc.desc: Test function of construction interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(BErrorTest, b_error_construction_0500, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BErrorTest-begin b_error_construction_0500"; + try { + throw BError(BError::Codes::UTILS_INVAL_JSON_ENTITY); + EXPECT_TRUE(false); + } catch (const BError &e) {} catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BErrorTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "BErrorTest-end b_error_construction_0500"; +} + +/** + * @tc.number: SUB_backup_b_error_GetCode_0100 + * @tc.name: b_error_GetCode_0100 + * @tc.desc: Test function of GetCode interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(BErrorTest, b_error_GetCode_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BErrorTest-begin b_error_GetCode_0100"; + BError be(BError::Codes::OK); + int result = be.GetCode(); + EXPECT_EQ(result, 0); + GTEST_LOG_(INFO) << "BErrorTest-end b_error_GetCode_0100"; +} + +/** + * @tc.number: SUB_backup_b_error_GetRawCode_0100 + * @tc.name: b_error_GetRawCode_0100 + * @tc.desc: Test function of GetRawCode interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(BErrorTest, b_error_GetRawCode_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BErrorTest-begin b_error_GetRawCode_0100"; + BError be(BError::Codes::OK); + BError::Codes result = be.GetRawCode(); + EXPECT_EQ(result, BError::Codes::OK); + GTEST_LOG_(INFO) << "BErrorTest-end b_error_GetRawCode_0100"; +} + +/** + * @tc.number: SUB_backup_b_error_what_0100 + * @tc.name: b_error_what_0100 + * @tc.desc: Test function of what interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(BErrorTest, b_error_what_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BErrorTest-begin b_error_what_0100"; + BError be(BError::Codes::OK); + auto result = be.what(); + EXPECT_NE(result, nullptr); + GTEST_LOG_(INFO) << "BErrorTest-end b_error_what_0100"; +} + +/** + * @tc.number: SUB_backup_b_error_bool_0100 + * @tc.name: b_error_bool_0100 + * @tc.desc: Test function of bool interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(BErrorTest, b_error_bool_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BErrorTest-begin b_error_bool_0100"; + bool result = BError(); + EXPECT_FALSE(result); + GTEST_LOG_(INFO) << "BErrorTest-end b_error_bool_0100"; +} + +/** + * @tc.number: SUB_backup_b_error_int_0100 + * @tc.name: b_error_int_0100 + * @tc.desc: Test function of int interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(BErrorTest, b_error_int_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BErrorTest-begin b_error_int_0100"; + int result = BError(); + EXPECT_EQ(result, 0); + GTEST_LOG_(INFO) << "BErrorTest-end b_error_int_0100"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_utils/b_filesystem/b_dir_test.cpp b/tests/unittests/backup_utils/b_filesystem/b_dir_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d35065bde0cf5167a46359510a2ed217c7e31ce5 --- /dev/null +++ b/tests/unittests/backup_utils/b_filesystem/b_dir_test.cpp @@ -0,0 +1,182 @@ +/* + * 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 +#include + +#include +#include + +#include +#include +#include + +#include "b_filesystem/b_dir.h" +#include "b_process/b_process.h" +#include "test_manager.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +class BDirTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() {}; + void TearDown() {}; +}; + +/** + * @tc.number: SUB_backup_b_dir_GetDirFiles_0100 + * @tc.name: b_dir_GetDirFiles_0100 + * @tc.desc: Test function of GetDirFiles interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(BDirTest, b_dir_GetDirFiles_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BDirTest-begin b_dir_GetDirFiles_0100"; + try { + TestManager tm("b_dir_GetDirFiles_0100"); + + string preparedDir = tm.GetRootDirCurTest(); + string touchFilePrefix = string("touch ") + preparedDir; + system(touchFilePrefix.append("a.txt").c_str()); + system(touchFilePrefix.append("b.txt").c_str()); + system(touchFilePrefix.append("c.txt").c_str()); + + bool bSucc; + vector out; + tie(bSucc, out) = BDir::GetDirFiles(preparedDir); + + vector expectedRes = {preparedDir.append("a.txt"), preparedDir.append("b.txt"), + preparedDir.append("c.txt")}; + EXPECT_EQ(out, expectedRes); + + tie(bSucc, out) = BDir::GetDirFiles("dev"); + EXPECT_EQ(bSucc, true); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BDirTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "BDirTest-end b_dir_GetDirFiles_0100"; +} + +/** + * @tc.number: SUB_backup_b_dir_GetBigFiles_0100 + * @tc.name: b_dir_GetBigFiles_0100 + * @tc.desc: 测试GetBigFiles接口是否能成功获取大文件 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(BDirTest, b_dir_GetBigFiles_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BDirTest-begin b_dir_GetBigFiles_0100"; + try { + TestManager tm("b_dir_GetBigFiles_0100"); + string rootDir = tm.GetRootDirCurTest(); + string filePath1 = rootDir + "a.txt"; + string filePath2 = rootDir + "b.txt"; + // 文件大小大于等于1GB(1024MB)的文件属于大文件,因此这里创建大小为1025MB和1026MB的大文件 + auto [bFatalErr, ret] = + BProcess::ExecuteCmd({"dd", "if=/dev/urandom", ("of=" + filePath1).c_str(), "bs=1M", "count=1025"}); + EXPECT_FALSE(bFatalErr); + EXPECT_EQ(ret, 0); + tie(bFatalErr, ret) = + BProcess::ExecuteCmd({"dd", "if=/dev/urandom", ("of=" + filePath2).c_str(), "bs=1M", "count=1026"}); + EXPECT_FALSE(bFatalErr); + EXPECT_EQ(ret, 0); + vector includes = {rootDir}; + vector excludes = {filePath2}; + auto [errCode, mpNameToStat] = BDir::GetBigFiles(includes, excludes); + EXPECT_EQ(errCode, ERR_OK); + EXPECT_EQ(mpNameToStat.at(filePath1).st_size, 1024 * 1024 * 1025); + EXPECT_EQ(mpNameToStat.find(filePath2), mpNameToStat.end()); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BDirTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "BDirTest-end b_dir_GetBigFiles_0100"; +} + +/** + * @tc.number: SUB_backup_b_dir_GetBigFiles_0200 + * @tc.name: b_dir_GetBigFiles_0200 + * @tc.desc: 测试GetBigFiles接口 分支逻辑 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(BDirTest, b_dir_GetBigFiles_0200, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BDirTest-begin b_dir_GetBigFiles_0200"; + try { + vector includes = {{}, {}}; + vector excludes = {{}}; + auto [errCode, mpNameToStat] = BDir::GetBigFiles(includes, excludes); + EXPECT_EQ(errCode, ERR_OK); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BDirTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "BDirTest-end b_dir_GetBigFiles_0200"; +} + +/** + * @tc.number: SUB_backup_b_dir_GetBigFiles_0300 + * @tc.name: b_dir_GetBigFiles_0300 + * @tc.desc: 测试GetBigFiles接口 分支逻辑 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(BDirTest, b_dir_GetBigFiles_0300, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BDirTest-begin b_dir_GetBigFiles_0300"; + try { + TestManager tm("b_dir_GetBigFiles_0300"); + string preparedDir = tm.GetRootDirCurTest(); + string cmdMkdir = string("mkdir -p ") + preparedDir + string("test/test1/test2"); + system(cmdMkdir.c_str()); + string touchFilePrefix = string("touch ") + preparedDir; + system(touchFilePrefix.append("a.txt").c_str()); + system(touchFilePrefix.append("b.txt").c_str()); + system(touchFilePrefix.append("c.txt").c_str()); + + touchFilePrefix = string("touch ") + preparedDir + string("test/"); + system(touchFilePrefix.append("a.txt").c_str()); + system(touchFilePrefix.append("b.txt").c_str()); + system(touchFilePrefix.append("c.txt").c_str()); + touchFilePrefix = string("touch ") + preparedDir + string("test/test1/test2"); + system(touchFilePrefix.append("a.txt").c_str()); + system(touchFilePrefix.append("b.txt").c_str()); + system(touchFilePrefix.append("c.txt").c_str()); + vector includes = {preparedDir + string("/*"), preparedDir + string("test")}; + vector excludes = {preparedDir + string("/test/test1/test2"), {}}; + auto [errCode, mpNameToStat] = BDir::GetBigFiles(includes, excludes); + EXPECT_EQ(errCode, ERR_OK); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BDirTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "BDirTest-end b_dir_GetBigFiles_0300"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_utils/b_filesystem/b_file_test.cpp b/tests/unittests/backup_utils/b_filesystem/b_file_test.cpp new file mode 100755 index 0000000000000000000000000000000000000000..604fc4e848afac5ac52f63c39cbab81363f8198a --- /dev/null +++ b/tests/unittests/backup_utils/b_filesystem/b_file_test.cpp @@ -0,0 +1,134 @@ +/* + * 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 +#include + +#include + +#include +#include + +#include "b_filesystem/b_file.h" +#include "test_manager.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +class BFileTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() {}; + void TearDown() {}; +}; + +/** + * @brief 创建测试文件 + * + * @return tuple 创建结果、文件路径、文件内容 + */ +static tuple GetTestFile(const TestManager &tm) +{ + string path = tm.GetRootDirCurTest(); + string filePath = path + "temp.txt"; + string content = "backup test"; + if (bool contentCreate = SaveStringToFile(filePath, content, true); !contentCreate) { + throw system_error(errno, system_category()); + } + return {filePath, content}; +} + +/** + * @tc.number: SUB_backup_b_file_ReadFile_0100 + * @tc.name: b_file_ReadFile_0100 + * @tc.desc: Test function of ReadFile interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(BFileTest, b_file_ReadFile_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BFileTest-begin b_file_ReadFile_0100"; + try { + TestManager tm(__func__); + const auto [filePath, content] = GetTestFile(tm); + BFile bf; + unique_ptr result = bf.ReadFile(UniqueFd(open(filePath.data(), O_RDWR))); + string readContent(result.get()); + EXPECT_EQ(readContent.compare(content), 0); + } catch (const exception &e) { + GTEST_LOG_(INFO) << "BFileTest-an exception occurred by ReadFile."; + e.what(); + } + GTEST_LOG_(INFO) << "BFileTest-end b_file_ReadFile_0100"; +} + +/** + * @tc.number: SUB_backup_b_file_SendFile_0100 + * @tc.name: b_file_SendFile_0100 + * @tc.desc: 测试SendFile接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(BFileTest, b_file_SendFile_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BFileTest-begin b_file_SendFile_0100"; + try { + TestManager tm(__func__); + const auto [filePath, content] = GetTestFile(tm); + TestManager tmInFile("b_file_GetFd_0100"); + string fileInPath = tmInFile.GetRootDirCurTest().append("1.tar"); + BFile::SendFile(UniqueFd(open(filePath.data(), O_RDWR)), + UniqueFd(open(fileInPath.data(), O_RDWR | O_CREAT, S_IRWXU))); + } catch (const exception &e) { + GTEST_LOG_(INFO) << "BFileTest-an exception occurred by SendFile."; + e.what(); + } + GTEST_LOG_(INFO) << "BFileTest-end b_file_SendFile_0100"; +} + +/** + * @tc.number: SUB_backup_b_file_CopyFile_0100 + * @tc.name: b_file_CopyFile_0100 + * @tc.desc: 测试CopyFile接口 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H037V + */ +HWTEST_F(BFileTest, b_file_CopyFile_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BFileTest-begin b_file_CopyFile_0100"; + try { + TestManager tm(__func__); + const auto [filePath, content] = GetTestFile(tm); + TestManager tmInFile("b_file_GetFd_0200"); + string fileInPath = tmInFile.GetRootDirCurTest().append("1.txt"); + auto ret = BFile::CopyFile(filePath, fileInPath); + EXPECT_TRUE(ret); + GTEST_LOG_(INFO) << "BFileTest-CopyFile Branches"; + ret = BFile::CopyFile(filePath, filePath); + EXPECT_TRUE(ret); + } catch (const exception &e) { + GTEST_LOG_(INFO) << "BFileTest-an exception occurred by CopyFile."; + e.what(); + } + GTEST_LOG_(INFO) << "BFileTest-end b_file_CopyFile_0100"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_utils/b_json/b_json_cached_entity_test.cpp b/tests/unittests/backup_utils/b_json/b_json_cached_entity_test.cpp new file mode 100755 index 0000000000000000000000000000000000000000..9b69006975f4b93e7575697a792f1c8bec4a33b4 --- /dev/null +++ b/tests/unittests/backup_utils/b_json/b_json_cached_entity_test.cpp @@ -0,0 +1,144 @@ +/* + * 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 +#include +#include +#include +#include + +#include "test_manager.h" +#include "b_json/b_json_cached_entity.h" +#include "b_json/b_json_entity_caps.h" +#include "directory_ex.h" +#include "file_ex.h" + +namespace OHOS::FileManagement::Backup { +class BJsonCachedEntityTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() {}; + void TearDown() {}; +}; + +/** + * @tc.number: SUB_backup_b_json_construction_0100 + * @tc.name: b_json_construction_0100 + * @tc.desc: Test function of construction interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonCachedEntityTest, b_json_construction_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BJsonCachedEntityTest-begin b_json_construction_0100"; + try { + TestManager tm("b_json_construction_0100"); + + std::string path = tm.GetRootDirCurTest(); + std::string filePath = path + ".json"; + BJsonCachedEntity jce(UniqueFd(open(filePath.data(), O_RDWR | O_CREAT, 0600))); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonCachedEntityTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "BJsonCachedEntityTest-end b_json_construction_0100"; +} + +/** + * @tc.number: SUB_backup_b_json_Structuralize_0100 + * @tc.name: b_json_Structuralize_0100 + * @tc.desc: Test function of Structuralize interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonCachedEntityTest, b_json_Structuralize_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BJsonCachedEntityTest-begin b_json_Structuralize_0100"; + try { + TestManager tm("b_json_Structuralize_0100"); + + std::string path = tm.GetRootDirCurTest(); + std::string filePath = path + ".json"; + BJsonCachedEntity jce(UniqueFd(open(filePath.data(), O_RDWR | O_CREAT, 0600))); + jce.Structuralize(); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonCachedEntityTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "BJsonCachedEntityTest-end b_json_Structuralize_0100"; +} + +/** + * @tc.number: SUB_backup_b_json_Persist_0100 + * @tc.name: b_json_Persist_0100 + * @tc.desc: Test function of Persist interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonCachedEntityTest, b_json_Persist_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BJsonCachedEntityTest-begin b_json_Persist_0100"; + try { + TestManager tm("b_json_Persist_0100"); + + std::string path = tm.GetRootDirCurTest(); + std::string filePath = path + ".json"; + BJsonCachedEntity jce(UniqueFd(open(filePath.data(), O_RDWR | O_CREAT, 0600))); + auto cache = jce.Structuralize(); + uint64_t space = 100; + cache.SetFreeDiskSpace(space); + jce.Persist(); + uint64_t result = cache.GetFreeDiskSpace(); + EXPECT_EQ(result, space); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonCachedEntityTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "BJsonCachedEntityTest-end b_json_Persist_0100"; +} + +/** + * @tc.number: SUB_backup_b_json_GetFd_0100 + * @tc.name: b_json_GetFd_0100 + * @tc.desc: Test function of GetFd interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonCachedEntityTest, b_json_GetFd_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BJsonCachedEntityTest-begin b_json_GetFd_0100"; + try { + TestManager tm("b_json_GetFd_0100"); + + std::string path = tm.GetRootDirCurTest(); + std::string filePath = path + ".json"; + BJsonCachedEntity jce(UniqueFd(open(filePath.data(), O_RDWR | O_CREAT, 0600))); + jce.GetFd(); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonCachedEntityTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "BJsonCachedEntityTest-end b_json_GetFd_0100"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_utils/b_json/b_json_entity_ext_manage_test.cpp b/tests/unittests/backup_utils/b_json/b_json_entity_ext_manage_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ef59a8db29874f2588d2d175d36059a0c87b0917 --- /dev/null +++ b/tests/unittests/backup_utils/b_json/b_json_entity_ext_manage_test.cpp @@ -0,0 +1,532 @@ +/* + * 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 +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "b_json/b_json_cached_entity.h" +#include "b_json/b_json_entity_ext_manage.h" +#include "test_manager.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +using namespace testing::ext; + +class BJsonEntityExtManageTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() {}; + void TearDown() {}; +}; + +bool IsEqual(const struct stat &lf, const struct stat &rh) +{ + if (lf.st_size != rh.st_size) { + return false; + } + if (lf.st_atim.tv_sec != rh.st_atim.tv_sec) { + return false; + } + if (lf.st_atim.tv_nsec != rh.st_atim.tv_nsec) { + return false; + } + if (lf.st_mtim.tv_sec != rh.st_mtim.tv_sec) { + return false; + } + if (lf.st_mtim.tv_nsec != rh.st_mtim.tv_nsec) { + return false; + } + return true; +} + +bool IsEqual(const map> &lf, const map> &rh) +{ + if (lf.size() != rh.size()) { + return false; + } + + auto itemLF = lf.begin(); + auto itemRH = rh.begin(); + for (; itemLF != lf.end(); ++itemLF, ++itemRH) { + if (itemLF->first != itemRH->first) { + return false; + } + if (itemLF->second.first != itemRH->second.first) { + return false; + } + if (!IsEqual(itemLF->second.second, itemRH->second.second)) { + return false; + } + } + + return true; +} + +struct stat GetFileStat(const string &pathTestFile) +{ + struct stat sta = {}; + if (stat(pathTestFile.data(), &sta) == -1) { + GTEST_LOG_(INFO) << pathTestFile << " invoked stat failure, errno :" << errno; + throw BError(errno); + } + return sta; +} + +/** + * @tc.number: SUB_backup_b_json_entity_ext_manage_0100 + * @tc.name: b_json_entity_ext_manage_0100 + * @tc.desc: 通过向接口SetExtManage传入不包含任何信息的空map参数,测试对索引文件的操作是否正确。 + * 0:通过向索引文件写入0条数据模拟对索引文件的(空)内容的测试覆盖 + * 1:调用接口SetExtManage,向索引文件写入数据 + * 2:调用接口GetExtManage,从索引文件读出文件名数据 + * 3:调用接口GetExtManageInfo,从索引文件读出文件详细数据(含文件名和对应文件的stat数据) + * 4:判断读出的文件名集合/文件详细数据记录个数是否为0 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0379 + */ +HWTEST_F(BJsonEntityExtManageTest, b_json_entity_ext_manage_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-begin b_json_entity_ext_manage_0100"; + try { + // 预置文件数据 + // 索引文件pathManageFile + TestManager tm("b_json_entity_ext_manage_0100"); + string root = tm.GetRootDirCurTest(); + string pathManageFile = root + "manage.json"; + BJsonCachedEntity cachedEntity(UniqueFd(open(pathManageFile.data(), O_RDONLY, 0))); + auto cache = cachedEntity.Structuralize(); + + // 写入空数据 + map> info; + cache.SetExtManage(info); + + // 读取索引文件信息并做结果判断 + auto fileNames = cache.GetExtManage(); + EXPECT_EQ(fileNames.size(), 0ul); + auto fileInfo = cache.GetExtManageInfo(); + EXPECT_EQ(fileInfo.size(), 0ul); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-end b_json_entity_ext_manage_0100"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_ext_manage_0200 + * @tc.name: b_json_entity_ext_manage_0200 + * @tc.desc: 通过向接口SetExtManage传入包含一条信息的map参数,测试对索引文件的操作是否正确。 + * 0:通过向索引文件写入1条有效数据模拟对索引文件的(有)内容的测试覆盖 + * 1:调用接口SetExtManage,向索引文件写入数据 + * 2:调用接口GetExtManage,从索引文件读出文件名数据 + * 3:调用接口GetExtManageInfo,从索引文件读出文件详细数据(含文件名和对应文件的stat数据) + * 4:判断读出的文件名集合/文件详细数据记录个数是否和写入时相等 + * 5:判断读出的文件名集合/文件详细数据记录内容是否和写入时相等 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0379 + */ +HWTEST_F(BJsonEntityExtManageTest, b_json_entity_ext_manage_0200, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-begin b_json_entity_ext_manage_0200"; + try { + TestManager tm("b_json_entity_ext_manage_0200"); + + // 预置文件数据 + // 索引文件pathManageFile, 测试文件路径pathTestFile, 测试文件名testFileHexName + string root = tm.GetRootDirCurTest(); + string pathManageFile = root + "manage.json"; + string pathTestFile = root + "test.txt"; + string testFileHexName = "1234567890abcdef"; + SaveStringToFile(pathTestFile, "hello world"); + BJsonCachedEntity cachedEntity(UniqueFd(open(pathManageFile.data(), O_RDONLY, 0))); + auto cache = cachedEntity.Structuralize(); + + // 生成一条有用数据并写入索引文件 + map> info; + struct stat sta = {}; + info.emplace(testFileHexName, make_pair(pathTestFile, sta = GetFileStat(pathTestFile))); + cache.SetExtManage(info); + + // 读取索引文件内容并做结果判断 + auto fileNames = cache.GetExtManage(); + ASSERT_EQ(fileNames.size(), 1ul); + EXPECT_EQ(*fileNames.begin(), testFileHexName); + auto fileInfo = cache.GetExtManageInfo(); + ASSERT_EQ(fileInfo.size(), 1ul); + EXPECT_EQ(fileInfo.begin()->first, testFileHexName); + EXPECT_EQ(fileInfo.begin()->second.first, pathTestFile); + EXPECT_TRUE(IsEqual(fileInfo.begin()->second.second, sta)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-end b_json_entity_ext_manage_0200"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_ext_manage_0300 + * @tc.name: b_json_entity_ext_manage_0300 + * @tc.desc: 通过向接口SetExtManage传入包含三条信息的map参数,测试对索引文件的操作是否正确。 + * 0:通过向索引文件写入3条有效数据模拟对索引文件的(无穷)内容的测试覆盖 + * 1:调用接口SetExtManage,向索引文件写入数据 + * 2:调用接口GetExtManage,从索引文件读出文件名数据 + * 3:调用接口GetExtManageInfo,从索引文件读出文件详细数据(含文件名和对应文件的stat数据) + * 4:判断读出的文件名集合/文件详细数据记录个数是否和写入时相等 + * 5:判断读出的文件名集合/文件详细数据记录内容是否和写入时相等 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0379 + */ +HWTEST_F(BJsonEntityExtManageTest, b_json_entity_ext_manage_0300, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-begin b_json_entity_ext_manage_0300"; + try { + TestManager tm("b_json_entity_ext_manage_0300"); + + // 预置文件数据 + // 索引文件pathManageFile1/2/3, 测试文件路径pathTestFile1/2/3, 测试文件名testFile1/2/3HexName + string root = tm.GetRootDirCurTest(); + string pathManageFile = root + "manage.json"; + string pathTestFile1 = root + "test1.txt"; + string pathTestFile2 = root + "test2.txt"; + string pathTestFile3 = root + "test3.txt"; + string testFile1HexName = "1234567890abcde1"; + string testFile2HexName = "1234567890abcde2"; + string testFile3HexName = "1234567890abcde3"; + SaveStringToFile(pathTestFile1, "h"); + SaveStringToFile(pathTestFile2, "hello"); + SaveStringToFile(pathTestFile3, "hello world"); + BJsonCachedEntity cachedEntity(UniqueFd(open(pathManageFile.data(), O_RDONLY, 0))); + auto cache = cachedEntity.Structuralize(); + + // 生成三条有用数据并写入索引文件 + map> info; + info.emplace(testFile1HexName, make_pair(pathTestFile1, GetFileStat(pathTestFile1))); + info.emplace(testFile2HexName, make_pair(pathTestFile2, GetFileStat(pathTestFile2))); + info.emplace(testFile3HexName, make_pair(pathTestFile3, GetFileStat(pathTestFile3))); + cache.SetExtManage(info); + + // 预置结果集,用以在读取索引文件后做结果判断 + set resultFileName {testFile1HexName, testFile2HexName, testFile3HexName}; + + // 读取索引文件内容并做结果判断 + auto fileNames = cache.GetExtManage(); + EXPECT_EQ(fileNames.size(), info.size()); + EXPECT_EQ(fileNames, resultFileName); + auto fileInfo = cache.GetExtManageInfo(); + EXPECT_EQ(fileInfo.size(), info.size()); + EXPECT_TRUE(IsEqual(fileInfo, info)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-end b_json_entity_ext_manage_0300"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_ext_manage_0400 + * @tc.name: b_json_entity_ext_manage_0400 + * @tc.desc: 通过向接口SetExtManage传入包含三条信息的map参数,测试对索引文件的操作是否正确。 + * 0:通过向索引文件写入3条有效数据模拟覆盖对索引文件的(无穷)内容的测试覆盖 + * 0:通过向索引文件的记录一写入0条、记录二写入1条、记录三写入2条有效硬链接数据模拟对索引文件含 + * 有硬链接(空、有、无穷)个的测试覆盖 + * 0:通过调用接口SetHardLinkInfo向索引文件中对应记录添加硬链接 + * 1:调用接口SetExtManage,向索引文件写入数据 + * 2:调用接口GetExtManage,从索引文件读出文件名数据 + * 3:调用接口GetExtManageInfo,从索引文件读出文件详细数据(含文件名和对应文件的stat数据) + * 4:判断读出的文件名集合/文件详细数据记录个数是否和写入时相等 + * 5:判断读出的文件名集合/文件详细数据记录内容是否和写入时相等 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0379 + */ +HWTEST_F(BJsonEntityExtManageTest, b_json_entity_ext_manage_0400, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-begin b_json_entity_ext_manage_0400"; + try { + TestManager tm("b_json_entity_ext_manage_0400"); + + // 预置文件数据 + // 索引文件pathManageFile1/2/3, 测试文件路径pathTestFile1/2/3, 测试文件名testFile1/2/3HexName + string root = tm.GetRootDirCurTest(); + string pathManageFile = root + "manage.json"; + string pathTestFile1 = root + "test1.txt"; + string pathTestFile2 = root + "test2.txt"; + string pathTestFile3 = root + "test3.txt"; + string testFile1HexName = "1234567890abcde1"; + string testFile2HexName = "1234567890abcde2"; + string testFile3HexName = "1234567890abcde3"; + SaveStringToFile(pathTestFile1, "h"); + SaveStringToFile(pathTestFile2, "hello"); + SaveStringToFile(pathTestFile3, "hello world"); + BJsonCachedEntity cachedEntity(UniqueFd(open(pathManageFile.data(), O_RDONLY, 0))); + auto cache = cachedEntity.Structuralize(); + + // 生成三条有用数据并写入索引文件 + map> info; + info.emplace(testFile1HexName, make_pair(pathTestFile1, GetFileStat(pathTestFile1))); + info.emplace(testFile2HexName, make_pair(pathTestFile2, GetFileStat(pathTestFile2))); + info.emplace(testFile3HexName, make_pair(pathTestFile3, GetFileStat(pathTestFile3))); + cache.SetExtManage(info); + + // 向索引文件中的三条记录分别追加0、1、2条硬链接信息 + set hardLinks1, hardLinks2, hardLinks3; + cache.SetHardLinkInfo(testFile1HexName, hardLinks1); + hardLinks2.emplace(root + "testFile2hardlink1"); + cache.SetHardLinkInfo(testFile2HexName, hardLinks2); + hardLinks3.emplace(root + "testFile3hardlink1"); + hardLinks3.emplace(root + "testFile3hardlink2"); + cache.SetHardLinkInfo(testFile3HexName, hardLinks3); + + // 预置结果集,用以在读取索引文件后做结果判断 + set resultFileName {testFile1HexName, testFile2HexName, testFile3HexName}; + + // 读取索引文件内容并做结果判断 + auto fileNames = cache.GetExtManage(); + EXPECT_EQ(fileNames.size(), info.size()); + EXPECT_EQ(fileNames, resultFileName); + auto fileInfo = cache.GetExtManageInfo(); + EXPECT_EQ(fileInfo.size(), info.size()); + EXPECT_TRUE(IsEqual(fileInfo, info)); + // 传入无效文件名"00000000",测试读取文件硬链接接口是否正确返回 + auto testFile0HardLinks = cache.GetHardLinkInfo("00000000"); + EXPECT_TRUE(testFile0HardLinks.empty()); + auto testFile1HardLinks = cache.GetHardLinkInfo(testFile1HexName); + EXPECT_TRUE(testFile1HardLinks.empty()); + auto testFile2HardLinks = cache.GetHardLinkInfo(testFile2HexName); + EXPECT_EQ(testFile2HardLinks, hardLinks2); + auto testFile3HardLinks = cache.GetHardLinkInfo(testFile3HexName); + EXPECT_EQ(testFile3HardLinks, hardLinks3); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-end b_json_entity_ext_manage_0400"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_ext_manage_0500 + * @tc.name: b_json_entity_ext_manage_0500 + * @tc.desc: 通过向接口SetExtManage传入包含三条信息的map参数,测试对索引文件的操作是否正确。 + * 0:通过向索引文件写入3条有效数据模拟覆盖对索引文件的(无穷)内容的测试覆盖 + * 0:通过向索引文件的记录一写入0条、记录二写入1条、记录三写入2条有效硬链接数据模拟对索引文件含 + * 有硬链接(空、有、无穷)个的测试覆盖 + * 0:通过传入和源文件相同stat信息向索引文件中对应记录添加硬链接 + * 1:调用接口SetExtManage,向索引文件写入数据 + * 2:调用接口GetExtManage,从索引文件读出文件名数据 + * 3:调用接口GetExtManageInfo,从索引文件读出文件详细数据(含文件名和对应文件的stat数据) + * 4:判断读出的文件名集合/文件详细数据记录个数是否和写入时相等 + * 5:判断读出的文件名集合/文件详细数据记录内容是否和写入时相等 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0379 + */ +HWTEST_F(BJsonEntityExtManageTest, b_json_entity_ext_manage_0500, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-begin b_json_entity_ext_manage_0500"; + try { + // 预置文件数据 + // 索引文件pathManageFile1/2/3, 测试文件路径pathTestFile1/2/3, 测试文件名testFile1/2/3HexName + TestManager tm("b_json_entity_ext_manage_0500"); + string root = tm.GetRootDirCurTest(); + string pathManageFile = root + "manage.json"; + string pathTestFile1 = root + "test1.txt"; + string pathTestFile2 = root + "test2.txt"; + string pathTestFile3 = root + "test3.txt"; + string testFile1HexName = "1234567890abcde1"; + string testFile2HexName = "1234567890abcde2"; + string testFile3HexName = "1234567890abcde3"; + SaveStringToFile(pathTestFile1, "h"); + SaveStringToFile(pathTestFile2, "hello"); + SaveStringToFile(pathTestFile3, "hello world"); + BJsonCachedEntity cachedEntity(UniqueFd(open(pathManageFile.data(), O_RDONLY, 0))); + auto cache = cachedEntity.Structuralize(); + + // 生成三条有用数据并写入索引文件 + // 通过重用原始文件的stat向该记录追加(0/1/2)条硬链接文件信息 + map> info; + struct stat sta = {}; + info.emplace(testFile1HexName, make_pair(pathTestFile1, GetFileStat(pathTestFile1))); + info.emplace(testFile2HexName, make_pair(pathTestFile2, sta = GetFileStat(pathTestFile2))); + info.emplace("testFile2hardlink1", make_pair(root + "testFile2hardlink1", sta)); + info.emplace(testFile3HexName, make_pair(pathTestFile3, sta = GetFileStat(pathTestFile3))); + info.emplace("testFile3hardlink1", make_pair(root + "testFile3hardlink1", sta)); + info.emplace("testFile3hardlink2", make_pair(root + "testFile3hardlink2", sta)); + cache.SetExtManage(info); + + // 预置结果集,用以在读取索引文件后做结果判断 + // 将info中的硬链接信息删除,保留原始文件信息,作为后续结果值判断的比较对象 + info.erase("testFile2hardlink1"); + info.erase("testFile3hardlink1"); + info.erase("testFile3hardlink2"); + set hardLinks2 {root + "testFile2hardlink1"}; + set hardLinks3 {root + "testFile3hardlink1", root + "testFile3hardlink2"}; + set resultFileName {testFile1HexName, testFile2HexName, testFile3HexName}; + + // 读取索引文件内容并做结果判断 + auto fileNames = cache.GetExtManage(); + EXPECT_EQ(fileNames.size(), 3ul); + EXPECT_EQ(fileNames, resultFileName); + auto fileInfo = cache.GetExtManageInfo(); + EXPECT_EQ(fileInfo.size(), info.size()); + EXPECT_TRUE(IsEqual(fileInfo, info)); + auto testFile1HardLinks = cache.GetHardLinkInfo(testFile1HexName); + EXPECT_TRUE(testFile1HardLinks.empty()); + auto testFile2HardLinks = cache.GetHardLinkInfo(testFile2HexName); + EXPECT_EQ(testFile2HardLinks, hardLinks2); + auto testFile3HardLinks = cache.GetHardLinkInfo(testFile3HexName); + EXPECT_EQ(testFile3HardLinks, hardLinks3); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-end b_json_entity_ext_manage_0500"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_ext_manage_0600 + * @tc.name: b_json_entity_ext_manage_0600 + * @tc.desc: 测试SetExtManage接口中的FindLinks在设备号或INode数目为0时能否成功通过GetExtManage获取相关信息 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0379 + */ +HWTEST_F(BJsonEntityExtManageTest, b_json_entity_ext_manage_0600, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-begin b_json_entity_ext_manage_0600"; + try { + map> mp = {{"key", {"first", {}}}}; + Json::Value jv; + BJsonEntityExtManage extMg(jv); + + extMg.SetExtManage(mp); + set ss = extMg.GetExtManage(); + EXPECT_EQ(ss.size(), 1); + + mp.at("key").second.st_dev = 1; + extMg.SetExtManage(mp); + ss = extMg.GetExtManage(); + EXPECT_EQ(ss.size(), 1); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-end b_json_entity_ext_manage_0600"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_ext_manage_0700 + * @tc.name: b_json_entity_ext_manage_0700 + * @tc.desc: 测试GetExtManageInfo在Json数据不为数组时能否成功返回空map + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0379 + */ +HWTEST_F(BJsonEntityExtManageTest, b_json_entity_ext_manage_0700, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-begin b_json_entity_ext_manage_0700"; + try { + string_view sv = R"({"key":1})"; + BJsonCachedEntity cachedEntity(sv); + auto cache = cachedEntity.Structuralize(); + auto mp = cache.GetExtManageInfo(); + EXPECT_TRUE(mp.empty()); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-end b_json_entity_ext_manage_0700"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_ext_manage_0800 + * @tc.name: b_json_entity_ext_manage_0800 + * @tc.desc: 测试GetExtManageInfo在Json数据为数组且仅有一个键不为information的对象时能否成功返回空map + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0379 + */ +HWTEST_F(BJsonEntityExtManageTest, b_json_entity_ext_manage_0800, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-begin b_json_entity_ext_manage_0800"; + try { + string_view sv = R"([{"key":1}])"; + BJsonCachedEntity cachedEntity(sv); + auto cache = cachedEntity.Structuralize(); + auto mp = cache.GetExtManageInfo(); + EXPECT_TRUE(mp.empty()); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-end b_json_entity_ext_manage_0800"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_ext_manage_0900 + * @tc.name: b_json_entity_ext_manage_0900 + * @tc.desc: 测试SetHardLinkInfo接口和GetHardLinkInfo接口在不符合相关条件时能否成功返回false和空set + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0379 + */ +HWTEST_F(BJsonEntityExtManageTest, b_json_entity_ext_manage_0900, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-begin b_json_entity_ext_manage_0900"; + try { + string_view sv = R"({"key":1})"; + BJsonCachedEntity cachedEntity(sv); + auto cache = cachedEntity.Structuralize(); + EXPECT_FALSE(cache.SetHardLinkInfo("", {})); + + Json::Value jv; + BJsonEntityExtManage extMg(jv); + EXPECT_FALSE(extMg.SetHardLinkInfo("1", {})); + + EXPECT_FALSE(cache.SetHardLinkInfo("1", {})); + + EXPECT_EQ(cache.GetHardLinkInfo(""), set()); + + EXPECT_EQ(extMg.GetHardLinkInfo("1"), set()); + + EXPECT_EQ(cache.GetHardLinkInfo("1"), set()); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtManageTest-end b_json_entity_ext_manage_0900"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_utils/b_json/b_json_entity_extension_config_test.cpp b/tests/unittests/backup_utils/b_json/b_json_entity_extension_config_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5306f7847f1aad9592e43edb2ad0ac3a0c407dbc --- /dev/null +++ b/tests/unittests/backup_utils/b_json/b_json_entity_extension_config_test.cpp @@ -0,0 +1,582 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "b_json/b_json_cached_entity.h" +#include "b_json/b_json_entity_caps.h" +#include "b_json/b_json_entity_extension_config.h" +#include "b_process/b_process.h" +#include "b_resources/b_constants.h" +#include "directory_ex.h" +#include "file_ex.h" +#include "parameter.h" +#include "test_manager.h" +#include "json/value.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +class BJsonEntityExtensionConfigTest : public testing::Test { +public: + static void SetUpTestCase(void) {}; + static void TearDownTestCase() {}; + void SetUp() {}; + void TearDown() {}; +}; + +static vector DEFAULT_INCLUDE_DIR = { + "data/storage/el2/database/", + "data/storage/el2/base/files/", + "data/storage/el2/base/preferences/", + "data/storage/el2/base/haps/*/database/", + "data/storage/el2/base/haps/*/base/files/", + "data/storage/el2/base/haps/*/base/preferences/", +}; +static vector DEFAULT_EXCLUDE_DIR = {}; + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_0100 + * @tc.name: b_json_entity_extension_config_0100 + * @tc.desc: 不包含includes和excludes + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_0100"; + try { + TestManager tm("b_json_entity_extension_config_0100"); + + string root = tm.GetRootDirCurTest(); + string pathConfigFile = root + "config.json"; + SaveStringToFile(pathConfigFile, ""); + + BJsonCachedEntity cachedEntity(UniqueFd(open(pathConfigFile.data(), O_RDONLY, 0))); + auto cache = cachedEntity.Structuralize(); + vector includes = cache.GetIncludes(); + EXPECT_EQ(includes, DEFAULT_INCLUDE_DIR); + vector excludes = cache.GetExcludes(); + EXPECT_EQ(excludes, DEFAULT_EXCLUDE_DIR); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_0100"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_0200 + * @tc.name: b_json_entity_extension_config_0200 + * @tc.desc: json文件中只包含includes + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_0200, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_0200"; + try { + TestManager tm("b_json_entity_extension_config_0200"); + + string root = tm.GetRootDirCurTest(); + string pathConfigFile = root + "config.json"; + SaveStringToFile(pathConfigFile, R"({"includes":["", "", ""]})"); + + BJsonCachedEntity cachedEntity(UniqueFd(open(pathConfigFile.data(), O_RDONLY, 0))); + auto cache = cachedEntity.Structuralize(); + vector includes = cache.GetIncludes(); + vector includesExpect = {"", "", ""}; + EXPECT_EQ(includes, includesExpect); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_0200"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_0300 + * @tc.name: b_json_entity_extension_config_0300 + * @tc.desc: json文件中只包含excludes + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_0300, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_0300"; + try { + TestManager tm("b_json_entity_extension_config_0300"); + + string root = tm.GetRootDirCurTest(); + string pathConfigFile = root + "config.json"; + SaveStringToFile(pathConfigFile, R"({"excludes":["", "", ""]})"); + + BJsonCachedEntity cachedEntity(UniqueFd(open(pathConfigFile.data(), O_RDONLY, 0))); + auto cache = cachedEntity.Structuralize(); + vector excludes = cache.GetExcludes(); + vector excludesExpect = {"", "", ""}; + EXPECT_EQ(excludes, excludesExpect); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_0300"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_0400 + * @tc.name: b_json_entity_extension_config_0400 + * @tc.desc: 同时包含includes和excludes + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_0400, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_0400"; + try { + TestManager tm("b_json_entity_extension_config_0400"); + + string root = tm.GetRootDirCurTest(); + string pathConfigFile = root + "config.json"; + SaveStringToFile(pathConfigFile, R"({"includes":["", "", ""], "excludes":["", "", ""]})"); + + BJsonCachedEntity cachedEntity(UniqueFd(open(pathConfigFile.data(), O_RDONLY, 0))); + auto cache = cachedEntity.Structuralize(); + vector includes = cache.GetIncludes(); + vector includesExpect = {"", "", ""}; + EXPECT_EQ(includes, includesExpect); + vector excludes = cache.GetExcludes(); + vector excludesExpect = {"", "", ""}; + EXPECT_EQ(excludes, excludesExpect); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_0400"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_0500 + * @tc.name: b_json_entity_extension_config_0500 + * @tc.desc: json文件中标签为特殊字符 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 2 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_0500, testing::ext::TestSize.Level2) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_0500"; + try { + TestManager tm("b_json_entity_extension_config_0500"); + + string root = tm.GetRootDirCurTest(); + string pathConfigFile = root + "config.json"; + SaveStringToFile(pathConfigFile, R"({"%#$%445":["", "", ""]})"); + + BJsonCachedEntity cachedEntity(UniqueFd(open(pathConfigFile.data(), O_RDONLY, 0))); + auto cache = cachedEntity.Structuralize(); + vector includes = cache.GetIncludes(); + vector includesExpect = {DEFAULT_INCLUDE_DIR}; + EXPECT_EQ(includes, includesExpect); + vector excludes = cache.GetExcludes(); + vector excludesExpect = {DEFAULT_EXCLUDE_DIR}; + EXPECT_EQ(excludes, excludesExpect); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_0500"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_0600 + * @tc.name: b_json_entity_extension_config_0600 + * @tc.desc: json文件中标签为中文汉字 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 2 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_0600, testing::ext::TestSize.Level2) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_0600"; + try { + TestManager tm("b_json_entity_extension_config_0600"); + + string root = tm.GetRootDirCurTest(); + string pathConfigFile = root + "config.json"; + SaveStringToFile(pathConfigFile, R"({"测试代码":["", "", ""]})"); + + BJsonCachedEntity cachedEntity(UniqueFd(open(pathConfigFile.data(), O_RDONLY, 0))); + auto cache = cachedEntity.Structuralize(); + vector includes = cache.GetIncludes(); + EXPECT_EQ(includes, DEFAULT_INCLUDE_DIR); + vector excludes = cache.GetExcludes(); + EXPECT_EQ(excludes, DEFAULT_EXCLUDE_DIR); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_0600"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_0700 + * @tc.name: b_json_entity_extension_config_0700 + * @tc.desc: json文件中无标签 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 2 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_0700, testing::ext::TestSize.Level2) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_0700"; + try { + TestManager tm("b_json_entity_extension_config_0700"); + + string root = tm.GetRootDirCurTest(); + string pathConfigFile = root + "config.json"; + SaveStringToFile(pathConfigFile, R"({"":["", "", ""]})"); + + BJsonCachedEntity cachedEntity(UniqueFd(open(pathConfigFile.data(), O_RDONLY, 0))); + auto cache = cachedEntity.Structuralize(); + vector includes = cache.GetIncludes(); + EXPECT_EQ(includes, DEFAULT_INCLUDE_DIR); + vector excludes = cache.GetExcludes(); + EXPECT_EQ(excludes, DEFAULT_EXCLUDE_DIR); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_0700"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_0800 + * @tc.name: b_json_entity_extension_config_0800 + * @tc.desc: json文件标签中有异常引号 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 2 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_0800, testing::ext::TestSize.Level2) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_0800"; + try { + TestManager tm("b_json_entity_extension_config_0800"); + + string root = tm.GetRootDirCurTest(); + string pathConfigFile = root + "config.json"; + SaveStringToFile( + pathConfigFile, + R"({"includes":["", "", ""], "excludes":["", "", ""], """""""""""""""""""""""""""""""""""""""""""""""""":[]})"); + + BJsonCachedEntity cachedEntity(UniqueFd(open(pathConfigFile.data(), O_RDONLY, 0))); + auto cache = cachedEntity.Structuralize(); + vector includes = cache.GetIncludes(); + EXPECT_EQ(includes, DEFAULT_INCLUDE_DIR); + vector excludes = cache.GetExcludes(); + EXPECT_EQ(excludes, DEFAULT_EXCLUDE_DIR); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by construction."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_0800"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_0900 + * @tc.name: b_json_entity_extension_config_0900 + * @tc.desc: 测试GetJSonSource接口能否在非service进程下正确读取backup_config.json + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 2 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_0900, testing::ext::TestSize.Level2) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_0900"; + try { + string jsonContent = R"({"allowToBackupRestore":true})"; + auto [bFatalErr, ret] = BProcess::ExecuteCmd({"mkdir", "-p", BConstants::BACKUP_CONFIG_EXTENSION_PATH}); + EXPECT_FALSE(bFatalErr); + EXPECT_EQ(ret, 0); + string jsonFilePath = string(BConstants::BACKUP_CONFIG_EXTENSION_PATH).append(BConstants::BACKUP_CONFIG_JSON); + SaveStringToFile(jsonFilePath, jsonContent); + string_view sv = R"({"allowToBackupRestore":false})"; + SetMockParameter(true); + BJsonCachedEntity cachedEntity(sv); + auto cache = cachedEntity.Structuralize(); + string jsonRead = cache.GetJSonSource(sv, any()); + EXPECT_EQ(jsonRead, jsonContent); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by GetJSonSource."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_0900"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_1000 + * @tc.name: b_json_entity_extension_config_1000 + * @tc.desc: 测试GetJSonSource接口能否在service进程下正确读取backup_config.json + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 2 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_1000, testing::ext::TestSize.Level2) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_1000"; + try { + string bundleName = "com.example.app2backup"; + string jsonFileDir = string(BConstants::SA_BUNDLE_BACKUP_ROOT_DIR).append(bundleName); + string jsonContent = R"({"allowToBackupRestore":true})"; + auto [bFatalErr, ret] = BProcess::ExecuteCmd({"mkdir", "-p", jsonFileDir}); + EXPECT_FALSE(bFatalErr); + EXPECT_EQ(ret, 0); + string jsonFilePath = jsonFileDir.append("/").append(BConstants::BACKUP_CONFIG_JSON); + SaveStringToFile(jsonFilePath, jsonContent); + uid_t currUid = getuid(); + setuid(BConstants::BACKUP_UID); + string_view sv = R"({"allowToBackupRestore":false})"; + SetMockParameter(true); + BJsonCachedEntity cachedEntity(sv, bundleName); + auto cache = cachedEntity.Structuralize(); + string jsonRead = cache.GetJSonSource(sv, bundleName); + setuid(currUid); + EXPECT_EQ(jsonRead, jsonContent); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by GetJSonSource."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_1000"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_1100 + * @tc.name: b_json_entity_extension_config_1100 + * @tc.desc: 测试GetJSonSource接口能否在backup.debug.overrideExtensionConfig为false的情况下保持原JSon字符串不变 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 2 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_1100, testing::ext::TestSize.Level2) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_1100"; + try { + string_view sv = R"({"allowToBackupRestore":false})"; + SetMockParameter(false); + BJsonCachedEntity cachedEntity(sv); + auto cache = cachedEntity.Structuralize(); + string jsonRead = cache.GetJSonSource(sv, any()); + EXPECT_EQ(jsonRead, string(sv)); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by GetJSonSource."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_1100"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_1200 + * @tc.name: b_json_entity_extension_config_1200 + * @tc.desc: 测试GetIncludes接口在Json数据中键为includes的值不为数组时能否成功返回默认目录 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 2 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_1200, testing::ext::TestSize.Level2) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_1200"; + try { + string_view sv = R"({"includes":1})"; + BJsonCachedEntity cachedEntity(sv); + auto cache = cachedEntity.Structuralize(); + vector vs = cache.GetIncludes(); + EXPECT_EQ(vs, DEFAULT_INCLUDE_DIR); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by GetIncludes."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_1200"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_1300 + * @tc.name: b_json_entity_extension_config_1300 + * @tc.desc: 测试GetIncludes接口在Json数据中键为includes的值为数组且数组元素全都不为字符串时能否成功返回空目录 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 2 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_1300, testing::ext::TestSize.Level2) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_1300"; + try { + string_view sv = R"({"includes":[1]})"; + BJsonCachedEntity cachedEntity(sv); + auto cache = cachedEntity.Structuralize(); + vector vs = cache.GetIncludes(); + EXPECT_EQ(vs, vector({""})); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by GetIncludes."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_1300"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_1400 + * @tc.name: b_json_entity_extension_config_1400 + * @tc.desc: 测试GetExcludes接口在Json数据中键为excludes的值不为数组时能否成功返回空vector + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 2 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_1400, testing::ext::TestSize.Level2) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_1400"; + try { + string_view sv = R"({"excludes":1})"; + BJsonCachedEntity cachedEntity(sv); + auto cache = cachedEntity.Structuralize(); + vector vs = cache.GetExcludes(); + EXPECT_EQ(vs, vector()); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by GetExcludes."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_1400"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_1500 + * @tc.name: b_json_entity_extension_config_1500 + * @tc.desc: 测试GetExcludes接口在Json数据中键为excludes的值为数组且数组元素全都不为字符串时能否成功返回空vector + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 2 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_1500, testing::ext::TestSize.Level2) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_1500"; + try { + string_view sv = R"({"excludes":[1]})"; + BJsonCachedEntity cachedEntity(sv); + auto cache = cachedEntity.Structuralize(); + vector vs = cache.GetExcludes(); + EXPECT_EQ(vs, vector()); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by GetExcludes."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_1500"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_1600 + * @tc.name: b_json_entity_extension_config_1600 + * @tc.desc: 测试GetAllowToBackupRestore接口在Json数据对象nullValue时能否成功返回false + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 2 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_1600, testing::ext::TestSize.Level2) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_1600"; + try { + Json::Value jv(Json::nullValue); + BJsonEntityExtensionConfig extCfg(jv); + EXPECT_FALSE(extCfg.GetAllowToBackupRestore()); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by GetAllowToBackupRestore."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_1600"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_1700 + * @tc.name: b_json_entity_extension_config_1700 + * @tc.desc: 测试GetAllowToBackupRestore接口在Json数据对象不含allowToBackupRestore键时能否成功返回false + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 2 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_1700, testing::ext::TestSize.Level2) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_1700"; + try { + string_view sv = R"({"allowToBackupRestore_":true})"; + BJsonCachedEntity cachedEntity(sv); + auto cache = cachedEntity.Structuralize(); + EXPECT_FALSE(cache.GetAllowToBackupRestore()); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by GetAllowToBackupRestore."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_1700"; +} + +/** + * @tc.number: SUB_backup_b_json_entity_extension_config_1800 + * @tc.name: b_json_entity_extension_config_1800 + * @tc.desc: 测试GetAllowToBackupRestore接口在Json数据对象键为allowToBackupRestore的值不为布尔值时能否成功返回false + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 2 + * @tc.require: SR000H037V + */ +HWTEST_F(BJsonEntityExtensionConfigTest, b_json_entity_extension_config_1800, testing::ext::TestSize.Level2) +{ + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-begin b_json_entity_extension_config_1800"; + try { + string_view sv = R"({"allowToBackupRestore":1})"; + BJsonCachedEntity cachedEntity(sv); + auto cache = cachedEntity.Structuralize(); + EXPECT_FALSE(cache.GetAllowToBackupRestore()); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-an exception occurred by GetAllowToBackupRestore."; + } + GTEST_LOG_(INFO) << "BJsonEntityExtensionConfigTest-end b_json_entity_extension_config_1800"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_utils/b_process/b_process_test.cpp b/tests/unittests/backup_utils/b_process/b_process_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..99dc64d9ff05de93e458d6fac83c3bbf90ca8957 --- /dev/null +++ b/tests/unittests/backup_utils/b_process/b_process_test.cpp @@ -0,0 +1,79 @@ +/* + * 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 +#include + +#include + +#include + +#include "b_process/b_process.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +class BProcessTest : public testing::Test { +public: + static void SetUpTestCase() {}; + static void TearDownTestCase() {}; + void SetUp() override {}; + void TearDown() override {}; +}; + +static bool DetectFatalLog(string_view output) +{ + GTEST_LOG_(INFO) << "DetectFatalLog " << output; + if (output.find("empty archive") != string_view::npos) { + return true; + } + return false; +} + +/** + * @tc.number: SUB_backup_tool_BProcess_0100 + * @tc.name: SUB_backup_tool_BProcess_0100 + * @tc.desc: 测试ExecuteCmd + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0377 + */ +HWTEST_F(BProcessTest, SUB_backup_tool_BProcess_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BProcessTest-begin SUB_backup_tool_BProcess_0100"; + try { + vector argvCf = { + "/system/bin/tar", + "-cf", + "/data/backup/", + }; + auto [bFatalError, ret] = BProcess::ExecuteCmd(argvCf, DetectFatalLog); + EXPECT_NE(ret, 0); + + vector argvTvf = { + "/system/bin/tar", + "-tvf", + "/data/backup/", + }; + auto [bFatalErro1r, retTvf] = BProcess::ExecuteCmd(argvTvf, DetectFatalLog); + EXPECT_NE(retTvf, 0); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BProcessTest-an exception occurred."; + } + GTEST_LOG_(INFO) << "BProcessTest-end SUB_backup_tool_BProcess_0100"; +} +} // namespace OHOS::FileManagement::Backup diff --git a/tests/unittests/backup_utils/b_tarball/b_tarball_cmdline_test.cpp b/tests/unittests/backup_utils/b_tarball/b_tarball_cmdline_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6a9b9573325a3fd332d942ec5fc01ab1ccd99946 --- /dev/null +++ b/tests/unittests/backup_utils/b_tarball/b_tarball_cmdline_test.cpp @@ -0,0 +1,149 @@ +/* + * 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 +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "b_error/b_error.h" +#include "b_tarball/b_tarball_cmdline.h" +#include "test_manager.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +class BTarballCmdlineTest : public testing::Test { +public: + static void SetUpTestCase() {}; + static void TearDownTestCase() {}; + void SetUp() {}; + void TearDown() {}; +}; + +/** + * @tc.number: SUB_b_tarball_cmdline_0100 + * @tc.name: b_tarball_cmdline_0100 + * @tc.desc: 测试BTarballCmdline类构造函数是否成功 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0379 + */ +HWTEST_F(BTarballCmdlineTest, b_tarball_cmdline_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BTarballCmdlineTest-begin b_tarball_cmdline_0100"; + try { + TestManager tm("b_tarball_cmdline_0100"); + string root = tm.GetRootDirCurTest(); + string_view tarballDir = root; + string_view tarballName = "test.tar"; + + BTarballCmdline tarballCmdline(tarballDir, tarballName); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BTarballCmdlineTest-an exception occurred by BTarballCmdline."; + } + GTEST_LOG_(INFO) << "BTarballCmdlineTest-end b_tarball_cmdline_0100"; +} + +/** + * @tc.number: SUB_b_tarball_cmdline_0200 + * @tc.name: b_tarball_cmdline_0200 + * @tc.desc: 测试BTarballCmdline类Tar函数是否成功 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0379 + */ +HWTEST_F(BTarballCmdlineTest, b_tarball_cmdline_0200, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BTarballCmdlineTest-begin b_tarball_cmdline_0200"; + try { + // 预置文件和目录 + TestManager tm("b_tarball_cmdline_0200"); + string root = tm.GetRootDirCurTest(); + string_view tarballDir = root; + string_view tarballName = "test.tar"; + string testDir = root + "/testdir"; + if (mkdir(testDir.data(), S_IRWXU) && errno != EEXIST) { + GTEST_LOG_(INFO) << " invoked mkdir failure, errno :" << errno; + throw BError(errno); + } + string strFile = root + tarballName.data(); + UniqueFd fd(open(strFile.data(), O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR)); + if (fd < 0) { + GTEST_LOG_(INFO) << " invoked open failure, errno :" << errno; + throw BError(errno); + } + + string aFile = testDir + "/a.txt"; + string bFile = testDir + "/b.txt"; + SaveStringToFile(aFile, "hello"); + SaveStringToFile(bFile, "world"); + vector includes {testDir}; + vector excludes {bFile}; + + // 调用tar打包 + BTarballCmdline tarballCmdline(tarballDir, tarballName); + tarballCmdline.Tar(root, includes, excludes); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BTarballCmdlineTest-an exception occurred by BTarballCmdline."; + } + GTEST_LOG_(INFO) << "BTarballCmdlineTest-end b_tarball_cmdline_0200"; +} + +/** + * @tc.number: SUB_b_tarball_cmdline_0300 + * @tc.name: b_tarball_cmdline_0300 + * @tc.desc: 测试BTarballCmdline类Untar函数是否成功 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0379 + */ +HWTEST_F(BTarballCmdlineTest, b_tarball_cmdline_0300, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BTarballCmdlineTest-begin b_tarball_cmdline_0300"; + try { + // 预置文件和目录 + TestManager tm("b_tarball_cmdline_0300"); + string root = tm.GetRootDirCurTest(); + string_view tarballDir = root; + string_view tarballName = "test.tar"; + string testUntarDir = root + "/untardir"; + if (mkdir(testUntarDir.data(), S_IRWXU) && errno != EEXIST) { + GTEST_LOG_(INFO) << " invoked mkdir failure, errno :" << errno; + throw BError(errno); + } + // 调用tar打包 + BTarballCmdline tarballCmdline(tarballDir, tarballName); + tarballCmdline.Untar(testUntarDir); + + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BTarballCmdlineTest-an exception occurred by BTarballCmdline."; + } + GTEST_LOG_(INFO) << "BTarballCmdlineTest-end b_tarball_cmdline_0300"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_utils/b_tarball/b_tarball_factory_test.cpp b/tests/unittests/backup_utils/b_tarball/b_tarball_factory_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..937da1882726bc30d4540930aa2b1ed016c9d475 --- /dev/null +++ b/tests/unittests/backup_utils/b_tarball/b_tarball_factory_test.cpp @@ -0,0 +1,67 @@ +/* + * 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 +#include + +#include +#include + +#include "b_tarball/b_tarball_factory.h" +#include "test_manager.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +class BTarballFactoryTest : public testing::Test { +public: + static void SetUpTestCase() {}; + static void TearDownTestCase() {}; + void SetUp() {}; + void TearDown() {}; +}; + +/** + * @tc.number: SUB_b_tarball_factory_0100 + * @tc.name: b_tarball_factory_0100 + * @tc.desc: 测试BTarballFactory类create函数是否成功 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0379 + */ +HWTEST_F(BTarballFactoryTest, b_tarball_factory_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BTarballFactoryTest-begin b_tarball_factory_0100"; + try { + // 预置路径 + TestManager tm("b_tarball_factory_0100"); + string root = tm.GetRootDirCurTest(); + string implType = "cmdline"; + string tarballPath = root + "/test.tar"; + SaveStringToFile(tarballPath, "data/storage/el2/database/"); + // 调用create获取打包解包能力 + auto tarballTar = BTarballFactory::Create(implType, tarballPath); + GTEST_LOG_(INFO) << "BTarballFactoryTest-tar"; + (tarballTar->tar)("/", {}, {"/data/storage/el2/database/", {}}); + GTEST_LOG_(INFO) << "BTarballFactoryTest-untar"; + (tarballTar->untar)("/"); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BTarballFactoryTest-an exception occurred by BTarballFactory."; + } + GTEST_LOG_(INFO) << "BTarballFactoryTest-end b_tarball_factory_0100"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/unittests/backup_utils/b_tarball/b_tarball_posix_tarball_test.cpp b/tests/unittests/backup_utils/b_tarball/b_tarball_posix_tarball_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ab53106e92001e4e8b1b374dfa9efa637614477b --- /dev/null +++ b/tests/unittests/backup_utils/b_tarball/b_tarball_posix_tarball_test.cpp @@ -0,0 +1,432 @@ +/* + * 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 +#include +#include + +#include + +#include + +#include "b_process/b_process.h" +#include "b_resources/b_constants.h" +#include "b_tarball/b_tarball_posix/b_tarball_posix_tarball.h" +#include "b_tarball_posix/b_tarball_posix_extended_entry.h" +#include "test_manager.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +class BTarballPosixTarballTest : public testing::Test { +public: + static void SetUpTestCase() {}; + static void TearDownTestCase() {}; + void SetUp() {}; + void TearDown() {}; +}; + +/** + * @tc.number: SUB_backup_b_tarball_posix_tarball_EmptyFile_0100 + * @tc.name: b_tarball_posix_tarball_EmptyFile_0100 + * @tc.desc: 测试BTarballPosixTarball类打包空普通文件是否成功 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0378 + */ +HWTEST_F(BTarballPosixTarballTest, b_tarball_posix_tarball_EmptyFile_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-begin b_tarball_posix_tarball_EmptyFile_0100"; + try { + TestManager testManager("b_tarball_posix_tarball_EmptyFile_0100"); + string backupRootDirPath = testManager.GetRootDirCurTest(); + // 创建空文件 + string fileName = "empty.file"; + string filePath = backupRootDirPath + fileName; + auto [bFatalError, ret] = BProcess::ExecuteCmd({"touch", filePath.c_str()}); + EXPECT_EQ(ret, 0); + // 创建用于存放解包文件的目录 + string unpackDirName = "unpack"; + string unpackDirPath = backupRootDirPath + unpackDirName; + tie(bFatalError, ret) = BProcess::ExecuteCmd({"mkdir", unpackDirPath.c_str()}); + EXPECT_EQ(ret, 0); + // 对空文件进行打包 + string tarballName = "empty.file.tar"; + string tarballPath = backupRootDirPath + tarballName; + BTarballPosixTarball tarball(tarballPath); + tarball.Emplace(filePath); + tarball.Publish(); + // 对包文件进行解包 + tie(bFatalError, ret) = BProcess::ExecuteCmd({"tar", "-xvf", tarballPath.c_str(), "-C", unpackDirPath.c_str()}); + EXPECT_EQ(ret, 0); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-an exception occurred by BTarballPosixTarball."; + } + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-end b_tarball_posix_tarball_EmptyFile_0100"; +} + +/** + * @tc.number: SUB_backup_b_tarball_posix_tarball_RegularFile_0100 + * @tc.name: b_tarball_posix_tarball_RegularFile_0100 + * @tc.desc: 测试BTarballPosixTarball类打包含数据的普通文件是否成功 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0378 + */ +HWTEST_F(BTarballPosixTarballTest, b_tarball_posix_tarball_RegularFile_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-begin b_tarball_posix_tarball_RegularFile_0100"; + try { + TestManager testManager("b_tarball_posix_tarball_RegularFile_0100"); + string backupRootDirPath = testManager.GetRootDirCurTest(); + // 创建普通文件(dd命令中bs设为1000是为了构造文件字节数不是512的整数倍的场景) + string fileName = "regular.file"; + string filePath = backupRootDirPath + fileName; + auto [bFatalError, ret] = + BProcess::ExecuteCmd({"dd", "if=/dev/urandom", ("of=" + filePath).c_str(), "bs=1000", "count=1"}); + EXPECT_EQ(ret, 0); + // 创建用于存放解包文件的目录 + string unpackDirName = "unpack"; + string unpackDirPath = backupRootDirPath + unpackDirName; + tie(bFatalError, ret) = BProcess::ExecuteCmd({"mkdir", unpackDirPath.c_str()}); + EXPECT_EQ(ret, 0); + // 对普通文件进行打包 + string tarballName = "regular.file.tar"; + string tarballPath = backupRootDirPath + tarballName; + BTarballPosixTarball tarball(tarballPath); + tarball.Emplace(filePath); + tarball.Publish(); + // 对包文件进行解包 + tie(bFatalError, ret) = BProcess::ExecuteCmd({"tar", "-xvf", tarballPath.c_str(), "-C", unpackDirPath.c_str()}); + EXPECT_EQ(ret, 0); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-an exception occurred by BTarballPosixTarball."; + } + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-end b_tarball_posix_tarball_RegularFile_0100"; +} + +/** + * @tc.number: SUB_backup_b_tarball_posix_tarball_EmptyDir_0100 + * @tc.name: b_tarball_posix_tarball_EmptyDir_0100 + * @tc.desc: 测试BTarballPosixTarball类打包空目录是否成功 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0378 + */ +HWTEST_F(BTarballPosixTarballTest, b_tarball_posix_tarball_EmptyDir_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-begin b_tarball_posix_tarball_EmptyDir_0100"; + try { + TestManager testManager("b_tarball_posix_tarball_EmptyDir_0100"); + string backupRootDirPath = testManager.GetRootDirCurTest(); + // 创建空目录 + string fileName = "empty.dir"; + string filePath = backupRootDirPath + fileName; + auto [bFatalError, ret] = BProcess::ExecuteCmd({"mkdir", filePath.c_str()}); + EXPECT_EQ(ret, 0); + // 创建用于存放解包文件的目录 + string unpackDirName = "unpack"; + string unpackDirPath = backupRootDirPath + unpackDirName; + tie(bFatalError, ret) = BProcess::ExecuteCmd({"mkdir", unpackDirPath.c_str()}); + EXPECT_EQ(ret, 0); + // 对空目录进行打包 + string tarballName = "empty.dir.tar"; + string tarballPath = backupRootDirPath + tarballName; + BTarballPosixTarball tarball(tarballPath); + tarball.Emplace(filePath); + tarball.Publish(); + // 对包文件进行解包 + tie(bFatalError, ret) = BProcess::ExecuteCmd({"tar", "-xvf", tarballPath.c_str(), "-C", unpackDirPath.c_str()}); + EXPECT_EQ(ret, 0); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-an exception occurred by BTarballPosixTarball."; + } + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-end b_tarball_posix_tarball_EmptyDir_0100"; +} + +/** + * @tc.number: SUB_backup_b_tarball_posix_tarball_SymbolicLink_0100 + * @tc.name: b_tarball_posix_tarball_SymbolicLink_0100 + * @tc.desc: 测试BTarballPosixTarball类打包软链接是否成功 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0378 + */ +HWTEST_F(BTarballPosixTarballTest, b_tarball_posix_tarball_SymbolicLink_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-begin b_tarball_posix_tarball_SymbolicLink_0100"; + try { + TestManager testManager("b_tarball_posix_tarball_SymbolicLink_0100"); + string backupRootDirPath = testManager.GetRootDirCurTest(); + // 创建普通文件(dd命令中bs设为1000是为了构造文件字节数不是512的整数倍的场景) + string fileName = "regular.file"; + string filePath = backupRootDirPath + fileName; + auto [bFatalError, ret] = + BProcess::ExecuteCmd({"dd", "if=/dev/urandom", ("of=" + filePath).c_str(), "bs=1000", "count=1"}); + EXPECT_EQ(ret, 0); + // 创建软链接 + string linkName = "symbolic.link"; + string linkPath = backupRootDirPath + linkName; + tie(bFatalError, ret) = BProcess::ExecuteCmd({"ln", "-s", filePath.c_str(), linkPath.c_str()}); + EXPECT_EQ(ret, 0); + // 创建用于存放解包文件的目录 + string unpackDirName = "unpack"; + string unpackDirPath = backupRootDirPath + unpackDirName; + tie(bFatalError, ret) = BProcess::ExecuteCmd({"mkdir", unpackDirPath.c_str()}); + EXPECT_EQ(ret, 0); + // 对普通文件进行打包 + string tarballName = "symbolic.link.tar"; + string tarballPath = backupRootDirPath + tarballName; + BTarballPosixTarball tarball(tarballPath); + tarball.Emplace(linkPath); + tarball.Publish(); + // 对包文件进行解包 + tie(bFatalError, ret) = BProcess::ExecuteCmd({"tar", "-xvf", tarballPath.c_str(), "-C", unpackDirPath.c_str()}); + EXPECT_EQ(ret, 0); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-an exception occurred by BTarballPosixTarball."; + } + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-end b_tarball_posix_tarball_SymbolicLink_0100"; +} + +/** + * @tc.number: SUB_backup_b_tarball_posix_tarball_SuperLongPathFile_0100 + * @tc.name: b_tarball_posix_tarball_SuperLongPathFile_0100 + * @tc.desc: + * 测试BTarballPosixTarball类打包超长路径名文件,由于tar工具采用GNU格式,而自研打包工具采用POSIX格式,故解包必定失败 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0378 + */ +HWTEST_F(BTarballPosixTarballTest, b_tarball_posix_tarball_SuperLongPathFile_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-begin b_tarball_posix_tarball_SuperLongPathFile_0100"; + try { + TestManager testManager("b_tarball_posix_tarball_SuperLongPathFile_0100"); + string backupRootDirPath = testManager.GetRootDirCurTest(); + // 文件路径长度超过99字节就属于长文件名文件 + string fileName = + "superLongPathSuperLongPathSuperLongPathSuperLongPathSuperLongPathSuperLongPathSuperLongPathSuperLongPath." + "file"; + string filePath = backupRootDirPath + fileName; + // 创建超长路径名文件(dd命令中bs设为1000是为了构造文件字节数不是512的整数倍的场景) + auto [bFatalError, ret] = + BProcess::ExecuteCmd({"dd", "if=/dev/urandom", ("of=" + filePath).c_str(), "bs=1000", "count=1"}); + EXPECT_EQ(ret, 0); + // 创建用于存放解包文件的目录 + string unpackDirName = "unpack"; + string unpackDirPath = backupRootDirPath + unpackDirName; + tie(bFatalError, ret) = BProcess::ExecuteCmd({"mkdir", unpackDirPath.c_str()}); + EXPECT_EQ(ret, 0); + // 对超长文件名文件进行打包 + string tarballName = "superLongPath.file.tar"; + string tarballPath = backupRootDirPath + tarballName; + BTarballPosixTarball tarball(tarballPath); + tarball.Emplace(filePath); + tarball.Publish(); + // 对包文件进行解包(由于tar工具不支持typeFlag='x'的场景,故解包会失败) + tie(bFatalError, ret) = BProcess::ExecuteCmd({"tar", "-xvf", tarballPath.c_str(), "-C", unpackDirPath.c_str()}); + EXPECT_NE(ret, 0); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-an exception occurred by BTarballPosixTarball."; + } + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-end b_tarball_posix_tarball_SuperLongPathFile_0100"; +} + +/** + * @tc.number: SUB_backup_b_tarball_posix_tarball_SuperLongSymbolicLink_0100 + * @tc.name: b_tarball_posix_tarball_SuperLongSymbolicLink_0100 + * @tc.desc: + * 测试BTarballPosixTarball类打包超长链接路径名软链接,由于tar工具采用GNU格式,而自研打包工具采用POSIX格式,故解包必定失败 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0378 + */ +HWTEST_F(BTarballPosixTarballTest, b_tarball_posix_tarball_SuperLongSymbolicLink_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-begin b_tarball_posix_tarball_SuperLongSymbolicLink_0100"; + try { + TestManager testManager("b_tarball_posix_tarball_SuperLongSymbolicLink_0100"); + string backupRootDirPath = testManager.GetRootDirCurTest(); + // 链接路径长度超过99字节就属于超长链接路径 + string fileName = + "superLongLinkSuperLongLinkSuperLongLinkSuperLongLinkSuperLongLinkSuperLongLinkSuperLongLinkSuperLongLink." + "file"; + string filePath = backupRootDirPath + fileName; + // 创建超长路径名文件(dd命令中bs设为1000是为了构造文件字节数不是512的整数倍的场景) + auto [bFatalError, ret] = + BProcess::ExecuteCmd({"dd", "if=/dev/urandom", ("of=" + filePath).c_str(), "bs=1000", "count=1"}); + EXPECT_EQ(ret, 0); + // 创建超长链接路径软链接 + string linkName = "superLongSymbolic.link"; + string linkPath = backupRootDirPath + linkName; + tie(bFatalError, ret) = BProcess::ExecuteCmd({"ln", "-s", filePath.c_str(), linkPath.c_str()}); + EXPECT_EQ(ret, 0); + // 创建用于存放解包文件的目录 + string unpackDirName = "unpack"; + string unpackDirPath = backupRootDirPath + unpackDirName; + tie(bFatalError, ret) = BProcess::ExecuteCmd({"mkdir", unpackDirPath.c_str()}); + EXPECT_EQ(ret, 0); + // 对超长链接路径软链接进行打包 + string tarballName = "superLongSymbolic.link.tar"; + string tarballPath = backupRootDirPath + tarballName; + BTarballPosixTarball tarball(tarballPath); + tarball.Emplace(linkPath); + tarball.Publish(); + // 对包文件进行解包(由于tar工具不支持typeFlag='x'的场景,故解包会失败) + tie(bFatalError, ret) = BProcess::ExecuteCmd({"tar", "-xvf", tarballPath.c_str(), "-C", unpackDirPath.c_str()}); + EXPECT_NE(ret, 0); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-an exception occurred by BTarballPosixTarball."; + } + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-end b_tarball_posix_tarball_SuperLongSymbolicLink_0100"; +} + +/** + * @tc.number: SUB_backup_b_tarball_posix_tarball_SuperLargeFile_0100 + * @tc.name: b_tarball_posix_tarball_SuperLargeFile_0100 + * @tc.desc: 测试BTarballPosixTarball类打包超大文件,由于tar工具采用GNU格式,而自研打包工具采用POSIX格式,故解包必定失败 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + * @tc.require: SR000H0378 + */ +HWTEST_F(BTarballPosixTarballTest, b_tarball_posix_tarball_SuperLargeFile_0100, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-begin b_tarball_posix_tarball_SuperLargeFile_0100"; + try { + TestManager testManager("b_tarball_posix_tarball_SuperLargeFile_0100"); + string backupRootDirPath = testManager.GetRootDirCurTest(); + // 创建超大文件(dd命令中count设为8200是为了构造文件字节数大于8589934591字节的场景,文件字节数超过该值属于超大文件) + string fileName = "superLarge.file"; + string filePath = backupRootDirPath + fileName; + auto [bFatalError, ret] = + BProcess::ExecuteCmd({"dd", "if=/dev/urandom", ("of=" + filePath).c_str(), "bs=1M", "count=8200"}); + EXPECT_EQ(ret, 0); + // 创建用于存放解包文件的目录 + string unpackDirName = "unpack"; + string unpackDirPath = backupRootDirPath + unpackDirName; + tie(bFatalError, ret) = BProcess::ExecuteCmd({"mkdir", unpackDirPath.c_str()}); + EXPECT_EQ(ret, 0); + // 对超大文件进行打包 + string tarballName = "superLarge.file.tar"; + string tarballPath = backupRootDirPath + tarballName; + BTarballPosixTarball tarball(tarballPath); + tarball.Emplace(filePath); + tarball.Publish(); + // 对包文件进行解包(由于tar工具不支持typeFlag='x'的场景,故解包会失败) + tie(bFatalError, ret) = BProcess::ExecuteCmd({"tar", "-xvf", tarballPath.c_str(), "-C", unpackDirPath.c_str()}); + EXPECT_NE(ret, 0); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-an exception occurred by BTarballPosixTarball."; + } + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-end b_tarball_posix_tarball_SuperLargeFile_0100"; +} + +/** + * @tc.number: SUB_backup_b_tarball_posix_tarball_EmplaceAndClear_0100 + * @tc.name: b_tarball_posix_tarball_EmplaceAndClear_0100 + * @tc.desc: 测试BTarballPosixTarball的Emplace接口和Clear接口能否正常使用 + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(BTarballPosixTarballTest, b_tarball_posix_tarball_EmplaceAndClear_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-begin b_tarball_posix_tarball_EmplaceAndClear_0100"; + try { + TestManager testManager("b_tarball_posix_tarball_EmplaceAndClear_0100"); + string backupRootDirPath = testManager.GetRootDirCurTest(); + // 指定包文件的名称和路径 + string pathTarball = backupRootDirPath + "test.tar"; + // 创建空文件 + string pathFile = backupRootDirPath + "empty.file"; + auto [bFatalErr, ret] = BProcess::ExecuteCmd({"touch", pathFile.c_str()}); + EXPECT_FALSE(bFatalErr); + EXPECT_EQ(ret, 0); + + BTarballPosixTarball tarball(pathTarball); + tarball.Publish(); + + tarball.Emplace(pathFile); + tarball.Publish(); + struct stat tarballStat = {}; + stat(pathTarball.c_str(), &tarballStat); + EXPECT_EQ(tarballStat.st_size, BConstants::HEADER_SIZE + BConstants::BLOCK_PADDING_SIZE); + + tarball.Clear(); + stat(pathTarball.c_str(), &tarballStat); + EXPECT_EQ(tarballStat.st_size, 0); + + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-Publish Branches"; + tarball.Publish(); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-an exception occurred by BTarballPosixTarball."; + } + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-end b_tarball_posix_tarball_EmplaceAndClear_0100"; +} + +/** + * @tc.number: SUB_backup_b_tarball_posix_tarball_TryToGetEntry_0100 + * @tc.name: b_tarball_posix_tarball_TryToGetEntry_0100 + * @tc.desc: 测试TryToGetEntry能否成功处理超长文件名场景并生成相应的entry + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + * @tc.require: SR000H0378 + */ +HWTEST_F(BTarballPosixTarballTest, b_tarball_posix_tarball_TryToGetEntry_0100, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-begin b_tarball_posix_tarball_TryToGetEntry_0100"; + try { + // 构造一个长度为992字节的文件名 + string pathName = + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + auto extEntryOptional = BTarballPosixExtendedEntry::TryToGetEntry(BConstants::SUPER_LONG_PATH, pathName, {}); + EXPECT_NE(extEntryOptional, nullopt); + // 长度为992字节的文件名对应entry的长度为1003("path"字段占4字节," =\n"占3字节,entry长度"1003"占4字节) + size_t entrySize = 1003; + EXPECT_EQ(extEntryOptional->GetEntrySize(), entrySize); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-an exception occurred by BTarballPosixTarball."; + } + GTEST_LOG_(INFO) << "BTarballPosixTarballTest-end b_tarball_posix_tarball_TryToGetEntry_0100"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tests/utils/BUILD.gn b/tests/utils/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..7dcf5cbd075196e3c06d35c59c573f9611963647 --- /dev/null +++ b/tests/utils/BUILD.gn @@ -0,0 +1,34 @@ +# 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. + +import("//build/ohos.gni") +import("//foundation/filemanagement/app_file_service/backup.gni") + +config("test_util_public_config") { + include_dirs = [ "include" ] +} + +ohos_static_library("backup_test_utils") { + testonly = true + + sources = [ "src/test_manager.cpp" ] + + public_configs = [ ":test_util_public_config" ] + + deps = [ "${path_backup}/utils:backup_utils" ] + public_deps = [ "${path_googletest}:gmock_main" ] + + use_exceptions = true + part_name = "app_file_service" + subsystem_name = "filemanagement" +} diff --git a/tests/utils/include/test_manager.h b/tests/utils/include/test_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..c5e675d9615dd7d043d499beebac806974b6ab64 --- /dev/null +++ b/tests/utils/include/test_manager.h @@ -0,0 +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 OHOS_FILEMGMT_BACKUP_TEST_MANAGER_H +#define OHOS_FILEMGMT_BACKUP_TEST_MANAGER_H + +#include + +namespace OHOS::FileManagement::Backup { +class TestManager { +public: + explicit TestManager(std::string functionName); + ~TestManager(); + + /** + * @brief 获取当前测试用例指定根目录 + * + * @return std::string 根目录 + */ + std::string GetRootDirCurTest() const; + +private: + std::string rootDirCurTest_; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_TEST_MANAGER_H diff --git a/tests/utils/src/test_manager.cpp b/tests/utils/src/test_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74518a6b7778c9c895ee7406d4b4aaa6d7795516 --- /dev/null +++ b/tests/utils/src/test_manager.cpp @@ -0,0 +1,42 @@ +/* + * 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 + +#include "directory_ex.h" +#include "test_manager.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +TestManager::TestManager(std::string functionName) +{ + rootDirCurTest_ = "/data/test/backup/" + functionName + "/"; + // REM:先删后创建 + if (bool created = ForceCreateDirectory(rootDirCurTest_); !created) { + throw std::system_error(errno, std::system_category()); + } +} + +TestManager::~TestManager() +{ + ForceRemoveDirectory(rootDirCurTest_); +} + +string TestManager::GetRootDirCurTest() const +{ + return rootDirCurTest_; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tools/backup_tool/BUILD.gn b/tools/backup_tool/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..162d5e6c16ed0113f6f060342a4265b84a0a935e --- /dev/null +++ b/tools/backup_tool/BUILD.gn @@ -0,0 +1,45 @@ +# 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. + +import("//build/ohos.gni") +import("//foundation/filemanagement/app_file_service/backup.gni") + +ohos_executable("backup_tool") { + sources = [ + "src/main.cpp", + "src/tools_op.cpp", + "src/tools_op_backup.cpp", + "src/tools_op_check_sa.cpp", + "src/tools_op_help.cpp", + "src/tools_op_restore.cpp", + ] + + defines = [ + "LOG_DOMAIN=0xD004304", + "LOG_TAG=\"BackupTool\"", + ] + + include_dirs = [ "include" ] + + external_deps = [ + "app_file_service:backup_kit_inner", + "hitrace_native:hitrace_meter", + ] + + deps = [ "${path_backup}/utils/:backup_utils" ] + + use_exceptions = true + install_enable = true + part_name = "app_file_service" + subsystem_name = "filemanagement" +} \ No newline at end of file diff --git a/tools/backup_tool/include/tools_op.h b/tools/backup_tool/include/tools_op.h new file mode 100644 index 0000000000000000000000000000000000000000..6e8002f21bfb7cfcf499f378989965239794893e --- /dev/null +++ b/tools/backup_tool/include/tools_op.h @@ -0,0 +1,121 @@ +/* + * 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_FILEMGMT_BACKUP_TOOLS_OP_H +#define OHOS_FILEMGMT_BACKUP_TOOLS_OP_H + +#include +#include +#include +#include +#include + +namespace OHOS::FileManagement::Backup { +class ToolsOp { +public: + using CRefVStrView = const std::vector &; + struct CmdInfo { + std::string paramName; + bool repeatable = false; + }; + + struct Descriptor { + // 命令名,必填 + std::vector opName; + // 参数,选填 + std::vector argList; + // 命令帮助语句,选填 + std::function funcGenHelpMsg; + // 命令执行主体,必填 + std::function> &args)> funcExec; + }; + + /** + * @brief 构造一个操作 + * + * @param desc 操作具体信息 + */ + explicit ToolsOp(Descriptor &&desc) : desc_(std::move(desc)) {} + + /** + * @brief 获取当前操作的名称。操作由多条字符串构成时,之间由空格隔开 + * + * @return const std::string 当前操作的名称 + */ + const std::string GetName() const; + + /** + * @brief 获取当前操作的参数 + * + * @return std::vector 当前参数的向量 + */ + const std::vector GetParams() const + { + return desc_.argList; + } + + /** + * @brief 获取当前操作的原始具体信息 + * + * @return const Descriptor& 当前操作的原始具体信息 + */ + const Descriptor &GetDescriptor() const + { + return desc_; + } + + /** + * @brief 获取所有操作 + * + * @return const std::vector& 所有操作 + */ + static const std::vector &GetAllOperations() + { + return ToolsOp::opsAvailable_; + } + + /** + * @brief 注册一个操作 + * + * @param op 操作 + * @return true 注册成功 + * @return false 注册失败 + */ + static bool Register(ToolsOp &&op); + + /** + * @brief 将当前操作与主函数给定的操作相匹配(大小写敏感) + * + * @param op 给定操作 + * @return true 匹配成功 + * @return false 匹配失败 + */ + bool TryMatch(CRefVStrView op) const; + + /** + * @brief 使用主函数给定的参数表执行当前操作 + * + * @param args 给定参数表 + * @return int 错误码(0 表示成功,非零表示失败) + */ + int Execute(std::map> mapArg) const; + +private: + Descriptor desc_; + static inline std::vector opsAvailable_; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_TOOLS_OP_H \ No newline at end of file diff --git a/tools/backup_tool/src/main.cpp b/tools/backup_tool/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cff28e2528faa8b893d6fc119cd1ab7b4b68adba --- /dev/null +++ b/tools/backup_tool/src/main.cpp @@ -0,0 +1,99 @@ +/* + * 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 "errors.h" +#include "tools_op.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace OHOS::FileManagement::Backup { +using namespace std; + +optional>> GetArgsMap(int argc, char *const argv[], const vector &argList) +{ + int i = 0; + map mapOptToName; + vector vecLongOptions; + for (auto &&arg : argList) { + mapOptToName[i] = arg.paramName; + vecLongOptions.emplace_back(option { + .name = arg.paramName.c_str(), + .has_arg = required_argument, + .flag = nullptr, + .val = i++, + }); + } + vecLongOptions.emplace_back(option {nullptr, 0, nullptr, 0}); + + int opt = 0; + int options_index = 0; + map> mapArgToVals; + while ((opt = getopt_long(argc, argv, "", vecLongOptions.data(), &options_index)) != -1) { + if (opt == '?') { + // "我们匹配到了一个奇怪的命令 返回 nullopt,getopt_long 在opterr 未被赋值0时 会自动打印未被定义参数到终端" + return nullopt; + } + string argName = mapOptToName[opt]; + if (mapArgToVals.find(argName) != mapArgToVals.end() && argList[opt].repeatable == true) { + mapArgToVals[argName].emplace_back(optarg); + } else if (mapArgToVals.find(argName) != mapArgToVals.end()) { + fprintf(stderr, "%s can only be entered once, but you repeat it.\n", argName.c_str()); + return nullopt; + } else { + mapArgToVals.emplace(argName, vector {optarg}); + } + } + return mapArgToVals; +} + +int ParseOpAndExecute(int argc, char *const argv[]) +{ + int flag = -1; + for (int i = 1; i < argc; i++) { + // 暂存 {argv[1]...argv[i]}; + vector curOp; + for (int j = 1; j <= i; ++j) { + curOp.emplace_back(argv[j]); + } + + // 尝试匹配当前命令,成功后执行 + auto tryOpSucceed = [&curOp](const ToolsOp &op) { return op.TryMatch(curOp); }; + auto &&opeartions = ToolsOp::GetAllOperations(); + auto matchedOp = find_if(opeartions.begin(), opeartions.end(), tryOpSucceed); + if (matchedOp != opeartions.end()) { + vector argList = matchedOp->GetParams(); + optional>> mapNameToArgs = GetArgsMap(argc, argv, argList); + if (mapNameToArgs.has_value()) { + flag = matchedOp->Execute(mapNameToArgs.value()); + } + } + } + if (flag != 0) { + printf("backup_tool: missing operand\nTry 'backup_tool help' for more information.\n"); + } + return flag; +} +} // namespace OHOS::FileManagement::Backup + +int main(int argc, char *const argv[]) +{ + return OHOS::FileManagement::Backup::ParseOpAndExecute(argc, argv); +} \ No newline at end of file diff --git a/tools/backup_tool/src/tools_op.cpp b/tools/backup_tool/src/tools_op.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3bb59d4c1d7bfb65e5634a8bf6ff558ae36e23cf --- /dev/null +++ b/tools/backup_tool/src/tools_op.cpp @@ -0,0 +1,87 @@ +/* + * 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 "tools_op.h" + +#include +#include + +namespace OHOS::FileManagement::Backup { +using namespace std; + +const std::string ToolsOp::GetName() const +{ + std::stringstream ss; + + auto &&allSubOps = desc_.opName; + for (size_t j = 0; j < allSubOps.size(); ++j) { + ss << allSubOps[j]; + if (j != allSubOps.size() - 1) { + ss << ' '; + } + } + + return ss.str(); +} + +bool ToolsOp::Register(ToolsOp &&op) +{ + auto &&opName = op.GetDescriptor().opName; + auto isIncorrect = [&opName](const std::string_view &subOp) { + std::vector patterns { + "\\W", // 匹配任意不是字母、数字、下划线的字符 + "^$", // 匹配空串 + }; + + for (auto subOp : opName) { + for (auto pattern : patterns) { + std::regex re(pattern); + if (std::regex_search(string(subOp), re)) { + fprintf(stderr, "Sub-op '%s' failed to pass regex '%s'\n", subOp.data(), pattern.c_str()); + return true; + } + } + } + + return false; + }; + if (std::any_of(opName.begin(), opName.end(), isIncorrect)) { + fprintf(stderr, "Failed to register an illegal operation '%s'\n", op.GetName().c_str()); + return false; + } + + ToolsOp::opsAvailable_.emplace_back(std::move(op)); + + // sort with ascending order + std::sort(opsAvailable_.begin(), opsAvailable_.end(), [](const ToolsOp &lop, const ToolsOp &rop) { + return lop.desc_.opName < rop.desc_.opName; + }); + return true; +} + +bool ToolsOp::TryMatch(CRefVStrView op) const +{ + return op == desc_.opName; +} + +int ToolsOp::Execute(map> args) const +{ + if (!desc_.funcExec) { + fprintf(stderr, "Incomplete operation: executor is missing\n"); + return -EPERM; + } + return desc_.funcExec(args); +} +} // namespace OHOS::FileManagement::Backup diff --git a/tools/backup_tool/src/tools_op_backup.cpp b/tools/backup_tool/src/tools_op_backup.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7bb49f9e71c3fe20e1c69ef0e474247ecb41b23e --- /dev/null +++ b/tools/backup_tool/src/tools_op_backup.cpp @@ -0,0 +1,289 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "b_error/b_error.h" +#include "b_filesystem/b_file.h" +#include "b_json/b_json_entity_ext_manage.h" +#include "b_resources/b_constants.h" +#include "backup_kit_inner.h" +#include "base/hiviewdfx/hitrace/interfaces/native/innerkits/include/hitrace_meter/hitrace_meter.h" +#include "service_proxy.h" +#include "tools_op.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +class Session { +public: + void UpdateBundleReceivedFiles(const BundleName &bundleName, const string &fileName) + { + lock_guard lk(lock_); + bundleStatusMap_[bundleName].receivedFile.insert(fileName); + TryClearBundleOfMap(bundleName); + } + + void SetIndexFiles(const BundleName &bundleName, UniqueFd fd) + { + BJsonCachedEntity cachedEntity(move(fd)); + auto cache = cachedEntity.Structuralize(); + lock_guard lk(lock_); + bundleStatusMap_[bundleName].indexFile = cache.GetExtManage(); + } + + void TryNotify(bool flag = false) + { + if (flag == true) { + ready_ = true; + cv_.notify_all(); + } else if (bundleStatusMap_.size() == 0 && cnt_ == 0) { + ready_ = true; + cv_.notify_all(); + } + } + + void UpdateBundleFinishedCount() + { + lock_guard lk(lock_); + cnt_--; + } + + void SetBundleFinishedCount(uint32_t cnt) + { + cnt_ = cnt; + } + + void Wait() + { + unique_lock lk(lock_); + cv_.wait(lk, [&] { return ready_; }); + } + + unique_ptr session_ = {}; + +private: + struct BundleStatus { + set receivedFile; + set indexFile; + }; + + void TryClearBundleOfMap(const BundleName &bundleName) + { + if (bundleStatusMap_[bundleName].indexFile == bundleStatusMap_[bundleName].receivedFile) { + bundleStatusMap_.erase(bundleName); + } + } + + map bundleStatusMap_; + mutable condition_variable cv_; + mutex lock_; + bool ready_ = false; + uint32_t cnt_ {0}; +}; + +static string GenHelpMsg() +{ + return "\t\tThis operation helps to backup application data.\n" + "\t\t--isLocal\t\t This parameter should be true or flase; true: local backup false: others.\n" + "\t\t--pathCapFile\t\t This parameter should be the path of the capability file.\n" + "\t\t--bundle\t\t This parameter is bundleName."; +} + +static void OnFileReady(shared_ptr ctx, const BFileInfo &fileInfo, UniqueFd fd) +{ + printf("FileReady owner = %s, fileName = %s, sn = %u, fd = %d\n", fileInfo.owner.c_str(), fileInfo.fileName.c_str(), + fileInfo.sn, fd.Get()); + string tmpPath = string(BConstants::BACKUP_TOOL_RECEIVE_DIR) + fileInfo.owner; + if (access(tmpPath.data(), F_OK) != 0 && mkdir(tmpPath.data(), S_IRWXU) != 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + if (!regex_match(fileInfo.fileName, regex("^[0-9a-zA-Z_.]+$"))) { + throw BError(BError::Codes::TOOL_INVAL_ARG, "Filename is not alphanumeric"); + } + UniqueFd fdLocal(open((tmpPath + "/" + fileInfo.fileName).data(), O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU)); + if (fdLocal < 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + BFile::SendFile(fdLocal, fd); + if (fileInfo.fileName == BConstants::EXT_BACKUP_MANAGE) { + ctx->SetIndexFiles(fileInfo.owner, move(fd)); + } else { + ctx->UpdateBundleReceivedFiles(fileInfo.owner, fileInfo.fileName); + } + ctx->TryNotify(); +} + +static void OnBundleStarted(shared_ptr ctx, ErrCode err, const BundleName name) +{ + printf("BundleStarted errCode = %d, BundleName = %s\n", err, name.c_str()); + if (err != 0) { + ctx->UpdateBundleFinishedCount(); + ctx->TryNotify(); + } +} + +static void OnBundleFinished(shared_ptr ctx, ErrCode err, const BundleName name) +{ + printf("BundleFinished errCode = %d, BundleName = %s\n", err, name.c_str()); + ctx->UpdateBundleFinishedCount(); + ctx->TryNotify(); +} + +static void OnAllBundlesFinished(shared_ptr ctx, ErrCode err) +{ + if (err == 0) { + printf("backup successful\n"); + } else { + printf("Failed to Unplanned Abort error: %d\n", err); + ctx->TryNotify(true); + return; + } + ctx->TryNotify(); +} + +static void OnBackupServiceDied(shared_ptr ctx) +{ + printf("backupServiceDied\n"); + ctx->TryNotify(true); +} + +static void BackupToolDirSoftlinkToBackupDir() +{ + // 判断BConstants::BACKUP_TOOL_LINK_DIR 是否是软链接 + if (access(BConstants::BACKUP_TOOL_LINK_DIR.data(), F_OK) == 0) { + struct stat inStat = {}; + if (lstat(BConstants::BACKUP_TOOL_LINK_DIR.data(), &inStat) == -1) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + + if ((inStat.st_mode & S_IFMT) == S_IFLNK) { + return; + } + // 非软连接删除重新创建 + if (!ForceRemoveDirectory(BConstants::BACKUP_TOOL_LINK_DIR.data())) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + } + + if (access(BConstants::SA_BUNDLE_BACKUP_TOOL_DIR.data(), F_OK) != 0 && + mkdir(BConstants::SA_BUNDLE_BACKUP_TOOL_DIR.data(), S_IRWXU) != 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + if (symlink(BConstants::SA_BUNDLE_BACKUP_TOOL_DIR.data(), BConstants::BACKUP_TOOL_LINK_DIR.data()) == -1) { + HILOGE("failed to create soft link file %{public}s errno : %{public}d", + BConstants::BACKUP_TOOL_LINK_DIR.data(), errno); + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } +} + +static int32_t InitPathCapFile(const string &isLocal, const string &pathCapFile, vector bundleNames) +{ + StartTrace(HITRACE_TAG_FILEMANAGEMENT, "InitPathCapFile"); + // SELinux backup_tool工具/data/文件夹下创建文件夹 SA服务因root用户的自定义标签无写入权限 此处调整为软链接形式 + BackupToolDirSoftlinkToBackupDir(); + + UniqueFd fd(open(pathCapFile.data(), O_RDWR | O_CREAT, S_IRWXU)); + if (fd < 0) { + fprintf(stderr, "Failed to open file error: %d %s\n", errno, strerror(errno)); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return -errno; + } + if (isLocal == "true") { + auto proxy = ServiceProxy::GetInstance(); + if (!proxy) { + fprintf(stderr, "Get an empty backup sa proxy\n"); + return -EFAULT; + } + BFile::SendFile(fd, proxy->GetLocalCapabilities()); + } + + if (access((BConstants::BACKUP_TOOL_RECEIVE_DIR).data(), F_OK) != 0 && + mkdir((BConstants::BACKUP_TOOL_RECEIVE_DIR).data(), S_IRWXU) != 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + auto ctx = make_shared(); + ctx->session_ = BSessionBackup::Init( + move(fd), bundleNames, + BSessionBackup::Callbacks {.onFileReady = bind(OnFileReady, ctx, placeholders::_1, placeholders::_2), + .onBundleStarted = bind(OnBundleStarted, ctx, placeholders::_1, placeholders::_2), + .onBundleFinished = bind(OnBundleFinished, ctx, placeholders::_1, placeholders::_2), + .onAllBundlesFinished = bind(OnAllBundlesFinished, ctx, placeholders::_1), + .onBackupServiceDied = bind(OnBackupServiceDied, ctx)}); + if (ctx->session_ == nullptr) { + printf("Failed to init backup"); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return -EPERM; + } + ctx->SetBundleFinishedCount(bundleNames.size()); + int ret = ctx->session_->Start(); + if (ret != 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, "backup start error"); + } + ctx->Wait(); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return 0; +} + +static int Exec(map> &mapArgToVal) +{ + if (mapArgToVal.find("pathCapFile") == mapArgToVal.end() || mapArgToVal.find("bundles") == mapArgToVal.end() || + mapArgToVal.find("isLocal") == mapArgToVal.end()) { + return -EPERM; + } + return InitPathCapFile(*(mapArgToVal["isLocal"].begin()), *(mapArgToVal["pathCapFile"].begin()), + mapArgToVal["bundles"]); +} + +/** + * @brief The hack behind is that "variable with static storage duration has initialization or a destructor with side + * effects; it shall not be eliminated even if it appears to be unused" -- point 2.[basic.stc.static].c++ draft + * + */ +static bool g_autoRegHack = ToolsOp::Register(ToolsOp {ToolsOp::Descriptor { + .opName = {"backup"}, + .argList = {{ + .paramName = "pathCapFile", + .repeatable = false, + }, + { + .paramName = "bundles", + .repeatable = true, + }, + { + .paramName = "isLocal", + .repeatable = false, + }}, + .funcGenHelpMsg = GenHelpMsg, + .funcExec = Exec, +}}); +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tools/backup_tool/src/tools_op_check_sa.cpp b/tools/backup_tool/src/tools_op_check_sa.cpp new file mode 100644 index 0000000000000000000000000000000000000000..58f25a851f5ac7a034a85e56a51222667ebab5c6 --- /dev/null +++ b/tools/backup_tool/src/tools_op_check_sa.cpp @@ -0,0 +1,53 @@ +/* + * 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 +#include + +#include "errors.h" +#include "service_proxy.h" +#include "tools_op.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +static string GenHelpMsg() +{ + return "\tThis operation helps to check if the backup sa is available."; +} + +static int Exec(map> &mapArgToVal) +{ + auto proxy = ServiceProxy::GetInstance(); + if (!proxy) { + fprintf(stderr, "Get an empty backup sa proxy\n"); + return -EFAULT; + } + + printf("successful\n"); + return 0; +} + +/** + * @brief The hack behind is that "variable with static storage duration has initialization or a destructor with side + * effects; it shall not be eliminated even if it appears to be unused" -- point 2.[basic.stc.static].c++ draft + * + */ +static bool g_autoRegHack = ToolsOp::Register(ToolsOp {ToolsOp::Descriptor { + .opName = {"check", "sa"}, + .funcGenHelpMsg = GenHelpMsg, + .funcExec = Exec, +}}); +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tools/backup_tool/src/tools_op_help.cpp b/tools/backup_tool/src/tools_op_help.cpp new file mode 100644 index 0000000000000000000000000000000000000000..500918144bb1c2fd85a62a286dbff78e22441eea --- /dev/null +++ b/tools/backup_tool/src/tools_op_help.cpp @@ -0,0 +1,62 @@ +/* + * 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 +#include + +#include "tools_op.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +static string GenHelpMsg() +{ + return "\t\tThis operation helps to dump the help messages."; +} + +static int Exec(map> &mapArgToVal) +{ + stringstream ss; + auto &&allOps = ToolsOp::GetAllOperations(); + ss << "Usage: backup_tool [OPTION]... [ARG]..." << endl; + for (size_t i = 0; i < allOps.size(); ++i) { + auto desc = allOps[i].GetDescriptor(); + + // echo: \n + ss << allOps[i].GetName(); + + // echo: help msgs\n\n + if (desc.funcGenHelpMsg) { + ss << desc.funcGenHelpMsg() << endl; + } + if (i != allOps.size() - 1) { + ss << endl; + } + } + printf("%s", ss.str().c_str()); + return 0; +} + +/** + * @brief The hack behind is that "variable with static storage duration has initialization or a destructor with side + * effects; it shall not be eliminated even if it appears to be unused" -- point 2.[basic.stc.static].c++ draft + * + */ +static bool g_autoRegHack = ToolsOp::Register(ToolsOp {ToolsOp::Descriptor { + .opName = {"help"}, + .funcGenHelpMsg = GenHelpMsg, + .funcExec = Exec, +}}); +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/tools/backup_tool/src/tools_op_restore.cpp b/tools/backup_tool/src/tools_op_restore.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e521bae4bf0902f3fe93531b9f7e5a47a6e5caf1 --- /dev/null +++ b/tools/backup_tool/src/tools_op_restore.cpp @@ -0,0 +1,291 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "b_filesystem/b_dir.h" +#include "b_filesystem/b_file.h" +#include "b_json/b_json_entity_ext_manage.h" +#include "b_resources/b_constants.h" +#include "backup_kit_inner.h" +#include "base/hiviewdfx/hitrace/interfaces/native/innerkits/include/hitrace_meter/hitrace_meter.h" +#include "errors.h" +#include "service_proxy.h" +#include "tools_op.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +class Session { +public: + void UpdateBundleSendFiles(const BundleName &bundleName, const string &fileName) + { + lock_guard lk(lock_); + bundleStatusMap_[bundleName].sendFile.insert(fileName); + } + + void UpdateBundleSentFiles(const BundleName &bundleName, const string &fileName) + { + lock_guard lk(lock_); + bundleStatusMap_[bundleName].sentFile.insert(fileName); + TryClearBundleOfMap(bundleName); + } + + void ClearBundleOfMap(const BundleName &bundleName) + { + lock_guard lk(lock_); + bundleStatusMap_.erase(bundleName); + } + + void TryNotify(bool flag = false) + { + if (flag == true) { + ready_ = true; + cv_.notify_all(); + } else if (bundleStatusMap_.size() == 0 && cnt_ == 0) { + ready_ = true; + cv_.notify_all(); + } + } + + void UpdateBundleFinishedCount() + { + lock_guard lk(lock_); + cnt_--; + } + + void SetBundleFinishedCount(uint32_t cnt) + { + cnt_ = cnt; + } + + void Wait() + { + unique_lock lk(lock_); + cv_.wait(lk, [&] { return ready_; }); + } + + unique_ptr session_ = {}; + +private: + struct BundleStatus { + set sendFile; + set sentFile; + }; + + void TryClearBundleOfMap(const BundleName &bundleName) + { + if (bundleStatusMap_[bundleName].sendFile == bundleStatusMap_[bundleName].sentFile) { + bundleStatusMap_.erase(bundleName); + } + } + + map bundleStatusMap_; + mutable condition_variable cv_; + mutex lock_; + bool ready_ = false; + uint32_t cnt_ {0}; +}; + +static string GenHelpMsg() +{ + return "\t\tThis operation helps to restore application data.\n" + "\t\t--pathCapFile\t\t This parameter should be the path of the capability file.\n" + "\t\t--bundle\t\t This parameter is bundleName."; +} + +static void OnFileReady(shared_ptr ctx, const BFileInfo &fileInfo, UniqueFd fd) +{ + printf("FileReady owner = %s, fileName = %s, sn = %u, fd = %d\n", fileInfo.owner.c_str(), fileInfo.fileName.c_str(), + fileInfo.sn, fd.Get()); + if (!regex_match(fileInfo.fileName, regex("^[0-9a-zA-Z_.]+$"))) { + throw BError(BError::Codes::TOOL_INVAL_ARG, "Filename is not alphanumeric"); + } + string tmpPath = string(BConstants::BACKUP_TOOL_RECEIVE_DIR) + fileInfo.owner + "/" + fileInfo.fileName; + if (access(tmpPath.data(), F_OK) != 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + UniqueFd fdLocal(open(tmpPath.data(), O_RDONLY)); + if (fdLocal < 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + BFile::SendFile(fd, fdLocal); + int ret = ctx->session_->PublishFile(fileInfo); + if (ret != 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, "PublishFile error"); + } + ctx->UpdateBundleSentFiles(fileInfo.owner, fileInfo.fileName); + ctx->TryNotify(); +} + +static void OnBundleStarted(shared_ptr ctx, ErrCode err, const BundleName name) +{ + printf("BundleStarted errCode = %d, BundleName = %s\n", err, name.c_str()); + if (err != 0) { + ctx->UpdateBundleFinishedCount(); + ctx->ClearBundleOfMap(name); + ctx->TryNotify(); + } +} + +static void OnBundleFinished(shared_ptr ctx, ErrCode err, const BundleName name) +{ + printf("BundleFinished errCode = %d, BundleName = %s\n", err, name.c_str()); + ctx->UpdateBundleFinishedCount(); + if (err != 0) { + ctx->ClearBundleOfMap(name); + } + ctx->TryNotify(); +} + +static void OnAllBundlesFinished(ErrCode err) +{ + if (err == 0) { + printf("Restore successful\n"); + } else { + printf("Failed to Unplanned Abort error: %d\n", err); + } +} + +static void OnBackupServiceDied(shared_ptr ctx) +{ + printf("backupServiceDied\n"); + ctx->TryNotify(true); +} + +static void RestoreApp(shared_ptr restore, vector &bundleNames) +{ + StartTrace(HITRACE_TAG_FILEMANAGEMENT, "RestoreApp"); + if (!restore || !restore->session_) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + for (auto &bundleName : bundleNames) { + if (!regex_match(bundleName, regex("^[0-9a-zA-Z_.]+$"))) { + throw BError(BError::Codes::TOOL_INVAL_ARG, "bundleName is not alphanumeric"); + } + string path = string(BConstants::BACKUP_TOOL_RECEIVE_DIR) + bundleName; + if (access(path.data(), F_OK) != 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, generic_category().message(errno)); + } + const auto [err, filePaths] = BDir::GetDirFiles(path); + if (err != 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, "error path"); + } + for (auto &filePath : filePaths) { + string fileName = filePath.substr(filePath.rfind("/") + 1); + restore->session_->GetExtFileName(bundleName, fileName); + restore->UpdateBundleSendFiles(bundleName, fileName); + } + } + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); +} + +static int32_t Init(const string &pathCapFile, vector bundleNames) +{ + StartTrace(HITRACE_TAG_FILEMANAGEMENT, "Init"); + auto ctx = make_shared(); + ctx->session_ = BSessionRestore::Init( + bundleNames, + BSessionRestore::Callbacks {.onFileReady = bind(OnFileReady, ctx, placeholders::_1, placeholders::_2), + .onBundleStarted = bind(OnBundleStarted, ctx, placeholders::_1, placeholders::_2), + .onBundleFinished = bind(OnBundleFinished, ctx, placeholders::_1, placeholders::_2), + .onAllBundlesFinished = OnAllBundlesFinished, + .onBackupServiceDied = bind(OnBackupServiceDied, ctx)}); + if (ctx->session_ == nullptr) { + printf("Failed to init restore"); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return -EPERM; + } + UniqueFd fdRemote(ctx->session_->GetLocalCapabilities()); + if (fdRemote < 0) { + printf("Failed to receive fd"); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return fdRemote; + } + if (lseek(fdRemote, 0, SEEK_SET) == -1) { + fprintf(stderr, "Failed to lseek. error: %d %s\n", errno, strerror(errno)); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return -errno; + } + struct stat stat = {}; + if (fstat(fdRemote, &stat) == -1) { + fprintf(stderr, "Failed to fstat. error: %d %s\n", errno, strerror(errno)); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return -errno; + } + UniqueFd fdLocal(open(pathCapFile.data(), O_WRONLY | O_CREAT, S_IRWXU)); + if (fdLocal < 0) { + fprintf(stderr, "Failed to open file. error: %d %s\n", errno, strerror(errno)); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return -errno; + } + if (sendfile(fdLocal, fdRemote, nullptr, stat.st_size) == -1) { + fprintf(stderr, "Failed to Copy file. error: %d %s\n", errno, strerror(errno)); + FinishTrace(HITRACE_TAG_FILEMANAGEMENT); + return -errno; + } + ctx->SetBundleFinishedCount(bundleNames.size()); + RestoreApp(ctx, bundleNames); + int ret = ctx->session_->Start(); + if (ret != 0) { + throw BError(BError::Codes::TOOL_INVAL_ARG, "restore start error"); + } + ctx->Wait(); + return 0; +} + +static int Exec(map> &mapArgToVal) +{ + if (mapArgToVal.find("pathCapFile") == mapArgToVal.end() || mapArgToVal.find("bundles") == mapArgToVal.end()) { + return -EPERM; + } + return Init(*(mapArgToVal["pathCapFile"].begin()), mapArgToVal["bundles"]); +} + +/** + * @brief The hack behind is that "variable with static storage duration has initialization or a destructor with side + * effects; it shall not be eliminated even if it appears to be unused" -- point 2.[basic.stc.static].c++ draft + * + */ +static bool g_autoRegHack = ToolsOp::Register(ToolsOp {ToolsOp::Descriptor { + .opName = {"restore"}, + .argList = {{ + .paramName = "pathCapFile", + .repeatable = false, + }, + { + .paramName = "bundles", + .repeatable = true, + }}, + .funcGenHelpMsg = GenHelpMsg, + .funcExec = Exec, +}}); +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/BUILD.gn b/utils/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..15597656a1731c5e10049655e6451eb9d65b73a4 --- /dev/null +++ b/utils/BUILD.gn @@ -0,0 +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. + +import("//build/ohos.gni") +import("//foundation/filemanagement/app_file_service/backup.gni") + +config("utils_private_config") { + defines = [ + "LOG_DOMAIN=0xD004305", + "LOG_TAG=\"BackupUtils\"", + ] +} + +config("utils_public_config") { + include_dirs = [ + "include", + "${path_base}/include", + ] +} + +ohos_shared_library("backup_utils") { + sources = [ + "src/b_encryption/b_encryption.cpp", + "src/b_error/b_error.cpp", + "src/b_filesystem/b_dir.cpp", + "src/b_filesystem/b_file.cpp", + "src/b_json/b_json_entity_ext_manage.cpp", + "src/b_json/b_json_entity_extension_config.cpp", + "src/b_ohos/startup/backup_para.cpp", + "src/b_process/b_guard_cwd.cpp", + "src/b_process/b_guard_signal.cpp", + "src/b_process/b_process.cpp", + "src/b_tarball/b_tarball_cmdline.cpp", + "src/b_tarball/b_tarball_factory.cpp", + "src/b_tarball/b_tarball_posix/b_tarball_posix_extended_data.cpp", + "src/b_tarball/b_tarball_posix/b_tarball_posix_extended_entry.cpp", + "src/b_tarball/b_tarball_posix/b_tarball_posix_extended_header.cpp", + "src/b_tarball/b_tarball_posix/b_tarball_posix_file.cpp", + "src/b_tarball/b_tarball_posix/b_tarball_posix_file_data.cpp", + "src/b_tarball/b_tarball_posix/b_tarball_posix_pax_header.cpp", + "src/b_tarball/b_tarball_posix/b_tarball_posix_tarball.cpp", + ] + + configs = [ ":utils_private_config" ] + public_configs = [ ":utils_public_config" ] + + external_deps = [ "faultloggerd:lib_dfx_dump_catcher" ] + + public_deps = [ + "${path_base}:utils", + "${path_distributedfile}/utils/filemgmt_libhilog:filemgmt_libhilog", + "${path_jsoncpp}:jsoncpp", + ] + + include_dirs = [ + "${path_init}/interfaces/innerkits/include/syspara", + "${path_backup}/interfaces/inner_api/native/backup_kit_inner/impl", + ] + + deps = [ "${path_init}/interfaces/innerkits:libbegetutil" ] + + use_exceptions = true + part_name = "app_file_service" + subsystem_name = "filemanagement" +} diff --git a/utils/include/b_encryption/b_encryption.h b/utils/include/b_encryption/b_encryption.h new file mode 100644 index 0000000000000000000000000000000000000000..29241d081462b0b632742f850b84347aeb53696f --- /dev/null +++ b/utils/include/b_encryption/b_encryption.h @@ -0,0 +1,23 @@ +/* + * 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_FILEMGMT_BACKUP_B_ENCRYPTION_H +#define OHOS_FILEMGMT_BACKUP_B_ENCRYPTION_H + +namespace OHOS::FileManagement::Backup::BEncryption { +unsigned int CalculateChksum(const char *byteBlock, int blockSize); +} // namespace OHOS::FileManagement::Backup::BEncryption + +#endif // OHOS_FILEMGMT_BACKUP_B_ENCRYPTION_H \ No newline at end of file diff --git a/utils/include/b_error/b_error.h b/utils/include/b_error/b_error.h new file mode 100644 index 0000000000000000000000000000000000000000..a2856582d6a12328473da105810abec9111042c1 --- /dev/null +++ b/utils/include/b_error/b_error.h @@ -0,0 +1,226 @@ +/* + * 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. + */ + +/* + * 本部件处理错误的原则: + * 原则1:使用异常表示错误,但只有无法处理的问题才算得上是错误,否则只是普通的边界分支; + * 原则2:仅在模块内部使用异常,而在界面层Catch所有异常,从而防止异常扩散; + * 原则3:在注释里通过throw关键字注明可能抛出的异常,通报使用风险。 + */ +#ifndef OHOS_FILEMGMT_BACKUP_B_ERROR_H +#define OHOS_FILEMGMT_BACKUP_B_ERROR_H + +#include +#include +#include +#include +#include + +#include "errors.h" + +#if __has_builtin(__builtin_FILE) && __has_builtin(__builtin_LINE) && __has_builtin(__builtin_FUNCTION) +#define DEFINE_SOURCE_LOCATION \ + int lineNo = __builtin_LINE(), const char *fileName = __builtin_FILE(), \ + const char *functionName = __builtin_FUNCTION() +#else +#define DEFINE_SOURCE_LOCATION int lineNo = -1, const char *fileName = "NA", const char *functionName = "NA" +#endif + +namespace OHOS::FileManagement::Backup { +class BError : public std::exception { +public: + /** + * @brief 错误码,新增错误码时需要同步补充默认错误信息 + * + */ + enum class Codes : ErrCode { + // 0 无错误 + OK = 0x0, + + // 1~999 标准平台错误 + + // 0x1000~0x1999 backup_utils错误 + UTILS_INVAL_JSON_ENTITY = 0x1000, + UTILS_INVAL_FILE_HANDLE = 0x1001, + UTILS_INVAL_TARBALL_ARG = 0x1002, + UTILS_INVAL_PROCESS_ARG = 0x1003, + UTILS_INTERRUPTED_PROCESS = 0x1004, + + // 0x2000~0x2999 backup_tool错误 + TOOL_INVAL_ARG = 0x2000, + + // 0x3000~0x3999 backup_sa错误 + SA_INVAL_ARG = 0x3000, + SA_BROKEN_IPC = 0x3001, + SA_REFUSED_ACT = 0x3002, + SA_BROKEN_ROOT_DIR = 0x3003, + + // 0x4000~0x4999 backup_SDK错误 + SDK_INVAL_ARG = 0x4000, + SDK_BROKEN_IPC = 0x4001, + SDK_MIXED_SCENARIO = 0x4002, + + // 0x5000~0x5999 backup_ext错误 + EXT_INVAL_ARG = 0x5000, + EXT_BROKEN_FRAMEWORK = 0x5001, + EXT_BROKEN_BACKUP_SA = 0x5002, + EXT_BROKEN_IPC = 0x5003, + }; + +public: + /** + * @brief 返回OHOS标准错误码 + * + * @return int 标注错误码 + */ + int GetCode() const + { + if (code_ == Codes::OK) { + return 0; + } else { + return -1 * (static_cast(code_) | ErrCodeOffset(SUBSYS_FILEMANAGEMENT, codeSubsystem_)); + } + } + + /** + * @brief 返回原始错误码 + * + * @return Codes 原始错误码 + */ + Codes GetRawCode() const + { + return code_; + } + + /** + * @brief 返回错误信息 + * + * @return const char* 错误信息 + */ + const char *what() const noexcept override + { + return msg_.c_str(); + } + +public: + /** + * @brief 重载bool操作符,判断当前错误是否是错误 + * + * @return true 是错误 + * @return false 不是错误 + */ + explicit operator bool() const + { + return code_ != Codes::OK; + } + + /** + * @brief 返回OHOS标准错误码 + * + * @return int 标准错误码 + */ + operator int() const + { + return GetCode(); + } + +public: + /** + * @brief 构造错误对象 + * + * @param code 备份系统标准错误码,取自本类中的Codes + * @param lineNo 构造错误对象的行号(不要自己填写) + * @param fileName 构造错误对象的文件(不要自己填写) + * @param functionName 构造错误对象的函数(不要自己填写) + */ + explicit BError(Codes code = Codes::OK, DEFINE_SOURCE_LOCATION) : code_(code) + { + msg_ = WrapMessageWithExtraInfos(fileName, lineNo, functionName, code_, {mpErrToMsg_.at(code_)}); + } + + /** + * @brief 构造错误对象 + * + * @param code 备份系统标准错误码,取自本类中的Codes + * @param extraMsg 追加的详细错误信息 + * @param lineNo 构造错误对象的行号(不要自己填写) + * @param fileName 构造错误对象的文件(不要自己填写) + * @param functionName 构造错误对象的函数(不要自己填写) + */ + BError(Codes code, const std::string_view &extraMsg, DEFINE_SOURCE_LOCATION) : code_(code) + { + msg_ = WrapMessageWithExtraInfos(fileName, lineNo, functionName, code_, {mpErrToMsg_.at(code_), extraMsg}); + } + + /** + * @brief 构造错误对象 + * + * @param stdErrno 失败的LIBC调用通过errno返回的错误码 + * @param lineNo 构造错误对象的行号(不要自己填写) + * @param fileName 构造错误对象的文件(不要自己填写) + * @param functionName 构造错误对象的函数(不要自己填写) + */ + explicit BError(int stdErrno, DEFINE_SOURCE_LOCATION) : code_ {stdErrno} + { + std::string rawMsg = std::generic_category().message(stdErrno); + msg_ = WrapMessageWithExtraInfos(fileName, lineNo, functionName, code_, {rawMsg}); + } + +private: + static inline const std::map mpErrToMsg_ = { + {Codes::OK, "No error"}, + {Codes::UTILS_INVAL_JSON_ENTITY, "Json utils operated on an invalid file"}, + {Codes::UTILS_INVAL_FILE_HANDLE, "File utils received an invalid file handle"}, + {Codes::UTILS_INVAL_TARBALL_ARG, "Tarball utils received an invalid argument"}, + {Codes::UTILS_INVAL_PROCESS_ARG, "Process utils received an invalid argument"}, + {Codes::UTILS_INTERRUPTED_PROCESS, "Can't launch a process or the process was corrupted"}, + {Codes::TOOL_INVAL_ARG, "TOOL received invalid arguments"}, + {Codes::SA_INVAL_ARG, "SA received invalid arguments"}, + {Codes::SA_BROKEN_IPC, "SA failed to issue a IPC"}, + {Codes::SA_REFUSED_ACT, "SA refuse to act"}, + {Codes::SA_BROKEN_ROOT_DIR, "SA failed to operate on the given root dir"}, + {Codes::SDK_INVAL_ARG, "SDK received invalid arguments"}, + {Codes::SDK_BROKEN_IPC, "SDK failed to do IPC"}, + {Codes::SDK_MIXED_SCENARIO, "SDK involed backup/restore when doing the contrary"}, + {Codes::EXT_INVAL_ARG, "Extension received an invalid argument"}, + {Codes::EXT_BROKEN_FRAMEWORK, "Extension found the appex framework is broken"}, + {Codes::EXT_BROKEN_BACKUP_SA, "Extension found the backup SA died"}, + {Codes::EXT_BROKEN_IPC, "Extension failed to do IPC"}, + }; + +private: + const int codeSubsystem_ {1}; + Codes code_ {Codes::OK}; + std::string msg_; + +private: + /** + * @brief 生成如下格式的打印信息 → [文件名:行号->函数名] 默认错误信息. 补充错误信息 + * + * @param fileName 构造错误对象的文件 + * @param lineNo 构造错误对象的行号 + * @param functionName 构造错误对象的函数 + * @param msgs 所有待追加的错误信息 + * @return std::string 打印信息 + */ + std::string WrapMessageWithExtraInfos(const char *fileName, + int lineNo, + const char *functionName, + Codes code, + const std::vector &msgs) const; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_ERROR_H \ No newline at end of file diff --git a/utils/include/b_filesystem/b_dir.h b/utils/include/b_filesystem/b_dir.h new file mode 100644 index 0000000000000000000000000000000000000000..aac007c003f1d083a0ecd320571353656124b6dd --- /dev/null +++ b/utils/include/b_filesystem/b_dir.h @@ -0,0 +1,55 @@ +/* + * 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_FILEMGMT_BACKUP_B_DIR_H +#define OHOS_FILEMGMT_BACKUP_B_DIR_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "errors.h" + +namespace OHOS::FileManagement::Backup { +class BDir { +public: + /** + * @brief 读取指定目录下所有文件(非递归) + * + * @param 目录 + * @return 错误码、文件名数组 + */ + static std::tuple> GetDirFiles(const std::string &path); + + /** + * @brief 从给定的includes和excludes目录及文件中获取所有有用大文件和其链接文件的集合 + * + * @param includes 需要包含的文件及目录集合 + * @param excludes 需要排除的文件及目录集合 + * @return 错误码、大文件名集合 + */ + static std::pair> GetBigFiles(const std::vector &includes, + const std::vector &excludes); + +private: +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_DIR_H \ No newline at end of file diff --git a/utils/include/b_filesystem/b_file.h b/utils/include/b_filesystem/b_file.h new file mode 100644 index 0000000000000000000000000000000000000000..e817e5ca375b6c8f0384cf4d7c1b54537952cab2 --- /dev/null +++ b/utils/include/b_filesystem/b_file.h @@ -0,0 +1,68 @@ +/* + * 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_FILEMGMT_BACKUP_B_FILE_H +#define OHOS_FILEMGMT_BACKUP_B_FILE_H + +#include +#include + +#include "unique_fd.h" +#include "json/json.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +class BFile { +public: + /** + * @brief 一次性读取文件全部内容 + * + * @param fd 文件描述符 + * @return std::unique_ptr 文件全部内容,保证最后一个字节为'\0' + * @throw std::system_error IO异常 + */ + static std::unique_ptr ReadFile(const UniqueFd &fd); + + /** + * @brief linux sendfile 二次封装 + * @param outFd 参数是待写入内容的文件描述符 + * @param inFd 参数是待读出内容的文件描述符 + * @throw std::system_error IO异常 + */ + static void SendFile(int outFd, int inFd); + + /** + * @brief linux write 二次封装 + * @param fd 参数是待写入内容的文件描述符 + * @param str 待写入文件的字符串 + * @throw std::system_error IO异常 + */ + static void Write(const UniqueFd &fd, const string &str); + + /** + * @brief copy file from old path to new path + * + * @param from old path + * @param to new path + * @return true copy succeess + * @return false some error occur + */ + static bool CopyFile(const string &from, const string &to); + +private: +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_FILE_H \ No newline at end of file diff --git a/utils/include/b_json/b_json_cached_entity.h b/utils/include/b_json/b_json_cached_entity.h new file mode 100644 index 0000000000000000000000000000000000000000..7fe66669ac73d96f80ccfc75b8b2644885ce5fb7 --- /dev/null +++ b/utils/include/b_json/b_json_cached_entity.h @@ -0,0 +1,161 @@ +/* + * 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_FILEMGMT_BACKUP_B_JSON_CACHED_ENTITY_H +#define OHOS_FILEMGMT_BACKUP_B_JSON_CACHED_ENTITY_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "b_filesystem/b_file.h" +#include "b_json/b_json_entity.h" +#include "filemgmt_libhilog.h" +#include "unique_fd.h" +#include "json/json.h" + +namespace OHOS::FileManagement::Backup { +template +class BJsonCachedEntity { +public: + /** + * @brief 获取结构化对象 + * + * @return T 结构化对象(即实体) + */ + T Structuralize() + { + static_assert(!std::is_default_constructible_v); + static_assert(!std::is_base_of_v); + return T(obj_); + } + + /** + * @brief 持久化JSon对象并完成 + * + * @throw std::system_error IO异常 + */ + void Persist() + { + Json::StreamWriterBuilder builder; + const std::string jsonFileContent = Json::writeString(builder, obj_); + HILOGI("Try to persist a Json object, whose content reads: %{public}s", jsonFileContent.c_str()); + + BFile::Write(srcFile_, jsonFileContent); + } + + /** + * @brief 从文件中重新加载JSon对象 + * + * @throw std::system_error IO异常或解析异常 + */ + int ReloadFromFile() + { + Json::CharReaderBuilder builder; + std::unique_ptr const jsonReader(builder.newCharReader()); + Json::Value jValue; + std::string errs; + std::unique_ptr rawBuf = BFile::ReadFile(srcFile_); + std::string_view sv(rawBuf.get()); + + if (sv.empty()) { + HILOGI("This Json file is empty"); + return 0; + } + + bool res = jsonReader->parse(sv.data(), sv.data() + sv.length(), &jValue, &errs); + if (!res || !errs.empty()) { + return BError(BError::Codes::UTILS_INVAL_JSON_ENTITY, errs).GetCode(); + } + + obj_ = std::move(jValue); + return 0; + } + + /** + * @brief 根据字符串重新加载JSon对象 + * + * @throw std::system_error IO异常或解析异常 + */ + void ReloadFromString(std::string_view sv) + { + Json::CharReaderBuilder builder; + std::unique_ptr const jsonReader(builder.newCharReader()); + Json::Value jValue; + std::string errs; + + bool res = jsonReader->parse(sv.data(), sv.data() + sv.length(), &jValue, &errs); + if (!res || !errs.empty()) { + throw BError(BError::Codes::UTILS_INVAL_JSON_ENTITY, errs); + } + + obj_ = std::move(jValue); + } + + /** + * @brief 获取JSon文件的文件描述符 + * + * @return UniqueFd& + */ + UniqueFd &GetFd() + { + return srcFile_; + } + +public: + /** + * @brief 构造方法,要求T必须具备T(Json::Value&)构造函数 + * + * @param fd 用于加载/持久化JSon对象的文件 + */ + explicit BJsonCachedEntity(UniqueFd fd) : srcFile_(std::move(fd)), entity_(std::ref(obj_)) + { + struct stat stat = {}; + if (fstat(srcFile_, &stat) == -1) { + std::stringstream ss; + ss << std::generic_category().message(errno) << " with fd eq" << srcFile_.Get(); + BError(BError::Codes::UTILS_INVAL_JSON_ENTITY, ss.str()); + return; + } + + (void)ReloadFromFile(); + } + + /** + * @brief 构造方法,要求T必须具备T(Json::Value&, std::any)构造函数 + * + * @param sv 用于加载/持久化JSon对象的字符串 + * @param option 任意类型对象 + */ + explicit BJsonCachedEntity(std::string_view sv, std::any option = std::any()) : entity_(std::ref(obj_)) + { + ReloadFromString(entity_.GetJSonSource(sv, option)); + } + +private: + UniqueFd srcFile_; + Json::Value obj_; + T entity_; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_JSON_CACHED_ENTITY_H \ No newline at end of file diff --git a/utils/include/b_json/b_json_entity.h b/utils/include/b_json/b_json_entity.h new file mode 100644 index 0000000000000000000000000000000000000000..87d141a283d662942dd16cd42d9b9d42065a37e1 --- /dev/null +++ b/utils/include/b_json/b_json_entity.h @@ -0,0 +1,57 @@ +/* + * 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_FILEMGMT_BACKUP_B_JSON_ENTITY_H +#define OHOS_FILEMGMT_BACKUP_B_JSON_ENTITY_H + +#include +#include +#include + +#include "json/json.h" + +namespace OHOS::FileManagement::Backup { +class BJsonEntity { +public: + /** + * @brief 获取JSon数据源 + * + * @param jsonFromRealWorld 直接来自真实用户场景的配置文件(即,非override配置) + * @param option 任意类型对象 + * @return std::string 取决于具体情况的配置文件 + */ + std::string GetJSonSource(std::string_view jsonFromRealWorld, std::any option = std::any()) + { + return std::string(jsonFromRealWorld); + } + +public: + /** + * @brief 构造方法,具备T(Json::Value&, std::any)能力的构造函数 + * + * @param obj Json对象引用 + * @param option 任意类型对象 + */ + explicit BJsonEntity(Json::Value &obj, std::any option = std::any()) : obj_(obj), option_(option) {} + BJsonEntity() = delete; + virtual ~BJsonEntity() = default; + +protected: + Json::Value &obj_; + std::any option_; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_JSON_ENTITY_H \ No newline at end of file diff --git a/utils/include/b_json/b_json_entity_caps.h b/utils/include/b_json/b_json_entity_caps.h new file mode 100644 index 0000000000000000000000000000000000000000..3f81b222de191a4706a631f75ecaadabe337017c --- /dev/null +++ b/utils/include/b_json/b_json_entity_caps.h @@ -0,0 +1,87 @@ +/* + * 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_FILEMGMT_BACKUP_B_JSON_ENTITY_CAPS_H +#define OHOS_FILEMGMT_BACKUP_B_JSON_ENTITY_CAPS_H + +#include "b_json/b_json_cached_entity.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::Backup { +class BJsonEntityCaps : public BJsonEntity { +public: + uint64_t GetFreeDiskSpace() + { + if (!obj_ || !obj_.isMember("freeDiskSpace") || !obj_["freeDiskSpace"].isUInt64()) { + HILOGE("Failed to init field FreeDiskSpace"); + return 0; + } + + return obj_["freeDiskSpace"].asUInt64(); + } + + void SetFreeDiskSpace(uint64_t freeDiskSpace) + { + obj_["freeDiskSpace"] = freeDiskSpace; + } + + void SetOSFullName(std::string osFullName) + { + obj_["OSFullName"] = osFullName; + } + + void SetDeviceType(std::string deviceType) + { + obj_["deviceType"] = deviceType; + } + + std::string GetOSFullName() + { + if (!obj_ || !obj_.isMember("OSFullName") || !obj_["OSFullName"].isString()) { + HILOGE("Failed to get field OSFullName"); + return ""; + } + + return obj_["OSFullName"].asString(); + } + + std::string GetDeviceType() + { + if (!obj_ || !obj_.isMember("deviceType") || !obj_["deviceType"].isString()) { + HILOGE("Failed to get field deviceType"); + return ""; + } + + return obj_["deviceType"].asString(); + } + +public: + /** + * @brief 构造方法,具备T(Json::Value&, std::any)能力的构造函数 + * + * @param obj Json对象引用 + * @param option 任意类型对象 + */ + explicit BJsonEntityCaps(Json::Value &obj, std::any option = std::any()) : BJsonEntity(obj, option) + { + SetFreeDiskSpace(GetFreeDiskSpace()); + } + + BJsonEntityCaps() = delete; + ~BJsonEntityCaps() override = default; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_JSON_ENTITY_CAPS_H \ No newline at end of file diff --git a/utils/include/b_json/b_json_entity_ext_manage.h b/utils/include/b_json/b_json_entity_ext_manage.h new file mode 100644 index 0000000000000000000000000000000000000000..7fa7ab9ad39d238dabd3e9a4ebd8a22966a42233 --- /dev/null +++ b/utils/include/b_json/b_json_entity_ext_manage.h @@ -0,0 +1,80 @@ +/* + * 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_FILEMGMT_BACKUP_B_JSON_ENTITY_EXT_MANAGE_H +#define OHOS_FILEMGMT_BACKUP_B_JSON_ENTITY_EXT_MANAGE_H + +#include +#include +#include +#include + +#include "b_json/b_json_cached_entity.h" +#include "json/json.h" + +namespace OHOS::FileManagement::Backup { +class BJsonEntityExtManage : public BJsonEntity { +public: + /** + * @brief 设置索引文件 + * + * @param info std::map> + */ + void SetExtManage(const map> &info) const; + + /** + * @brief 获取索引文件 + * + * @return std::set + */ + std::set GetExtManage() const; + + /** + * @brief 获取索引文件及详细信息 + * + * @return map> + */ + std::map> GetExtManageInfo() const; + + /** + * @brief Set the hard link Information + * + * @param origin 原始文件名 + * @param hardLinks 硬链接文件名 + * @return true 设置成功 + * @return false 设置失败 + */ + bool SetHardLinkInfo(const std::string origin, const std::set hardLinks); + + /** + * @brief Get the hard link Information + * + * @param origin 原始文件名 + * @return const 硬链接集合 + */ + const std::set GetHardLinkInfo(const string origin); + +public: + /** + * @brief 构造方法,具备T(Json::Value&, std::any)能力的构造函数 + * + * @param obj Json对象引用 + * @param option 任意类型对象 + */ + explicit BJsonEntityExtManage(Json::Value &obj, std::any option = std::any()) : BJsonEntity(obj, option) {} +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_JSON_ENTITY_EXT_MANAGE_H \ No newline at end of file diff --git a/utils/include/b_json/b_json_entity_extension_config.h b/utils/include/b_json/b_json_entity_extension_config.h new file mode 100644 index 0000000000000000000000000000000000000000..5901fbd0ca602d7d3167344d349cd7e71a6d6658 --- /dev/null +++ b/utils/include/b_json/b_json_entity_extension_config.h @@ -0,0 +1,65 @@ +/* + * 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_FILEMGMT_BACKUP_B_JSON_ENTITY_EXTENSION_CONFIG_H +#define OHOS_FILEMGMT_BACKUP_B_JSON_ENTITY_EXTENSION_CONFIG_H + +#include +#include + +#include "b_json/b_json_cached_entity.h" +#include "json/json.h" + +namespace OHOS::FileManagement::Backup { +class BJsonEntityExtensionConfig : public BJsonEntity { +public: + /** + * @brief 从JSon对象中通过includes字段获取待备份目录模式串清单 + * + * @return 待备份目录模式串清单 + * @note 如果用户没有配置该字段,则返回默认打包目录{@link BConstants::PATHES_TO_BACKUP} + * @note 如果用户配置了空数组,则返回""表示生成空打包文件 + */ + std::vector GetIncludes() const; + + /** + * @brief 从JSon对象中获取排除目录列表 + * + * @return 排除目录 + */ + std::vector GetExcludes() const; + + /** + * @brief 从JSon对象中获取备份恢复权限 + * + * @return 备份权限 + */ + bool GetAllowToBackupRestore() const; + +public: + std::string GetJSonSource(std::string_view jsonFromRealWorld, std::any option); + +public: + /** + * @brief 构造方法,具备T(Json::Value&, std::any)能力的构造函数 + * + * @param obj Json对象引用 + * @param option 任意类型对象 + */ + explicit BJsonEntityExtensionConfig(Json::Value &obj, std::any option = std::any()) : BJsonEntity(obj, option) {} +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_JSON_ENTITY_EXTENSION_CONFIG_H \ No newline at end of file diff --git a/utils/include/b_ohos/startup/backup_para.h b/utils/include/b_ohos/startup/backup_para.h new file mode 100644 index 0000000000000000000000000000000000000000..fb8cb46ac29af25ccbc6340d316fcd69ab3c5925 --- /dev/null +++ b/utils/include/b_ohos/startup/backup_para.h @@ -0,0 +1,31 @@ +/* + * 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_FILEMGMT_BACKUP_BACKUP_PARA_H +#define OHOS_FILEMGMT_BACKUP_BACKUP_PARA_H + +namespace OHOS::FileManagement::Backup { +class BackupPara { +public: + /** + * @brief 获取backup.para配置项backup.debug.overrideExtensionConfig的值 + * + * @return 获取的配置项backup.debug.overrideExtensionConfig值为true时则返回true,否则返回false + */ + bool GetBackupDebugOverrideExtensionConfig(); +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_BACKUP_PARA_H \ No newline at end of file diff --git a/utils/include/b_process/b_guard_cwd.h b/utils/include/b_process/b_guard_cwd.h new file mode 100644 index 0000000000000000000000000000000000000000..f0ce7f53f0f07acc34aec151b4c0f802c023f1d4 --- /dev/null +++ b/utils/include/b_process/b_guard_cwd.h @@ -0,0 +1,51 @@ +/* + * 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_FILEMGMT_BACKUP_B_GUARD_CWD_H +#define OHOS_FILEMGMT_BACKUP_B_GUARD_CWD_H + +/** + * @file b_cwd_guard.h + * @brief 异常安全的临时变更目录方法 + * + */ + +#include + +#include "nocopyable.h" + +namespace OHOS::FileManagement::Backup { +class BGuardCwd final : protected NoCopyable { +public: + /** + * @brief 构造器,其中会把当前目录变更为目标目录 + * + * @param tgtDir 目标目录 + */ + explicit BGuardCwd(std::string_view tgtDir); + + /** + * @brief 析构器,其中会把目标目录恢复为当前目录 + * + */ + ~BGuardCwd() final; + +private: + BGuardCwd() = delete; + char *pwd_ {nullptr}; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_GUARD_CWD_H \ No newline at end of file diff --git a/utils/include/b_process/b_guard_signal.h b/utils/include/b_process/b_guard_signal.h new file mode 100644 index 0000000000000000000000000000000000000000..2d8dc66dafd8e9e9bdc8c7f901311d56eaebe02e --- /dev/null +++ b/utils/include/b_process/b_guard_signal.h @@ -0,0 +1,52 @@ +/* + * 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_FILEMGMT_BACKUP_B_GUARD_SIGNAL_H +#define OHOS_FILEMGMT_BACKUP_B_GUARD_SIGNAL_H + +/** + * @file b_guard_signal.h + * @brief 异常安全的临时调整信号处理程序方法 + * + */ + +#include + +#include "nocopyable.h" + +namespace OHOS::FileManagement::Backup { +class BGuardSignal final : protected NoCopyable { +public: + /** + * @brief 构造器,其中会把给定信号的处理程序重置为默认值 + * + * @param sig 给定信号 + */ + explicit BGuardSignal(int sig); + + /** + * @brief 析构器,其中会还原给定信号的处理程序 + * + */ + ~BGuardSignal() final; + +private: + BGuardSignal() = delete; + sighandler_t prevHandler_ {nullptr}; + int sig_ {-1}; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_GUARD_SIGNAL_H \ No newline at end of file diff --git a/utils/include/b_process/b_multiuser.h b/utils/include/b_process/b_multiuser.h new file mode 100644 index 0000000000000000000000000000000000000000..082e2e6a1832c0a1be7f61c9e314c766e66224dd --- /dev/null +++ b/utils/include/b_process/b_multiuser.h @@ -0,0 +1,40 @@ +/* + * 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_FILEMGMT_BACKUP_B_MULTIUSER_H +#define OHOS_FILEMGMT_BACKUP_B_MULTIUSER_H + +#include "b_resources/b_constants.h" + +namespace OHOS::FileManagement::Backup { +class BMultiuser { +public: + struct UidReadOut { + int userId; + int appId; + }; + +public: + static UidReadOut ParseUid(int uid) + { + return UidReadOut { + .userId = uid / BConstants::SPAN_USERID_UID, + .appId = uid % BConstants::SPAN_USERID_UID, + }; + } +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_MULTIUSER_H \ No newline at end of file diff --git a/utils/include/b_process/b_process.h b/utils/include/b_process/b_process.h new file mode 100644 index 0000000000000000000000000000000000000000..467f800f4bce571d15ab8065ccd6b229b6134a27 --- /dev/null +++ b/utils/include/b_process/b_process.h @@ -0,0 +1,54 @@ +/* + * 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_FILEMGMT_BACKUP_B_PROCESS_H +#define OHOS_FILEMGMT_BACKUP_B_PROCESS_H + +#include +#include +#include +#include + +#include "errors.h" +#include "nocopyable.h" + +namespace OHOS::FileManagement::Backup { +class BProcess final : protected NoCopyable { +public: + /** + * @brief 执行一个命令并同步等待执行结果 + * + * @param argv 命令参数表 + * Parameter one is the command name represented by the absolute path. + * After that, parameter indicates the corresponding command parameter. + * Finally,nullptr does not need to be appended. + * + * @param DetectFatalLog 回调函数,用来对命令的stderr输出错误信息做进一步处理,检测是否发生了严重错误等。 + * + * @return 回调函数返回值,命令执行结果 + * + * @throw BError(UTILS_INVAL_PROCESS_ARG) 系统调用异常(子进程启动失败、waitpid调用失败) + * + * @throw BError(UTILS_INTERRUPTED_PROCESS) 系统调用异常(pipe调用失败、dup2调用失败、子进程被信号终止) + */ + static std::tuple ExecuteCmd(std::vector argv, + std::function DetectFatalLog = nullptr); + +private: + BProcess() = delete; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_PROCESS_H \ No newline at end of file diff --git a/utils/include/b_resources/b_constants.h b/utils/include/b_resources/b_constants.h new file mode 100644 index 0000000000000000000000000000000000000000..36cf7014b99ff939dfa73f6b480f92388aa37694 --- /dev/null +++ b/utils/include/b_resources/b_constants.h @@ -0,0 +1,133 @@ +/* + * 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_FILEMGMT_BACKUP_B_CONSTANTS_H +#define OHOS_FILEMGMT_BACKUP_B_CONSTANTS_H + +#include +#include +#include +#include +#include + +namespace OHOS::FileManagement::Backup::BConstants { +static inline const char *EXTENSION_ACTION_PARA = "extensionAction"; +enum class ExtensionAction { + INVALID = 0, + BACKUP = 1, + RESTORE = 2, +}; + +enum ServiceSchedAction { + WAIT = 0, + START = 1, + RUNNING = 2, + FINISH = 3, +}; + +enum EntryKey { + SUPER_LONG_PATH = 0, + SUPER_LONG_LINK_PATH, + SUPER_LONG_SIZE, +}; + +constexpr int SPAN_USERID_UID = 20000000; +constexpr int SYSTEM_UID = 1000; +constexpr int BACKUP_UID = 1089; +constexpr int EXTENSION_THREAD_POOL_COUNT = 1; +constexpr int BACKUP_LOADSA_TIMEOUT_MS = 4000; + +constexpr int DECIMAL_BASE = 10; // 十进制基数 + +constexpr int HEADER_SIZE = 512; // 打包文件头部Header结构体大小 +constexpr int BLOCK_SIZE = 512; // 打包文件数据段尾部补充的全零字节块上限大小 +constexpr int BLOCK_PADDING_SIZE = 1024; // 打包文件尾部追加的全零字节块大小 +constexpr off_t BIG_FILE_BOUNDARY = 1024 * 1024 * 1024; // 大文件边界 +constexpr unsigned long BIG_FILE_NAME_SIZE = 16; // 大文件名长度(hash处理) + +// 打包文件头部Header结构体各字段数组/字符串大小。 +constexpr int PATHNAME_MAX_SIZE = 100; +constexpr int MODE_MAX_SIZE = 8; +constexpr int UGID_MAX_SIZE = 8; +constexpr int FILESIZE_MAX_SIZE = 12; +constexpr int TIME_MAX_SIZE = 12; +constexpr int CHKSUM_MAX_SIZE = 8; +constexpr int LINKNAME_MAX_SIZE = 100; +constexpr int MAGIC_SIZE = 6; +constexpr int VERSION_SIZE = 2; +constexpr int UGNAME_MAX_SIZE = 32; +constexpr int DEV_MAX_SIZE = 8; +constexpr int PREFIX_SIZE = 155; +constexpr int PADDING_SIZE = 12; + +// 读取backup.para字段值的最大长度 +constexpr uint32_t BACKUP_PARA_VALUE_MAX = 5; + +// SA THREAD_POOL 最大线程数 +constexpr int SA_THREAD_POOL_COUNT = 1; +// extension 最大启动数 +constexpr int EXT_CONNECT_MAX_COUNT = 3; +// SA 启动 extension 等待连接最大时间 +constexpr int EXT_CONNECT_MAX_TIME = 15000; + +// 打包文件头部Header结构体fileSize字段最大值。 +constexpr off_t FILESIZE_MAX = 077777777777; + +// 打包文件头部Header结构体typeFlag字段值。 +constexpr char TYPEFLAG_REGULAR_FILE = '0'; +constexpr char TYPEFLAG_SYMBOLIC_LINK = '2'; +constexpr char TYPEFLAG_DIRECTORY = '5'; +constexpr char TYPEFLAG_EXTENDED = 'x'; + +// 打包文件扩展数据段字段值。 +static inline std::string ENTRY_NAME_LINKPATH = "linkpath"; +static inline std::string ENTRY_NAME_PATH = "path"; +static inline std::string ENTRY_NAME_SIZE = "size"; + +// backup.para内配置项的名称,改配置项值为true时可在不更新hap包的情况下,可以读取包管理元数据配置文件的内容 +static inline std::string BACKUP_DEBUG_OVERRIDE_EXTENSION_CONFIG_KEY = "backup.debug.overrideExtensionConfig"; + +// 应用备份数据暂存路径。 +static inline std::string_view SA_BUNDLE_BACKUP_DIR = "/data/service/el2/100/backup/bundles/"; +static inline std::string_view SA_BUNDLE_BACKUP_BACKUP = "/backup/"; +static inline std::string_view SA_BUNDLE_BACKUP_RESTORE = "/restore/"; +static inline std::string_view SA_BUNDLE_BACKUP_ROOT_DIR = "/data/service/el2/100/backup/backup_sa/"; +static inline std::string_view SA_BUNDLE_BACKUP_TMP_DIR = "/tmp/"; +static inline std::string_view BACKUP_TOOL_RECEIVE_DIR = "/data/backup/received/"; +static inline std::string_view PATH_BUNDLE_BACKUP_HOME = "/data/storage/el2/backup"; +static inline std::string_view SA_BUNDLE_BACKUP_TOOL_DIR = "/data/service/el2/100/backup/backup_tool/"; +static inline std::string_view BACKUP_TOOL_LINK_DIR = "/data/backup"; + +// 备份恢复配置文件暂存路径 +static inline std::string_view BACKUP_CONFIG_EXTENSION_PATH = "/data/storage/el2/base/temp/"; + +// 应用备份恢复所需的索引文件 +static inline std::string_view EXT_BACKUP_MANAGE = "manage.json"; + +// 包管理元数据配置文件 +static inline std::string_view BACKUP_CONFIG_JSON = "backup_config.json"; + +// 应用默认备份的目录,其均为相对根路径的路径。为避免模糊匹配,务必以斜线为结尾。 +static inline std::array PATHES_TO_BACKUP = { + "data/storage/el2/database/", + "data/storage/el2/base/files/", + "data/storage/el2/base/preferences/", + "data/storage/el2/base/haps/*/database/", + "data/storage/el2/base/haps/*/base/files/", + "data/storage/el2/base/haps/*/base/preferences/", +}; +} // namespace OHOS::FileManagement::Backup::BConstants + +#endif // OHOS_FILEMGMT_BACKUP_B_CONSTANTS_H \ No newline at end of file diff --git a/utils/include/b_tarball/b_tarball_cmdline.h b/utils/include/b_tarball/b_tarball_cmdline.h new file mode 100644 index 0000000000000000000000000000000000000000..3d9202e3a60ec6ea5a8ccec323ee3c768ca19c02 --- /dev/null +++ b/utils/include/b_tarball/b_tarball_cmdline.h @@ -0,0 +1,40 @@ +/* + * 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_FILEMGMT_BACKUP_B_TARBALL_CMDLINE_H +#define OHOS_FILEMGMT_BACKUP_B_TARBALL_CMDLINE_H + +#include +#include +#include + +#include "nocopyable.h" + +namespace OHOS::FileManagement::Backup { +class BTarballCmdline final : protected NoCopyable { +public: + void Tar(std::string_view root, std::vector includes, std::vector excludes); + void Untar(std::string_view root); + +public: + BTarballCmdline(std::string_view tarballDir, std::string_view tarballName); + +private: + std::string tarballDir_; + std::string tarballName_; + std::string tarballPath_; +}; +} // namespace OHOS::FileManagement::Backup +#endif // OHOS_FILEMGMT_BACKUP_B_TARBALL_CMDLINE_H diff --git a/utils/include/b_tarball/b_tarball_factory.h b/utils/include/b_tarball/b_tarball_factory.h new file mode 100644 index 0000000000000000000000000000000000000000..b43ca9ba42372b40a0b73459255c93da66a8db16 --- /dev/null +++ b/utils/include/b_tarball/b_tarball_factory.h @@ -0,0 +1,77 @@ +/* + * 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_FILEMGMT_BACKUP_B_TARBALL_FACTORY_H +#define OHOS_FILEMGMT_BACKUP_B_TARBALL_FACTORY_H + +/** + * @file b_tarball.h + * @brief 使用指定实现打包/解包,本层在进行打包/解包前还负责防御路径穿越攻击 + * + */ +#include +#include +#include + +#include "nocopyable.h" + +namespace OHOS::FileManagement::Backup { +class BTarballFactory final : protected NoCopyable { +public: + /** + * @brief 打包器仿函数集合 + * 当前迫于时间所限,不得不采用命令行实现。后续必然要实现自研打包协议,从而满足在同一个进程进行打包的诉求。 + * 在降低调用成本后,就可以实现逐个向tarball追加文件的append方法。append方法是优化方法,和tar二选一即可。 + * 然而纯虚函数必须得在子类实现,这一性质使得基于继承的设计模式无法方便地选择合适的打包方法,为了解决这个问题, + * 这里采用组合的方式实现。现在在外层简单地判断相应仿函数是否为空,就知道如何进行选择了。 + */ + struct Impl { + /** + * @brief 打包 + * + * @param _1 进入该参数指定路径打包文件。 + * An absolute path is required. + * @param _2 _1中需要打包的路径。 + * 要求输入相对路径,除禁止路径穿越外无其余要求,不填默认全部打包 + * @param _3 The part that does not need to be packed in the path to be packed. + * 要求输入相对路径,路径穿越场景无实际意义因此予以禁止。可用于排除部分子目录 + */ + std::function, std::vector)> tar; + + /** + * @brief 解包 + * + * @param _1 用于存储解包文件的根目录 + * An absolute path is required. + */ + std::function untar; + }; + +public: + /** + * @brief 打包器工厂方法 + * + * @param implType 打包器实现方式,可选择'cmdline' + * @param tarballPath Absolute path of the file package。Cannot contain extra slashes, must be suffixed with .tar + * @return std::unique_ptr 打包器仿函数集合 + */ + static std::unique_ptr Create(std::string_view implType, std::string_view tarballPath); + +public: + BTarballFactory() = delete; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_TARBALL_FACTORY_H \ No newline at end of file diff --git a/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_extended_data.h b/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_extended_data.h new file mode 100644 index 0000000000000000000000000000000000000000..ebaf142feb10a0189da08129d274a166c2aa11a1 --- /dev/null +++ b/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_extended_data.h @@ -0,0 +1,41 @@ +/* + * 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_FILEMGMT_BACKUP_B_TARBALL_POSIX_EXTENDED_DATA_H +#define OHOS_FILEMGMT_BACKUP_B_TARBALL_POSIX_EXTENDED_DATA_H + +#include + +#include "b_tarball_posix_extended_entry.h" +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +class BTarballPosixExtendedData { +public: + size_t GetEntriesSize(); + void Publish(const UniqueFd &outFile); + +public: + BTarballPosixExtendedData() = default; + BTarballPosixExtendedData(const std::string &pathName, const struct stat &statInfo); + ~BTarballPosixExtendedData() = default; + +private: + size_t entriesSize_ {0}; + std::vector entries_; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_TARBALL_POSIX_EXTENDED_DATA_H \ No newline at end of file diff --git a/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_extended_entry.h b/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_extended_entry.h new file mode 100644 index 0000000000000000000000000000000000000000..e7ffabc7c0282218e2c5d8576ab0912b134b40ae --- /dev/null +++ b/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_extended_entry.h @@ -0,0 +1,50 @@ +/* + * 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_FILEMGMT_BACKUP_B_TARBALL_POSIX_EXTENDED_ENTRY_H +#define OHOS_FILEMGMT_BACKUP_B_TARBALL_POSIX_EXTENDED_ENTRY_H + +#include +#include + +#include "b_resources/b_constants.h" +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +class BTarballPosixExtendedEntry { +public: + static std::optional TryToGetEntry(BConstants::EntryKey entryKey, + const std::string &pathName, + const struct stat &statInfo); + +public: + size_t GetEntrySize(); + void Publish(const UniqueFd &outFile); + +public: + ~BTarballPosixExtendedEntry() = default; + +private: + size_t entrySize_ {0}; + std::string entryName_; + std::string entryValue_; + std::string entry_; + +private: + BTarballPosixExtendedEntry(const std::string &entryName, const std::string &entryValue); +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_TARBALL_POSIX_EXTENDED_ENTRY_H \ No newline at end of file diff --git a/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_extended_header.h b/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_extended_header.h new file mode 100644 index 0000000000000000000000000000000000000000..34f2afcbac675ce428379f107ec4983575789bea --- /dev/null +++ b/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_extended_header.h @@ -0,0 +1,38 @@ +/* + * 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_FILEMGMT_BACKUP_B_TARBALL_POSIX_EXTENDED_HEADER_H +#define OHOS_FILEMGMT_BACKUP_B_TARBALL_POSIX_EXTENDED_HEADER_H + +#include "b_tarball_posix_extended_data.h" +#include "b_tarball_posix_header.h" +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +class BTarballPosixExtendedHeader { +public: + void Publish(const UniqueFd &outFile); + +public: + BTarballPosixExtendedHeader() = default; + explicit BTarballPosixExtendedHeader(BTarballPosixExtendedData &extData); + ~BTarballPosixExtendedHeader() = default; + +private: + BTarballPosixHeader header_; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_TARBALL_POSIX_EXTENDED_HEADER_H \ No newline at end of file diff --git a/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_file.h b/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_file.h new file mode 100644 index 0000000000000000000000000000000000000000..6df182a718c5ab20d91c7d4b4db76ab78bd176fe --- /dev/null +++ b/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_file.h @@ -0,0 +1,45 @@ +/* + * 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_FILEMGMT_BACKUP_B_TARBALL_POSIX_FILE_H +#define OHOS_FILEMGMT_BACKUP_B_TARBALL_POSIX_FILE_H + +#include "b_tarball_posix_extended_data.h" +#include "b_tarball_posix_extended_header.h" +#include "b_tarball_posix_file_data.h" +#include "b_tarball_posix_pax_header.h" +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +class BTarballPosixFile { +public: + void Publish(const UniqueFd &outFile); + +public: + BTarballPosixFile() = default; + explicit BTarballPosixFile(const std::string &pathName); + ~BTarballPosixFile() = default; + +private: + std::string pathName_; + UniqueFd file_ {-1}; + BTarballPosixExtendedData extData_; + BTarballPosixExtendedHeader extHdr_; + BTarballPosixPaxHeader paxHdr_; + BTarballPosixFileData fileData_; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_TARBALL_POSIX_FILE_H \ No newline at end of file diff --git a/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_file_data.h b/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_file_data.h new file mode 100644 index 0000000000000000000000000000000000000000..1798cbb390c51ecbf91b1df9f2890763ac2fe08c --- /dev/null +++ b/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_file_data.h @@ -0,0 +1,38 @@ +/* + * 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_FILEMGMT_BACKUP_B_TARBALL_POSIX_FILE_DATA_H +#define OHOS_FILEMGMT_BACKUP_B_TARBALL_POSIX_FILE_DATA_H + +#include + +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +class BTarballPosixFileData { +public: + void Publish(const UniqueFd &inFile, const UniqueFd &outFile); + +public: + BTarballPosixFileData() = default; + explicit BTarballPosixFileData(struct stat &statInfo); + ~BTarballPosixFileData() = default; + +private: + struct stat stat_; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_TARBALL_POSIX_FILE_DATA_H \ No newline at end of file diff --git a/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_header.h b/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_header.h new file mode 100644 index 0000000000000000000000000000000000000000..7679b05c0275e1ebf8bac860753ef00098718365 --- /dev/null +++ b/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_header.h @@ -0,0 +1,43 @@ +/* + * 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_FILEMGMT_BACKUP_B_TARBALL_POSIX_HEADER_H +#define OHOS_FILEMGMT_BACKUP_B_TARBALL_POSIX_HEADER_H + +#include "b_resources/b_constants.h" + +namespace OHOS::FileManagement::Backup { +struct BTarballPosixHeader { + char pathName[BConstants::PATHNAME_MAX_SIZE] {}; + char mode[BConstants::MODE_MAX_SIZE] {}; + char uid[BConstants::UGID_MAX_SIZE] {}; + char gid[BConstants::UGID_MAX_SIZE] {}; + char fileSize[BConstants::FILESIZE_MAX_SIZE] {}; + char mtime[BConstants::TIME_MAX_SIZE] {}; + char chksum[BConstants::CHKSUM_MAX_SIZE] {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}; + char typeFlag {}; + char linkName[BConstants::LINKNAME_MAX_SIZE] {}; + char magic[BConstants::MAGIC_SIZE] {"ustar"}; + char version[BConstants::VERSION_SIZE] {'0', '0'}; + char uname[BConstants::UGNAME_MAX_SIZE] {}; + char gname[BConstants::UGNAME_MAX_SIZE] {}; + char devMajor[BConstants::DEV_MAX_SIZE] {}; + char devMinor[BConstants::DEV_MAX_SIZE] {}; + char prefix[BConstants::PREFIX_SIZE] {}; + char padding[BConstants::PADDING_SIZE] {}; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_TARBALL_POSIX_HEADER_H \ No newline at end of file diff --git a/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_pax_header.h b/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_pax_header.h new file mode 100644 index 0000000000000000000000000000000000000000..ad7232c2881dddebdae91d0ec7dde3d00db29d4d --- /dev/null +++ b/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_pax_header.h @@ -0,0 +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 OHOS_FILEMGMT_BACKUP_B_TARBALL_POSIX_PAX_HEADER_H +#define OHOS_FILEMGMT_BACKUP_B_TARBALL_POSIX_PAX_HEADER_H + +#include + +#include "b_tarball_posix_header.h" +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +class BTarballPosixPaxHeader { +public: + void Publish(const UniqueFd &outFile); + +public: + BTarballPosixPaxHeader() = default; + BTarballPosixPaxHeader(const std::string &pathName, const struct stat &statInfo); + ~BTarballPosixPaxHeader() = default; + +private: + BTarballPosixHeader header_; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_TARBALL_POSIX_PAX_HEADER_H \ No newline at end of file diff --git a/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_tarball.h b/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_tarball.h new file mode 100644 index 0000000000000000000000000000000000000000..534a24d5b73e3b030a759391469d60f7276a78d4 --- /dev/null +++ b/utils/include/b_tarball/b_tarball_posix/b_tarball_posix_tarball.h @@ -0,0 +1,41 @@ +/* + * 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_FILEMGMT_BACKUP_B_TARBALL_POSIX_TARBALL_H +#define OHOS_FILEMGMT_BACKUP_B_TARBALL_POSIX_TARBALL_H + +#include + +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +class BTarballPosixTarball { +public: + void Emplace(const std::string pathName); + void Publish(); + void Clear(); + +public: + BTarballPosixTarball() = default; + explicit BTarballPosixTarball(const std::string pathTarball); + ~BTarballPosixTarball() = default; + +private: + UniqueFd fileTarball_ {-1}; + bool isPublished_ {false}; +}; +} // namespace OHOS::FileManagement::Backup + +#endif // OHOS_FILEMGMT_BACKUP_B_TARBALL_POSIX_TARBALL_H \ No newline at end of file diff --git a/utils/src/b_encryption/b_encryption.cpp b/utils/src/b_encryption/b_encryption.cpp new file mode 100644 index 0000000000000000000000000000000000000000..004256801ac2cb1c35d4d80c9d5664bd065a9954 --- /dev/null +++ b/utils/src/b_encryption/b_encryption.cpp @@ -0,0 +1,27 @@ +/* + * 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 "b_encryption/b_encryption.h" + +namespace OHOS::FileManagement::Backup::BEncryption { +unsigned int CalculateChksum(const char *byteBlock, int blockSize) +{ + unsigned int chksum = 0U; + for (int i = 0; i < blockSize; ++i) { + chksum += 0xFF & *(byteBlock + i); + } + return chksum; +} +} // namespace OHOS::FileManagement::Backup::BEncryption \ No newline at end of file diff --git a/utils/src/b_error/b_error.cpp b/utils/src/b_error/b_error.cpp new file mode 100644 index 0000000000000000000000000000000000000000..099bc66b3f13418c16c02fd598cff22c0a79ae47 --- /dev/null +++ b/utils/src/b_error/b_error.cpp @@ -0,0 +1,52 @@ +/* + * 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 "b_error/b_error.h" + +#include +#include + +#include "dfx_dump_catcher.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +string BError::WrapMessageWithExtraInfos(const char *fileName, + int lineNo, + const char *functionName, + Codes code, + const vector &msgs) const +{ + stringstream ss; + ss << '[' << fileName << ':' << lineNo << " -> " << functionName << ']' << ' '; + for (size_t i = 0; i < msgs.size(); ++i) { + ss << msgs[i]; + if (i != msgs.size() - 1) { + ss << ". "; + } + } + + if (code != Codes::OK) { + string msg; + HiviewDFX::DfxDumpCatcher().DumpCatch(getpid(), syscall(SYS_gettid), msg); + ss << endl << msg; + } + + string res = ss.str(); + HiviewDFX::HiLog::Error(FILEMGMT_LOG_LABEL, "%{public}s", res.c_str()); + return res; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/src/b_filesystem/b_dir.cpp b/utils/src/b_filesystem/b_dir.cpp new file mode 100644 index 0000000000000000000000000000000000000000..238589d369dc40e6e3949612e04ddab6a905785f --- /dev/null +++ b/utils/src/b_filesystem/b_dir.cpp @@ -0,0 +1,179 @@ +/* + * 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 "b_filesystem/b_dir.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "b_resources/b_constants.h" +#include "directory_ex.h" +#include "errors.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +pair> GetDirFilesDetail(const string &path, bool recursion, off_t size = -1) +{ + map files; + unique_ptr> dir = {opendir(path.c_str()), closedir}; + if (!dir) { + HILOGE("Invalid directory path: %{private}s", path.c_str()); + return {BError(errno).GetCode(), files}; + } + + struct dirent *ptr = nullptr; + while (!!(ptr = readdir(dir.get()))) { + // current dir OR parent dir + if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0)) { + continue; + } else if (ptr->d_type == DT_DIR) { + if (!recursion) { + continue; + } + + auto [errCode, subfiles] = + GetDirFilesDetail(IncludeTrailingPathDelimiter(path) + string(ptr->d_name), recursion, size); + if (errCode != 0) { + return {errCode, files}; + } + files.merge(subfiles); + } else if (ptr->d_type == DT_LNK) { + continue; + } else { + struct stat sta = {}; + string fileName = IncludeTrailingPathDelimiter(path) + string(ptr->d_name); + if (stat(fileName.data(), &sta) == -1) { + continue; + } + if (sta.st_size < size) { + continue; + } + HILOGI("%{public}s is big file", fileName.c_str()); + files.try_emplace(fileName, sta); + } + } + + return {BError(BError::Codes::OK).GetCode(), files}; +} + +tuple> BDir::GetDirFiles(const string &path) +{ + vector files; + unique_ptr> dir = {opendir(path.c_str()), closedir}; + if (!dir) { + HILOGE("Invalid directory path: %{private}s", path.c_str()); + return {BError(errno).GetCode(), files}; + } + + struct dirent *ptr = nullptr; + while (!!(ptr = readdir(dir.get()))) { + // current dir OR parent dir + if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0)) { + continue; + } else if (ptr->d_type == DT_DIR) { + continue; + } else { + files.push_back(IncludeTrailingPathDelimiter(path) + string(ptr->d_name)); + } + } + + return {BError(BError::Codes::OK).GetCode(), files}; +} + +set ExpandPathWildcard(const vector &vec) +{ + unique_ptr> gl {new glob_t, [](glob_t *ptr) { globfree(ptr); }}; + *gl = {}; + + int flags = GLOB_DOOFFS | GLOB_MARK; + for (const string &pattern : vec) { + if (!pattern.empty()) { + glob(pattern.data(), flags, NULL, gl.get()); + flags |= GLOB_APPEND; + } + } + + set expandPath, filteredPath; + for (size_t i = 0; i < gl->gl_pathc; ++i) { + expandPath.emplace(gl->gl_pathv[i]); + } + + for (auto it = expandPath.begin(); it != expandPath.end(); ++it) { + filteredPath.insert(*it); + if (*it->rbegin() != '/') { + continue; + } + auto jt = it; + for (++jt; jt != expandPath.end() && (jt->find(*it) == 0); ++jt) { + } + + it = --jt; + } + + return filteredPath; +} + +pair> BDir::GetBigFiles(const vector &includes, + const vector &excludes) +{ + set inc = ExpandPathWildcard(includes); + + map incFiles; + for (const auto &item : inc) { + auto [errCode, files] = + OHOS::FileManagement::Backup::GetDirFilesDetail(item, true, BConstants::BIG_FILE_BOUNDARY); + if (errCode == 0) { + int32_t num = static_cast(files.size()); + HILOGI("found big files. total number is : %{public}d", num); + incFiles.merge(move(files)); + } + } + + auto isMatch = [](const vector &s, const string &str) -> bool { + if (str.empty()) { + return false; + } + for (const string &item : s) { + if (!item.empty() && (fnmatch(item.data(), str.data(), FNM_LEADING_DIR) == 0)) { + HILOGI("file %{public}s matchs exclude condition", str.c_str()); + return true; + } + } + return false; + }; + + map bigFiles; + for (const auto &item : incFiles) { + if (!isMatch(excludes, item.first)) { + HILOGI("file %{public}s matchs include condition and unmatchs exclude condition", item.first.c_str()); + bigFiles[item.first] = item.second; + } + } + int32_t num = static_cast(bigFiles.size()); + HILOGI("total number of big files is %{public}d", num); + return {ERR_OK, move(bigFiles)}; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/src/b_filesystem/b_file.cpp b/utils/src/b_filesystem/b_file.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a71bd379de8291a52b26b9a128a37fb9ea49a289 --- /dev/null +++ b/utils/src/b_filesystem/b_file.cpp @@ -0,0 +1,139 @@ +/* + * 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 "b_filesystem/b_file.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +unique_ptr BFile::ReadFile(const UniqueFd &fd) +{ + if (lseek(fd, 0, SEEK_SET) == -1) { + throw BError(errno); + } + + struct stat stat = {}; + if (fstat(fd, &stat) == -1) { + throw BError(errno); + } + off_t fileSize = stat.st_size; + if (fileSize == 0) { + HILOGI("Deserialized an empty file"); + return make_unique(1); + } + + auto buf = make_unique(fileSize + 1); + if (read(fd, buf.get(), fileSize) == -1) { + throw BError(errno); + } + return buf; +} + +void BFile::SendFile(int outFd, int inFd) +{ + off_t offset = 0; + long ret = 0; + if (lseek(outFd, 0, SEEK_SET) == -1) { + throw BError(errno); + } + if (lseek(inFd, 0, SEEK_SET) == -1) { + throw BError(errno); + } + struct stat stat = {}; + if (fstat(inFd, &stat) == -1) { + throw BError(errno); + } + while ((ret = sendfile(outFd, inFd, &offset, stat.st_size)) > 0) { + }; + + if (ret == -1) { + throw BError(errno); + } +} + +void BFile::Write(const UniqueFd &fd, const string &str) +{ + int ret = pwrite(fd, str.c_str(), str.length(), 0); + if (ret == -1) { + throw BError(errno); + } + if (ftruncate(fd, ret) == -1) { + throw BError(errno); + } +} + +bool BFile::CopyFile(const string &from, const string &to) +{ + if (from == to) { + return true; + } + + try { + auto resolvedPath = make_unique(PATH_MAX); + if (!realpath(from.data(), resolvedPath.get())) { + HILOGI("failed to real path for the file %{public}s", from.c_str()); + return false; + } + string oldPath(resolvedPath.get()); + UniqueFd fdFrom(open(oldPath.data(), O_RDONLY)); + if (fdFrom == -1) { + HILOGE("failed to open the file %{public}s", from.c_str()); + throw BError(errno); + } + + unique_ptr> dir {strdup(to.data()), free}; + if (!dir) { + throw BError(errno); + } + if (!realpath(dirname(dir.get()), resolvedPath.get())) { + HILOGI("failed to real path for %{public}s", to.c_str()); + return false; + } + string newPath(resolvedPath.get()); + unique_ptr> name {strdup(to.data()), free}; + if (!name) { + throw BError(errno); + } + newPath.append("/").append(basename(name.get())); + UniqueFd fdTo(open(newPath.data(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)); + if (fdTo == -1) { + HILOGE("failed to open the file %{public}s", to.c_str()); + throw BError(errno); + } + + SendFile(fdTo, fdFrom); + return true; + } catch (const BError &e) { + HILOGE("%{public}s", e.what()); + } catch (const exception &e) { + HILOGE("%{public}s", e.what()); + } catch (...) { + HILOGE(""); + } + return false; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/src/b_ipc/b_want_2_ext.cpp b/utils/src/b_ipc/b_want_2_ext.cpp new file mode 100644 index 0000000000000000000000000000000000000000..094567e72118b131e690d6aba97a8578820e1593 --- /dev/null +++ b/utils/src/b_ipc/b_want_2_ext.cpp @@ -0,0 +1,30 @@ +/* + * 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 "b_ipc/b_want_2_ext.h" + +#include + +#include "b_error/b_error.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +constexpr const char *PARA_EXT_ACTION = "extensionAction"; + +void BWant2Ext::Issue() const +{ +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/src/b_json/b_json_entity_ext_manage.cpp b/utils/src/b_json/b_json_entity_ext_manage.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2b444d9f03e40d79953e6a96ff629d22b3bdf7b6 --- /dev/null +++ b/utils/src/b_json/b_json_entity_ext_manage.cpp @@ -0,0 +1,215 @@ +/* + * 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 +#include +#include +#include + +#include "b_json/b_json_entity_ext_manage.h" +#include "filemgmt_libhilog.h" +#include "json/value.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +Json::Value Stat2JsonValue(struct stat sta) +{ + Json::Value value; + + value["st_size"] = static_cast(sta.st_size); + value["st_atim"]["tv_sec"] = static_cast(sta.st_atim.tv_sec); + value["st_atim"]["tv_nsec"] = static_cast(sta.st_atim.tv_nsec); + value["st_mtim"]["tv_sec"] = static_cast(sta.st_mtim.tv_sec); + value["st_mtim"]["tv_nsec"] = static_cast(sta.st_mtim.tv_nsec); + + return value; +} + +struct stat JsonValue2Stat(const Json::Value &value) +{ + struct stat sta = {}; + + sta.st_size = value.isMember("st_size") ? value["st_size"].asInt64() : 0; + if (value.isMember("st_atim")) { + sta.st_atim.tv_sec = value["st_atim"].isMember("tv_sec") ? value["st_atim"]["tv_sec"].asInt64() : 0; + sta.st_atim.tv_nsec = value["st_atim"].isMember("tv_nsec") ? value["st_atim"]["tv_nsec"].asInt64() : 0; + } + if (value.isMember("st_mtim")) { + sta.st_mtim.tv_sec = value["st_mtim"].isMember("tv_sec") ? value["st_mtim"]["tv_sec"].asInt64() : 0; + sta.st_mtim.tv_nsec = value["st_mtim"].isMember("tv_nsec") ? value["st_mtim"]["tv_nsec"].asInt64() : 0; + } + + return sta; +} + +void BJsonEntityExtManage::SetExtManage(const map> &info) const +{ + obj_.clear(); + + vector vec(info.size(), false); + + auto FindLinks = [&vec](map>::const_iterator it, + unsigned long index) -> set { + if (it->second.second.st_dev == 0 || it->second.second.st_ino == 0) { + return {}; + } + + set lks; + auto item = it; + item++; + + for (auto i = index + 1; i < vec.size(); ++i, ++item) { + if (it->second.second.st_dev == item->second.second.st_dev && + it->second.second.st_ino == item->second.second.st_ino) { + vec[i] = true; + lks.insert(item->second.first); + } + } + return lks; + }; + + unsigned long index = 0; + for (auto item = info.begin(); item != info.end(); ++item, ++index) { + if (vec[index]) { + HILOGI("skipped file is %{public}s", item->first.c_str()); + continue; + } + HILOGI("file name is %{public}s", item->first.c_str()); + + Json::Value value; + value["fileName"] = item->first; + value["information"]["path"] = item->second.first; + value["information"]["stat"] = Stat2JsonValue(item->second.second); + set lks = FindLinks(item, index); + for (const auto &lk : lks) { + value["hardlinks"].append(lk); + } + + obj_.append(value); + } +} + +set BJsonEntityExtManage::GetExtManage() const +{ + if (!obj_) { + HILOGE("Uninitialized JSon Object reference"); + return {}; + } + if (!obj_.isArray()) { + HILOGE("json object isn't an array"); + return {}; + } + + set info; + for (Json::Value &item : obj_) { + string fileName = item.isMember("fileName") ? item["fileName"].asString() : ""; + info.emplace(fileName); + } + return info; +} + +map> BJsonEntityExtManage::GetExtManageInfo() const +{ + if (!obj_) { + HILOGE("Uninitialized JSon Object reference"); + return {}; + } + if (!obj_.isArray()) { + HILOGE("json object isn't an array"); + return {}; + } + + map> info; + for (const Json::Value &item : obj_) { + string fileName = item.isMember("fileName") ? item["fileName"].asString() : ""; + + if (!item.isMember("information")) { + continue; + } + + struct stat sta = {}; + string path = item["information"].isMember("path") ? item["information"]["path"].asString() : ""; + if (item["information"].isMember("stat")) { + sta = JsonValue2Stat(item["information"]["stat"]); + } + + if (!fileName.empty() && !path.empty()) { + info.emplace(fileName, make_pair(path, sta)); + } + } + + return info; +} + +bool BJsonEntityExtManage::SetHardLinkInfo(const string origin, const set hardLinks) +{ + if (origin.empty()) { + HILOGE("origin file name can not empty"); + return false; + } + if (!obj_) { + HILOGE("Uninitialized JSon Object reference"); + return false; + } + if (!obj_.isArray()) { + HILOGE("json object isn't an array"); + return false; + } + + for (Json::Value &item : obj_) { + string fileName = item.isMember("fileName") ? item["fileName"].asString() : ""; + if (origin == fileName) { + for (const auto &lk : hardLinks) { + item["hardlinks"].append(lk); + } + return true; + } + } + + return false; +} + +const set BJsonEntityExtManage::GetHardLinkInfo(const string origin) +{ + if (origin.empty()) { + HILOGE("origin file name can not empty"); + return {}; + } + if (!obj_) { + HILOGE("Uninitialized JSon Object reference"); + return {}; + } + if (!obj_.isArray()) { + HILOGE("json object isn't an array"); + return {}; + } + + set hardlinks; + for (const Json::Value &item : obj_) { + string fileName = item.isMember("fileName") ? item["fileName"].asString() : ""; + if (origin == fileName) { + if (!(item.isMember("hardlinks") && item["hardlinks"].isArray())) { + break; + } + for (const auto &lk : item["hardlinks"]) { + hardlinks.emplace(lk.asString()); + } + } + } + + return hardlinks; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/src/b_json/b_json_entity_extension_config.cpp b/utils/src/b_json/b_json_entity_extension_config.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9a6e870b596c30a3374a2f59e643b8d94bd23200 --- /dev/null +++ b/utils/src/b_json/b_json_entity_extension_config.cpp @@ -0,0 +1,128 @@ +/* + * 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 "b_json/b_json_entity_extension_config.h" + +#include +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "b_filesystem/b_file.h" +#include "b_ohos/startup/backup_para.h" +#include "b_resources/b_constants.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +vector BJsonEntityExtensionConfig::GetIncludes() const +{ + if (!obj_) { + HILOGE("Uninitialized JSon Object reference"); + return {BConstants::PATHES_TO_BACKUP.begin(), BConstants::PATHES_TO_BACKUP.end()}; + } + if (!obj_.isMember("includes")) { + HILOGE("'includes' field not found"); + return {BConstants::PATHES_TO_BACKUP.begin(), BConstants::PATHES_TO_BACKUP.end()}; + } + if (!obj_["includes"].isArray()) { + HILOGE("'includes' field must be an array"); + return {BConstants::PATHES_TO_BACKUP.begin(), BConstants::PATHES_TO_BACKUP.end()}; + } + + vector dirs; + for (auto &&item : obj_["includes"]) { + if (!item.isString()) { + HILOGE("Each item of array 'includes' must be of the type string"); + continue; + } + dirs.push_back(item.asString()); + } + + if (dirs.empty()) { + dirs.emplace_back(""); + } + return dirs; +} + +vector BJsonEntityExtensionConfig::GetExcludes() const +{ + if (!obj_) { + HILOGE("Uninitialized JSon Object reference"); + return {}; + } + if (!obj_.isMember("excludes")) { + HILOGE("'excludes' field not found"); + return {}; + } + if (!obj_["excludes"].isArray()) { + HILOGE("'excludes' field must be an array"); + return {}; + } + + vector dirs; + for (auto &&item : obj_["excludes"]) { + if (!item.isString()) { + HILOGE("Each item of array 'excludes' must be of the type string"); + return {}; + } + dirs.push_back(item.asString()); + } + return dirs; +} + +bool BJsonEntityExtensionConfig::GetAllowToBackupRestore() const +{ + if (!obj_ || !obj_.isMember("allowToBackupRestore") || !obj_["allowToBackupRestore"].isBool()) { + HILOGE("Failed to init field allowToBackupRestore"); + return false; + } + + return obj_["allowToBackupRestore"].asBool(); +} + +string BJsonEntityExtensionConfig::GetJSonSource(string_view jsonFromRealWorld, any option) +{ + if (!BackupPara().GetBackupDebugOverrideExtensionConfig()) { + return string(jsonFromRealWorld); + } + + if (!option.has_value()) { + if (getuid() == static_cast(BConstants::BACKUP_UID)) { + throw BError(BError::Codes::SA_INVAL_ARG, "Current process is not extension process"); + } + string jsonFilePath = string(BConstants::BACKUP_CONFIG_EXTENSION_PATH).append(BConstants::BACKUP_CONFIG_JSON); + return BFile::ReadFile(UniqueFd(open(jsonFilePath.c_str(), O_RDONLY))).get(); + } + + if (getuid() != static_cast(BConstants::BACKUP_UID)) { + throw BError(BError::Codes::SA_INVAL_ARG, "Current process is not service process"); + } + string bundleName; + try { + bundleName = any_cast(option); + } catch (const bad_any_cast &e) { + throw BError(BError::Codes::SA_INVAL_ARG, e.what()); + } + string jsonFilePath = string(BConstants::SA_BUNDLE_BACKUP_ROOT_DIR) + .append(bundleName) + .append("/") + .append(BConstants::BACKUP_CONFIG_JSON); + return BFile::ReadFile(UniqueFd(open(jsonFilePath.c_str(), O_RDONLY))).get(); +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/src/b_ohos/startup/backup_para.cpp b/utils/src/b_ohos/startup/backup_para.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ab5c183231f0aa65f2799ec4db69dc56c734107f --- /dev/null +++ b/utils/src/b_ohos/startup/backup_para.cpp @@ -0,0 +1,68 @@ +/* + * 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 "b_ohos/startup/backup_para.h" + +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "b_resources/b_constants.h" +#include "filemgmt_libhilog.h" +#include "parameter.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +/** + * @brief 获取配置参数的值 + * + * @param key 配置参数的参数名 + * @param len 配置参数值的最大长度 + * @return 成功获取配置参数的值则返回true,失败则返回false;以及表示配置参数值的字符串 + */ +static tuple GetConfigParameterValue(const string &key, uint32_t len) +{ + int handle = static_cast(FindParameter(key.c_str())); + if (handle == -1) { + HILOGI("Fail to find parameter."); + return {false, ""}; + } + try { + unique_ptr buffer = make_unique(len + 1); + int res = GetParameterValue(handle, buffer.get(), len + 1); + if (res < 0) { + HILOGI("Fail to get parameter value."); + return {false, ""}; + } + return {true, buffer.get()}; + } catch (const bad_alloc &e) { + HILOGI("Fail to get parameter value: %{public}s.", e.what()); + return {false, ""}; + } +} + +bool BackupPara::GetBackupDebugOverrideExtensionConfig() +{ + auto [getCfgParaValSucc, value] = GetConfigParameterValue(BConstants::BACKUP_DEBUG_OVERRIDE_EXTENSION_CONFIG_KEY, + BConstants::BACKUP_PARA_VALUE_MAX); + if (!getCfgParaValSucc) { + throw BError(BError::Codes::SA_INVAL_ARG, "Fail to get configuration parameter value of backup.para"); + } + return value == "true"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/src/b_process/b_guard_cwd.cpp b/utils/src/b_process/b_guard_cwd.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a5dd5388f594a44b5e9cedc6b1058ea8519f912 --- /dev/null +++ b/utils/src/b_process/b_guard_cwd.cpp @@ -0,0 +1,42 @@ +/* + * 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 "b_process/b_guard_cwd.h" +#include "b_error/b_error.h" + +#include +#include + +namespace OHOS::FileManagement::Backup { +using namespace std; + +BGuardCwd::BGuardCwd(std::string_view tgtDir) +{ + pwd_ = getcwd(nullptr, 0); + if (!pwd_) { + throw BError(BError::Codes::UTILS_INVAL_PROCESS_ARG, "Out of memory"); + } + if (chdir(tgtDir.data())) { + std::free(pwd_); + throw BError(BError::Codes::UTILS_INVAL_PROCESS_ARG, std::generic_category().message(errno)); + } +} + +BGuardCwd::~BGuardCwd() +{ + chdir(pwd_); + free(pwd_); +} +} // namespace OHOS::FileManagement::Backup diff --git a/utils/src/b_process/b_guard_signal.cpp b/utils/src/b_process/b_guard_signal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..90f0f80503fe5501e677baa2eb19d1b40133c464 --- /dev/null +++ b/utils/src/b_process/b_guard_signal.cpp @@ -0,0 +1,41 @@ +/* + * 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 "b_process/b_guard_signal.h" + +#include + +#include "b_error/b_error.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; +BGuardSignal::BGuardSignal(int sig) : sig_(sig) +{ + prevHandler_ = signal(sig, SIG_DFL); + if (prevHandler_ == SIG_ERR) { + stringstream ss; + ss << "Invalid sigal " << sig << ", received error " << system_category().message(errno); + throw BError(BError::Codes::UTILS_INVAL_PROCESS_ARG, ss.str()); + } +} + +BGuardSignal::~BGuardSignal() +{ + if (signal(sig_, prevHandler_) == SIG_ERR) { + HILOGE("Failed to reset sig %{public}d", sig_); + } +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/src/b_process/b_process.cpp b/utils/src/b_process/b_process.cpp new file mode 100644 index 0000000000000000000000000000000000000000..752353cb31145f86e49f7cb44cf3448cadd2e891 --- /dev/null +++ b/utils/src/b_process/b_process.cpp @@ -0,0 +1,116 @@ +/* + * 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 "b_process/b_process.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "b_process/b_guard_signal.h" +#include "errors.h" +#include "filemgmt_libhilog.h" +#include "securec.h" +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +static tuple WaitForChild(pid_t pid, + unique_ptr> pipeStream, + function DetectFatalLog) +{ + const int BUF_LEN = 1024; + auto buf = make_unique(BUF_LEN); + int status = 0; + + do { + regex reg("^\\W*$"); + while ((void)memset_s(buf.get(), BUF_LEN, 0, BUF_LEN), + fgets(buf.get(), BUF_LEN - 1, pipeStream.get()) != nullptr) { + if (regex_match(buf.get(), reg)) { + continue; + } + HILOGE("child process output error: %{public}s", buf.get()); + if (DetectFatalLog && DetectFatalLog(string_view(buf.get()))) { + return {true, EPERM}; + } + } + + if (waitpid(pid, &status, 0) == -1) { + throw BError(BError::Codes::UTILS_INVAL_PROCESS_ARG, generic_category().message(errno)); + } else if (WIFEXITED(status)) { + return {false, WEXITSTATUS(status)}; + } else if (WIFSIGNALED(status)) { + // 因某种信号中断获取状态 + // 异常机制存在问题,导致应用在正常的错误下Crash。为确保测试顺利展开,此处暂时屏蔽崩溃错误。 + HILOGE("some fatal errors occurred, child process is killed by a signal."); + return {true, EPERM}; + } + } while (!WIFEXITED(status) && !WIFSIGNALED(status)); + + HILOGE("If you look at me, there are some fatal errors occurred!!!"); + return {true, EPERM}; +} + +tuple BProcess::ExecuteCmd(vector argvSv, function DetectFatalLog) +{ + vector argv; + auto getStringViewData = [](const auto &arg) { return arg.data(); }; + transform(argvSv.begin(), argvSv.end(), back_inserter(argv), getStringViewData); + argv.push_back(nullptr); + + // 临时将SIGCHLD恢复成默认值,从而能够从作为僵尸进程的子进程中获得返回值 + BGuardSignal guard(SIGCHLD); + + int pipeFd[2]; + if (pipe(pipeFd) < 0) { + throw BError(BError::Codes::UTILS_INTERRUPTED_PROCESS, generic_category().message(errno)); + } + + pid_t pid = 0; + if ((pid = fork()) == 0) { + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(pipeFd[0]); + UniqueFd fd(pipeFd[1]); + if (dup2(pipeFd[1], STDERR_FILENO) == -1) { + throw BError(BError::Codes::UTILS_INTERRUPTED_PROCESS, generic_category().message(errno)); + } + exit((execvp(argv[0], const_cast(argv.data())) == -1) ? errno : 0); + } + + UniqueFd fd(pipeFd[0]); + close(pipeFd[1]); + if (pid == -1) { + throw BError(BError::Codes::UTILS_INVAL_PROCESS_ARG, generic_category().message(errno)); + } + unique_ptr> pipeStream {fdopen(pipeFd[0], "r"), fclose}; + if (!pipeStream) { + throw BError(errno); + } + fd.Release(); + + return WaitForChild(pid, move(pipeStream), DetectFatalLog); +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/src/b_tarball/b_tarball_cmdline.cpp b/utils/src/b_tarball/b_tarball_cmdline.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eff185c439865b6561720bd12ca3c5d5bf97be62 --- /dev/null +++ b/utils/src/b_tarball/b_tarball_cmdline.cpp @@ -0,0 +1,91 @@ +/* + * 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 "b_tarball/b_tarball_cmdline.h" + +#include +#include +#include + +#include "b_error/b_error.h" +#include "b_process/b_guard_cwd.h" +#include "b_process/b_process.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +static bool IsTarFatalErrorOccur(string_view output) +{ + vector fatalError {"EOF", "bad xform", "bad header", "sparse overflow", + "short header", "empty archive", "Not tar"}; + for (auto &item : fatalError) { + if (output.find(item) != string_view::npos) { + return true; + } + } + return false; +} + +void BTarballCmdline::Tar(string_view root, vector includes, vector excludes) +{ + // 切换到根路径,从而在打包时使用文件或目录的相对路径 + BGuardCwd guard(root); + + vector argv = { + "/system/bin/tar", + "-cf", + tarballPath_, + }; + + if (includes.empty()) { + throw BError(BError::Codes::UTILS_INVAL_TARBALL_ARG, "tar includes argument must be not empty"); + } + + for (auto &&include : includes) { + argv.push_back(include); + } + for (auto &&exclude : excludes) { + argv.push_back("--exclude"); + argv.push_back(exclude); + } + + // 如果打包后生成了打包文件,则默认打包器打包时生成的错误可以忽略(比如打包一个不存在的文件) + auto [bFatalError, errCode] = BProcess::ExecuteCmd(argv, IsTarFatalErrorOccur); + if (bFatalError || (errCode && access(tarballPath_.data(), F_OK) != 0)) { + stringstream ss; + ss << "Is a fatal error occurred: " << bFatalError << ", error code : " << errCode; + throw BError(BError::Codes::UTILS_INVAL_PROCESS_ARG, ss.str()); + } +} + +void BTarballCmdline::Untar(string_view root) +{ + vector argv = { + "tar", "-xf", tarballPath_, "-C", root, + }; + auto [bFatalError, errCode] = BProcess::ExecuteCmd(argv, IsTarFatalErrorOccur); + if (bFatalError) { + stringstream ss; + ss << "Is a fatal error occurred in untar process: " << bFatalError << ", error code : " << errCode; + throw BError(BError::Codes::UTILS_INVAL_PROCESS_ARG, ss.str()); + } +} + +BTarballCmdline::BTarballCmdline(string_view tarballDir, string_view tarballName) + : tarballDir_(tarballDir), tarballName_(tarballName) +{ + tarballPath_ = tarballDir_ + "/" + tarballName_; +} +} // namespace OHOS::FileManagement::Backup diff --git a/utils/src/b_tarball/b_tarball_factory.cpp b/utils/src/b_tarball/b_tarball_factory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f3d13032b29f07eb80e4fb1bf8a3dc421ff0a4b --- /dev/null +++ b/utils/src/b_tarball/b_tarball_factory.cpp @@ -0,0 +1,181 @@ +/* + * 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 "b_tarball/b_tarball_factory.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "b_error/b_error.h" +#include "b_tarball/b_tarball_cmdline.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +/** + * @brief Verifying untar input parameters + * + * @param root Root directory for storing unpacked files + * An absolute path is required. + */ +static void UntarFort(string_view root) +{ + auto resolvedPath = make_unique(PATH_MAX); + if (!realpath(root.data(), resolvedPath.get()) || (string_view(resolvedPath.get()) != root)) { + throw BError(BError::Codes::UTILS_INVAL_TARBALL_ARG, "The root must be an existing canonicalized path"); + } +} + +/** + * @brief Filtering tar input parameters + * + * @param tarballDir Directory where the package file is stored + * @param root Root directory of the file to be packed + * An absolute path is required. + * @param includes Path to be packed in the root directory. + * The relative path is required. If this parameter is not specified, all packages are packed by default. + * @param excludes The part that does not need to be packed in the path to be packed + * Requires a relative path. Can be used to exclude some subdirectories + * @return std::tuple, vector> 返回合法的includes, excludes + */ +static tuple, vector> TarFilter(string_view tarballDir, + string_view root, + const vector &includes, + const vector &excludes) +{ + auto resolvedPath = make_unique(PATH_MAX); + if (!realpath(root.data(), resolvedPath.get()) || (string_view(resolvedPath.get()) != root)) { + throw BError(BError::Codes::UTILS_INVAL_TARBALL_ARG, "The root must be an existing canonicalized path"); + } + + auto removeBackSlash = [](const string_view &arg) -> string { + if (arg.empty()) { + return ""; + } + + size_t i = arg.size() - 1; + for (; i > 0; --i) { + if (arg[i] != '/') { + break; + } + } + return {arg.data(), i + 1}; + }; + + vector newExcludes; + for (auto &item : excludes) { + string str = removeBackSlash(item); + if (!str.empty()) { + newExcludes.push_back(str); + } + } + + return {{includes.begin(), includes.end()}, newExcludes}; +} + +/** + * @brief 校验tarball路径,并将之拆分为路径和文件名 + * + * @param tarballPath tarball全路径 + * @return tuple 路径和文件名 + */ +static tuple GetTarballDirAndName(string_view tarballPath) +{ + char *buf4Dir = strdup(tarballPath.data()); + if (!buf4Dir) { + throw BError(BError::Codes::UTILS_INVAL_TARBALL_ARG, "Out of memory"); + } + string tarballDir = dirname(buf4Dir); + free(buf4Dir); + + char *buf4Name = strdup(tarballPath.data()); + if (!buf4Name) { + throw BError(BError::Codes::UTILS_INVAL_TARBALL_ARG, "Out of memory"); + } + string tarballName = basename(buf4Name); + free(buf4Name); + + auto resolvedPath = make_unique(PATH_MAX); + if (!realpath(tarballDir.data(), resolvedPath.get())) { + throw BError(BError::Codes::UTILS_INVAL_TARBALL_ARG, generic_category().message(errno)); + } + if (auto canonicalizedTarballDir = string_view(resolvedPath.get()); canonicalizedTarballDir != tarballDir) { + throw BError(BError::Codes::UTILS_INVAL_TARBALL_ARG, "Tarball path differed after canonicalizing"); + } + if (auto suffix = string_view(".tar"); + tarballPath.length() <= suffix.length() || + !equal(tarballPath.rbegin(), next(tarballPath.rbegin(), suffix.length()), suffix.rbegin(), suffix.rend())) { + throw BError(BError::Codes::UTILS_INVAL_TARBALL_ARG, "Tarball path didn't end with '.tar'"); + } + return {tarballDir, tarballName}; +} + +/** + * @brief 绑定命令行实现的打包器 + * + * @param tarballDir taball路径 + * @param tarballName taball文件名 + * @return unique_ptr 打包器实现,包括tar和untar两种方法 + * @see GetTarballDirAndName + */ +static unique_ptr BindCmdline(string_view tarballDir, string_view tarballName) +{ + auto ptr = make_shared(tarballDir, tarballName); + + return make_unique(BTarballFactory::Impl { + .tar = bind(&BTarballCmdline::Tar, ptr, placeholders::_1, placeholders::_2, placeholders::_3), + .untar = bind(&BTarballCmdline::Untar, ptr, placeholders::_1), + }); +} + +unique_ptr BTarballFactory::Create(string_view implType, string_view tarballPath) +{ + static map(string_view, string_view)>> mapType2Tarball = { + {"cmdline", BindCmdline}, + }; + + try { + auto [tarballDir, tarballName] = GetTarballDirAndName(tarballPath); + auto tarballImpl = mapType2Tarball.at(implType)(tarballDir, tarballName); + if (tarballImpl->tar) { + tarballImpl->tar = [tarballDir {string(tarballDir)}, tar {tarballImpl->tar}]( + string_view root, vector includes, vector excludes) { + auto [newIncludes, newExcludes] = TarFilter(tarballDir, root, includes, excludes); + tar(root, {newIncludes.begin(), newIncludes.end()}, {newExcludes.begin(), newExcludes.end()}); + }; + } + if (tarballImpl->untar) { + tarballImpl->untar = [untar {tarballImpl->untar}](string_view root) { + UntarFort(root); + untar(root); + }; + } + return tarballImpl; + } catch (const out_of_range &e) { + stringstream ss; + ss << "Unsupported implementation " << implType; + throw BError(BError::Codes::UTILS_INVAL_TARBALL_ARG, ss.str()); + } +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_extended_data.cpp b/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_extended_data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc613a1bf40848bde0ae157fa82f4f5d665fbc9e --- /dev/null +++ b/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_extended_data.cpp @@ -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. + */ + +#include "b_tarball/b_tarball_posix/b_tarball_posix_extended_data.h" + +#include + +#include "b_resources/b_constants.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +BTarballPosixExtendedData::BTarballPosixExtendedData(const string &pathName, const struct stat &statInfo) +{ + for (BConstants::EntryKey entryKey = BConstants::SUPER_LONG_PATH; entryKey <= BConstants::SUPER_LONG_SIZE; + entryKey = static_cast(entryKey + 1)) { + auto extEntryOptional = BTarballPosixExtendedEntry::TryToGetEntry(entryKey, pathName, statInfo); + if (extEntryOptional != nullopt) { + entries_.emplace_back(move(extEntryOptional.value())); + } + } + + for (BTarballPosixExtendedEntry &entry : entries_) { + entriesSize_ += entry.GetEntrySize(); + } +} + +size_t BTarballPosixExtendedData::GetEntriesSize() +{ + return entriesSize_; +} + +void BTarballPosixExtendedData::Publish(const UniqueFd &outFile) +{ + for (BTarballPosixExtendedEntry &entry : entries_) { + entry.Publish(outFile); + } + char block[BConstants::BLOCK_SIZE] {}; + size_t nBytesCompleted = BConstants::BLOCK_SIZE - entriesSize_ % BConstants::BLOCK_SIZE; + if (nBytesCompleted < BConstants::BLOCK_SIZE) { + if (write(outFile, block, nBytesCompleted) == -1) { + printf("BTarballPosixExtendedData::Publish: write\n"); + throw exception(); + } + } +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_extended_entry.cpp b/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_extended_entry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c01b88eacdab07206c226a0a3ab4ff1745b2e17 --- /dev/null +++ b/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_extended_entry.cpp @@ -0,0 +1,91 @@ +/* + * 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 "b_tarball/b_tarball_posix/b_tarball_posix_extended_entry.h" + +#include +#include +#include + +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +optional BTarballPosixExtendedEntry::TryToGetEntry(BConstants::EntryKey entryKey, + const string &pathName, + const struct stat &statInfo) +{ + switch (entryKey) { + case BConstants::SUPER_LONG_PATH: { + string::size_type firstNotSlashIndex = pathName.find_first_not_of('/'); + string tmpPathName = pathName.substr(firstNotSlashIndex); + if (tmpPathName.size() > BConstants::PATHNAME_MAX_SIZE) { + return BTarballPosixExtendedEntry(BConstants::ENTRY_NAME_PATH, tmpPathName); + } + break; + } + case BConstants::SUPER_LONG_LINK_PATH: { + if ((statInfo.st_mode & S_IFMT) == S_IFLNK) { + char linkName[PATH_MAX] {}; + ssize_t linkSize = readlink(pathName.c_str(), linkName, PATH_MAX); + if (linkSize > BConstants::LINKNAME_MAX_SIZE) { + return BTarballPosixExtendedEntry(BConstants::ENTRY_NAME_LINKPATH, linkName); + } + } + break; + } + case BConstants::SUPER_LONG_SIZE: { + if (statInfo.st_size > BConstants::FILESIZE_MAX) { + return BTarballPosixExtendedEntry(BConstants::ENTRY_NAME_SIZE, to_string(statInfo.st_size)); + } + break; + } + } + return {}; +} + +size_t BTarballPosixExtendedEntry::GetEntrySize() +{ + return entrySize_; +} + +void BTarballPosixExtendedEntry::Publish(const UniqueFd &outFile) +{ + if (write(outFile, entry_.c_str(), entry_.size()) == -1) { + printf("BTarballPosixExtendedEntry::Publish: write\n"); + throw exception(); + } +} + +BTarballPosixExtendedEntry::BTarballPosixExtendedEntry(const string &entryName, const string &entryValue) + : entryName_(entryName), entryValue_(entryValue) +{ + size_t fieldSize = entryName_.size() + entryValue_.size() + string_view(" =\n").size(); + size_t digitsNum = 0; + size_t tmp = fieldSize; + size_t nextHigherPowerOfTen = 1; + while (tmp > 0) { + tmp /= BConstants::DECIMAL_BASE; + ++digitsNum; + nextHigherPowerOfTen *= BConstants::DECIMAL_BASE; + } + if (digitsNum + fieldSize >= nextHigherPowerOfTen) { + ++digitsNum; + } + entrySize_ = digitsNum + fieldSize; + entry_ = to_string(entrySize_) + " " + entryName_ + "=" + entryValue_ + "\n"; +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_extended_header.cpp b/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_extended_header.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b348006c52a511c84b51fdc4534659661dc277bc --- /dev/null +++ b/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_extended_header.cpp @@ -0,0 +1,47 @@ +/* + * 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 "b_tarball/b_tarball_posix/b_tarball_posix_extended_header.h" + +#include + +#include "b_encryption/b_encryption.h" +#include "b_resources/b_constants.h" +#include "securec.h" +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +BTarballPosixExtendedHeader::BTarballPosixExtendedHeader(BTarballPosixExtendedData &extData) +{ + (void)snprintf_s(header_.fileSize, BConstants::FILESIZE_MAX_SIZE, BConstants::FILESIZE_MAX_SIZE - 1, "%lo", + extData.GetEntriesSize()); + header_.typeFlag = BConstants::TYPEFLAG_EXTENDED; // typeFlag = 'x' + unsigned int chksum = BEncryption::CalculateChksum((char *)&header_, BConstants::HEADER_SIZE); + (void)snprintf_s(header_.chksum, BConstants::CHKSUM_MAX_SIZE - 1, BConstants::CHKSUM_MAX_SIZE - 2, "%6o", + chksum); // chksum字段的字符串休止符在字段数组的倒数第2个位置 +} + +void BTarballPosixExtendedHeader::Publish(const UniqueFd &outFile) +{ + if (strcmp(header_.fileSize, "0") != 0) { + if (write(outFile, &header_, BConstants::HEADER_SIZE) == -1) { + printf("ExtendedHeader::Publish: write\n"); + throw exception(); + } + } +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_file.cpp b/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_file.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a59a3143be93fb724a13566a57ea2a8ca6bbc3c --- /dev/null +++ b/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_file.cpp @@ -0,0 +1,61 @@ +/* + * 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 "b_tarball/b_tarball_posix/b_tarball_posix_file.h" + +#include +#include +#include + +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +BTarballPosixFile::BTarballPosixFile(const string &pathName) : pathName_(pathName) +{ + struct stat inStat = {}; + file_ = UniqueFd(open(pathName.c_str(), O_RDONLY | O_NOFOLLOW)); + if (file_ == -1) { + if (errno == ELOOP) { // if this file is a symbolic link + if (lstat(pathName.c_str(), &inStat) == -1) { + printf("BTarballPosixFile::BTarballPosixFile: lstat\n"); + throw exception(); + } + } else { + printf("BTarballPosixFile::BTarballPosixFile: open\n"); + throw exception(); + } + } else { + if (fstat(file_, &inStat) == -1) { + printf("BTarballPosixFile::BTarballPosixFile: fstat\n"); + throw exception(); + } + } + + extData_ = BTarballPosixExtendedData(pathName, inStat); + extHdr_ = BTarballPosixExtendedHeader(extData_); + paxHdr_ = BTarballPosixPaxHeader(pathName, inStat); + fileData_ = BTarballPosixFileData(inStat); +} + +void BTarballPosixFile::Publish(const UniqueFd &outFile) +{ + extHdr_.Publish(outFile); + extData_.Publish(outFile); + paxHdr_.Publish(outFile); + fileData_.Publish(file_, outFile); +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_file_data.cpp b/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_file_data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b90369a1f52b418d7f16afd83fe5380e16320874 --- /dev/null +++ b/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_file_data.cpp @@ -0,0 +1,63 @@ +/* + * 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 "b_tarball/b_tarball_posix/b_tarball_posix_file_data.h" + +#include +#include + +#include "b_resources/b_constants.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +BTarballPosixFileData::BTarballPosixFileData(struct stat &statInfo) : stat_(statInfo) {} + +void BTarballPosixFileData::Publish(const UniqueFd &inFile, const UniqueFd &outFile) +{ + switch (stat_.st_mode & S_IFMT) { + case S_IFLNK: + case S_IFDIR: + break; + case S_IFREG: { + loff_t inOffset = 0; + loff_t outOffset = lseek(outFile, 0, SEEK_CUR); + ssize_t lengthToCopy = stat_.st_size; + do { + ssize_t nBytesCopied = + syscall(__NR_copy_file_range, inFile.Get(), &inOffset, outFile.Get(), &outOffset, lengthToCopy, 0); + if (nBytesCopied == -1) { + printf("BTarballPosixFileData::Publish: copy_file_range\n"); + throw exception(); + } + lseek(outFile, nBytesCopied, SEEK_CUR); + lengthToCopy -= nBytesCopied; + } while (lengthToCopy > 0); + + char block[BConstants::BLOCK_SIZE] {}; + size_t nBytesCompleted = BConstants::BLOCK_SIZE - stat_.st_size % BConstants::BLOCK_SIZE; + if (nBytesCompleted < BConstants::BLOCK_SIZE) { + if (write(outFile, block, nBytesCompleted) == -1) { + printf("BTarballPosixFileData::Publish: write\n"); + throw exception(); + } + } + break; + } + default: + break; + } +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_pax_header.cpp b/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_pax_header.cpp new file mode 100644 index 0000000000000000000000000000000000000000..03ff1033b93f38ad29ee42429559b28faf77bf21 --- /dev/null +++ b/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_pax_header.cpp @@ -0,0 +1,82 @@ +/* + * 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 "b_tarball/b_tarball_posix/b_tarball_posix_pax_header.h" + +#include +#include +#include +#include + +#include "b_encryption/b_encryption.h" +#include "b_resources/b_constants.h" +#include "securec.h" +#include "unique_fd.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +BTarballPosixPaxHeader::BTarballPosixPaxHeader(const string &pathName, const struct stat &statInfo) +{ + string::size_type firstNotSlashIndex = pathName.find_first_not_of('/'); + string tmpPathName = pathName.substr(firstNotSlashIndex); + memcpy_s(header_.pathName, BConstants::PATHNAME_MAX_SIZE, tmpPathName.c_str(), tmpPathName.size()); + (void)snprintf_s(header_.mode, BConstants::MODE_MAX_SIZE, BConstants::MODE_MAX_SIZE - 1, "%o", statInfo.st_mode); + (void)snprintf_s(header_.uid, BConstants::UGID_MAX_SIZE, BConstants::UGID_MAX_SIZE - 1, "%o", statInfo.st_uid); + (void)snprintf_s(header_.gid, BConstants::UGID_MAX_SIZE, BConstants::UGID_MAX_SIZE - 1, "%o", statInfo.st_gid); + if (statInfo.st_size <= BConstants::FILESIZE_MAX) { + (void)snprintf_s(header_.fileSize, BConstants::FILESIZE_MAX_SIZE, BConstants::FILESIZE_MAX_SIZE - 1, "%lo", + statInfo.st_size); + } + (void)snprintf_s(header_.mtime, BConstants::TIME_MAX_SIZE, BConstants::TIME_MAX_SIZE - 1, "%lo", statInfo.st_mtime); + switch (statInfo.st_mode & S_IFMT) { + case S_IFREG: + header_.typeFlag = BConstants::TYPEFLAG_REGULAR_FILE; // typeFlag = '0' + break; + case S_IFDIR: + header_.typeFlag = BConstants::TYPEFLAG_DIRECTORY; // typeFlag = '5' + break; + case S_IFLNK: + strncpy_s(header_.fileSize, BConstants::FILESIZE_MAX_SIZE, "0", 1); // size of link file is 0 + header_.typeFlag = BConstants::TYPEFLAG_SYMBOLIC_LINK; // typeFlag = '2' + if (readlink(pathName.c_str(), header_.linkName, BConstants::LINKNAME_MAX_SIZE) == -1) { + printf("BTarballPosixPaxHeader::BTarballPosixPaxHeader: readlink\n"); + throw exception(); + } + break; + default: + break; + } + strncpy_s(header_.uname, BConstants::UGNAME_MAX_SIZE, getpwuid(statInfo.st_uid)->pw_name, + BConstants::UGNAME_MAX_SIZE - 1); + strncpy_s(header_.gname, BConstants::UGNAME_MAX_SIZE, getgrgid(statInfo.st_gid)->gr_name, + BConstants::UGNAME_MAX_SIZE - 1); + (void)snprintf_s(header_.devMajor, BConstants::DEV_MAX_SIZE, BConstants::DEV_MAX_SIZE - 1, "%o", + major(statInfo.st_dev)); + (void)snprintf_s(header_.devMinor, BConstants::DEV_MAX_SIZE, BConstants::DEV_MAX_SIZE - 1, "%o", + minor(statInfo.st_dev)); + unsigned int chksum = BEncryption::CalculateChksum((char *)&header_, BConstants::HEADER_SIZE); + (void)snprintf_s(header_.chksum, BConstants::CHKSUM_MAX_SIZE - 1, BConstants::CHKSUM_MAX_SIZE - 2, "%6o", + chksum); // chksum字段的字符串休止符在字段数组的倒数第2个位置 +} + +void BTarballPosixPaxHeader::Publish(const UniqueFd &outFile) +{ + if (write(outFile, &header_, BConstants::HEADER_SIZE) == -1) { + printf("BTarballPosixPaxHeader::Publish: write\n"); + throw exception(); + } +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file diff --git a/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_tarball.cpp b/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_tarball.cpp new file mode 100644 index 0000000000000000000000000000000000000000..56e305b1f38c73c297142043209a775ec11ee7d3 --- /dev/null +++ b/utils/src/b_tarball/b_tarball_posix/b_tarball_posix_tarball.cpp @@ -0,0 +1,63 @@ +/* + * 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 "b_tarball/b_tarball_posix/b_tarball_posix_tarball.h" + +#include +#include + +#include "b_resources/b_constants.h" +#include "b_tarball/b_tarball_posix/b_tarball_posix_file.h" + +namespace OHOS::FileManagement::Backup { +using namespace std; + +BTarballPosixTarball::BTarballPosixTarball(const string pathTarball) +{ + fileTarball_ = UniqueFd(open(pathTarball.c_str(), O_WRONLY | O_CREAT, 0664)); + if (fileTarball_ == -1) { + printf("BTarballPosixTarball::BTarballPosixTarball: open\n"); + throw exception(); + } +} + +void BTarballPosixTarball::Emplace(const string pathName) +{ + BTarballPosixFile file(pathName); + if (isPublished_) { + lseek(fileTarball_, -BConstants::BLOCK_PADDING_SIZE, SEEK_CUR); + isPublished_ = false; + } + file.Publish(fileTarball_); +} + +void BTarballPosixTarball::Publish() +{ + if (!isPublished_) { + char block[BConstants::BLOCK_PADDING_SIZE] {}; + if (write(fileTarball_, block, BConstants::BLOCK_PADDING_SIZE) == -1) { + printf("BTarballPosixTarball::Publish: write\n"); + throw exception(); + } + isPublished_ = true; + } +} + +void BTarballPosixTarball::Clear() +{ + ftruncate(fileTarball_, 0); + lseek(fileTarball_, 0, SEEK_SET); +} +} // namespace OHOS::FileManagement::Backup \ No newline at end of file