From 52a7ad970ff38c44279dc8dd6e3a05979cedd412 Mon Sep 17 00:00:00 2001
From: Sergey Yakubov <sergey.yakubov@desy.de>
Date: Fri, 24 Aug 2018 16:27:25 +0200
Subject: [PATCH] work at folder event detector

---
 producer/event_monitor_producer/src/common.h  |  25 ++++
 .../src/event_detector.h                      |   4 +-
 .../src/event_monitor_error.h                 |  70 +++++++++++
 .../src/eventmon_config.cpp                   |   3 +
 .../src/eventmon_config.h                     |   3 +-
 .../src/eventmon_main.cpp                     |   5 +
 .../src/folder_event_detector.cpp             |  36 +++++-
 .../src/folder_event_detector.h               |   4 +-
 .../src/system_folder_watch_linux.cpp         |  11 ++
 .../src/system_folder_watch_linux.h           |  12 +-
 .../unittests/MockSystemFolderWatch.h         |  17 ---
 .../unittests/mock_eventmon_config.cpp        |   9 ++
 .../unittests/mock_system_folder_watch.h      |  36 ++++++
 .../unittests/test_eventmon_config.cpp        |   6 +-
 .../unittests/test_folder_event_detector.cpp  | 116 +++++++++++++++---
 15 files changed, 318 insertions(+), 39 deletions(-)
 create mode 100644 producer/event_monitor_producer/src/common.h
 create mode 100644 producer/event_monitor_producer/src/event_monitor_error.h
 delete mode 100644 producer/event_monitor_producer/unittests/MockSystemFolderWatch.h
 create mode 100644 producer/event_monitor_producer/unittests/mock_system_folder_watch.h

diff --git a/producer/event_monitor_producer/src/common.h b/producer/event_monitor_producer/src/common.h
new file mode 100644
index 000000000..374caa901
--- /dev/null
+++ b/producer/event_monitor_producer/src/common.h
@@ -0,0 +1,25 @@
+#ifndef ASAPO_EVENT_MONITOR_PRODUCER_COMMON_H
+#define ASAPO_EVENT_MONITOR_PRODUCER_COMMON_H
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace asapo {
+
+enum class EventType {
+  closed,
+  renamed_from
+};
+
+struct FileEvent {
+  EventType type;
+  uint64_t size;
+  std::string name;
+};
+
+using FileEvents = std::vector<FileEvent>;
+
+}
+
+#endif //ASAPO_EVENT_MONITOR_PRODUCER_COMMON_H
diff --git a/producer/event_monitor_producer/src/event_detector.h b/producer/event_monitor_producer/src/event_detector.h
index 0be06648e..dd1b9ec8a 100644
--- a/producer/event_monitor_producer/src/event_detector.h
+++ b/producer/event_monitor_producer/src/event_detector.h
@@ -2,13 +2,15 @@
 #define ASAPO_EVENT_DETECTOR_H
 
 #include <memory>
-#include "producer/common.h"
+#include "asapo_producer.h"
 
 namespace asapo {
 
 class AbstractEventDetector {
   public:
     virtual Error GetNextEvent(EventHeader* event_header) = 0;
+    virtual Error StartMonitoring() = 0;
+    virtual ~AbstractEventDetector() = default;
 };
 
 using EventDetector = std::unique_ptr<AbstractEventDetector>;
diff --git a/producer/event_monitor_producer/src/event_monitor_error.h b/producer/event_monitor_producer/src/event_monitor_error.h
new file mode 100644
index 000000000..8b05cd8fd
--- /dev/null
+++ b/producer/event_monitor_producer/src/event_monitor_error.h
@@ -0,0 +1,70 @@
+#ifndef ASAPO_EventMonitor_ERROR_H
+#define ASAPO_EventMonitor_ERROR_H
+
+#include "common/error.h"
+
+namespace asapo {
+
+enum class EventMonitorErrorType {
+  kNoNewEvent,
+  kSystemError
+};
+
+class EventMonitorError : public SimpleError {
+ private:
+  EventMonitorErrorType error_type_;
+ public:
+  EventMonitorError(const std::string& error, EventMonitorErrorType error_type) : SimpleError(error,
+                                                                                               ErrorType::kHidraError) {
+      error_type_ = error_type;
+  }
+
+  EventMonitorErrorType GetEventMonitorErrorType() const noexcept {
+      return error_type_;
+  }
+};
+
+class EventMonitorErrorTemplate : public SimpleErrorTemplate {
+ protected:
+  EventMonitorErrorType error_type_;
+ public:
+  EventMonitorErrorTemplate(const std::string& error, EventMonitorErrorType error_type) : SimpleErrorTemplate(error,
+                                                                                              ErrorType::kHidraError) {
+      error_type_ = error_type;
+  }
+
+  inline EventMonitorErrorType GetEventMonitorErrorType() const noexcept {
+      return error_type_;
+  }
+
+  inline Error Generate() const noexcept override {
+      return Error(new EventMonitorError(error_, error_type_));
+  }
+
+  inline bool operator==(const Error& rhs) const override {
+      return SimpleErrorTemplate::operator==(rhs)
+          && GetEventMonitorErrorType() == ((EventMonitorError*) rhs.get())->GetEventMonitorErrorType();
+  }
+};
+
+static inline std::ostream& operator<<(std::ostream& os, const EventMonitorErrorTemplate& err) {
+    return os << err.Text();
+}
+
+
+namespace EventMonitorErrorTemplates {
+auto const kNoNewEvent = EventMonitorErrorTemplate {
+    "no new event", EventMonitorErrorType::kNoNewEvent
+};
+
+auto const kSystemError = EventMonitorErrorTemplate {
+    "system error", EventMonitorErrorType::kSystemError
+};
+
+
+
+};
+}
+
+#endif //ASAPO_EventMonitor_ERROR_H
+
diff --git a/producer/event_monitor_producer/src/eventmon_config.cpp b/producer/event_monitor_producer/src/eventmon_config.cpp
index b5ac647a2..66082225f 100644
--- a/producer/event_monitor_producer/src/eventmon_config.cpp
+++ b/producer/event_monitor_producer/src/eventmon_config.cpp
@@ -20,6 +20,8 @@ Error EventMonConfigFactory::ParseConfigFile(std::string file_name) {
     (err = parser.GetString("Mode", &config.mode_str)) ||
     (err = parser.GetUInt64("NThreads", &config.nthreads)) ||
     (err = parser.GetString("LogLevel", &config.log_level_str));
+    (err = parser.GetArrayString("MonitoredFolders", &config.monitored_folders));
+
     return err;
 }
 
@@ -29,6 +31,7 @@ Error EventMonConfigFactory::CheckConfig() {
     (err = CheckMode()) ||
     (err = CheckLogLevel()) ||
     (err = CheckNThreads());
+//todo: check monitored folders exist?
     return err;
 }
 
diff --git a/producer/event_monitor_producer/src/eventmon_config.h b/producer/event_monitor_producer/src/eventmon_config.h
index ea3c6d1a2..90f986fa2 100644
--- a/producer/event_monitor_producer/src/eventmon_config.h
+++ b/producer/event_monitor_producer/src/eventmon_config.h
@@ -4,7 +4,7 @@
 #include "io/io.h"
 #include "common/error.h"
 #include "logger/logger.h"
-#include "producer/common.h"
+#include "asapo_producer.h"
 #include "eventmon_config_factory.h"
 
 namespace asapo {
@@ -16,6 +16,7 @@ struct EventMonConfig {
     uint64_t nthreads = 1;
     std::string beamtime_id;
     RequestHandlerType mode = RequestHandlerType::kTcp;
+    std::vector<std::string> monitored_folders;
   private:
     std::string log_level_str;
     std::string mode_str;
diff --git a/producer/event_monitor_producer/src/eventmon_main.cpp b/producer/event_monitor_producer/src/eventmon_main.cpp
index e2894cf9f..e8e8b1f1b 100644
--- a/producer/event_monitor_producer/src/eventmon_main.cpp
+++ b/producer/event_monitor_producer/src/eventmon_main.cpp
@@ -65,6 +65,11 @@ int main (int argc, char* argv[]) {
     asapo::EventDetectorFactory factory;
     auto event_detector = factory.CreateEventDetector();
 
+    err = event_detector->StartMonitoring();
+    if (err) {
+        return EXIT_FAILURE;
+    }
+
     int i = 0;
     while (true && i < 1000) {
         asapo::EventHeader event_header;
diff --git a/producer/event_monitor_producer/src/folder_event_detector.cpp b/producer/event_monitor_producer/src/folder_event_detector.cpp
index 833d508b4..ff62551ca 100644
--- a/producer/event_monitor_producer/src/folder_event_detector.cpp
+++ b/producer/event_monitor_producer/src/folder_event_detector.cpp
@@ -1,15 +1,47 @@
 #include "folder_event_detector.h"
 #include "io/io_factory.h"
 #include "eventmon_logger.h"
+#include "event_monitor_error.h"
 
 namespace asapo {
 
+FolderEventDetector::FolderEventDetector(const EventMonConfig* config) : system_folder_watch__{new SystemFolderWatch()},
+config_{config}{
+}
+
 Error FolderEventDetector::GetNextEvent(EventHeader* event_header) {
+    if (!monitoring_started_) {
+            auto err = TextError("monitoring is not started yet");
+            return err;
+    }
+
+    Error err;
+    auto file_events = system_folder_watch__->GetFileEventList(&err);
+    if (err) {
+        return err;
+    }
+    if (file_events.size() == 0) {
+        return EventMonitorErrorTemplates::kNoNewEvent.Generate();
+    }
+
+    FileEvent file_event = file_events[0];
+    event_header->file_size = file_event.size;
+    event_header->file_name = std::move(file_event.name);
     return nullptr;
 }
-FolderEventDetector::FolderEventDetector(const EventMonConfig* config) : system_folder_watch__{new SystemFolderWatch()},
-log__{GetDefaultEventMonLogger()}, config_{config}{
 
+Error FolderEventDetector::StartMonitoring() {
+    if (monitoring_started_) {
+        return nullptr;
+    }
+
+    auto err = system_folder_watch__->StartFolderMonitor(config_->monitored_folders);
+    if (err) {
+        return err;
+    }
+
+    monitoring_started_ = true;
+    return nullptr;
 }
 
 }
\ No newline at end of file
diff --git a/producer/event_monitor_producer/src/folder_event_detector.h b/producer/event_monitor_producer/src/folder_event_detector.h
index 1d0901e58..c6748aa69 100644
--- a/producer/event_monitor_producer/src/folder_event_detector.h
+++ b/producer/event_monitor_producer/src/folder_event_detector.h
@@ -4,7 +4,6 @@
 #include "event_detector.h"
 #include "eventmon_config.h"
 #include "io/io.h"
-#include "logger/logger.h"
 
 #include "system_folder_watch.h"
 
@@ -13,11 +12,12 @@ namespace asapo {
 class FolderEventDetector : public AbstractEventDetector {
   public:
     Error GetNextEvent(EventHeader* event_header) override;
+    Error StartMonitoring() override;
     FolderEventDetector(const EventMonConfig* config);
     std::unique_ptr<SystemFolderWatch> system_folder_watch__;
-    const AbstractLogger* log__;
   private:
     const EventMonConfig* config_;
+    bool monitoring_started_= false;
 };
 
 }
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 57291cf35..996c40e11 100644
--- a/producer/event_monitor_producer/src/system_folder_watch_linux.cpp
+++ b/producer/event_monitor_producer/src/system_folder_watch_linux.cpp
@@ -2,4 +2,15 @@
 
 namespace asapo {
 
+Error SystemFolderWatch::StartFolderMonitor(const std::vector<std::string> &monitored_folders) {
+    return nullptr;
+}
+
+FileEvents SystemFolderWatch::GetFileEventList(Error* err) {
+    FileEvents events;
+    *err = nullptr;
+    return events;
+}
+
+
 }
\ 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 e948f1aa3..e7f64aca4 100644
--- a/producer/event_monitor_producer/src/system_folder_watch_linux.h
+++ b/producer/event_monitor_producer/src/system_folder_watch_linux.h
@@ -1,10 +1,20 @@
 #ifndef ASAPO_SYSTEM_FOLDER_WATCH_LINUX_H
 #define ASAPO_SYSTEM_FOLDER_WATCH_LINUX_H
 
+#include <vector>
+#include <string>
+
+#include "common/error.h"
+#include "preprocessor/definitions.h"
+#include "asapo_producer.h"
+#include "common.h"
+
 namespace asapo {
 
 class SystemFolderWatch {
-
+ public:
+  VIRTUAL Error StartFolderMonitor(const std::vector<std::string>& monitored_folders);
+  VIRTUAL FileEvents GetFileEventList(Error* err);
 };
 
 }
diff --git a/producer/event_monitor_producer/unittests/MockSystemFolderWatch.h b/producer/event_monitor_producer/unittests/MockSystemFolderWatch.h
deleted file mode 100644
index e79d9951d..000000000
--- a/producer/event_monitor_producer/unittests/MockSystemFolderWatch.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef ASAPO_MOCKSYSTEMFOLDERWATCH_H
-#define ASAPO_MOCKSYSTEMFOLDERWATCH_H
-
-#include <gtest/gtest.h>
-#include <gmock/gmock.h>
-
-#include "../src/system_folder_watch.h"
-
-namespace asapo {
-
-class MockSystemFolderWatch : public SystemFolderWatch {
-};
-
-}
-
-
-#endif //ASAPO_MOCKSYSTEMFOLDERWATCH_H
diff --git a/producer/event_monitor_producer/unittests/mock_eventmon_config.cpp b/producer/event_monitor_producer/unittests/mock_eventmon_config.cpp
index ecf5a3d10..a031b4889 100644
--- a/producer/event_monitor_producer/unittests/mock_eventmon_config.cpp
+++ b/producer/event_monitor_producer/unittests/mock_eventmon_config.cpp
@@ -48,6 +48,15 @@ Error SetFolderMonConfig (const EventMonConfig& config) {
     config_string += "," + std::string("\"Mode\":") + "\"" + mode + "\"";
     config_string += "," + std::string("\"NThreads\":") + std::to_string(config.nthreads);
     config_string += "," + std::string("\"LogLevel\":") + "\"" + log_level + "\"";
+    std::string mon_folders;
+    for (auto folder:config.monitored_folders) {
+        mon_folders+="\""+folder+"\""+",";
+    }
+    if (mon_folders.size()) {
+        mon_folders.pop_back();
+    }
+
+    config_string += "," + std::string("\"MonitoredFolders\":") + "[" + mon_folders + "]";
     config_string += "," + std::string("\"Tag\":") + "\"" + config.tag + "\"";
     config_string += "," + std::string("\"AsapoEndpoint\":") + "\"" + config.asapo_endpoint + "\"";
 
diff --git a/producer/event_monitor_producer/unittests/mock_system_folder_watch.h b/producer/event_monitor_producer/unittests/mock_system_folder_watch.h
new file mode 100644
index 000000000..92a696b3d
--- /dev/null
+++ b/producer/event_monitor_producer/unittests/mock_system_folder_watch.h
@@ -0,0 +1,36 @@
+#ifndef ASAPO_MOCKSYSTEMFOLDERWATCH_H
+#define ASAPO_MOCKSYSTEMFOLDERWATCH_H
+
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include "../src/system_folder_watch.h"
+#include "io/io.h"
+
+namespace asapo {
+
+class MockSystemFolderWatch : public SystemFolderWatch {
+ public:
+  MOCK_METHOD1(StartFolderMonitor_t, ErrorInterface* (const std::vector<std::string>& monitored_folders));
+
+  Error StartFolderMonitor(const std::vector<std::string>& monitored_folders) override {
+      return Error{StartFolderMonitor_t(monitored_folders)};
+
+  }
+
+  MOCK_METHOD1(GetFileEventList_t, FileEvents (ErrorInterface** error));
+
+   FileEvents GetFileEventList(Error* err) override {
+      ErrorInterface* error = nullptr;
+      auto data = GetFileEventList_t(&error);
+      err->reset(error);
+      return data;
+  };
+
+
+};
+
+}
+
+
+#endif //ASAPO_MOCKSYSTEMFOLDERWATCH_H
diff --git a/producer/event_monitor_producer/unittests/test_eventmon_config.cpp b/producer/event_monitor_producer/unittests/test_eventmon_config.cpp
index 779d7d9c1..7b65865ee 100644
--- a/producer/event_monitor_producer/unittests/test_eventmon_config.cpp
+++ b/producer/event_monitor_producer/unittests/test_eventmon_config.cpp
@@ -20,6 +20,8 @@ using ::testing::SaveArg;
 using ::testing::SaveArgPointee;
 using ::testing::InSequence;
 using ::testing::SetArgPointee;
+using testing::ElementsAre;
+
 using ::asapo::Error;
 using ::asapo::ErrorInterface;
 using ::asapo::FileDescriptor;
@@ -54,7 +56,7 @@ TEST_F(ConfigTests, ReadSettingsOK) {
     test_config.beamtime_id = "test";
     test_config.asapo_endpoint = "uri:001";
     test_config.mode = asapo::RequestHandlerType::kTcp;
-
+    test_config.monitored_folders={"test1","test2"};
     auto err = asapo::SetFolderMonConfig(test_config);
 
     auto config = asapo::GetEventMonConfig();
@@ -66,6 +68,8 @@ TEST_F(ConfigTests, ReadSettingsOK) {
     ASSERT_THAT(config->beamtime_id, Eq("test"));
     ASSERT_THAT(config->asapo_endpoint, Eq("uri:001"));
     ASSERT_THAT(config->mode, Eq(asapo::RequestHandlerType::kTcp));
+    ASSERT_THAT(config->monitored_folders, ElementsAre("test1","test2"));
+
 }
 
 TEST_F(ConfigTests, ReadSettingsChecksNthreads) {
diff --git a/producer/event_monitor_producer/unittests/test_folder_event_detector.cpp b/producer/event_monitor_producer/unittests/test_folder_event_detector.cpp
index d8d0e2ff6..868a9a6bb 100644
--- a/producer/event_monitor_producer/unittests/test_folder_event_detector.cpp
+++ b/producer/event_monitor_producer/unittests/test_folder_event_detector.cpp
@@ -2,11 +2,12 @@
 #include <gmock/gmock.h>
 
 #include "../src/folder_event_detector.h"
+#include "../src/event_monitor_error.h"
+#include "../src/common.h"
 
 #include "unittests/MockIO.h"
-#include "unittests/MockLogger.h"
 
-#include "MockSystemFolderWatch.h"
+#include "mock_system_folder_watch.h"
 
 
 
@@ -26,6 +27,7 @@ using ::testing::HasSubstr;
 using ::asapo::Error;
 using ::asapo::FileDescriptor;
 using ::asapo::ErrorInterface;
+using asapo::FileEvents;
 
 using asapo::FolderEventDetector;
 
@@ -42,38 +44,124 @@ TEST(FolderEventDetector, Constructor) {
 class FolderEventDetectorTests : public testing::Test {
  public:
   Error err;
-  ::testing::NiceMock<asapo::MockLogger> mock_logger;
   ::testing::NiceMock<asapo::MockSystemFolderWatch> mock_system_folder_watch;
   asapo::EventMonConfig test_config;
   FolderEventDetector detector{&test_config};
   std::vector<std::string> expected_folders{"test1","test2"};
   void SetUp() override {
-//      test_config.expected_folders = expected_folders;
+      test_config.monitored_folders = expected_folders;
       err = nullptr;
       detector.system_folder_watch__ = std::unique_ptr<asapo::SystemFolderWatch> {&mock_system_folder_watch};
-      detector.log__ = &mock_logger;
   }
   void TearDown() override {
       detector.system_folder_watch__.release();
   }
+  void MockStartMonitoring();
 
+  };
+
+void FolderEventDetectorTests::MockStartMonitoring() {
+    EXPECT_CALL(mock_system_folder_watch, StartFolderMonitor_t(expected_folders))
+        .WillOnce(
+            Return(nullptr)
+        );
+}
+
+
+
+TEST_F(FolderEventDetectorTests, StartsFolderMonitoringOK) {
+    EXPECT_CALL(mock_system_folder_watch, StartFolderMonitor_t(expected_folders))
+        .WillOnce(
+            Return(nullptr)
+        );
+    auto err = detector.StartMonitoring();
+    ASSERT_THAT(err, Eq(nullptr));
+}
+
+TEST_F(FolderEventDetectorTests, StartFolderMonitoringInitiatesOnlyOnce) {
+    EXPECT_CALL(mock_system_folder_watch, StartFolderMonitor_t(expected_folders))
+        .WillOnce(
+            Return(nullptr)
+        );
+    auto err = detector.StartMonitoring();
+    ASSERT_THAT(err, Eq(nullptr));
+    err = detector.StartMonitoring();
+    ASSERT_THAT(err, Eq(nullptr));
+}
+
+TEST_F(FolderEventDetectorTests, StartFolderMonitoringReturnsError) {
+    EXPECT_CALL(mock_system_folder_watch, StartFolderMonitor_t(expected_folders))
+        .Times(2)
+        .WillOnce(
+            Return(asapo::ErrorTemplates::kMemoryAllocationError.Generate().release())
+        )
+        .WillOnce(
+            Return(nullptr)
+        )
+        ;
+    auto err = detector.StartMonitoring();
+    ASSERT_THAT(err, Ne(nullptr));
+    err = detector.StartMonitoring();
+    ASSERT_THAT(err, Eq(nullptr));
+}
+
+TEST_F(FolderEventDetectorTests, GetNextReturnsErrorIfMonitoringNotStarted) {
+    auto err = detector.GetNextEvent(nullptr);
+    ASSERT_THAT(err, Ne(nullptr));
+}
+
+TEST_F(FolderEventDetectorTests, GetNextCallsSystemGetNextFirstTimeNoEvents) {
+    MockStartMonitoring();
+    asapo::EventHeader event_header;
+    EXPECT_CALL(mock_system_folder_watch, GetFileEventList_t(_));
 
-};
 
-TEST_F(FolderEventDetectorTests, GetNextEventCallsGetFolderEvents) {
+    detector.StartMonitoring();
 
-//    EXPECT_CALL(mock_system_folder_watch, StartFolderMonitor_t(expected_folders, receiver.kMaxUnacceptedConnectionsBacklog, _))
-//        .WillOnce(DoAll(
-//            SetArgPointee<2>(asapo::IOErrorTemplates::kUnknownIOError.Generate().release()),
-//            Return(0)
-//        ));
+    auto err = detector.GetNextEvent(&event_header);
+    ASSERT_THAT(err, Eq(asapo::EventMonitorErrorTemplates::kNoNewEvent));
+}
+
+TEST_F(FolderEventDetectorTests, GetNextEventError) {
+    MockStartMonitoring();
+    asapo::EventHeader event_header;
+    EXPECT_CALL(mock_system_folder_watch, GetFileEventList_t(_)).WillOnce(
+        DoAll(
+            SetArgPointee<0>(asapo::EventMonitorErrorTemplates::kSystemError.Generate().release()),
+            Return(FileEvents{})
+        ));
 
-    //EXPECT_CALL(mock_logger, Error(HasSubstr("prepare listener")));
 
 
-//    ASSERT_THAT(err, Eq(asapo::IOErrorTemplates::kUnknownIOError));
+    detector.StartMonitoring();
+
+    auto err = detector.GetNextEvent(&event_header);
+    ASSERT_THAT(err, Eq(asapo::EventMonitorErrorTemplates::kSystemError));
 }
 
+
+TEST_F(FolderEventDetectorTests, GetNextEventOK) {
+    MockStartMonitoring();
+    asapo::EventHeader event_header;
+    EXPECT_CALL(mock_system_folder_watch, GetFileEventList_t(_)).WillOnce(
+        DoAll(
+            SetArgPointee<0>(nullptr),
+            Return(FileEvents{asapo::FileEvent{asapo::EventType::closed,10,"test"}})
+        ));
+
+
+
+    detector.StartMonitoring();
+
+    auto err = detector.GetNextEvent(&event_header);
+    ASSERT_THAT(err, Eq(nullptr));
+
+    ASSERT_THAT(event_header.file_name, Eq("test"));
+    ASSERT_THAT(event_header.file_size, Eq(10));
+
+}
+
+
 }
 
 
-- 
GitLab