From 574a02f3e77d1405251416a49d968b1f915d7de7 Mon Sep 17 00:00:00 2001 From: Sergey Yakubov <sergey.yakubov@desy.de> Date: Wed, 29 Aug 2018 17:00:19 +0200 Subject: [PATCH] start unit testing for inotify --- .../event_monitor_producer/CMakeLists.txt | 7 +- .../src/inotify_linux.cpp | 24 ++++ .../src/inotify_linux.h | 21 +++ .../src/system_folder_watch_linux.cpp | 16 ++- .../src/system_folder_watch_linux.h | 10 +- .../unittests/mock_inotify.h | 22 +++ .../test_system_folder_watch_linux.cpp | 128 ++++++++++++++++++ 7 files changed, 217 insertions(+), 11 deletions(-) create mode 100644 producer/event_monitor_producer/src/inotify_linux.cpp create mode 100644 producer/event_monitor_producer/src/inotify_linux.h create mode 100644 producer/event_monitor_producer/unittests/mock_inotify.h create mode 100644 producer/event_monitor_producer/unittests/test_system_folder_watch_linux.cpp diff --git a/producer/event_monitor_producer/CMakeLists.txt b/producer/event_monitor_producer/CMakeLists.txt index a6b4b82e9..616cd34b0 100644 --- a/producer/event_monitor_producer/CMakeLists.txt +++ b/producer/event_monitor_producer/CMakeLists.txt @@ -9,7 +9,7 @@ set(SOURCE_FILES IF(WIN32) set(SOURCE_FILES ${SOURCE_FILES} src/system_folder_watch_windows.cpp) ELSEIF(UNIX) - set(SOURCE_FILES ${SOURCE_FILES} src/system_folder_watch_linux.cpp src/inotify_event.cpp src/inotify_event.h) + set(SOURCE_FILES ${SOURCE_FILES} src/system_folder_watch_linux.cpp src/inotify_event.cpp src/inotify_linux.cpp) ENDIF(WIN32) @@ -53,6 +53,11 @@ set(TEST_SOURCE_FILES unittests/test_folder_event_detector.cpp ) +IF(UNIX) +set(TEST_SOURCE_FILES ${TEST_SOURCE_FILES} unittests/test_system_folder_watch_linux.cpp) +ENDIF(WIN32) + + set(TEST_LIBRARIES "${TARGET_NAME}") gtest(${TARGET_NAME} "${TEST_SOURCE_FILES}" "${TEST_LIBRARIES}" ${CMAKE_CURRENT_SOURCE_DIR}/src/eventmon_main.cpp) diff --git a/producer/event_monitor_producer/src/inotify_linux.cpp b/producer/event_monitor_producer/src/inotify_linux.cpp new file mode 100644 index 000000000..6cf907c8e --- /dev/null +++ b/producer/event_monitor_producer/src/inotify_linux.cpp @@ -0,0 +1,24 @@ +#include "inotify_linux.h" + +#include <sys/inotify.h> + + +namespace asapo { + +int Inotify::Init() { + return inotify_init(); +} +int Inotify::AddWatch(int fd, const char* name, uint32_t mask) { + return inotify_add_watch(fd, name, mask); +} +int Inotify::DeleteWatch(int fd, int wd) { + return inotify_rm_watch(fd, wd); +} + + +ssize_t Inotify::Read(int fd, void* buf, size_t nbytes) { + return read(fd, buf, nbytes); +} + + +} \ No newline at end of file diff --git a/producer/event_monitor_producer/src/inotify_linux.h b/producer/event_monitor_producer/src/inotify_linux.h new file mode 100644 index 000000000..195e86580 --- /dev/null +++ b/producer/event_monitor_producer/src/inotify_linux.h @@ -0,0 +1,21 @@ +#ifndef ASAPO_INOTIFY_H +#define ASAPO_INOTIFY_H + +#include <stdint.h> +#include <unistd.h> + +#include "preprocessor/definitions.h" + + +namespace asapo { + +class Inotify { + public: + VIRTUAL int Init(); + VIRTUAL int AddWatch(int fd, const char* name, uint32_t mask); + VIRTUAL int DeleteWatch(int fd, int wd); + VIRTUAL ssize_t Read(int fd, void* buf, size_t nbytes); +}; + +} +#endif //ASAPO_INOTIFY_H diff --git a/producer/event_monitor_producer/src/system_folder_watch_linux.cpp b/producer/event_monitor_producer/src/system_folder_watch_linux.cpp index 956a4c82e..b5782b5f3 100644 --- a/producer/event_monitor_producer/src/system_folder_watch_linux.cpp +++ b/producer/event_monitor_producer/src/system_folder_watch_linux.cpp @@ -3,11 +3,12 @@ #include "event_monitor_error.h" #include "eventmon_logger.h" +#include "io/io_factory.h" namespace asapo { Error SystemFolderWatch::AddFolderToWatch(std::string folder) { - int id = inotify_add_watch(watch_fd_, folder.c_str(), kInotifyWatchFlags); + int id = inotify__->AddWatch(watch_fd_, folder.c_str(), kInotifyWatchFlags); if (id == -1) { return EventMonitorErrorTemplates::kSystemError.Generate("cannot add watch for " + folder); } @@ -23,7 +24,7 @@ Error SystemFolderWatch::AddFolderAndSubfoldersToWatch(std::string folder) { if (err) { return err; } - auto subdirs = io_-> GetSubDirectories(folder, &err); + auto subdirs = io__-> GetSubDirectories(folder, &err); if (err) { return err; } @@ -40,7 +41,7 @@ Error SystemFolderWatch::AddFolderAndSubfoldersToWatch(std::string folder) { Error SystemFolderWatch::StartFolderMonitor(const std::string& root_folder, const std::vector<std::string>& monitored_folders) { - watch_fd_ = inotify_init(); + watch_fd_ = inotify__->Init(); if (watch_fd_ == -1) { return EventMonitorErrorTemplates::kSystemError.Generate("cannot initialize inotify"); } @@ -93,7 +94,7 @@ Error SystemFolderWatch::ProcessInotifyEvent(const InotifyEvent& event, FileEven oldpath += std::string("/") + event.Name(); for (auto val = watched_folders_paths_.begin(); val != watched_folders_paths_.end();) { if ((oldpath.size() <= val->second.size()) && std::equal(oldpath.begin(), oldpath.end(), val->second.begin())) { - inotify_rm_watch(val->first, watch_fd_); + inotify__->DeleteWatch(val->first, watch_fd_); GetDefaultEventMonLogger()->Debug("removed folder from monitor: " + val->second); val = watched_folders_paths_.erase(val); } else { @@ -103,7 +104,7 @@ Error SystemFolderWatch::ProcessInotifyEvent(const InotifyEvent& event, FileEven } } else { - inotify_rm_watch(it->first, watch_fd_); + inotify__->DeleteWatch(it->first, watch_fd_); watched_folders_paths_.erase(it); GetDefaultEventMonLogger()->Debug("removed folder from monitor: " + oldpath); } @@ -130,7 +131,7 @@ Error SystemFolderWatch::ProcessInotifyEvent(const InotifyEvent& event, FileEven } Error SystemFolderWatch::ReadInotifyEvents(int* bytes_read) { - *bytes_read = read(watch_fd_, buffer, sizeof(buffer)); + *bytes_read = inotify__->Read(watch_fd_, buffer, sizeof(buffer)); if (*bytes_read < 0) { return EventMonitorErrorTemplates::kSystemError.Generate("read from inotify fd"); } @@ -173,5 +174,8 @@ FileEvents SystemFolderWatch::GetFileEventList(Error* err) { } return events; } +SystemFolderWatch::SystemFolderWatch() : io__{GenerateDefaultIO()}, inotify__{new Inotify()} { + +} } \ No newline at end of file diff --git a/producer/event_monitor_producer/src/system_folder_watch_linux.h b/producer/event_monitor_producer/src/system_folder_watch_linux.h index dee18bf28..a44205808 100644 --- a/producer/event_monitor_producer/src/system_folder_watch_linux.h +++ b/producer/event_monitor_producer/src/system_folder_watch_linux.h @@ -4,16 +4,16 @@ #include <vector> #include <string> #include <map> +#include <unistd.h> #include "common/error.h" #include "preprocessor/definitions.h" #include "asapo_producer.h" #include "common.h" #include "io/io.h" -#include "io/io_factory.h" -#include <sys/inotify.h> -#include <unistd.h> #include "inotify_event.h" +#include "inotify_linux.h" + namespace asapo { @@ -34,10 +34,12 @@ class SystemFolderWatch { public: VIRTUAL Error StartFolderMonitor(const std::string& root_folder, const std::vector<std::string>& monitored_folders); VIRTUAL FileEvents GetFileEventList(Error* err); + SystemFolderWatch(); + std::unique_ptr<IO> io__; + std::unique_ptr<Inotify> inotify__; private: Error AddFolderAndSubfoldersToWatch(std::string folder); Error AddFolderToWatch(std::string folder); - std::unique_ptr<IO> io_{GenerateDefaultIO()}; Error ProcessInotifyEvent(const InotifyEvent& event, FileEvents* file_events); private: char buffer[kBufLen] __attribute__ ((aligned(8))); diff --git a/producer/event_monitor_producer/unittests/mock_inotify.h b/producer/event_monitor_producer/unittests/mock_inotify.h new file mode 100644 index 000000000..54ab163f0 --- /dev/null +++ b/producer/event_monitor_producer/unittests/mock_inotify.h @@ -0,0 +1,22 @@ +#ifndef ASAPO_MOCKSYSTEMFOLDERWATCH_H +#define ASAPO_MOCKSYSTEMFOLDERWATCH_H + +#include <gtest/gtest.h> +#include <gmock/gmock.h> + +#include "../src/inotify_linux.h" + +namespace asapo { + +class MockInotify : public Inotify { + public: + MOCK_METHOD0(Init, int ()); + MOCK_METHOD3(AddWatch, int (int,const char*,uint32_t)); + MOCK_METHOD2(DeleteWatch, int (int,int)); + MOCK_METHOD3(Read, ssize_t (int,void*,size_t)); +}; + +} + + +#endif //ASAPO_MOCKSYSTEMFOLDERWATCH_H diff --git a/producer/event_monitor_producer/unittests/test_system_folder_watch_linux.cpp b/producer/event_monitor_producer/unittests/test_system_folder_watch_linux.cpp new file mode 100644 index 000000000..c4d8bcf04 --- /dev/null +++ b/producer/event_monitor_producer/unittests/test_system_folder_watch_linux.cpp @@ -0,0 +1,128 @@ +#include <gtest/gtest.h> +#include <gmock/gmock.h> + +#include "../src/system_folder_watch_linux.h" +#include "../src/event_monitor_error.h" +#include "../src/common.h" + +#include "mock_inotify.h" +#include <unittests/MockIO.h> + + + +using ::testing::Return; +using ::testing::_; +using ::testing::DoAll; +using ::testing::SetArgReferee; +using ::testing::SetArgPointee; +using ::testing::Gt; +using ::testing::Eq; +using ::testing::Ne; +using ::testing::Mock; +using ::testing::InSequence; +using ::testing::HasSubstr; +using testing::StrEq; + +using ::asapo::Error; +using ::asapo::ErrorInterface; +using asapo::FileEvents; +using asapo::FileEvent; +using asapo::SystemFolderWatch; + +namespace { + + +TEST(SystemFolderWatch, Constructor) { + SystemFolderWatch watch; + ASSERT_THAT(dynamic_cast<asapo::IO*>(watch.io__.get()), Ne(nullptr)); + ASSERT_THAT(dynamic_cast<asapo::Inotify*>(watch.inotify__.get()), Ne(nullptr)); +} + +class SystemFolderWatchTests : public testing::Test { + public: + Error err; + ::testing::NiceMock<asapo::MockInotify> mock_inotify; + ::testing::NiceMock<asapo::MockIO> mock_io; + SystemFolderWatch watch{}; + std::string expected_root_folder = "/tmp"; + std::vector<std::string> expected_folders{"test1", "test2"}; + std::vector<std::string> expected_subfolders1{"/tmp/test1/sub11"}; + std::vector<std::string> expected_subfolders2{"/tmp/test2/sub21","/tmp/test2/sub22"}; + std::vector<std::string> expected_watches{"/tmp/test1", "/tmp/test2","/tmp/test1/sub11","/tmp/test2/sub21","/tmp/test2/sub22"}; + int expected_wd = 1; + int expected_fd = 1; + void MockStartMonitoring(); + void SetUp() override { + watch.inotify__ = std::unique_ptr<asapo::Inotify> {&mock_inotify}; + watch.io__ = std::unique_ptr<asapo::IO> {&mock_io}; + } + void TearDown() override { + watch.inotify__.release(); + watch.io__.release(); + } +}; + +void SystemFolderWatchTests::MockStartMonitoring() { + EXPECT_CALL(mock_inotify, Init()) + .WillOnce( + Return(expected_wd) + ); + EXPECT_CALL(mock_io, GetSubDirectories_t(expected_root_folder+"/"+expected_folders[0],_)) + .WillOnce( + Return(expected_subfolders1) + ); + EXPECT_CALL(mock_io, GetSubDirectories_t(expected_root_folder+"/"+expected_folders[1],_)) + .WillOnce( + Return(expected_subfolders2) + ); + + for (auto& watch : expected_watches) { + EXPECT_CALL(mock_inotify,AddWatch(expected_wd,StrEq(watch),asapo::kInotifyWatchFlags)) + .WillOnce( + Return(expected_fd) + ); + } + + auto err = watch.StartFolderMonitor(expected_root_folder,expected_folders); + ASSERT_THAT(err, Eq(nullptr)); + + + Mock::VerifyAndClearExpectations(&mock_inotify); +} + +TEST_F(SystemFolderWatchTests, ErrorInitInotifyStartMonitoring) { + EXPECT_CALL(mock_inotify, Init()) + .WillOnce( + Return(-1) + ); + + auto err = watch.StartFolderMonitor(expected_root_folder,expected_folders); + ASSERT_THAT(err, Eq(asapo::EventMonitorErrorTemplates::kSystemError)); +} + + +TEST_F(SystemFolderWatchTests, OKInitInotifyStartMonitoring) { + MockStartMonitoring(); +} + + +TEST_F(SystemFolderWatchTests, ErrorGetSubdirsStartMonitoring) { + EXPECT_CALL(mock_inotify, Init()) + .WillOnce( + Return(expected_wd) + ); + EXPECT_CALL(mock_io, GetSubDirectories_t(expected_root_folder+"/"+expected_folders[0],_)) + .WillOnce(DoAll( + SetArgPointee<1>(asapo::IOErrorTemplates::kUnknownIOError.Generate().release()), + Return(asapo::SubDirList{})) + ); + + auto err = watch.StartFolderMonitor(expected_root_folder,expected_folders); + ASSERT_THAT(err, Eq(asapo::EventMonitorErrorTemplates::kSystemError)); +} + + + +} + + -- GitLab