From 753a6e3efb17af23c154d1285b1a766762474473 Mon Sep 17 00:00:00 2001 From: tianp Date: Sat, 26 Jul 2025 14:31:38 +0800 Subject: [PATCH 1/2] =?UTF-8?q?watcher=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: tianp Change-Id: I5c6e9f85569b14ef50cb271864b63b6d451bb980 --- .../class_watcher/ani/fs_watcher_ani.cpp | 68 + .../mod_fs/class_watcher/ani/fs_watcher_ani.h | 36 + .../class_watcher/ani/fs_watcher_wrapper.cpp | 73 + .../class_watcher/ani/fs_watcher_wrapper.h | 37 + .../ani/watch_event_listener.cpp | 114 ++ .../class_watcher/ani/watch_event_listener.h | 48 + .../class_watcher/ani/watch_event_wrapper.cpp | 66 + .../class_watcher/ani/watch_event_wrapper.h | 37 + .../mod_fs/class_watcher/fs_file_watcher.cpp | 348 +++++ .../mod_fs/class_watcher/fs_file_watcher.h | 79 + .../mod_fs/class_watcher/fs_watch_entity.h | 50 + .../src/mod_fs/class_watcher/fs_watcher.cpp | 78 + .../js/src/mod_fs/class_watcher/fs_watcher.h | 48 + .../mod_fs/class_watcher/i_watcher_callback.h | 32 + .../class_watcher/watcher_data_cache.cpp | 162 ++ .../mod_fs/class_watcher/watcher_data_cache.h | 54 + .../src/mod_fs/properties/ani/watcher_ani.cpp | 79 + .../src/mod_fs/properties/ani/watcher_ani.h | 36 + .../js/src/mod_fs/properties/watcher_core.cpp | 108 ++ .../js/src/mod_fs/properties/watcher_core.h | 32 + .../fs_file_watcher_mock_test.cpp | 1324 +++++++++++++++++ .../class_watcher/fs_watcher_mock_test.cpp | 266 ++++ .../js/mod_fs/mock/mock_watcher_callback.h | 41 + .../properties/watcher_core_mock_test.cpp | 193 +++ 24 files changed, 3409 insertions(+) create mode 100644 interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_ani.cpp create mode 100644 interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_ani.h create mode 100644 interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_wrapper.cpp create mode 100644 interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_wrapper.h create mode 100644 interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_listener.cpp create mode 100644 interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_listener.h create mode 100644 interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_wrapper.cpp create mode 100644 interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_wrapper.h create mode 100644 interfaces/kits/js/src/mod_fs/class_watcher/fs_file_watcher.cpp create mode 100644 interfaces/kits/js/src/mod_fs/class_watcher/fs_file_watcher.h create mode 100644 interfaces/kits/js/src/mod_fs/class_watcher/fs_watch_entity.h create mode 100644 interfaces/kits/js/src/mod_fs/class_watcher/fs_watcher.cpp create mode 100644 interfaces/kits/js/src/mod_fs/class_watcher/fs_watcher.h create mode 100644 interfaces/kits/js/src/mod_fs/class_watcher/i_watcher_callback.h create mode 100644 interfaces/kits/js/src/mod_fs/class_watcher/watcher_data_cache.cpp create mode 100644 interfaces/kits/js/src/mod_fs/class_watcher/watcher_data_cache.h create mode 100644 interfaces/kits/js/src/mod_fs/properties/ani/watcher_ani.cpp create mode 100644 interfaces/kits/js/src/mod_fs/properties/ani/watcher_ani.h create mode 100644 interfaces/kits/js/src/mod_fs/properties/watcher_core.cpp create mode 100644 interfaces/kits/js/src/mod_fs/properties/watcher_core.h create mode 100644 interfaces/test/unittest/js/mod_fs/class_watcher/fs_file_watcher_mock_test.cpp create mode 100644 interfaces/test/unittest/js/mod_fs/class_watcher/fs_watcher_mock_test.cpp create mode 100644 interfaces/test/unittest/js/mod_fs/mock/mock_watcher_callback.h create mode 100644 interfaces/test/unittest/js/mod_fs/properties/watcher_core_mock_test.cpp diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_ani.cpp b/interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_ani.cpp new file mode 100644 index 000000000..39d11f496 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_ani.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fs_watcher_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "fs_watcher.h" +#include "fs_watcher_wrapper.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace std; + +void FsWatcherAni::Start(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto watcher = FsWatcherWrapper::Unwrap(env, object); + if (watcher == nullptr) { + HILOGE("Cannot unwrap watcher!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return; + } + auto ret = watcher->Start(); + if (!ret.IsSuccess()) { + HILOGE("Cannot start watcher!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +void FsWatcherAni::Stop(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto watcher = FsWatcherWrapper::Unwrap(env, object); + if (watcher == nullptr) { + HILOGE("Cannot unwrap watcher!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return; + } + auto ret = watcher->Stop(); + if (!ret.IsSuccess()) { + HILOGE("Cannot stop watcher!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_ani.h b/interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_ani.h new file mode 100644 index 000000000..e6badfc7b --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_ANI_FS_WATCHER_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_ANI_FS_WATCHER_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class FsWatcherAni final { +public: + static void Start(ani_env *env, [[maybe_unused]] ani_object object); + static void Stop(ani_env *env, [[maybe_unused]] ani_object object); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_ANI_FS_WATCHER_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_wrapper.cpp b/interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_wrapper.cpp new file mode 100644 index 000000000..79d6fb1dc --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_wrapper.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fs_watcher_wrapper.h" + +#include "ani_signature.h" +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature; + +FsWatcher *FsWatcherWrapper::Unwrap(ani_env *env, ani_object object) +{ + ani_long nativePtr; + auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr); + if (ret != ANI_OK) { + HILOGE("Unwrap fsWatcher err: %{private}d", ret); + return nullptr; + } + uintptr_t ptrValue = static_cast(nativePtr); + FsWatcher *watcher = reinterpret_cast(ptrValue); + return watcher; +} + +ani_object FsWatcherWrapper::Wrap(ani_env *env, const FsWatcher *watcher) +{ + if (watcher == nullptr) { + HILOGE("FsWatcher pointer is null!"); + return nullptr; + } + auto classDesc = FS::WatcherInner::classDesc.c_str(); + ani_class cls; + if (ANI_OK != env->FindClass(classDesc, &cls)) { + HILOGE("Cannot find class %s", classDesc); + return nullptr; + } + auto ctorDesc = FS::WatcherInner::ctorDesc.c_str(); + auto ctorSig = FS::WatcherInner::ctorSig.c_str(); + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, ctorDesc, ctorSig, &ctor)) { + HILOGE("Cannot find constructor method for class %s", classDesc); + return nullptr; + } + ani_long ptr = static_cast(reinterpret_cast(watcher)); + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj, ptr)) { + HILOGE("New %s obj Failed!", classDesc); + return nullptr; + } + return obj; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_wrapper.h b/interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_wrapper.h new file mode 100644 index 000000000..15d24f94e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_wrapper.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_ANI_FS_WATCHER_WRAPPER_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_ANI_FS_WATCHER_WRAPPER_H + +#include +#include "fs_watcher.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class FsWatcherWrapper final { +public: + static FsWatcher *Unwrap(ani_env *env, ani_object object); + static ani_object Wrap(ani_env *env, const FsWatcher *watcher); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_ANI_FS_WATCHER_WRAPPER_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_listener.cpp b/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_listener.cpp new file mode 100644 index 000000000..36ac7517d --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_listener.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "watch_event_listener.h" + +#include +#include "ani_helper.h" +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" +#include "watch_event_wrapper.h" + +namespace OHOS::FileManagement::ModuleFileIO::ANI { +using namespace std; + +bool WatchEventListener::IsStrictEquals(const shared_ptr &other) const +{ + if (other->GetClassName() != className_) { + return false; + } + + const auto otherListener = static_pointer_cast(other); + if (!otherListener) { + HILOGE("Cannot convert IWatcherCallback to WatchEventListener"); + return false; + } + + ani_env *env = AniHelper::GetThreadEnv(vm); + if (!env) { + HILOGE("Current object's env is null"); + return false; + } + + ani_boolean isSame = false; + ani_status status = env->Reference_StrictEquals(callback, otherListener->callback, &isSame); + if (status != ANI_OK) { + HILOGE("Compare ref for strict equality failed. status = %{public}d", static_cast(status)); + return false; + } + return isSame; +} + +void WatchEventListener::InvokeCallback(const string &fileName, uint32_t event, uint32_t cookie) const +{ + auto watchEvent = CreateSharedPtr(); + if (watchEvent == nullptr) { + HILOGE("Failed to request heap memory."); + return; + } + + watchEvent->fileName = fileName; + watchEvent->event = event; + watchEvent->cookie = cookie; + auto task = [this, watchEvent]() { SendWatchEvent(*watchEvent); }; + AniHelper::SendEventToMainThread(task); +} + +inline static const int32_t ANI_SCOPE_SIZE = 16; + +void WatchEventListener::SendWatchEvent(const WatchEvent &watchEvent) const +{ + if (vm == nullptr) { + HILOGE("Cannot send WatchEvent because the vm is null."); + return; + } + if (callback == nullptr) { + HILOGE("Cannot send WatchEvent because the callback is null."); + return; + } + ani_size scopeSize = ANI_SCOPE_SIZE; + ani_env *env = AniHelper::GetThreadEnv(vm); + if (env == nullptr) { + HILOGE("Cannot send WatchEvent because the env is null."); + return; + } + ani_status status = env->CreateLocalScope(scopeSize); + if (status != ANI_OK) { + HILOGE("Failed to creat local scope, status: %{public}d", static_cast(status)); + return; + } + auto evtObj = WatchEventWrapper::Wrap(env, watchEvent); + if (evtObj == nullptr) { + HILOGE("Create WatchEvent obj failed!"); + return; + } + vector args = { static_cast(evtObj) }; + auto argc = args.size(); + ani_ref result; + auto cbObj = static_cast(callback); + status = env->FunctionalObject_Call(cbObj, argc, args.data(), &result); + if (status != ANI_OK) { + HILOGE("Failed to call FunctionalObject_Call, status: %{public}d", static_cast(status)); + // continue execution and not exit. + } + status = env->DestroyLocalScope(); + if (status != ANI_OK) { + HILOGE("Failed to destroy local scope, status: %{public}d", static_cast(status)); + return; + } +} + +} // namespace OHOS::FileManagement::ModuleFileIO::ANI diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_listener.h b/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_listener.h new file mode 100644 index 000000000..919739228 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_listener.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_ANI_WATCH_EVENT_LISTENER_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_ANI_WATCH_EVENT_LISTENER_H + +#include + +#include + +#include "fs_watch_entity.h" +#include "i_watcher_callback.h" + +namespace OHOS::FileManagement::ModuleFileIO::ANI { + +class WatchEventListener final : public IWatcherCallback { +public: + WatchEventListener(ani_vm *vm, const ani_ref &callback) : vm(vm), callback(callback) {} + bool IsStrictEquals(const std::shared_ptr &other) const override; + void InvokeCallback(const std::string &fileName, uint32_t event, uint32_t cookie) const override; + + std::string GetClassName() const override + { + return className_; + } + +private: + inline static const std::string className_ = "WatchEventListener"; + void SendWatchEvent(const WatchEvent &watchEvent) const; + + ani_vm *vm; + ani_ref callback; +}; + +} // namespace OHOS::FileManagement::ModuleFileIO::ANI +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_ANI_WATCH_EVENT_LISTENER_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_wrapper.cpp b/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_wrapper.cpp new file mode 100644 index 000000000..1712f7f1f --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_wrapper.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "watch_event_wrapper.h" + +#include "ani_signature.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature; + +ani_object WatchEventWrapper::Wrap(ani_env *env, const WatchEvent &evt) +{ + auto classDesc = FS::WatchEventInner::classDesc.c_str(); + ani_class cls; + if (ANI_OK != env->FindClass(classDesc, &cls)) { + HILOGE("Cannot find class %s", classDesc); + return nullptr; + } + auto ctorDesc = FS::WatchEventInner::ctorDesc.c_str(); + auto ctorSig = FS::WatchEventInner::ctorSig.c_str(); + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, ctorDesc, ctorSig, &ctor)) { + HILOGE("Cannot find constructor method for class %s", classDesc); + return nullptr; + } + + auto [succ, fileName] = TypeConverter::ToAniString(env, evt.fileName); + if (!succ) { + HILOGE("Convert fileName to ani string failed!"); + return nullptr; + } + + auto event = static_cast(evt.event); + auto cookie = static_cast(evt.cookie); + + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj, fileName, event, cookie)) { + HILOGE("Create %s obj failed!", classDesc); + return nullptr; + } + return obj; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_wrapper.h b/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_wrapper.h new file mode 100644 index 000000000..8e2ca980c --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_wrapper.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_ANI_WATCH_EVENT_WRAPPER_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_ANI_WATCH_EVENT_WRAPPER_H + +#include +#include +#include "fs_watch_entity.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class WatchEventWrapper final { +public: + static ani_object Wrap(ani_env *env, const WatchEvent &evt); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_ANI_WATCH_EVENT_WRAPPER_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/fs_file_watcher.cpp b/interfaces/kits/js/src/mod_fs/class_watcher/fs_file_watcher.cpp new file mode 100644 index 000000000..9f77d49df --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_watcher/fs_file_watcher.cpp @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "fs_file_watcher.h" + +#include +#include +#include +#include +#include + +#include + +#include "filemgmt_libhilog.h" +#include "uv.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +int32_t FsFileWatcher::GetNotifyId() +{ + return notifyFd_; +} + +bool FsFileWatcher::InitNotify() +{ + notifyFd_ = inotify_init(); + if (notifyFd_ < 0) { + HILOGE("Failed to init notify errCode:%{public}d", errno); + return false; + } + eventFd_ = eventfd(0, EFD_CLOEXEC); + if (eventFd_ < 0) { + HILOGE("Failed to init eventfd errCode:%{public}d", errno); + return false; + } + return true; +} + +int32_t FsFileWatcher::StartNotify(shared_ptr info) +{ + if (!info) { + HILOGE("Invalid param: info"); + return EINVAL; + } + + if (notifyFd_ < 0) { + HILOGE("Failed to start notify notifyFd_:%{public}d", notifyFd_); + return EIO; + } + + auto [isWatched, wd] = dataCache_.FindWatchedWd(info->fileName, info->events); + if (isWatched && wd > 0) { + info->wd = wd; + return ERRNO_NOERR; + } + + uint32_t watchEvents = 0; + if (wd != -1) { + watchEvents = dataCache_.GetFileEvents(info->fileName) | info->events; + } else { + watchEvents = info->events; + } + + int32_t newWd = inotify_add_watch(notifyFd_, info->fileName.c_str(), watchEvents); + if (newWd < 0) { + HILOGE("Failed to start notify errCode:%{public}d", errno); + return errno; + } + + info->wd = newWd; + dataCache_.UpdateWatchedEvents(info->fileName, newWd, watchEvents); + return ERRNO_NOERR; +} + +int32_t FsFileWatcher::NotifyToWatchNewEvents(const string &fileName, int32_t wd, uint32_t watchEvents) +{ + int32_t newWd = inotify_add_watch(notifyFd_, fileName.c_str(), watchEvents); + if (newWd < 0) { + HILOGE("Failed to start new notify errCode:%{public}d", errno); + return errno; + } + + if (newWd != wd) { + HILOGE("New notify wd is error"); + return EIO; + } + + dataCache_.UpdateWatchedEvents(fileName, wd, watchEvents); + return ERRNO_NOERR; +} + +int32_t FsFileWatcher::CloseNotifyFd() +{ + int32_t closeRet = ERRNO_NOERR; + + if (!dataCache_.HasWatcherInfo()) { + run_ = false; + closeRet = close(notifyFd_); + if (closeRet != 0) { + HILOGE("Failed to stop notify close fd errCode:%{public}d", errno); + } + notifyFd_ = -1; + + closeRet = close(eventFd_); + if (closeRet != 0) { + HILOGE("Failed to close eventfd errCode:%{public}d", errno); + } + eventFd_ = -1; + DestroyTaskThead(); + } + + closed_ = false; + return closeRet; +} + +int32_t FsFileWatcher::CloseNotifyFdLocked() +{ + { + lock_guard lock(readMutex_); + closed_ = true; + if (reading_) { + HILOGE("close while reading"); + return ERRNO_NOERR; + } + } + return CloseNotifyFd(); +} + +int32_t FsFileWatcher::StopNotify(shared_ptr info) +{ + if (!info) { + HILOGE("Invalid param: info"); + return EINVAL; + } + + if (notifyFd_ < 0) { + HILOGE("Failed to stop notify notifyFd_:%{public}d", notifyFd_); + return EIO; + } + + uint32_t remainingEvents = RemoveWatcherInfo(info); + if (remainingEvents > 0) { + // There are still events remaining to be listened for. + if (access(info->fileName.c_str(), F_OK) == 0) { + return NotifyToWatchNewEvents(info->fileName, info->wd, remainingEvents); + } + HILOGE("The Watched file does not exist, and the remaining monitored events will be invalid."); + return ERRNO_NOERR; + } + + // No events remain to be listened for, and proceed to the file watch removal process. + int32_t oldWd = -1; + { + lock_guard lock(readMutex_); + if (!(closed_ && reading_)) { + oldWd = inotify_rm_watch(notifyFd_, info->wd); + } else { + HILOGE("rm watch fail"); + } + } + + if (oldWd == -1) { + int32_t rmErr = errno; + if (access(info->fileName.c_str(), F_OK) == 0) { + HILOGE("Failed to stop notify errCode:%{public}d", rmErr); + dataCache_.RemoveFileWatcher(info->fileName); + CloseNotifyFdLocked(); + return rmErr; + } + } + + dataCache_.RemoveFileWatcher(info->fileName); + return CloseNotifyFdLocked(); +} + +void FsFileWatcher::ReadNotifyEvent() +{ + int32_t len = 0; + int32_t index = 0; + char buf[BUF_SIZE] = { 0 }; + struct inotify_event *event = nullptr; + + do { + len = read(notifyFd_, &buf, sizeof(buf)); + if (len < 0 && errno != EINTR) { + HILOGE("Read notify event failed! ret: %d", errno); + break; + } + } while (len < 0); + + while (index < len) { + event = reinterpret_cast(buf + index); + NotifyEvent(event); + index += sizeof(struct inotify_event) + static_cast(event->len); + } +} + +void FsFileWatcher::ReadNotifyEventLocked() +{ + { + lock_guard lock(readMutex_); + if (closed_) { + HILOGE("read after close"); + return; + } + reading_ = true; + } + + ReadNotifyEvent(); + + { + lock_guard lock(readMutex_); + reading_ = false; + if (closed_) { + HILOGE("close after read"); + CloseNotifyFd(); + return; + } + } +} + +void FsFileWatcher::AsyncGetNotifyEvent() +{ + lock_guard lock(taskMutex_); + if (!taskRunning_) { + taskRunning_ = true; + taskThead_ = thread(&FsFileWatcher::GetNotifyEvent, this); + } +} + +void FsFileWatcher::GetNotifyEvent() +{ + if (run_) { + return; + } + + run_ = true; + nfds_t nfds = 2; + struct pollfd fds[2] = { { -1 } }; + fds[0].fd = eventFd_; + fds[0].events = POLLIN; + fds[1].fd = notifyFd_; + fds[1].events = POLLIN; + int32_t ret = 0; + + while (run_) { + ret = poll(fds, nfds, pollTimeoutMs); + if (ret > 0) { + if (static_cast(fds[0].revents) & POLLNVAL) { + run_ = false; + break; + } + if (static_cast(fds[0].revents) & POLLIN) { + run_ = false; + break; + } + if (static_cast(fds[1].revents) & POLLIN) { + ReadNotifyEventLocked(); + } + } else if (ret < 0 && errno != EINTR) { + HILOGE("Failed to poll NotifyFd, errno=%{public}d", errno); + break; + } + // Ignore cases where poll returns 0 (timeout) or EINTR (interrupted system call) + } +} + +bool FsFileWatcher::AddWatcherInfo(shared_ptr info) +{ + if (!info) { + HILOGE("Invalid param: info"); + return false; + } + return dataCache_.AddWatcherInfo(info); +} + +uint32_t FsFileWatcher::RemoveWatcherInfo(shared_ptr info) +{ + if (!info) { + HILOGE("Invalid param: info"); + return EINVAL; + } + return dataCache_.RemoveWatcherInfo(info); +} + +void FsFileWatcher::NotifyEvent(const struct inotify_event *event) +{ + if (!event) { + HILOGE("Invalid inotify event"); + return; + } + + auto [matched, fileName, watcherInfos] = dataCache_.FindWatcherInfos(event->wd, event->mask); + if (!matched) { + HILOGE("Cannot find matched watcherInfos"); + return; + } + + for (const auto &info : watcherInfos) { + if (event->len > 0) { + fileName += "/" + string(event->name); + } + info->TriggerCallback(fileName, event->mask & IN_ALL_EVENTS, event->cookie); + } +} + +bool FsFileWatcher::CheckEventValid(uint32_t event) +{ + if ((event & IN_ALL_EVENTS) == event) { + return true; + } else { + HILOGE("Param event:%{public}x is not valid", event); + return false; + } +} + +void FsFileWatcher::DestroyTaskThead() +{ + if (taskThead_.joinable()) { + if (taskThead_.get_id() != std::this_thread::get_id()) { + taskThead_.join(); + } else { + taskThead_.detach(); + } + } + + { + lock_guard lock(taskMutex_); + if (taskRunning_) { + taskRunning_ = false; + run_ = false; + } + } + dataCache_.ClearCache(); +} +} // namespace OHOS::FileManagement::ModuleFileIO diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/fs_file_watcher.h b/interfaces/kits/js/src/mod_fs/class_watcher/fs_file_watcher.h new file mode 100644 index 000000000..57b83d331 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_watcher/fs_file_watcher.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_FS_FILE_WATCHER_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_FS_FILE_WATCHER_H + +#include +#include +#include + +#include + +#include "filemgmt_libfs.h" +#include "fs_watch_entity.h" +#include "singleton.h" +#include "watcher_data_cache.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +constexpr int32_t BUF_SIZE = 1024; + +class FsFileWatcher : public Singleton { +public: + int32_t GetNotifyId(); + bool InitNotify(); + int32_t StartNotify(shared_ptr info); + int32_t StopNotify(shared_ptr info); + void GetNotifyEvent(); + void AsyncGetNotifyEvent(); + bool AddWatcherInfo(shared_ptr info); + bool CheckEventValid(uint32_t event); + +public: + FsFileWatcher() = default; + ~FsFileWatcher() = default; + FsFileWatcher(const FsFileWatcher &) = delete; + FsFileWatcher &operator=(const FsFileWatcher &) = delete; + +private: + uint32_t RemoveWatcherInfo(shared_ptr info); + void NotifyEvent(const struct inotify_event *event); + int32_t CloseNotifyFd(); + int32_t CloseNotifyFdLocked(); + int32_t NotifyToWatchNewEvents(const string &fileName, int32_t wd, uint32_t watchEvents); + void ReadNotifyEvent(); + void ReadNotifyEventLocked(); + void DestroyTaskThead(); + +private: + static constexpr int32_t pollTimeoutMs = 500; + + mutex taskMutex_; + mutex readMutex_; + + atomic taskRunning_ = false; + thread taskThead_; + + bool run_ = false; + bool reading_ = false; + bool closed_ = false; + int32_t notifyFd_ = -1; + int32_t eventFd_ = -1; + WatcherDataCache dataCache_; +}; + +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_FS_FILE_WATCHER_H diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/fs_watch_entity.h b/interfaces/kits/js/src/mod_fs/class_watcher/fs_watch_entity.h new file mode 100644 index 000000000..88fe92b18 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_watcher/fs_watch_entity.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_FS_WATCH_ENTITY_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_FS_WATCH_ENTITY_H + +#include +#include +#include +#include "i_watcher_callback.h" + +namespace OHOS::FileManagement::ModuleFileIO { + +struct WatchEvent { + std::string fileName = ""; + uint32_t event = 0; + uint32_t cookie = 0; +}; + +struct WatcherInfo { + std::string fileName = ""; + uint32_t events = 0; + int32_t wd = -1; + std::shared_ptr callback; + + explicit WatcherInfo(std::shared_ptr callback) : callback(std::move(callback)) {} + + void TriggerCallback(const std::string &fileName, uint32_t event, uint32_t cookie) const + { + callback->InvokeCallback(fileName, event, cookie); + } +}; + +struct FsWatchEntity { + std::shared_ptr data_; +}; + +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_FS_WATCH_ENTITY_H diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/fs_watcher.cpp b/interfaces/kits/js/src/mod_fs/class_watcher/fs_watcher.cpp new file mode 100644 index 000000000..6be590065 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_watcher/fs_watcher.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "fs_watcher.h" + +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "fs_file_watcher.h" +#include "fs_watch_entity.h" +#include "securec.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +FsResult FsWatcher::Constructor() +{ + auto watchEntity = CreateUniquePtr(); + if (watchEntity == nullptr) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + + FsWatcher *watcherPtr = new FsWatcher(move(watchEntity)); + + if (watcherPtr == nullptr) { + HILOGE("Failed to create FsWatcher object on heap."); + return FsResult::Error(ENOMEM); + } + + return FsResult::Success(move(watcherPtr)); +} + +FsResult FsWatcher::Stop() +{ + if (!watchEntity) { + HILOGE("Failed to get watchEntity when stop."); + return FsResult::Error(EINVAL); + } + int ret = FsFileWatcher::GetInstance().StopNotify(watchEntity->data_); + if (ret != ERRNO_NOERR) { + HILOGE("Failed to stopNotify errno:%{public}d", errno); + return FsResult::Error(ret); + } + return FsResult::Success(); +} + +FsResult FsWatcher::Start() +{ + if (!watchEntity) { + HILOGE("Failed to get watchEntity when start."); + return FsResult::Error(EINVAL); + } + + shared_ptr info = watchEntity->data_; + int ret = FsFileWatcher::GetInstance().StartNotify(info); + if (ret != ERRNO_NOERR) { + HILOGE("Failed to startNotify."); + return FsResult::Error(ret); + } + + FsFileWatcher::GetInstance().AsyncGetNotifyEvent(); + + return FsResult::Success(); +} + +} // namespace OHOS::FileManagement::ModuleFileIO diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/fs_watcher.h b/interfaces/kits/js/src/mod_fs/class_watcher/fs_watcher.h new file mode 100644 index 000000000..46a1c5340 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_watcher/fs_watcher.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_FS_WATCHER_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_FS_WATCHER_H + +#include "filemgmt_libfs.h" +#include "fs_watch_entity.h" + +namespace OHOS::FileManagement::ModuleFileIO { + +class FsWatcher { +public: + static FsResult Constructor(); + FsResult Start(); + FsResult Stop(); + + FsWatchEntity *GetWatchEntity() const + { + return watchEntity.get(); + } + + FsWatcher(const FsWatcher &) = delete; + FsWatcher &operator=(const FsWatcher &) = delete; + + FsWatcher(FsWatcher &&) noexcept = default; + FsWatcher &operator=(FsWatcher &&) noexcept = default; + + ~FsWatcher() = default; + +private: + unique_ptr watchEntity; + explicit FsWatcher(unique_ptr entity) : watchEntity(move(entity)) {} +}; +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_FS_WATCHER_H diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/i_watcher_callback.h b/interfaces/kits/js/src/mod_fs/class_watcher/i_watcher_callback.h new file mode 100644 index 000000000..a6baaa782 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_watcher/i_watcher_callback.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_I_WATCHER_CALLBACK_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_I_WATCHER_CALLBACK_H + +#include + +namespace OHOS::FileManagement::ModuleFileIO { + +class IWatcherCallback { +public: + virtual ~IWatcherCallback() = default; + virtual bool IsStrictEquals(const std::shared_ptr &other) const = 0; + virtual void InvokeCallback(const std::string &fileName, uint32_t event, uint32_t cookie) const = 0; + virtual std::string GetClassName() const = 0; +}; + +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_I_WATCHER_CALLBACK_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/watcher_data_cache.cpp b/interfaces/kits/js/src/mod_fs/class_watcher/watcher_data_cache.cpp new file mode 100644 index 000000000..83b5e2a51 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_watcher/watcher_data_cache.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "watcher_data_cache.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::ModuleFileIO { + +bool WatcherDataCache::AddWatcherInfo(std::shared_ptr info) +{ + std::lock_guard lock(cacheMutex_); + for (auto &iter : watcherInfoCache_) { + if (iter->fileName == info->fileName && iter->events == info->events) { + bool isSame = iter->callback->IsStrictEquals(info->callback); + if (isSame) { + HILOGE("Failed to add watcher, fileName:%{private}s the callback is same", info->fileName.c_str()); + return false; + } + } + } + watcherInfoCache_.push_back(info); + wdFileNameCache_[info->fileName] = std::make_pair(info->wd, info->events); + return true; +} + +uint32_t WatcherDataCache::RemoveWatcherInfo(std::shared_ptr info) +{ + std::lock_guard lock(cacheMutex_); + auto it = std::find(watcherInfoCache_.begin(), watcherInfoCache_.end(), info); + if (it != watcherInfoCache_.end()) { + watcherInfoCache_.erase(it); + } + + uint32_t remainingEvents = 0; + for (const auto &iter : watcherInfoCache_) { + if (iter->fileName == info->fileName && iter->wd > 0) { + remainingEvents |= iter->events; + } + } + + return remainingEvents; +} + +bool WatcherDataCache::RemoveFileWatcher(const std::string &fileName) +{ + std::lock_guard lock(cacheMutex_); + + auto iter = wdFileNameCache_.find(fileName); + if (iter == wdFileNameCache_.end()) { + return false; + } + wdFileNameCache_.erase(iter); + + watcherInfoCache_.erase(std::remove_if(watcherInfoCache_.begin(), watcherInfoCache_.end(), + [&fileName](const std::shared_ptr &info) { + return info->fileName == fileName; + }), watcherInfoCache_.end()); + + return true; +} + +std::tuple WatcherDataCache::FindWatchedWd(const std::string &fileName, uint32_t event) +{ + std::lock_guard lock(cacheMutex_); + + int32_t wd = -1; + auto iter = wdFileNameCache_.find(fileName); + if (iter == wdFileNameCache_.end()) { + return { false, wd }; + } + + wd = iter->second.first; + if ((iter->second.second & event) == event) { + return { true, wd }; + } + + return { false, wd }; +} + +bool WatcherDataCache::UpdateWatchedEvents(const std::string &fileName, int32_t wd, uint32_t events) +{ + std::lock_guard lock(cacheMutex_); + auto iter = wdFileNameCache_.find(fileName); + if (iter == wdFileNameCache_.end()) { + return false; + } + + iter->second = std::make_pair(wd, events); + return true; +} + +static bool CheckIncludeEvent(uint32_t mask, uint32_t event) +{ + return (mask & event) > 0; +} + +std::tuple>> WatcherDataCache::FindWatcherInfos( + int32_t wd, uint32_t eventMask) +{ + std::lock_guard lock(cacheMutex_); + std::string fileName; + bool found = false; + for (const auto &[key, val] : wdFileNameCache_) { + if (val.first == wd) { + fileName = key; + found = true; + break; + } + } + + if (!found) { + return { false, "", {} }; + } + + std::vector> matchedInfos; + for (const auto &info : watcherInfoCache_) { + uint32_t watchEvent = 0; + if ((info->fileName == fileName) && (info->wd > 0)) { + watchEvent = info->events; + } + if (CheckIncludeEvent(eventMask, watchEvent)) { + matchedInfos.push_back(info); + } + } + return { !matchedInfos.empty(), fileName, matchedInfos }; +} + +uint32_t WatcherDataCache::GetFileEvents(const std::string &fileName) +{ + std::lock_guard lock(cacheMutex_); + auto iter = wdFileNameCache_.find(fileName); + if (iter == wdFileNameCache_.end()) { + return 0; + } + return iter->second.second; +} + +bool WatcherDataCache::HasWatcherInfo() const +{ + std::lock_guard lock(cacheMutex_); + return !watcherInfoCache_.empty(); +} + +void WatcherDataCache::ClearCache() +{ + std::lock_guard lock(cacheMutex_); + watcherInfoCache_.clear(); + wdFileNameCache_.clear(); +} + +} // namespace OHOS::FileManagement::ModuleFileIO \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/watcher_data_cache.h b/interfaces/kits/js/src/mod_fs/class_watcher/watcher_data_cache.h new file mode 100644 index 000000000..e18d584f1 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_watcher/watcher_data_cache.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_WATCHER_DATA_CACHE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_WATCHER_DATA_CACHE_H + +#include +#include +#include +#include +#include + +#include "fs_watch_entity.h" + +namespace OHOS::FileManagement::ModuleFileIO { + +class WatcherDataCache { +public: + bool AddWatcherInfo(std::shared_ptr info); + uint32_t RemoveWatcherInfo(std::shared_ptr info); + bool RemoveFileWatcher(const std::string &fileName); + std::tuple FindWatchedWd(const std::string &fileName, uint32_t event); + bool UpdateWatchedEvents(const std::string &fileName, int32_t wd, uint32_t events); + std::tuple>> FindWatcherInfos( + int32_t wd, uint32_t eventMask); + uint32_t GetFileEvents(const std::string &fileName); + bool HasWatcherInfo() const; + void ClearCache(); + +public: + WatcherDataCache() = default; + ~WatcherDataCache() = default; + WatcherDataCache(const WatcherDataCache &) = delete; + WatcherDataCache &operator=(const WatcherDataCache &) = delete; + +private: + mutable std::mutex cacheMutex_; + std::vector> watcherInfoCache_; + std::unordered_map> wdFileNameCache_; +}; + +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_WATCHER_WATCHER_DATA_CACHE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/watcher_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/watcher_ani.cpp new file mode 100644 index 000000000..f0641c93f --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/watcher_ani.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "watcher_ani.h" + +#include "ani_helper.h" +#include "error_handler.h" +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "fs_watcher_wrapper.h" +#include "watch_event_listener.h" +#include "watcher_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace OHOS::FileManagement::ModuleFileIO; + +ani_object WatcherAni::CreateWatcherSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_double events, ani_ref listener) +{ + auto [succPath, filePath] = TypeConverter::ToUTF8String(env, path); + if (!succPath) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + ani_ref cbRef; + if (ANI_OK != env->GlobalReference_Create(move(listener), &cbRef)) { + HILOGE("Failed to get callback"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + ani_vm *vm = nullptr; + env->GetVM(&vm); + auto eventListener = CreateSharedPtr(vm, cbRef); + if (eventListener == nullptr) { + HILOGE("Failed to request heap memory."); + ErrorHandler::Throw(env, ENOMEM); + return nullptr; + } + + FsResult ret = + WatcherCore::DoCreateWatcher(filePath, static_cast(events), move(eventListener)); + if (!ret.IsSuccess()) { + HILOGE("Create watcher failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + const FsWatcher *watcher = ret.GetData().value(); + auto result = FsWatcherWrapper::Wrap(env, move(watcher)); + if (result == nullptr) { + delete watcher; + watcher = nullptr; + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/watcher_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/watcher_ani.h new file mode 100644 index 000000000..1175c2f6f --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/watcher_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_WATCHER_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_WATCHER_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class WatcherAni final { +public: + static ani_object CreateWatcherSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_double events, ani_ref listener); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_WATCHER_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/watcher_core.cpp b/interfaces/kits/js/src/mod_fs/properties/watcher_core.cpp new file mode 100644 index 000000000..1ea4a713a --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/watcher_core.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "watcher_core.h" + +#include +#include +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "fs_file_watcher.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +static FsResult InstantiateWatcher() +{ + if (FsFileWatcher::GetInstance().GetNotifyId() < 0 && !FsFileWatcher::GetInstance().InitNotify()) { + HILOGE("Failed to get notifyId or initnotify fail"); + return FsResult::Error(errno); + } + FsResult result = FsWatcher::Constructor(); + if (!result.IsSuccess()) { + HILOGE("Failed to instantiate watcher"); + return FsResult::Error(EIO); + } + return result; +} + +shared_ptr ToWatcherInfo( + const string &path, const int32_t events, shared_ptr callback, int32_t &errCode) +{ + if (events <= 0 || !FsFileWatcher::GetInstance().CheckEventValid(events)) { + HILOGE("Failed to get watcher event."); + errCode = EINVAL; + return nullptr; + } + + if (!callback) { + HILOGE("Failed to get callback"); + errCode = EINVAL; + return nullptr; + } + + auto info = CreateSharedPtr(callback); + if (info == nullptr) { + HILOGE("Failed to request heap memory."); + errCode = ENOMEM; + return nullptr; + } + + info->events = static_cast(events); + info->fileName = move(path); + return info; +} + +FsResult WatcherCore::DoCreateWatcher( + const string &path, const int32_t events, shared_ptr callback) +{ + int errCode = 0; + auto info = ToWatcherInfo(path, events, callback, errCode); + if (errCode != 0) { + HILOGE("Failed to parse param"); + return FsResult::Error(errCode); + } + + auto result = InstantiateWatcher(); + if (!result.IsSuccess()) { + return result; + } + + const FsWatcher *objWatcher = result.GetData().value(); + if (!objWatcher) { + HILOGE("Failed to get fsWatcher"); + return FsResult::Error(EIO); + } + + auto *watchEntity = objWatcher->GetWatchEntity(); + if (!watchEntity) { + HILOGE("Failed to get watchEntity."); + delete objWatcher; + objWatcher = nullptr; + return FsResult::Error(EIO); + } + + watchEntity->data_ = info; + + bool ret = FsFileWatcher::GetInstance().AddWatcherInfo(info); + if (!ret) { + HILOGE("Failed to add watcher info."); + return FsResult::Error(EINVAL); + } + return result; +} +} // namespace OHOS::FileManagement::ModuleFileIO diff --git a/interfaces/kits/js/src/mod_fs/properties/watcher_core.h b/interfaces/kits/js/src/mod_fs/properties/watcher_core.h new file mode 100644 index 000000000..4a303dbcb --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/watcher_core.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_WATCHER_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_WATCHER_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_watch_entity.h" +#include "fs_watcher.h" + +namespace OHOS::FileManagement::ModuleFileIO { + +class WatcherCore final { +public: + static FsResult DoCreateWatcher( + const std::string &path, const int32_t events, std::shared_ptr callback); +}; + +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_WATCHER_CORE_H \ No newline at end of file diff --git a/interfaces/test/unittest/js/mod_fs/class_watcher/fs_file_watcher_mock_test.cpp b/interfaces/test/unittest/js/mod_fs/class_watcher/fs_file_watcher_mock_test.cpp new file mode 100644 index 000000000..fe585ef71 --- /dev/null +++ b/interfaces/test/unittest/js/mod_fs/class_watcher/fs_file_watcher_mock_test.cpp @@ -0,0 +1,1324 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include + +#include "eventfd_mock.h" +#include "filemgmt_libhilog.h" +#include "fs_file_watcher.h" +#include "inotify_mock.h" +#include "mock_watcher_callback.h" +#include "poll_mock.h" +#include "securec.h" +#include "unistd_mock.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace Test { + +class FsFileWatcherMockTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void FsFileWatcherMockTest::SetUpTestCase(void) +{ + GTEST_LOG_(INFO) << "SetUpTestCase"; + EventfdMock::EnableMock(); + InotifyMock::EnableMock(); + PollMock::EnableMock(); + UnistdMock::EnableMock(); +} + +void FsFileWatcherMockTest::TearDownTestCase(void) +{ + EventfdMock::DisableMock(); + InotifyMock::DisableMock(); + PollMock::DisableMock(); + UnistdMock::DisableMock(); + GTEST_LOG_(INFO) << "TearDownTestCase"; +} + +void FsFileWatcherMockTest::SetUp(void) +{ + GTEST_LOG_(INFO) << "SetUp"; + errno = 0; // Reset errno +} + +void FsFileWatcherMockTest::TearDown(void) +{ + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.taskRunning_ = false; + watcher.run_ = false; + watcher.reading_ = false; + watcher.closed_ = false; + watcher.notifyFd_ = -1; + watcher.eventFd_ = -1; + watcher.dataCache_.ClearCache(); + GTEST_LOG_(INFO) << "TearDown"; +} + +inline const int32_t EXPECTED_WD = 100; +inline const int32_t UNEXPECTED_WD = 200; + +/** + * @tc.name: FsFileWatcherMockTest_GetNotifyId_001 + * @tc.desc: Test function of FsFileWatcher::GetNotifyId interface. + * @tc.size: SMALL + * @tc.type: FUNC + * @tc.level Level 0 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_GetNotifyId_001, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_GetNotifyId_001"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + int32_t expected = -1; + // Do testing + int32_t result = watcher.GetNotifyId(); + // Verify results + EXPECT_EQ(result, expected); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_GetNotifyId_001"; +} + +/** + * @tc.name: FsFileWatcherMockTest_InitNotify_001 + * @tc.desc: Test function of FsFileWatcher::InitNotify interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_InitNotify_001, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_InitNotify_001"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + // Set mock behaviors + auto eventfdMock = EventfdMock::GetMock(); + auto inotifyMock = InotifyMock::GetMock(); + EXPECT_CALL(*inotifyMock, inotify_init()).Times(1).WillOnce(testing::Return(1)); + EXPECT_CALL(*eventfdMock, eventfd(testing::_, testing::_)).Times(1).WillOnce(testing::Return(2)); + // Do testing + bool result = watcher.InitNotify(); + // Verify results + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + testing::Mock::VerifyAndClearExpectations(eventfdMock.get()); + EXPECT_TRUE(result); + EXPECT_EQ(watcher.notifyFd_, 1); + EXPECT_EQ(watcher.eventFd_, 2); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_InitNotify_001"; +} + +/** + * @tc.name: FsFileWatcherMockTest_InitNotify_002 + * @tc.desc: Test function of FsFileWatcher::InitNotify interface for FAILURE when inotify_init fails. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_InitNotify_002, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_InitNotify_002"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + // Set mock behaviors + auto inotifyMock = InotifyMock::GetMock(); + EXPECT_CALL(*inotifyMock, inotify_init()).Times(1).WillOnce(testing::SetErrnoAndReturn(EIO, -1)); + // Do testing + bool result = watcher.InitNotify(); + // Verify results + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + EXPECT_FALSE(result); + EXPECT_EQ(watcher.notifyFd_, -1); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_InitNotify_002"; +} + +/** + * @tc.name: FsFileWatcherMockTest_InitNotify_003 + * @tc.desc: Test function of FsFileWatcher::InitNotify interface for FAILURE when eventfd fails. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_InitNotify_003, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_InitNotify_003"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + // Set mock behaviors + auto inotifyMock = InotifyMock::GetMock(); + auto eventfdMock = EventfdMock::GetMock(); + EXPECT_CALL(*inotifyMock, inotify_init()).Times(1).WillOnce(testing::Return(1)); + EXPECT_CALL(*eventfdMock, eventfd(testing::_, testing::_)).Times(1).WillOnce(testing::SetErrnoAndReturn(EIO, -1)); + // Do testing + bool result = watcher.InitNotify(); + // Verify results + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + testing::Mock::VerifyAndClearExpectations(eventfdMock.get()); + EXPECT_FALSE(result); + EXPECT_EQ(watcher.notifyFd_, 1); + EXPECT_EQ(watcher.eventFd_, -1); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_InitNotify_003"; +} + +/** + * @tc.name: FsFileWatcherMockTest_StartNotify_001 + * @tc.desc: Test function of FsFileWatcher::StartNotify interface for SUCCESS when path is not watched. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_StartNotify_001, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_StartNotify_001"; + // Prepare test parameters + auto info = std::make_shared(nullptr); + info->fileName = "fakePath/FsFileWatcherMockTest_StartNotify_001"; + info->events = IN_CREATE | IN_DELETE; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = 1; + // Set mock behaviors + auto inotifyMock = InotifyMock::GetMock(); + EXPECT_CALL(*inotifyMock, inotify_add_watch(testing::_, testing::_, testing::_)) + .Times(1) + .WillOnce(testing::Return(EXPECTED_WD)); + // Do testing + int32_t result = watcher.StartNotify(info); + // Verify results + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + EXPECT_EQ(result, ERRNO_NOERR); + EXPECT_EQ(info->wd, EXPECTED_WD); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_StartNotify_001"; +} + +/** + * @tc.name: FsFileWatcherMockTest_StartNotify_002 + * @tc.desc: Test function of FsFileWatcher::StartNotify interface for SUCCESS when path is already watched with same + * events. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_StartNotify_002, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_StartNotify_002"; + // Prepare test parameters + auto info = std::make_shared(nullptr); + info->fileName = "fakePath/FsFileWatcherMockTest_StartNotify_002"; + info->events = IN_CREATE | IN_DELETE; + info->wd = EXPECTED_WD; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = 1; + watcher.dataCache_.AddWatcherInfo(info); + // Set mock behaviors + auto inotifyMock = InotifyMock::GetMock(); + EXPECT_CALL(*inotifyMock, inotify_add_watch(testing::_, testing::_, testing::_)).Times(0); + // Do testing + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + int32_t result = watcher.StartNotify(info); + // Verify results + EXPECT_EQ(result, ERRNO_NOERR); + EXPECT_EQ(info->wd, EXPECTED_WD); +} + +/** + * @tc.name: FsFileWatcherMockTest_StartNotify_003 + * @tc.desc: Test function of FsFileWatcher::StartNotify interface for FAILURE when info is nullptr. + * @tc.size: SMALL + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_StartNotify_003, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_StartNotify_003"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + // Do testing with nullptr parameter + int32_t result = watcher.StartNotify(nullptr); + // Verify results + EXPECT_EQ(result, EINVAL); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_StartNotify_003"; +} + +/** + * @tc.name: FsFileWatcherMockTest_StartNotify_004 + * @tc.desc: Test function of FsFileWatcher::StartNotify interface for FAILURE when notifyFd_ is invalid. + * @tc.size: SMALL + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_StartNotify_004, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_StartNotify_004"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = -1; + // Build test parameters + auto info = std::make_shared(nullptr); + info->fileName = "fakePath/FsFileWatcherMockTest_StartNotify_004"; + info->events = IN_CREATE; + // Do testing + int32_t result = watcher.StartNotify(info); + // Verify results + EXPECT_EQ(result, EIO); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_StartNotify_004"; +} + +/** + * @tc.name: FsFileWatcherMockTest_StartNotify_005 + * @tc.desc: Test function of FsFileWatcher::StartNotify interface for FAILURE when inotify_add_watch fails. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_StartNotify_005, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_StartNotify_005"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = 1; + // Build test parameters + auto info = std::make_shared(nullptr); + info->fileName = "fakePath/FsFileWatcherMockTest_StartNotify_005"; + info->events = IN_DELETE; + // Set mock behaviors for inotify_add_watch failure + auto inotifyMock = InotifyMock::GetMock(); + EXPECT_CALL(*inotifyMock, inotify_add_watch(testing::_, testing::_, testing::_)) + .Times(1) + .WillOnce(testing::SetErrnoAndReturn(EIO, -1)); + // Do testing + int32_t result = watcher.StartNotify(info); + // Verify results + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + EXPECT_EQ(result, EIO); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_StartNotify_005"; +} + +/** + * @tc.name: FsFileWatcherMockTest_StartNotify_006 + * @tc.desc: Test function of FsFileWatcher::StartNotify interface for SUCCESS when path is already watched. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_StartNotify_006, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_StartNotify_006"; + // Prepare test parameters + auto info = std::make_shared(nullptr); + info->fileName = "fakePath/FsFileWatcherMockTest_StartNotify_006"; + info->events = IN_CREATE; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = 1; + auto cachedInfo = std::make_shared(nullptr); + cachedInfo->fileName = "fakePath/FsFileWatcherMockTest_StartNotify_006"; + cachedInfo->events = IN_DELETE; + cachedInfo->wd = EXPECTED_WD; + watcher.dataCache_.AddWatcherInfo(cachedInfo); + // Set mock behaviors + auto inotifyMock = InotifyMock::GetMock(); + EXPECT_CALL(*inotifyMock, inotify_add_watch(testing::_, testing::_, testing::_)) + .Times(1) + .WillOnce(testing::Return(EXPECTED_WD)); + // Do testing + int32_t result = watcher.StartNotify(info); + // Verify results + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + EXPECT_EQ(result, ERRNO_NOERR); + EXPECT_EQ(info->wd, EXPECTED_WD); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_StartNotify_006"; +} + +/** + * @tc.name: FsFileWatcherMockTest_StopNotify_001 + * @tc.desc: Test function of FsFileWatcher::StopNotify interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_StopNotify_001, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_StopNotify_001"; + // Prepare test parameters + auto info = std::make_shared(nullptr); + info->fileName = "fakePath/FsFileWatcherMockTest_StopNotify_001"; + info->events = IN_CREATE | IN_DELETE; + info->wd = EXPECTED_WD; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = 1; + watcher.dataCache_.AddWatcherInfo(info); + // Set mock behaviors + auto unistdMock = UnistdMock::GetMock(); + auto inotifyMock = InotifyMock::GetMock(); + EXPECT_CALL(*unistdMock, access(testing::_, testing::_)).Times(0); + EXPECT_CALL(*unistdMock, close(testing::_)).Times(2).WillRepeatedly(testing::Return(0)); + EXPECT_CALL(*inotifyMock, inotify_rm_watch(testing::_, testing::_)).Times(1).WillOnce(testing::Return(0)); + // Do testing + int32_t result = watcher.StopNotify(info); + // Verify results + testing::Mock::VerifyAndClearExpectations(unistdMock.get()); + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + EXPECT_EQ(result, ERRNO_NOERR); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_StopNotify_001"; +} + +/** + * @tc.name: FsFileWatcherMockTest_StopNotify_002 + * @tc.desc: Test function of FsFileWatcher::StopNotify interface for FAILURE when info is nullptr. + * @tc.size: SMALL + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_StopNotify_002, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_StopNotify_002"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + // Do testing + int32_t result = watcher.StopNotify(nullptr); + // Verify results + EXPECT_EQ(result, EINVAL); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_StopNotify_002"; +} + +/** + * @tc.name: FsFileWatcherMockTest_StopNotify_003 + * @tc.desc: Test function of FsFileWatcher::StopNotify interface for FAILURE when notifyFd_ is invalid. + * @tc.size: SMALL + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_StopNotify_003, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_StopNotify_003"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = -1; + // Prepare test parameters + auto info = std::make_shared(nullptr); + info->fileName = "fakePath/FsFileWatcherMockTest_StopNotify_003"; + info->events = IN_CREATE; + info->wd = EXPECTED_WD; + // Do testing + int32_t result = watcher.StopNotify(info); + // Verify results + EXPECT_EQ(result, EIO); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_StopNotify_003"; +} + +/** + * @tc.name: FsFileWatcherMockTest_StopNotify_004 + * @tc.desc: Test function of FsFileWatcher::StopNotify interface for FAILURE when inotify_rm_watch fails. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_StopNotify_004, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_StopNotify_004"; + // Prepare test parameters + auto info = std::make_shared(nullptr); + info->fileName = "fakePath/FsFileWatcherMockTest_StopNotify_004"; + info->events = IN_DELETE; + info->wd = EXPECTED_WD; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = 1; + watcher.dataCache_.AddWatcherInfo(info); + // Set mock behaviors + auto unistdMock = UnistdMock::GetMock(); + auto inotifyMock = InotifyMock::GetMock(); + EXPECT_CALL(*unistdMock, access(testing::_, testing::_)).Times(1).WillOnce(testing::Return(0)); + EXPECT_CALL(*unistdMock, close(testing::_)).Times(2).WillRepeatedly(testing::Return(0)); + EXPECT_CALL(*inotifyMock, inotify_rm_watch(testing::_, testing::_)) + .Times(1) + .WillOnce(testing::SetErrnoAndReturn(EIO, -1)); + // Do testing + int32_t result = watcher.StopNotify(info); + // Verify results + testing::Mock::VerifyAndClearExpectations(unistdMock.get()); + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + EXPECT_EQ(result, EIO); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_StopNotify_004"; +} + +/** + * @tc.name: FsFileWatcherMockTest_StopNotify_005 + * @tc.desc: Test function of FsFileWatcher::StopNotify interface for SUCCESS when rm watch fail. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_StopNotify_005, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_StopNotify_005"; + // Prepare test parameters + auto info = std::make_shared(nullptr); + info->fileName = "fakePath/FsFileWatcherMockTest_StopNotify_005"; + info->events = IN_DELETE; + info->wd = EXPECTED_WD; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = 1; + watcher.dataCache_.AddWatcherInfo(info); + // Set rm watch fail condition + watcher.closed_ = true; + watcher.reading_ = true; + // Set mock behaviors + auto unistdMock = UnistdMock::GetMock(); + auto inotifyMock = InotifyMock::GetMock(); + EXPECT_CALL(*unistdMock, access(testing::_, testing::_)).Times(1).WillOnce(testing::Return(1)); + EXPECT_CALL(*unistdMock, close(testing::_)).Times(0); + EXPECT_CALL(*inotifyMock, inotify_rm_watch(testing::_, testing::_)).Times(0); + // Do testing + int32_t result = watcher.StopNotify(info); + // Verify results + testing::Mock::VerifyAndClearExpectations(unistdMock.get()); + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + EXPECT_EQ(result, ERRNO_NOERR); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_StopNotify_005"; +} + +/** + * @tc.name: FsFileWatcherMockTest_StopNotify_006 + * @tc.desc: Test function of FsFileWatcher::StopNotify interface for SUCCESS when having remainingEvents but access + * file failed. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_StopNotify_006, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_StopNotify_006"; + // Prepare test parameters + auto info = std::make_shared(nullptr); + info->fileName = "fakePath/FsFileWatcherMockTest_StopNotify_006"; + info->events = IN_DELETE; + info->wd = EXPECTED_WD; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = 1; + watcher.dataCache_.AddWatcherInfo(info); + // Set having remainingEvents condition + auto remainingInfo = std::make_shared(nullptr); + remainingInfo->fileName = "fakePath/FsFileWatcherMockTest_StopNotify_006"; + remainingInfo->events = IN_CREATE; + remainingInfo->wd = EXPECTED_WD; + watcher.dataCache_.AddWatcherInfo(remainingInfo); + // Set mock behaviors + auto unistdMock = UnistdMock::GetMock(); + auto inotifyMock = InotifyMock::GetMock(); + EXPECT_CALL(*unistdMock, access(testing::_, testing::_)).Times(1).WillOnce(testing::SetErrnoAndReturn(EIO, -1)); + EXPECT_CALL(*unistdMock, close(testing::_)).Times(0); + EXPECT_CALL(*inotifyMock, inotify_rm_watch(testing::_, testing::_)).Times(0); + // Do testing + int32_t result = watcher.StopNotify(info); + // Verify results + testing::Mock::VerifyAndClearExpectations(unistdMock.get()); + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + EXPECT_EQ(result, ERRNO_NOERR); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_StopNotify_006"; +} + +/** + * @tc.name: FsFileWatcherMockTest_StopNotify_007 + * @tc.desc: Test function of FsFileWatcher::StopNotify interface for SUCCESS when having remainingEvents and + * NotifyToWatchNewEvents success. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_StopNotify_007, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_StopNotify_007"; + // Prepare test parameters + auto info = std::make_shared(nullptr); + info->fileName = "fakePath/FsFileWatcherMockTest_StopNotify_007"; + info->events = IN_DELETE; + info->wd = EXPECTED_WD; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = 1; + watcher.dataCache_.AddWatcherInfo(info); + // Set having remainingEvents condition + auto remainingInfo = std::make_shared(nullptr); + remainingInfo->fileName = "fakePath/FsFileWatcherMockTest_StopNotify_007"; + remainingInfo->events = IN_CREATE; + remainingInfo->wd = EXPECTED_WD; + watcher.dataCache_.AddWatcherInfo(remainingInfo); + // Set mock behaviors + auto unistdMock = UnistdMock::GetMock(); + auto inotifyMock = InotifyMock::GetMock(); + EXPECT_CALL(*unistdMock, access(testing::_, testing::_)).Times(1).WillOnce(testing::Return(0)); + EXPECT_CALL(*unistdMock, close(testing::_)).Times(0); + EXPECT_CALL(*inotifyMock, inotify_rm_watch(testing::_, testing::_)).Times(0); + EXPECT_CALL(*inotifyMock, inotify_add_watch(testing::_, testing::_, testing::_)) + .Times(1) + .WillOnce(testing::Return(EXPECTED_WD)); + // Do testing + int32_t result = watcher.StopNotify(info); + // Verify results + testing::Mock::VerifyAndClearExpectations(unistdMock.get()); + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + EXPECT_EQ(result, ERRNO_NOERR); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_StopNotify_007"; +} + +/** + * @tc.name: FsFileWatcherMockTest_StopNotify_008 + * @tc.desc: Test function of FsFileWatcher::StopNotify interface for FAILURE when having remainingEvents but + * NotifyToWatchNewEvents fails for inotify_add_watch fails. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_StopNotify_008, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_StopNotify_008"; + // Prepare test parameters + auto info = std::make_shared(nullptr); + info->fileName = "fakePath/FsFileWatcherMockTest_StopNotify_008"; + info->events = IN_DELETE; + info->wd = EXPECTED_WD; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = 1; + watcher.dataCache_.AddWatcherInfo(info); + // Set having remainingEvents condition + auto remainingInfo = std::make_shared(nullptr); + remainingInfo->fileName = "fakePath/FsFileWatcherMockTest_StopNotify_008"; + remainingInfo->events = IN_CREATE; + remainingInfo->wd = EXPECTED_WD; + watcher.dataCache_.AddWatcherInfo(remainingInfo); + // Set mock behaviors + auto unistdMock = UnistdMock::GetMock(); + auto inotifyMock = InotifyMock::GetMock(); + EXPECT_CALL(*unistdMock, access(testing::_, testing::_)).Times(1).WillOnce(testing::Return(0)); + EXPECT_CALL(*unistdMock, close(testing::_)).Times(0); + EXPECT_CALL(*inotifyMock, inotify_rm_watch(testing::_, testing::_)).Times(0); + EXPECT_CALL(*inotifyMock, inotify_add_watch(testing::_, testing::_, testing::_)) + .Times(1) + .WillOnce(testing::SetErrnoAndReturn(EIO, -1)); + // Do testing + int32_t result = watcher.StopNotify(info); + // Verify results + testing::Mock::VerifyAndClearExpectations(unistdMock.get()); + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + EXPECT_EQ(result, EIO); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_StopNotify_008"; +} + +/** + * @tc.name: FsFileWatcherMockTest_StopNotify_009 + * @tc.desc: Test function of FsFileWatcher::StopNotify interface for FAILURE when having remainingEvents but + * NotifyToWatchNewEvents fails for inotify_add_watch return another wd. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_StopNotify_009, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_StopNotify_009"; + // Prepare test parameters + auto info = std::make_shared(nullptr); + info->fileName = "fakePath/FsFileWatcherMockTest_StopNotify_009"; + info->events = IN_DELETE; + info->wd = EXPECTED_WD; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = 1; + watcher.dataCache_.AddWatcherInfo(info); + // Set having remainingEvents condition + auto remainingInfo = std::make_shared(nullptr); + remainingInfo->fileName = "fakePath/FsFileWatcherMockTest_StopNotify_009"; + remainingInfo->events = IN_CREATE; + remainingInfo->wd = EXPECTED_WD; + watcher.dataCache_.AddWatcherInfo(remainingInfo); + // Set mock behaviors + auto unistdMock = UnistdMock::GetMock(); + auto inotifyMock = InotifyMock::GetMock(); + EXPECT_CALL(*unistdMock, access(testing::_, testing::_)).Times(1).WillOnce(testing::Return(0)); + EXPECT_CALL(*unistdMock, close(testing::_)).Times(0); + EXPECT_CALL(*inotifyMock, inotify_rm_watch(testing::_, testing::_)).Times(0); + EXPECT_CALL(*inotifyMock, inotify_add_watch(testing::_, testing::_, testing::_)) + .Times(1) + .WillOnce(testing::Return(UNEXPECTED_WD)); + // Do testing + int32_t result = watcher.StopNotify(info); + // Verify results + testing::Mock::VerifyAndClearExpectations(unistdMock.get()); + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + EXPECT_EQ(result, EIO); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_StopNotify_009"; +} + +/** + * @tc.name: FsFileWatcherMockTest_StopNotify_010 + * @tc.desc: Test function of FsFileWatcher::StopNotify interface for FAILURE when CloseNotifyFd fails. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_StopNotify_010, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_StopNotify_010"; + // Prepare test parameters + auto info = std::make_shared(nullptr); + info->fileName = "fakePath/FsFileWatcherMockTest_StopNotify_010"; + info->events = IN_DELETE; + info->wd = EXPECTED_WD; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = 1; + watcher.eventFd_ = 1; + watcher.dataCache_.AddWatcherInfo(info); + // Set mock behaviors + auto unistdMock = UnistdMock::GetMock(); + auto inotifyMock = InotifyMock::GetMock(); + EXPECT_CALL(*unistdMock, access(testing::_, testing::_)).Times(0); + EXPECT_CALL(*unistdMock, close(testing::_)).Times(2).WillRepeatedly(testing::Return(EIO)); + EXPECT_CALL(*inotifyMock, inotify_rm_watch(testing::_, testing::_)).Times(1).WillOnce(testing::Return(0)); + // Do testing + int32_t result = watcher.StopNotify(info); + // Verify results + testing::Mock::VerifyAndClearExpectations(unistdMock.get()); + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + EXPECT_EQ(result, EIO); + EXPECT_EQ(watcher.notifyFd_, -1); + EXPECT_EQ(watcher.eventFd_, -1); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_StopNotify_010"; +} + +/** + * @tc.name: FsFileWatcherMockTest_GetNotifyEvent_001 + * @tc.desc: Test function of FsFileWatcher::GetNotifyEvent interface when run_ is true. + * @tc.size: SMALL + * @tc.type: FUNC + * @tc.level Level 0 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_GetNotifyEvent_001, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_GetNotifyEvent_001"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.run_ = true; + // Set mock behaviors + auto pollMock = PollMock::GetMock(); + EXPECT_CALL(*pollMock, poll(testing::_, testing::_, testing::_)).Times(0); + // Do testing + watcher.GetNotifyEvent(); + // Verify results + testing::Mock::VerifyAndClearExpectations(pollMock.get()); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_GetNotifyEvent_001"; +} + +/** + * @tc.name: FsFileWatcherMockTest_GetNotifyEvent_002 + * @tc.desc: Test function of FsFileWatcher::GetNotifyEvent interface when poll returns ret > 0 and fds[0].revents has + * POLLNVAL. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_GetNotifyEvent_002, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_GetNotifyEvent_002"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.run_ = false; + watcher.notifyFd_ = 1; + watcher.eventFd_ = 2; + // Set mock behaviors + auto pollMock = PollMock::GetMock(); + EXPECT_CALL(*pollMock, poll(testing::_, testing::_, testing::_)) + .Times(1) + .WillOnce([](struct pollfd *fds, nfds_t n, int timeout) { + fds[0].revents = POLLNVAL; + return 1; + }); + // Do testing + watcher.GetNotifyEvent(); + // Verify results + testing::Mock::VerifyAndClearExpectations(pollMock.get()); + EXPECT_FALSE(watcher.run_); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_GetNotifyEvent_002"; +} + +/** + * @tc.name: FsFileWatcherMockTest_GetNotifyEvent_003 + * @tc.desc: Test function of FsFileWatcher::GetNotifyEvent interface when poll returns ret > 0 and fds[0].revents has + * POLLIN. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_GetNotifyEvent_003, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_GetNotifyEvent_003"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.run_ = false; + watcher.notifyFd_ = 1; + watcher.eventFd_ = 2; + // Set mock behaviors + auto pollMock = PollMock::GetMock(); + EXPECT_CALL(*pollMock, poll(testing::_, testing::_, testing::_)) + .Times(1) + .WillOnce([](struct pollfd *fds, nfds_t n, int timeout) { + fds[0].revents = POLLIN; + return 1; + }); + // Do testing + watcher.GetNotifyEvent(); + // Verify results + testing::Mock::VerifyAndClearExpectations(pollMock.get()); + EXPECT_FALSE(watcher.run_); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_GetNotifyEvent_003"; +} + +/** + * @tc.name: FsFileWatcherMockTest_GetNotifyEvent_004 + * @tc.desc: Test function of FsFileWatcher::GetNotifyEvent interface when poll returns ret > 0 and fds[1].revents has + * POLLIN. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_GetNotifyEvent_004, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_GetNotifyEvent_004"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.run_ = false; + watcher.notifyFd_ = 1; + watcher.eventFd_ = 2; + watcher.closed_ = true; // Avoid calling ReadNotifyEvent + // Set mock behaviors + auto pollMock = PollMock::GetMock(); + EXPECT_CALL(*pollMock, poll(testing::_, testing::_, testing::_)) + .Times(1) + .WillOnce([&watcher](struct pollfd *fds, nfds_t n, int timeout) { + fds[1].revents = POLLIN; + watcher.run_ = false; // Ensure the loop will exit + return 1; + }); + // Do testing + watcher.GetNotifyEvent(); + // Verify results + testing::Mock::VerifyAndClearExpectations(pollMock.get()); + EXPECT_FALSE(watcher.run_); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_GetNotifyEvent_004"; +} + +/** + * @tc.name: FsFileWatcherMockTest_GetNotifyEvent_005 + * @tc.desc: Test function of FsFileWatcher::GetNotifyEvent interface when poll returns ret == 0. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_GetNotifyEvent_005, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_GetNotifyEvent_005"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.run_ = false; + watcher.notifyFd_ = 1; + watcher.eventFd_ = 2; + // Set mock behaviors + auto pollMock = PollMock::GetMock(); + EXPECT_CALL(*pollMock, poll(testing::_, testing::_, testing::_)) + .Times(1) + .WillOnce([&watcher](struct pollfd *fds, nfds_t n, int timeout) { + watcher.run_ = false; // Ensure the loop will exit + return 0; + }); + // Do testing + watcher.GetNotifyEvent(); + // Verify results + testing::Mock::VerifyAndClearExpectations(pollMock.get()); + EXPECT_FALSE(watcher.run_); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_GetNotifyEvent_005"; +} + +/** + * @tc.name: FsFileWatcherMockTest_GetNotifyEvent_006 + * @tc.desc: Test function of FsFileWatcher::GetNotifyEvent interface when poll returns ret < 0 and errno == EINTR. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_GetNotifyEvent_006, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_GetNotifyEvent_006"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.run_ = false; + watcher.notifyFd_ = 1; + watcher.eventFd_ = 2; + // Set mock behaviors + auto pollMock = PollMock::GetMock(); + EXPECT_CALL(*pollMock, poll(testing::_, testing::_, testing::_)) + .Times(1) + .WillOnce([&watcher](struct pollfd *fds, nfds_t n, int timeout) { + errno = EINTR; + watcher.run_ = false; // Ensure the loop will exit + return -1; + }); + // Do testing + watcher.GetNotifyEvent(); + // Verify results + testing::Mock::VerifyAndClearExpectations(pollMock.get()); + EXPECT_FALSE(watcher.run_); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_GetNotifyEvent_006"; +} + +/** + * @tc.name: FsFileWatcherMockTest_GetNotifyEvent_007 + * @tc.desc: Test function of FsFileWatcher::GetNotifyEvent interface when poll returns ret < 0 and errno != EINTR. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_GetNotifyEvent_007, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_GetNotifyEvent_007"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.run_ = false; + watcher.notifyFd_ = 1; + watcher.eventFd_ = 2; + // Set mock behaviors + auto pollMock = PollMock::GetMock(); + EXPECT_CALL(*pollMock, poll(testing::_, testing::_, testing::_)) + .Times(1) + .WillOnce([&watcher](struct pollfd *fds, nfds_t n, int timeout) { + errno = EIO; + watcher.run_ = false; // Ensure the loop will exit + return -1; + }); + // Do testing + watcher.GetNotifyEvent(); + // Verify results + testing::Mock::VerifyAndClearExpectations(pollMock.get()); + EXPECT_FALSE(watcher.run_); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_GetNotifyEvent_007"; +} + +/** + * @tc.name: FsFileWatcherMockTest_ReadNotifyEventLocked_001 + * @tc.desc: Test ReadNotifyEventLocked when closed_ is false. + * @tc.size: SMALL + * @tc.type: FUNC + * @tc.level Level 0 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_ReadNotifyEventLocked_001, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_ReadNotifyEventLocked_001"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.closed_ = false; + // Set mock behaviors + auto unistdMock = UnistdMock::GetMock(); + EXPECT_CALL(*unistdMock, read(testing::_, testing::_, testing::_)).Times(1).WillOnce(testing::Return(0)); + EXPECT_CALL(*unistdMock, close(testing::_)).Times(0); + // Do testing + watcher.ReadNotifyEventLocked(); + // Verify results + testing::Mock::VerifyAndClearExpectations(unistdMock.get()); + EXPECT_FALSE(watcher.reading_); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_ReadNotifyEventLocked_001"; +} + +/** + * @tc.name: FsFileWatcherMockTest_ReadNotifyEventLocked_002 + * @tc.desc: Test ReadNotifyEventLocked when close after read. + * @tc.size: SMALL + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_ReadNotifyEventLocked_002, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_ReadNotifyEventLocked_002"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.closed_ = false; + // Set mock behaviors + auto unistdMock = UnistdMock::GetMock(); + EXPECT_CALL(*unistdMock, read(testing::_, testing::_, testing::_)) + .Times(1) + .WillOnce([&watcher](int fd, void *buf, size_t count) { + errno = EIO; + watcher.closed_ = true; // Set close after read condition + return 0; + }); + EXPECT_CALL(*unistdMock, close(testing::_)).Times(2).WillRepeatedly(testing::Return(0)); + // Do testing + watcher.ReadNotifyEventLocked(); + // Verify results + testing::Mock::VerifyAndClearExpectations(unistdMock.get()); + EXPECT_FALSE(watcher.closed_); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_ReadNotifyEventLocked_002"; +} + +/** + * @tc.name: FsFileWatcherMockTest_ReadNotifyEvent_001 + * @tc.desc: Test function of FsFileWatcher::ReadNotifyEvent interface for SUCCESS when read valid event data. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_ReadNotifyEvent_001, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_ReadNotifyEvent_001"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + int32_t len = static_cast(sizeof(struct inotify_event)); + // Set mock behaviors + auto unistdMock = UnistdMock::GetMock(); + EXPECT_CALL(*unistdMock, read(testing::_, testing::_, testing::_)).Times(1).WillOnce(testing::Return(len)); + // Do testing + watcher.ReadNotifyEvent(); + // Verify results + testing::Mock::VerifyAndClearExpectations(unistdMock.get()); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_ReadNotifyEvent_001"; +} + +/** + * @tc.name: FsFileWatcherMockTest_ReadNotifyEvent_002 + * @tc.desc: Test function of FsFileWatcher::ReadNotifyEvent interface for FAILURE when read returns -1. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_ReadNotifyEvent_002, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_ReadNotifyEvent_002"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + // Set mock behaviors + auto unistdMock = UnistdMock::GetMock(); + EXPECT_CALL(*unistdMock, read(testing::_, testing::_, testing::_)) + .Times(1) + .WillOnce(testing::SetErrnoAndReturn(EIO, -1)); + // Do testing + watcher.ReadNotifyEvent(); + // Verify results + testing::Mock::VerifyAndClearExpectations(unistdMock.get()); + EXPECT_EQ(errno, EIO); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_ReadNotifyEvent_002"; +} + +/** + * @tc.name: FsFileWatcherMockTest_ReadNotifyEvent_003 + * @tc.desc: Test function of FsFileWatcher::ReadNotifyEvent interface for SUCCESS when read returns 0 (EOF). + * @tc.size: SMALL + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_ReadNotifyEvent_003, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_ReadNotifyEvent_003"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + // Set mock behaviors + auto unistdMock = UnistdMock::GetMock(); + EXPECT_CALL(*unistdMock, read(testing::_, testing::_, testing::_)) + .Times(1) + .WillOnce(testing::SetErrnoAndReturn(0, 0)); + // Do testing + watcher.ReadNotifyEvent(); + // Verify results + testing::Mock::VerifyAndClearExpectations(unistdMock.get()); + EXPECT_EQ(errno, 0); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_ReadNotifyEvent_003"; +} + +/** + * @tc.name: FsFileWatcherMockTest_NotifyEvent_001 + * @tc.desc: Test function of FsFileWatcher::NotifyEvent interface for SUCCESS when valid event without filename. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_NotifyEvent_001, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_NotifyEvent_001"; + // Prepare test parameters + uint32_t mask = IN_CREATE; + struct inotify_event event = { .wd = EXPECTED_WD, .mask = mask, .cookie = 0, .len = 0 }; + // Prepare test condition + auto callback = std::make_shared(); + auto info = std::make_shared(callback); + info->fileName = "fakePath/FsFileWatcherMockTest_NotifyEvent_001"; + info->events = mask; + info->wd = EXPECTED_WD; + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.dataCache_.AddWatcherInfo(info); + // Set mock behaviors + EXPECT_CALL(*callback, InvokeCallback(testing::_, testing::_, testing::_)).Times(1); + // Do testing + watcher.NotifyEvent(&event); + // Verify results + testing::Mock::VerifyAndClearExpectations(callback.get()); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_NotifyEvent_001"; +} + +/** + * @tc.name: FsFileWatcherMockTest_NotifyEvent_002 + * @tc.desc: Test function of FsFileWatcher::NotifyEvent interface for SUCCESS when valid event with filename. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_NotifyEvent_002, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_NotifyEvent_002"; + // Prepare test parameters + const char *name = "test.txt"; + size_t len = strlen(name); + uint32_t mask = IN_CREATE; + size_t totalSize = sizeof(struct inotify_event) + len + 1; + std::vector buffer(totalSize); + struct inotify_event *event = reinterpret_cast(buffer.data()); + event->wd = EXPECTED_WD; + event->mask = mask; + event->cookie = 0; + event->len = len + 1; + char *namePtr = reinterpret_cast(event + 1); + int ret = memcpy_s(namePtr, len + 1, name, len + 1); + if (ret != 0) { + EXPECT_EQ(ret, 0); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_NotifyEvent_002"; + return; + } + // Prepare test condition + auto callback = std::make_shared(); + auto info = std::make_shared(callback); + info->fileName = "fakePath/FsFileWatcherMockTest_NotifyEvent_002"; + info->events = mask; + info->wd = EXPECTED_WD; + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.dataCache_.AddWatcherInfo(info); + // Set mock behaviors + EXPECT_CALL(*callback, InvokeCallback(testing::_, testing::_, testing::_)).Times(1); + // Do testing + watcher.NotifyEvent(event); + // Verify results + testing::Mock::VerifyAndClearExpectations(callback.get()); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_NotifyEvent_002"; +} + +/** + * @tc.name: FsFileWatcherMockTest_NotifyEvent_003 + * @tc.desc: Test function of FsFileWatcher::NotifyEvent interface for FAILURE when event pointer is NULL. + * @tc.size: SMALL + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_NotifyEvent_003, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_NotifyEvent_003"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + // Do testing + watcher.NotifyEvent(nullptr); + // Verify results + EXPECT_TRUE(watcher.dataCache_.wdFileNameCache_.empty()); + EXPECT_TRUE(watcher.dataCache_.watcherInfoCache_.empty()); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_NotifyEvent_003"; +} + +/** + * @tc.name: FsFileWatcherMockTest_NotifyEvent_004 + * @tc.desc: Test function of FsFileWatcher::NotifyEvent interface for FAILURE when no matched watcher found. + * @tc.size: SMALL + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_NotifyEvent_004, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_NotifyEvent_004"; + // Prepare test parameters + struct inotify_event event = { .wd = EXPECTED_WD, .mask = IN_CREATE, .cookie = 0, .len = 0 }; + // Prepare test condition + auto callback = std::make_shared(); + auto info = std::make_shared(callback); + info->fileName = "fakePath/FsFileWatcherMockTest_NotifyEvent_004"; + info->events = IN_MODIFY; // Not matched mask + info->wd = UNEXPECTED_WD; // Not matched wd + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.dataCache_.AddWatcherInfo(info); + // Set mock behaviors + EXPECT_CALL(*callback, InvokeCallback(testing::_, testing::_, testing::_)).Times(0); + // Do testing + watcher.NotifyEvent(&event); + // Verify results + testing::Mock::VerifyAndClearExpectations(callback.get()); + EXPECT_FALSE(watcher.dataCache_.wdFileNameCache_.empty()); + EXPECT_FALSE(watcher.dataCache_.watcherInfoCache_.empty()); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_NotifyEvent_004"; +} + +/** + * @tc.name: FsFileWatcherMockTest_AddWatcherInfo_001 + * @tc.desc: Test function of FsFileWatcher::AddWatcherInfo interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_AddWatcherInfo_001, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_AddWatcherInfo_001"; + // Prepare test parameters + auto info = std::make_shared(nullptr); + info->fileName = "fakePath/FsFileWatcherMockTest_AddWatcherInfo_001"; + info->events = IN_CREATE; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + auto cachedInfo0 = std::make_shared(nullptr); + cachedInfo0->fileName = "fakePath/FsFileWatcherMockTest_AddWatcherInfo_001_cachedInfo0"; + watcher.dataCache_.AddWatcherInfo(cachedInfo0); + + auto cachedInfo1 = std::make_shared(nullptr); + cachedInfo1->fileName = "fakePath/FsFileWatcherMockTest_AddWatcherInfo_001"; + cachedInfo1->events = IN_DELETE; + watcher.dataCache_.AddWatcherInfo(cachedInfo1); + + auto callback = std::make_shared(); + auto cachedInfo2 = std::make_shared(callback); + cachedInfo2->fileName = "fakePath/FsFileWatcherMockTest_AddWatcherInfo_001"; + cachedInfo2->events = IN_CREATE; + watcher.dataCache_.AddWatcherInfo(cachedInfo2); + + // Set mock behaviors + EXPECT_CALL(*callback, IsStrictEquals(testing::_)).Times(1).WillOnce(testing::Return(false)); + // Do testing + bool result = watcher.AddWatcherInfo(info); + // Verify results + testing::Mock::VerifyAndClearExpectations(callback.get()); + EXPECT_TRUE(result); + cachedInfo2->callback = nullptr; + watcher.dataCache_.ClearCache(); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_AddWatcherInfo_001"; +} + +/** + * @tc.name: FsFileWatcherMockTest_AddWatcherInfo_002 + * @tc.desc: Test function of FsFileWatcher::AddWatcherInfo interface for FAILURE when param is nullptr. + * @tc.size: SMALL + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_AddWatcherInfo_002, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_AddWatcherInfo_002"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + // Do testing + bool result = watcher.AddWatcherInfo(nullptr); + // Verify results + EXPECT_FALSE(result); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_AddWatcherInfo_002"; +} + +/** + * @tc.name: FsFileWatcherMockTest_AddWatcherInfo_003 + * @tc.desc: Test function of FsFileWatcher::AddWatcherInfo interface for FAILURE when having same info. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_AddWatcherInfo_003, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_AddWatcherInfo_003"; + // Prepare test parameters + auto info = std::make_shared(nullptr); + info->fileName = "fakePath/FsFileWatcherMockTest_AddWatcherInfo_003"; + info->events = IN_CREATE; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + auto callback = std::make_shared(); + auto cachedInfo = std::make_shared(callback); + cachedInfo->fileName = "fakePath/FsFileWatcherMockTest_AddWatcherInfo_003"; + cachedInfo->events = IN_CREATE; + watcher.dataCache_.AddWatcherInfo(cachedInfo); + // Set mock behaviors + EXPECT_CALL(*callback, IsStrictEquals(testing::_)).Times(1).WillOnce(testing::Return(true)); + // Do testing + bool result = watcher.AddWatcherInfo(info); + // Verify results + testing::Mock::VerifyAndClearExpectations(callback.get()); + EXPECT_FALSE(result); + cachedInfo->callback = nullptr; + watcher.dataCache_.ClearCache(); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_AddWatcherInfo_003"; +} + +/** + * @tc.name: FsFileWatcherMockTest_RemoveWatcherInfo_001 + * @tc.desc: Test function of FsFileWatcher::RemoveWatcherInfo interface for FAILURE when param is nullptr. + * @tc.size: SMALL + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_RemoveWatcherInfo_001, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_RemoveWatcherInfo_001"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + // Do testing + auto result = watcher.RemoveWatcherInfo(nullptr); + // Verify results + EXPECT_EQ(result, EINVAL); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_RemoveWatcherInfo_001"; +} + +/** + * @tc.name: FsFileWatcherMockTest_DestroyTaskThead_001 + * @tc.desc: Test function of FsFileWatcher::DestroyTaskThead interface when taskRunning is true. + * @tc.size: SMALL + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_DestroyTaskThead_001, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_DestroyTaskThead_001"; + // Prepare test condition + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.taskRunning_ = true; + // Do testing + watcher.DestroyTaskThead(); + // Verify results + EXPECT_FALSE(watcher.taskRunning_); + GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_DestroyTaskThead_001"; +} + +} // namespace Test +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS diff --git a/interfaces/test/unittest/js/mod_fs/class_watcher/fs_watcher_mock_test.cpp b/interfaces/test/unittest/js/mod_fs/class_watcher/fs_watcher_mock_test.cpp new file mode 100644 index 000000000..805c6af56 --- /dev/null +++ b/interfaces/test/unittest/js/mod_fs/class_watcher/fs_watcher_mock_test.cpp @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "fs_err_code.h" +#include "fs_file_watcher.h" +#include "fs_watcher.h" +#include "inotify_mock.h" +#include "unistd_mock.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace Test { + +class FsWatcherMockTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void FsWatcherMockTest::SetUpTestCase(void) +{ + GTEST_LOG_(INFO) << "SetUpTestCase"; + InotifyMock::EnableMock(); + UnistdMock::EnableMock(); +} + +void FsWatcherMockTest::TearDownTestCase(void) +{ + InotifyMock::DisableMock(); + UnistdMock::DisableMock(); + GTEST_LOG_(INFO) << "TearDownTestCase"; +} + +void FsWatcherMockTest::SetUp(void) +{ + GTEST_LOG_(INFO) << "SetUp"; + errno = 0; // Reset errno +} + +void FsWatcherMockTest::TearDown(void) +{ + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.taskRunning_ = false; + watcher.run_ = false; + watcher.reading_ = false; + watcher.closed_ = false; + watcher.notifyFd_ = -1; + watcher.eventFd_ = -1; + watcher.dataCache_.ClearCache(); + GTEST_LOG_(INFO) << "TearDown"; +} + +/** + * @tc.name: FsWatcherTest_Constructor_001 + * @tc.desc: Test function of FsWatcher::Constructor interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + */ +HWTEST_F(FsWatcherMockTest, FsWatcherTest_Constructor_001, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FsWatcherMockTest-begin FsWatcherTest_Constructor_001"; + // Do testing + auto result = FsWatcher::Constructor(); + // Verify results + EXPECT_TRUE(result.IsSuccess()); + auto *watcher = result.GetData().value(); + EXPECT_NE(watcher, nullptr); + if (watcher) { + auto *watcherEntity = watcher->GetWatchEntity(); + EXPECT_NE(watcherEntity, nullptr); + } + delete watcher; + watcher = nullptr; + GTEST_LOG_(INFO) << "FsWatcherMockTest-end FsWatcherTest_Constructor_001"; +} + +/** + * @tc.name: FsWatcherTest_Start_001 + * @tc.desc: Test function of FsWatcher::Start interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + */ +HWTEST_F(FsWatcherMockTest, FsWatcherTest_Start_001, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FsWatcherMockTest-begin FsWatcherTest_Start_001"; + // Prepare test condition + int32_t expectedWd = 100; + auto watchEntity = CreateUniquePtr(); + FsWatcher fsWatcher(std::move(watchEntity)); + std::shared_ptr info = std::make_shared(nullptr); + fsWatcher.GetWatchEntity()->data_ = info; + // Prepare test condition for FsFileWatcher + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = 1; // Valid notifyFd + watcher.taskRunning_ = true; // Avoid starting thread + // Set mock behaviors + auto inotifyMock = InotifyMock::GetMock(); + EXPECT_CALL(*inotifyMock, inotify_add_watch(testing::_, testing::_, testing::_)) + .Times(1) + .WillOnce(testing::Return(expectedWd)); + // Do testing + auto result = fsWatcher.Start(); + // Verify results + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + EXPECT_TRUE(result.IsSuccess()); + GTEST_LOG_(INFO) << "FsWatcherMockTest-end FsWatcherTest_Start_001"; +} + +/** + * @tc.name: FsWatcherTest_Start_002 + * @tc.desc: Test function of FsWatcher::Start interface for FAILURE when watchEntity is nullptr. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsWatcherMockTest, FsWatcherTest_Start_002, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsWatcherMockTest-begin FsWatcherTest_Start_002"; + // Prepare test condition + FsWatcher fsWatcher(nullptr); + // Do testing + auto result = fsWatcher.Start(); + // Verify results + EXPECT_FALSE(result.IsSuccess()); + auto errCode = result.GetError().GetErrNo(); + EXPECT_EQ(errCode, E_INVAL_CODE); + GTEST_LOG_(INFO) << "FsWatcherMockTest-end FsWatcherTest_Start_002"; +} + +/** + * @tc.name: FsWatcherTest_Start_003 + * @tc.desc: Test function of FsWatcher::Start interface for FAILURE when StartNotify fails. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsWatcherMockTest, FsWatcherTest_Start_003, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsWatcherMockTest-begin FsWatcherTest_Start_003"; + // Prepare test condition + auto watchEntity = CreateUniquePtr(); + FsWatcher fsWatcher(std::move(watchEntity)); + std::shared_ptr info = std::make_shared(nullptr); + fsWatcher.GetWatchEntity()->data_ = info; + // Prepare test condition for FsFileWatcher + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = -1; // Invalid notifyFd + // Do testing + auto result = fsWatcher.Start(); + // Verify results + EXPECT_FALSE(result.IsSuccess()); + auto errCode = result.GetError().GetErrNo(); + EXPECT_EQ(errCode, E_IO_CODE); + GTEST_LOG_(INFO) << "FsWatcherMockTest-end FsWatcherTest_Start_003"; +} + +/** + * @tc.name: FsWatcherTest_Stop_001 + * @tc.desc: Test function of FsWatcher::Stop interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + */ +HWTEST_F(FsWatcherMockTest, FsWatcherTest_Stop_001, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "FsWatcherMockTest-begin FsWatcherTest_Stop_001"; + // Prepare test condition + auto watchEntity = CreateUniquePtr(); + FsWatcher fsWatcher(std::move(watchEntity)); + std::shared_ptr info = std::make_shared(nullptr); + fsWatcher.GetWatchEntity()->data_ = info; + // Prepare test condition for FsFileWatcher + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = 1; + // Set mock behaviors + auto inotifyMock = InotifyMock::GetMock(); + auto unistdMock = UnistdMock::GetMock(); + EXPECT_CALL(*inotifyMock, inotify_rm_watch(testing::_, testing::_)) + .Times(1) + .WillOnce(testing::SetErrnoAndReturn(0, 0)); + EXPECT_CALL(*unistdMock, close(testing::_)).Times(2).WillRepeatedly(testing::Return(0)); + // Do testing + auto result = fsWatcher.Stop(); + // Verify results + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + testing::Mock::VerifyAndClearExpectations(unistdMock.get()); + EXPECT_TRUE(result.IsSuccess()); + GTEST_LOG_(INFO) << "FsWatcherMockTest-end FsWatcherTest_Stop_001"; +} + +/** + * @tc.name: FsWatcherTest_Stop_002 + * @tc.desc: Test function of FsWatcher::Stop interface for FAILURE when watchEntity is nullptr. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsWatcherMockTest, FsWatcherTest_Stop_002, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsWatcherMockTest-begin FsWatcherTest_Stop_002"; + // Prepare test condition + FsWatcher fsWatcher(nullptr); + // Do testing + auto result = fsWatcher.Stop(); + // Verify results + EXPECT_FALSE(result.IsSuccess()); + auto errCode = result.GetError().GetErrNo(); + EXPECT_EQ(errCode, E_INVAL_CODE); + GTEST_LOG_(INFO) << "FsWatcherMockTest-end FsWatcherTest_Stop_002"; +} + +/** + * @tc.name: FsWatcherTest_Stop_003 + * @tc.desc: Test function of FsWatcher::Stop interface for FAILURE when StopNotify fails. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(FsWatcherMockTest, FsWatcherTest_Stop_003, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "FsWatcherMockTest-begin FsWatcherTest_Stop_003"; + // Prepare test condition + auto watchEntity = CreateUniquePtr(); + FsWatcher fsWatcher(std::move(watchEntity)); + std::shared_ptr info = std::make_shared(nullptr); + fsWatcher.GetWatchEntity()->data_ = info; + // Prepare test condition for FsFileWatcher + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.notifyFd_ = -1; // Invalid notifyFd + // Do testing + auto result = fsWatcher.Stop(); + // Verify results + EXPECT_FALSE(result.IsSuccess()); + auto errCode = result.GetError().GetErrNo(); + EXPECT_EQ(errCode, E_IO_CODE); + GTEST_LOG_(INFO) << "FsWatcherMockTest-end FsWatcherTest_Stop_003"; +} + +} // namespace Test +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/test/unittest/js/mod_fs/mock/mock_watcher_callback.h b/interfaces/test/unittest/js/mod_fs/mock/mock_watcher_callback.h new file mode 100644 index 000000000..c1004d84f --- /dev/null +++ b/interfaces/test/unittest/js/mod_fs/mock/mock_watcher_callback.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_TEST_UNITTEST_JS_MOD_FS_MOCK_MOCK_WATCHER_CALLBACK_H +#define INTERFACES_TEST_UNITTEST_JS_MOD_FS_MOCK_MOCK_WATCHER_CALLBACK_H + +#include +#include +#include "i_watcher_callback.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace Test { +using namespace OHOS::FileManagement::ModuleFileIO; + +class MockWatcherCallback : public IWatcherCallback { +public: + MOCK_METHOD(bool, IsStrictEquals, (const std::shared_ptr &other), (const, override)); + MOCK_METHOD( + void, InvokeCallback, (const std::string &fileName, uint32_t event, uint32_t cookie), (const, override)); + MOCK_METHOD(std::string, GetClassName, (), (const, override)); +}; + +} // namespace Test +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_TEST_UNITTEST_JS_MOD_FS_MOCK_MOCK_WATCHER_CALLBACK_H \ No newline at end of file diff --git a/interfaces/test/unittest/js/mod_fs/properties/watcher_core_mock_test.cpp b/interfaces/test/unittest/js/mod_fs/properties/watcher_core_mock_test.cpp new file mode 100644 index 000000000..680a2ce32 --- /dev/null +++ b/interfaces/test/unittest/js/mod_fs/properties/watcher_core_mock_test.cpp @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include "eventfd_mock.h" +#include "filemgmt_libhilog.h" +#include "fs_file_watcher.h" +#include "inotify_mock.h" +#include "mock_watcher_callback.h" +#include "watcher_core.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace Test { + +class WatcherCoreMockTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void WatcherCoreMockTest::SetUpTestCase(void) +{ + GTEST_LOG_(INFO) << "SetUpTestCase"; + EventfdMock::EnableMock(); + InotifyMock::EnableMock(); +} + +void WatcherCoreMockTest::TearDownTestCase(void) +{ + EventfdMock::DisableMock(); + InotifyMock::DisableMock(); + GTEST_LOG_(INFO) << "TearDownTestCase"; +} + +void WatcherCoreMockTest::SetUp(void) +{ + GTEST_LOG_(INFO) << "SetUp"; + errno = 0; // Reset errno +} + +void WatcherCoreMockTest::TearDown(void) +{ + FsFileWatcher &watcher = FsFileWatcher::GetInstance(); + watcher.taskRunning_ = false; + watcher.run_ = false; + watcher.reading_ = false; + watcher.closed_ = false; + watcher.notifyFd_ = -1; + watcher.eventFd_ = -1; + watcher.dataCache_.ClearCache(); + GTEST_LOG_(INFO) << "TearDown"; +} + +/** + * @tc.name: WatcherCoreMockTest_DoCreateWatcher_001 + * @tc.desc: Test function of WatcherCore::DoCreateWatcher interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 0 + */ +HWTEST_F(WatcherCoreMockTest, WatcherCoreMockTest_DoCreateWatcher_001, testing::ext::TestSize.Level0) +{ + GTEST_LOG_(INFO) << "WatcherCoreMockTest-begin WatcherCoreMockTest_DoCreateWatcher_001"; + // Prepare test parameters + std::string path = "/test/WatcherCoreMockTest_DoCreateWatcher_001"; + int32_t events = IN_CREATE; + std::shared_ptr callback = std::make_shared(); + // Set mock behaviors + auto inotifyMock = InotifyMock::GetMock(); + auto eventfdMock = EventfdMock::GetMock(); + EXPECT_CALL(*inotifyMock, inotify_init()).Times(1).WillOnce(testing::Return(1)); + EXPECT_CALL(*eventfdMock, eventfd(testing::_, testing::_)).Times(1).WillOnce(testing::Return(2)); + // Do testing + auto result = WatcherCore::DoCreateWatcher(path, events, callback); + // Verify results + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + testing::Mock::VerifyAndClearExpectations(eventfdMock.get()); + EXPECT_TRUE(result.IsSuccess()); + GTEST_LOG_(INFO) << "WatcherCoreMockTest-end WatcherCoreMockTest_DoCreateWatcher_001"; +} + +/** + * @tc.name: WatcherCoreMockTest_DoCreateWatcher_002 + * @tc.desc: Test function of WatcherCore::DoCreateWatcher interface for FAILURE when InitNotify fails. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(WatcherCoreMockTest, WatcherCoreMockTest_DoCreateWatcher_002, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "WatcherCoreMockTest-begin WatcherCoreMockTest_DoCreateWatcher_002"; + // Prepare test parameters + std::string path = "/test/WatcherCoreMockTest_DoCreateWatcher_002"; + int32_t events = IN_CREATE; + std::shared_ptr callback = std::make_shared(); + // Set mock behaviors + auto inotifyMock = InotifyMock::GetMock(); + EXPECT_CALL(*inotifyMock, inotify_init()).Times(1).WillOnce(testing::SetErrnoAndReturn(EIO, -1)); + // Do testing + auto result = WatcherCore::DoCreateWatcher(path, events, callback); + // Verify results + testing::Mock::VerifyAndClearExpectations(inotifyMock.get()); + EXPECT_FALSE(result.IsSuccess()); + GTEST_LOG_(INFO) << "WatcherCoreMockTest-end WatcherCoreMockTest_DoCreateWatcher_002"; +} + +/** + * @tc.name: WatcherCoreMockTest_DoCreateWatcher_003 + * @tc.desc: Test function of WatcherCore::DoCreateWatcher interface for FAILURE when events are invalid. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(WatcherCoreMockTest, WatcherCoreMockTest_DoCreateWatcher_003, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "WatcherCoreMockTest-begin WatcherCoreMockTest_DoCreateWatcher_003"; + // Prepare test parameters + std::string path = "/test/WatcherCoreMockTest_DoCreateWatcher_003"; + int32_t events = -1; + std::shared_ptr callback = std::make_shared(); + // Do testing + auto result = WatcherCore::DoCreateWatcher(path, events, callback); + // Verify results + EXPECT_FALSE(result.IsSuccess()); + GTEST_LOG_(INFO) << "WatcherCoreMockTest-end WatcherCoreMockTest_DoCreateWatcher_003"; +} + +/** + * @tc.name: WatcherCoreMockTest_DoCreateWatcher_004 + * @tc.desc: Test function of WatcherCore::DoCreateWatcher interface for FAILURE when CheckEventValid false. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(WatcherCoreMockTest, WatcherCoreMockTest_DoCreateWatcher_004, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "WatcherCoreMockTest-begin WatcherCoreMockTest_DoCreateWatcher_004"; + // Prepare test parameters + std::string path = "/test/WatcherCoreMockTest_DoCreateWatcher_004"; + int32_t invalidEvents = ~IN_ALL_EVENTS; + std::shared_ptr callback = std::make_shared(); + // Do testing + auto result = WatcherCore::DoCreateWatcher(path, invalidEvents, callback); + // Verify results + EXPECT_FALSE(result.IsSuccess()); + GTEST_LOG_(INFO) << "WatcherCoreMockTest-end WatcherCoreMockTest_DoCreateWatcher_004"; +} + +/** + * @tc.name: WatcherCoreMockTest_DoCreateWatcher_005 + * @tc.desc: Test function of WatcherCore::DoCreateWatcher interface for FAILURE when callback is null. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(WatcherCoreMockTest, WatcherCoreMockTest_DoCreateWatcher_005, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "WatcherCoreMockTest-begin WatcherCoreMockTest_DoCreateWatcher_005"; + // Prepare test parameters + std::string path = "/test/WatcherCoreMockTest_DoCreateWatcher_005"; + int32_t events = IN_CREATE; + std::shared_ptr callback = nullptr; + // Do testing + auto result = WatcherCore::DoCreateWatcher(path, events, callback); + // Verify results + EXPECT_FALSE(result.IsSuccess()); + GTEST_LOG_(INFO) << "WatcherCoreMockTest-end WatcherCoreMockTest_DoCreateWatcher_005"; +} + +} // namespace Test +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file -- Gitee From b435fc28e6c64c2ccd07dc381ff26bce62150e4b Mon Sep 17 00:00:00 2001 From: tianp Date: Sun, 27 Jul 2025 14:42:09 +0800 Subject: [PATCH 2/2] =?UTF-8?q?watcher=E5=8A=9F=E8=83=BD=E6=A3=80=E8=A7=86?= =?UTF-8?q?=E6=84=8F=E8=A7=81=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: tianp Change-Id: I171a31f7d399afd91976ec7819d96367f1120f7e --- .../kits/js/src/common/ani_helper/ani_signature.cpp | 1 + interfaces/kits/js/src/common/ani_helper/ani_signature.h | 1 + .../src/mod_fs/class_watcher/ani/fs_watcher_wrapper.cpp | 8 ++++---- .../src/mod_fs/class_watcher/ani/watch_event_listener.cpp | 4 +++- .../src/mod_fs/class_watcher/ani/watch_event_listener.h | 1 - .../src/mod_fs/class_watcher/ani/watch_event_wrapper.cpp | 6 +++--- .../js/src/mod_fs/class_watcher/ani/watch_event_wrapper.h | 1 + .../kits/js/src/mod_fs/class_watcher/fs_file_watcher.cpp | 7 +++---- .../kits/js/src/mod_fs/class_watcher/fs_watch_entity.h | 5 +++-- .../js/src/mod_fs/class_watcher/watcher_data_cache.cpp | 2 ++ .../kits/js/src/mod_fs/properties/ani/watcher_ani.cpp | 3 ++- interfaces/kits/js/src/mod_fs/properties/watcher_core.cpp | 1 + .../js/mod_fs/class_watcher/fs_file_watcher_mock_test.cpp | 7 ++++--- .../test/unittest/js/mod_fs/mock/mock_watcher_callback.h | 1 + 14 files changed, 29 insertions(+), 19 deletions(-) diff --git a/interfaces/kits/js/src/common/ani_helper/ani_signature.cpp b/interfaces/kits/js/src/common/ani_helper/ani_signature.cpp index d92dd44d0..1599dfa75 100644 --- a/interfaces/kits/js/src/common/ani_helper/ani_signature.cpp +++ b/interfaces/kits/js/src/common/ani_helper/ani_signature.cpp @@ -116,6 +116,7 @@ const string FS::TaskSignal::nativeTaskSignal = "nativeTaskSignal"; const Type FS::WatcherInner::classType = Builder::BuildClass("@ohos.file.fs.fileIo.WatcherInner"); const string FS::WatcherInner::classDesc = FS::WatcherInner::classType.Descriptor(); const string FS::WatcherInner::ctorSig = Builder::BuildSignatureDescriptor({ BasicTypes::longType }); +const string FS::WatcherInner::nativePtr = "nativePtr"; // FS::WatchEventInner const Type FS::WatchEventInner::classType = Builder::BuildClass("@ohos.file.fs.WatchEventInner"); const string FS::WatchEventInner::classDesc = FS::WatchEventInner::classType.Descriptor(); diff --git a/interfaces/kits/js/src/common/ani_helper/ani_signature.h b/interfaces/kits/js/src/common/ani_helper/ani_signature.h index 122459794..c422af267 100644 --- a/interfaces/kits/js/src/common/ani_helper/ani_signature.h +++ b/interfaces/kits/js/src/common/ani_helper/ani_signature.h @@ -190,6 +190,7 @@ struct WatcherInner : public BaseType { static const Type classType; static const string classDesc; static const string ctorSig; + static const string nativePtr; }; struct WatchEventInner : public BaseType { diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_wrapper.cpp b/interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_wrapper.cpp index 79d6fb1dc..51ea2e2d3 100644 --- a/interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_wrapper.cpp +++ b/interfaces/kits/js/src/mod_fs/class_watcher/ani/fs_watcher_wrapper.cpp @@ -29,9 +29,9 @@ using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature; FsWatcher *FsWatcherWrapper::Unwrap(ani_env *env, ani_object object) { ani_long nativePtr; - auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr); + auto ret = env->Object_GetFieldByName_Long(object, FS::WatcherInner::nativePtr, &nativePtr); if (ret != ANI_OK) { - HILOGE("Unwrap fsWatcher err: %{private}d", ret); + HILOGE("Unwrap fsWatcher err: %{public}d", ret); return nullptr; } uintptr_t ptrValue = static_cast(nativePtr); @@ -55,13 +55,13 @@ ani_object FsWatcherWrapper::Wrap(ani_env *env, const FsWatcher *watcher) auto ctorSig = FS::WatcherInner::ctorSig.c_str(); ani_method ctor; if (ANI_OK != env->Class_FindMethod(cls, ctorDesc, ctorSig, &ctor)) { - HILOGE("Cannot find constructor method for class %s", classDesc); + HILOGE("Cannot find constructor method for class %{public}s", classDesc); return nullptr; } ani_long ptr = static_cast(reinterpret_cast(watcher)); ani_object obj; if (ANI_OK != env->Object_New(cls, ctor, &obj, ptr)) { - HILOGE("New %s obj Failed!", classDesc); + HILOGE("New %{public}s obj Failed!", classDesc); return nullptr; } return obj; diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_listener.cpp b/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_listener.cpp index 36ac7517d..16b4f4b4f 100644 --- a/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_listener.cpp +++ b/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_listener.cpp @@ -16,6 +16,7 @@ #include "watch_event_listener.h" #include + #include "ani_helper.h" #include "file_utils.h" #include "filemgmt_libhilog.h" @@ -28,6 +29,7 @@ using namespace std; bool WatchEventListener::IsStrictEquals(const shared_ptr &other) const { if (other->GetClassName() != className_) { + HILOGE("Cannot GetClassName"); return false; } @@ -46,7 +48,7 @@ bool WatchEventListener::IsStrictEquals(const shared_ptr &othe ani_boolean isSame = false; ani_status status = env->Reference_StrictEquals(callback, otherListener->callback, &isSame); if (status != ANI_OK) { - HILOGE("Compare ref for strict equality failed. status = %{public}d", static_cast(status)); + HILOGE("Compare ref for strict equality failed. status = %{public}d", status); return false; } return isSame; diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_listener.h b/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_listener.h index 919739228..4e818233c 100644 --- a/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_listener.h +++ b/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_listener.h @@ -19,7 +19,6 @@ #include #include - #include "fs_watch_entity.h" #include "i_watcher_callback.h" diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_wrapper.cpp b/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_wrapper.cpp index 1712f7f1f..073f73872 100644 --- a/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_wrapper.cpp +++ b/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_wrapper.cpp @@ -32,14 +32,14 @@ ani_object WatchEventWrapper::Wrap(ani_env *env, const WatchEvent &evt) auto classDesc = FS::WatchEventInner::classDesc.c_str(); ani_class cls; if (ANI_OK != env->FindClass(classDesc, &cls)) { - HILOGE("Cannot find class %s", classDesc); + HILOGE("Cannot find class %{public}s", classDesc); return nullptr; } auto ctorDesc = FS::WatchEventInner::ctorDesc.c_str(); auto ctorSig = FS::WatchEventInner::ctorSig.c_str(); ani_method ctor; if (ANI_OK != env->Class_FindMethod(cls, ctorDesc, ctorSig, &ctor)) { - HILOGE("Cannot find constructor method for class %s", classDesc); + HILOGE("Cannot find constructor method for class %{public}s", classDesc); return nullptr; } @@ -54,7 +54,7 @@ ani_object WatchEventWrapper::Wrap(ani_env *env, const WatchEvent &evt) ani_object obj; if (ANI_OK != env->Object_New(cls, ctor, &obj, fileName, event, cookie)) { - HILOGE("Create %s obj failed!", classDesc); + HILOGE("Create %{public}s obj failed!", classDesc); return nullptr; } return obj; diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_wrapper.h b/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_wrapper.h index 8e2ca980c..7f00e4ebe 100644 --- a/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_wrapper.h +++ b/interfaces/kits/js/src/mod_fs/class_watcher/ani/watch_event_wrapper.h @@ -18,6 +18,7 @@ #include #include + #include "fs_watch_entity.h" namespace OHOS { diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/fs_file_watcher.cpp b/interfaces/kits/js/src/mod_fs/class_watcher/fs_file_watcher.cpp index 9f77d49df..7e6ce5c70 100644 --- a/interfaces/kits/js/src/mod_fs/class_watcher/fs_file_watcher.cpp +++ b/interfaces/kits/js/src/mod_fs/class_watcher/fs_file_watcher.cpp @@ -19,7 +19,6 @@ #include #include #include - #include #include "filemgmt_libhilog.h" @@ -167,7 +166,7 @@ int32_t FsFileWatcher::StopNotify(shared_ptr info) if (!(closed_ && reading_)) { oldWd = inotify_rm_watch(notifyFd_, info->wd); } else { - HILOGE("rm watch fail"); + HILOGE("Rm watch fail"); } } @@ -212,7 +211,7 @@ void FsFileWatcher::ReadNotifyEventLocked() { lock_guard lock(readMutex_); if (closed_) { - HILOGE("read after close"); + HILOGE("Read after close"); return; } reading_ = true; @@ -224,7 +223,7 @@ void FsFileWatcher::ReadNotifyEventLocked() lock_guard lock(readMutex_); reading_ = false; if (closed_) { - HILOGE("close after read"); + HILOGE("Close after read"); CloseNotifyFd(); return; } diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/fs_watch_entity.h b/interfaces/kits/js/src/mod_fs/class_watcher/fs_watch_entity.h index 88fe92b18..9f568f988 100644 --- a/interfaces/kits/js/src/mod_fs/class_watcher/fs_watch_entity.h +++ b/interfaces/kits/js/src/mod_fs/class_watcher/fs_watch_entity.h @@ -18,6 +18,7 @@ #include #include #include + #include "i_watcher_callback.h" namespace OHOS::FileManagement::ModuleFileIO { @@ -36,9 +37,9 @@ struct WatcherInfo { explicit WatcherInfo(std::shared_ptr callback) : callback(std::move(callback)) {} - void TriggerCallback(const std::string &fileName, uint32_t event, uint32_t cookie) const + void TriggerCallback(const std::string &eventFileName, uint32_t event, uint32_t cookie) const { - callback->InvokeCallback(fileName, event, cookie); + callback->InvokeCallback(eventFileName, event, cookie); } }; diff --git a/interfaces/kits/js/src/mod_fs/class_watcher/watcher_data_cache.cpp b/interfaces/kits/js/src/mod_fs/class_watcher/watcher_data_cache.cpp index 83b5e2a51..1cca6b4d8 100644 --- a/interfaces/kits/js/src/mod_fs/class_watcher/watcher_data_cache.cpp +++ b/interfaces/kits/js/src/mod_fs/class_watcher/watcher_data_cache.cpp @@ -13,6 +13,7 @@ * limitations under the License. */ #include "watcher_data_cache.h" + #include "filemgmt_libhilog.h" namespace OHOS::FileManagement::ModuleFileIO { @@ -58,6 +59,7 @@ bool WatcherDataCache::RemoveFileWatcher(const std::string &fileName) auto iter = wdFileNameCache_.find(fileName); if (iter == wdFileNameCache_.end()) { + HILOGE("Failed to find fileName"); return false; } wdFileNameCache_.erase(iter); diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/watcher_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/watcher_ani.cpp index f0641c93f..d2780b87e 100644 --- a/interfaces/kits/js/src/mod_fs/properties/ani/watcher_ani.cpp +++ b/interfaces/kits/js/src/mod_fs/properties/ani/watcher_ani.cpp @@ -20,9 +20,9 @@ #include "file_utils.h" #include "filemgmt_libhilog.h" #include "fs_watcher_wrapper.h" +#include "type_converter.h" #include "watch_event_listener.h" #include "watcher_core.h" -#include "type_converter.h" namespace OHOS { namespace FileManagement { @@ -66,6 +66,7 @@ ani_object WatcherAni::CreateWatcherSync( const FsWatcher *watcher = ret.GetData().value(); auto result = FsWatcherWrapper::Wrap(env, move(watcher)); if (result == nullptr) { + HILOGE("Failed to Wrap"); delete watcher; watcher = nullptr; ErrorHandler::Throw(env, UNKNOWN_ERR); diff --git a/interfaces/kits/js/src/mod_fs/properties/watcher_core.cpp b/interfaces/kits/js/src/mod_fs/properties/watcher_core.cpp index 1ea4a713a..3c7f4093b 100644 --- a/interfaces/kits/js/src/mod_fs/properties/watcher_core.cpp +++ b/interfaces/kits/js/src/mod_fs/properties/watcher_core.cpp @@ -32,6 +32,7 @@ static FsResult InstantiateWatcher() HILOGE("Failed to get notifyId or initnotify fail"); return FsResult::Error(errno); } + FsResult result = FsWatcher::Constructor(); if (!result.IsSuccess()) { HILOGE("Failed to instantiate watcher"); diff --git a/interfaces/test/unittest/js/mod_fs/class_watcher/fs_file_watcher_mock_test.cpp b/interfaces/test/unittest/js/mod_fs/class_watcher/fs_file_watcher_mock_test.cpp index fe585ef71..8b66766cc 100644 --- a/interfaces/test/unittest/js/mod_fs/class_watcher/fs_file_watcher_mock_test.cpp +++ b/interfaces/test/unittest/js/mod_fs/class_watcher/fs_file_watcher_mock_test.cpp @@ -83,7 +83,7 @@ inline const int32_t UNEXPECTED_WD = 200; /** * @tc.name: FsFileWatcherMockTest_GetNotifyId_001 - * @tc.desc: Test function of FsFileWatcher::GetNotifyId interface. + * @tc.desc: Test function of FsFileWatcher::GetNotifyId interface for FAILED. * @tc.size: SMALL * @tc.type: FUNC * @tc.level Level 0 @@ -111,13 +111,14 @@ HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_GetNotifyId_001, testing:: HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_InitNotify_001, testing::ext::TestSize.Level0) { GTEST_LOG_(INFO) << "FsFileWatcherMockTest-begin FsFileWatcherMockTest_InitNotify_001"; + int32_t eventFd = 2; // Prepare test condition FsFileWatcher &watcher = FsFileWatcher::GetInstance(); // Set mock behaviors auto eventfdMock = EventfdMock::GetMock(); auto inotifyMock = InotifyMock::GetMock(); EXPECT_CALL(*inotifyMock, inotify_init()).Times(1).WillOnce(testing::Return(1)); - EXPECT_CALL(*eventfdMock, eventfd(testing::_, testing::_)).Times(1).WillOnce(testing::Return(2)); + EXPECT_CALL(*eventfdMock, eventfd(testing::_, testing::_)).Times(1).WillOnce(testing::Return(eventFd)); // Do testing bool result = watcher.InitNotify(); // Verify results @@ -125,7 +126,7 @@ HWTEST_F(FsFileWatcherMockTest, FsFileWatcherMockTest_InitNotify_001, testing::e testing::Mock::VerifyAndClearExpectations(eventfdMock.get()); EXPECT_TRUE(result); EXPECT_EQ(watcher.notifyFd_, 1); - EXPECT_EQ(watcher.eventFd_, 2); + EXPECT_EQ(watcher.eventFd_, eventFd); GTEST_LOG_(INFO) << "FsFileWatcherMockTest-end FsFileWatcherMockTest_InitNotify_001"; } diff --git a/interfaces/test/unittest/js/mod_fs/mock/mock_watcher_callback.h b/interfaces/test/unittest/js/mod_fs/mock/mock_watcher_callback.h index c1004d84f..dccff9ff1 100644 --- a/interfaces/test/unittest/js/mod_fs/mock/mock_watcher_callback.h +++ b/interfaces/test/unittest/js/mod_fs/mock/mock_watcher_callback.h @@ -18,6 +18,7 @@ #include #include + #include "i_watcher_callback.h" namespace OHOS { -- Gitee