Implemented thread specific error-downgrading to events and wrote corresponding unit test

checksum-failure-logging
EricLiu2000 2019-07-24 12:52:15 -04:00
parent 42a5d525ce
commit 6f8d307850
5 changed files with 87 additions and 4 deletions

View File

@ -45,6 +45,10 @@ std::string APIEvent::describe() const noexcept {
return ss.str(); return ss.str();
} }
void APIEvent::downgradeFromError() noexcept {
eventStruct.severity = (uint8_t) APIEvent::Severity::EventWarning;
}
bool APIEvent::isForDevice(std::string filterSerial) const noexcept { bool APIEvent::isForDevice(std::string filterSerial) const noexcept {
if(!device || filterSerial.length() == 0) if(!device || filterSerial.length() == 0)
return false; return false;

View File

@ -15,6 +15,14 @@ void EventManager::ResetInstance() {
singleton = std::unique_ptr<EventManager>(new EventManager()); singleton = std::unique_ptr<EventManager>(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<APIEvent>& eventOutput, size_t max, EventFilter filter) { void EventManager::get(std::vector<APIEvent>& eventOutput, size_t max, EventFilter filter) {
std::lock_guard<std::mutex> lk(mutex); std::lock_guard<std::mutex> lk(mutex);

View File

@ -103,6 +103,8 @@ public:
const Device* getDevice() const noexcept { return device; } // Will return nullptr if this is an API-wide event const Device* getDevice() const noexcept { return device; } // Will return nullptr if this is an API-wide event
EventTimePoint getTimestamp() const noexcept { return timepoint; } EventTimePoint getTimestamp() const noexcept { return timepoint; }
void downgradeFromError() noexcept;
bool isForDevice(const Device* forDevice) const noexcept { return forDevice == device; } bool isForDevice(const Device* forDevice) const noexcept { return forDevice == device; }
bool isForDevice(std::string serial) const noexcept; bool isForDevice(std::string serial) const noexcept;

View File

@ -2,11 +2,13 @@
#define __ICSNEO_API_EVENTMANAGER_H_ #define __ICSNEO_API_EVENTMANAGER_H_
#include <vector> #include <vector>
#include <set>
#include <list> #include <list>
#include <mutex> #include <mutex>
#include <functional> #include <functional>
#include<map> #include<map>
#include <thread> #include <thread>
#include <algorithm>
#include "icsneo/api/event.h" #include "icsneo/api/event.h"
namespace icsneo { namespace icsneo {
@ -19,6 +21,10 @@ public:
static void ResetInstance(); static void ResetInstance();
void downgradeErrorsOnCurrentThread();
void cancelErrorDowngradingOnCurrentThread();
size_t eventCount(EventFilter filter = EventFilter()) const { size_t eventCount(EventFilter filter = EventFilter()) const {
std::lock_guard<std::mutex> lk(mutex); std::lock_guard<std::mutex> lk(mutex);
return count_internal(filter); return count_internal(filter);
@ -67,13 +73,15 @@ public:
} }
private: private:
EventManager() : mutex(), events(), lastUserErrors(), eventLimit(10000) {} EventManager() : mutex(), downgradedThreads(), events(), lastUserErrors(), eventLimit(10000) {}
EventManager(const EventManager &other); EventManager(const EventManager &other);
EventManager& operator=(const EventManager &other); EventManager& operator=(const EventManager &other);
// Used by functions for threadsafety // Used by functions for threadsafety
mutable std::mutex mutex; mutable std::mutex mutex;
std::set<std::thread::id> downgradedThreads;
// Stores all events // Stores all events
std::list<APIEvent> events; std::list<APIEvent> events;
std::map<std::thread::id, APIEvent> lastUserErrors; std::map<std::thread::id, APIEvent> lastUserErrors;
@ -82,9 +90,14 @@ private:
size_t count_internal(EventFilter filter = EventFilter()) const; size_t count_internal(EventFilter filter = EventFilter()) const;
void add_internal(APIEvent event) { void add_internal(APIEvent event) {
if(event.getSeverity() == APIEvent::Severity::Error) 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); add_internal_error(event);
else } else
add_internal_event(event); add_internal_event(event);
} }

View File

@ -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. * 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. * 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.