From 6f8d30785081884c61301f9b30ca32071c4ee8a3 Mon Sep 17 00:00:00 2001 From: EricLiu2000 Date: Wed, 24 Jul 2019 12:52:15 -0400 Subject: [PATCH] Implemented thread specific error-downgrading to events and wrote corresponding unit test --- api/icsneocpp/event.cpp | 4 +++ api/icsneocpp/eventmanager.cpp | 8 +++++ include/icsneo/api/event.h | 2 ++ include/icsneo/api/eventmanager.h | 21 +++++++++--- test/eventmanagertest.cpp | 56 +++++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 4 deletions(-) diff --git a/api/icsneocpp/event.cpp b/api/icsneocpp/event.cpp index 9aee9de..49fa47f 100644 --- a/api/icsneocpp/event.cpp +++ b/api/icsneocpp/event.cpp @@ -45,6 +45,10 @@ std::string APIEvent::describe() const noexcept { return ss.str(); } +void APIEvent::downgradeFromError() noexcept { + eventStruct.severity = (uint8_t) APIEvent::Severity::EventWarning; +} + bool APIEvent::isForDevice(std::string filterSerial) const noexcept { if(!device || filterSerial.length() == 0) return false; diff --git a/api/icsneocpp/eventmanager.cpp b/api/icsneocpp/eventmanager.cpp index 4a5b2d3..c9357fb 100644 --- a/api/icsneocpp/eventmanager.cpp +++ b/api/icsneocpp/eventmanager.cpp @@ -15,6 +15,14 @@ void EventManager::ResetInstance() { singleton = std::unique_ptr(new EventManager()); } +void EventManager::downgradeErrorsOnCurrentThread() { + downgradedThreads.insert(std::this_thread::get_id()); +} + +void EventManager::cancelErrorDowngradingOnCurrentThread() { + downgradedThreads.erase(std::this_thread::get_id()); +} + void EventManager::get(std::vector& eventOutput, size_t max, EventFilter filter) { std::lock_guard lk(mutex); diff --git a/include/icsneo/api/event.h b/include/icsneo/api/event.h index b96acf9..3076cea 100644 --- a/include/icsneo/api/event.h +++ b/include/icsneo/api/event.h @@ -102,6 +102,8 @@ public: std::string getDescription() const noexcept { return std::string(eventStruct.description); } const Device* getDevice() const noexcept { return device; } // Will return nullptr if this is an API-wide event EventTimePoint getTimestamp() const noexcept { return timepoint; } + + void downgradeFromError() noexcept; bool isForDevice(const Device* forDevice) const noexcept { return forDevice == device; } bool isForDevice(std::string serial) const noexcept; diff --git a/include/icsneo/api/eventmanager.h b/include/icsneo/api/eventmanager.h index 4f15d81..c0a2d56 100644 --- a/include/icsneo/api/eventmanager.h +++ b/include/icsneo/api/eventmanager.h @@ -2,11 +2,13 @@ #define __ICSNEO_API_EVENTMANAGER_H_ #include +#include #include #include #include #include #include +#include #include "icsneo/api/event.h" namespace icsneo { @@ -19,6 +21,10 @@ public: static void ResetInstance(); + void downgradeErrorsOnCurrentThread(); + + void cancelErrorDowngradingOnCurrentThread(); + size_t eventCount(EventFilter filter = EventFilter()) const { std::lock_guard lk(mutex); return count_internal(filter); @@ -67,13 +73,15 @@ public: } private: - EventManager() : mutex(), events(), lastUserErrors(), eventLimit(10000) {} + EventManager() : mutex(), downgradedThreads(), events(), lastUserErrors(), eventLimit(10000) {} EventManager(const EventManager &other); EventManager& operator=(const EventManager &other); // Used by functions for threadsafety mutable std::mutex mutex; + std::set downgradedThreads; + // Stores all events std::list events; std::map lastUserErrors; @@ -82,9 +90,14 @@ private: size_t count_internal(EventFilter filter = EventFilter()) const; void add_internal(APIEvent event) { - if(event.getSeverity() == APIEvent::Severity::Error) - add_internal_error(event); - else + if(event.getSeverity() == APIEvent::Severity::Error) { + // if the error was added on a thread that downgrades errors (non-user thread) + if(std::find(downgradedThreads.begin(), downgradedThreads.end(), std::this_thread::get_id()) != downgradedThreads.end()) { + event.downgradeFromError(); + add_internal_event(event); + } else + add_internal_error(event); + } else add_internal_event(event); } diff --git a/test/eventmanagertest.cpp b/test/eventmanagertest.cpp index 381ec44..76e4543 100644 --- a/test/eventmanagertest.cpp +++ b/test/eventmanagertest.cpp @@ -13,6 +13,62 @@ protected: } }; +TEST_F(EventManagerTest, ErrorDowngradingTest) { + // Check that main thread has no errors + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound); + + // Adds 500 {OutputTruncated, Warning} and 500 {OutputTruncated, Info} + // Adds and checks errors as well. + std::thread t1([]() { + for(int i = 0; i < 500; i++) { + EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning)); + EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventInfo)); + } + + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound); + + EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error)); + + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::OutputTruncated); + + EventManager::GetInstance().downgradeErrorsOnCurrentThread(); + EventManager::GetInstance().add(APIEvent(APIEvent::Type::BufferInsufficient, APIEvent::Severity::Error)); + + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound); + auto events = GetEvents(EventFilter(APIEvent::Type::BufferInsufficient, APIEvent::Severity::EventWarning)); + EXPECT_EQ(events.empty(), false); + + EventManager::GetInstance().cancelErrorDowngradingOnCurrentThread(); + + EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error)); + + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::OutputTruncated); + }); + + // Adds 500 {OutputTruncated, Warning} and 500 {OutputTruncated, Info} + // Adds and checks errors as well. + std::thread t2([]() { + for(int i = 0; i < 500; i++) { + EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning)); + EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventInfo)); + } + + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound); + + EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error)); + EventManager::GetInstance().add(APIEvent(APIEvent::Type::BufferInsufficient, APIEvent::Severity::Error)); + + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::BufferInsufficient); + + EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error)); + + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::OutputTruncated); + }); + + t1.join(); + t2.join(); +} + /** * Adds a total of 3000 events from 3 different threads, checking that all were correctly added after all threads are joined. * Also adds errors from each of the 3 threads, checking that the last error is correct for that thread and that the main thread has no errors.