From 42690d1f9a500f889b70f6510e95170ae2a53326 Mon Sep 17 00:00:00 2001 From: EricLiu2000 Date: Fri, 28 Jun 2019 11:11:58 -0400 Subject: [PATCH] Updated documentation, added multithreaded test with both events and errors for eventmanager --- api/icsneocpp/eventmanager.cpp | 2 +- include/icsneo/icsneoc.h | 27 ++-- test/eventmanagertest.cpp | 225 +++++++++++++++++++++++++++------ 3 files changed, 204 insertions(+), 50 deletions(-) diff --git a/api/icsneocpp/eventmanager.cpp b/api/icsneocpp/eventmanager.cpp index f6b9443..4a5b2d3 100644 --- a/api/icsneocpp/eventmanager.cpp +++ b/api/icsneocpp/eventmanager.cpp @@ -17,7 +17,7 @@ void EventManager::ResetInstance() { void EventManager::get(std::vector& eventOutput, size_t max, EventFilter filter) { std::lock_guard lk(mutex); - + if(max == 0) // A limit of 0 indicates no limit max = (size_t)-1; diff --git a/include/icsneo/icsneoc.h b/include/icsneo/icsneoc.h index be4a892..4530e52 100644 --- a/include/icsneo/icsneoc.h +++ b/include/icsneo/icsneoc.h @@ -9,7 +9,7 @@ #include "icsneo/platform/dynamiclib.h" // Dynamic library loading and exporting #include "icsneo/communication/network.h" // Network type and netID defines #include "icsneo/api/version.h" // For version info -#include "icsneo/api/event.h" // For error info +#include "icsneo/api/event.h" // For event and error info #ifndef ICSNEOC_DYNAMICLOAD @@ -569,7 +569,7 @@ extern neoversion_t DLLExport icsneo_getVersion(void); * holds the maximum number of events to be written, and after the call holds the number of events written. * \returns True if the events were read out successfully (even if there were no events to report). * - * Events contain INFO and WARNINGS, and may potentially contain one TooManyEvents ERROR at the end. No other ERRORS are found in Events, see icsneo_getLastError() instead. + * Events contain INFO and WARNINGS, and may potentially contain one TooManyEvents WARNING at the end. No ERRORS are found in Events, see icsneo_getLastError() instead. * * Events can be caused by API usage, such as providing too small of a buffer or disconnecting from a device. * @@ -579,7 +579,7 @@ extern neoversion_t DLLExport icsneo_getVersion(void); * As they are read out, they are removed from the API managed buffer. * * If size is too small to contain all events, as many events as will fit will be read out. - * Subsequent calls to icsneo_getErrors() can retrieve any events which were not read out. + * Subsequent calls to icsneo_getEvents() can retrieve any events which were not read out. */ extern bool DLLExport icsneo_getEvents(neoevent_t* events, size_t* size); @@ -601,7 +601,7 @@ extern bool DLLExport icsneo_getDeviceEvents(const neodevice_t* device, neoevent * \returns True if an error was read out. * * All errors are stored on a per-thread basis, meaning that calling icsneo_getLastError() will return the last error that occured on the calling thread. - * Any errors can only be retrieved through this function, and NOT ics_neo_getEvents() or similar! Only INFO and WARNING level events are accessible through those, with the exception of the + * Any errors can only be retrieved through this function, and NOT ics_neo_getEvents() or similar! Only INFO and WARNING level events are accessible through those. * Only the last error is stored, so call this function often! * Calling icsneo_getLastError() will remove the returned error, meaning that subsequent calls to icsneo_getLastError() on the same thread will return false (barring any additional errors) * @@ -612,30 +612,31 @@ extern bool DLLExport icsneo_getDeviceEvents(const neodevice_t* device, neoevent extern bool DLLExport icsneo_getLastError(neoevent_t* error); /** - * \brief Discard all errors which have occurred in API operation. + * \brief Discard all events which have occurred in API operation. Does NOT discard any errors. */ extern void DLLExport icsneo_discardAllEvents(void); /** - * \brief Discard all errors which have occurred in API operation. - * \param[in] device A pointer to the neodevice_t structure specifying the device to discard errors for. NULL can be passed, which indicates that **ONLY** errors *not* associated with a device are desired (API errors). + * \brief Discard all events which have occurred in API operation. + * \param[in] device A pointer to the neodevice_t structure specifying the device to discard events for. NULL can be passed, which indicates that **ONLY** events *not* associated with a device are desired (API events). + * Does NOT discard any errors (device or otherwise). */ extern void DLLExport icsneo_discardDeviceEvents(const neodevice_t* device); /** - * \brief Set the number of errors which will be held in the API managed buffer before icsneo::APIEvent::TooManyEvents - * \param[in] newLimit The new limit. Must be >10. 1 error slot is always reserved for a potential icsneo::APIEvent::TooManyEvents, so (newLimit - 1) other errors can be stored. + * \brief Set the number of events which will be held in the API managed buffer before icsneo::APIEvent::TooManyEvents + * \param[in] newLimit The new limit. Must be >10. 1 event slot is always reserved for a potential icsneo::APIEvent::TooManyEvents, so (newLimit - 1) other events can be stored. * - * If the error limit is reached, an icsneo::APIEvent::TooManyEvents will be flagged. + * If the event limit is reached, an icsneo::APIEvent::TooManyEvents will be flagged. * - * If the `newLimit` is smaller than the current error count, - * errors will be removed in order of decreasing age. + * If the `newLimit` is smaller than the current event count, + * events will be removed in order of decreasing age. * This will also flag an icsneo::APIEvent::TooManyEvents. */ extern void DLLExport icsneo_setEventLimit(size_t newLimit); /** - * \brief Get the number of errors which can be held in the API managed buffer + * \brief Get the number of events which can be held in the API managed buffer * \returns The current limit. */ extern size_t DLLExport icsneo_getEventLimit(void); diff --git a/test/eventmanagertest.cpp b/test/eventmanagertest.cpp index 927d859..381ec44 100644 --- a/test/eventmanagertest.cpp +++ b/test/eventmanagertest.cpp @@ -7,12 +7,128 @@ using namespace icsneo; class EventManagerTest : public ::testing::Test { protected: + // Start with a clean instance of eventmanager for every test void SetUp() override { EventManager::ResetInstance(); } }; -// Tests that adding and removing events properly updates EventCount(). Also tests that EventCount() does not go past the limit. +/** + * 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. + */ +TEST_F(EventManagerTest, MultithreadedTest) { + + // 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)); + 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); + }); + + // Check that main thread has no errors + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound); + + // Adds 500 {CANFDNotSupported, Warning} and 500 {CANFDSettingsNotAvailable, Info} + // Adds and checks errors as well. + std::thread t2( []() { + for(int i = 0; i < 500; i++) { + EventManager::GetInstance().add(APIEvent(APIEvent::Type::CANFDNotSupported, APIEvent::Severity::EventWarning)); + EventManager::GetInstance().add(APIEvent(APIEvent::Type::CANFDSettingsNotAvailable, APIEvent::Severity::EventInfo)); + } + + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound); + + EventManager::GetInstance().add(APIEvent(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error)); + EventManager::GetInstance().add(APIEvent(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error)); + + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::DeviceCurrentlyOffline); + + EventManager::GetInstance().add(APIEvent(APIEvent::Type::DeviceCurrentlyOnline, APIEvent::Severity::Error)); + + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::DeviceCurrentlyOnline); + + EventManager::GetInstance().add(APIEvent(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error)); + }); + + // Check that main thread has no errors + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound); + + // Adds 500 {CANFDNotSupported, Warning} and 500 {FailedToWrite, Info} + // Adds and checks errors as well. + std::thread t3( []() { + for(int i = 0; i < 500; i++) { + EventManager::GetInstance().add(APIEvent(APIEvent::Type::CANFDNotSupported, APIEvent::Severity::EventWarning)); + EventManager::GetInstance().add(APIEvent(APIEvent::Type::FailedToWrite, APIEvent::Severity::EventInfo)); + } + + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound); + + EventManager::GetInstance().add(APIEvent(APIEvent::Type::NoSerialNumber, APIEvent::Severity::Error)); + EventManager::GetInstance().add(APIEvent(APIEvent::Type::SettingsChecksumError, APIEvent::Severity::Error)); + + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::SettingsChecksumError); + + EventManager::GetInstance().add(APIEvent(APIEvent::Type::SWCANSettingsNotAvailable, APIEvent::Severity::Error)); + + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::SWCANSettingsNotAvailable); + }); + + // Check that main thread has no errors + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound); + + // Wait for threads to finish + t1.join(); + t2.join(); + t3.join(); + + // Check that main thread has no errors + EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound); + + // Should be 500 {OutputTruncated, Warning}, 500 {OutputTruncated, Info}, 1000 {CANFDNotSupported, Warning}, 500 {CANFDSettingsNotAvailable, Info}, 500 {FailedToWrite, Info} + EXPECT_EQ(EventCount(), 3000); + + auto events = GetEvents(EventFilter(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning)); + EXPECT_EQ(EventCount(), 2500); + EXPECT_EQ(events.size(), 500); + + events = GetEvents(EventFilter(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventInfo)); + EXPECT_EQ(EventCount(), 2000); + EXPECT_EQ(events.size(), 500); + + events = GetEvents(EventFilter(APIEvent::Type::CANFDNotSupported, APIEvent::Severity::EventWarning)); + EXPECT_EQ(EventCount(), 1000); + EXPECT_EQ(events.size(), 1000); + + events = GetEvents(EventFilter(APIEvent::Type::CANFDSettingsNotAvailable, APIEvent::Severity::EventInfo)); + EXPECT_EQ(EventCount(), 500); + EXPECT_EQ(events.size(), 500); + + events = GetEvents(EventFilter(APIEvent::Type::FailedToWrite, APIEvent::Severity::EventInfo)); + EXPECT_EQ(EventCount(), 0); + EXPECT_EQ(events.size(), 500); +} + +/** + * Checks that errors do not go into the events list, and that TooManyEvents events are not added either. + * Checks that EventCount() updates accordingly, even when overflowing (trying to add 11000 events when the limit is 10000) + */ TEST_F(EventManagerTest, CountTest) { // Add an error event, should not go into events list. EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error)); @@ -46,7 +162,9 @@ TEST_F(EventManagerTest, CountTest) { EXPECT_EQ(EventCount(), 10000); } -// Test default get params +/** + * Checks that the default get() clears out and returns all events. + */ TEST_F(EventManagerTest, GetDefaultTest) { for(int i = 0; i < 5; i++) { EventManager::GetInstance().add(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::EventWarning); @@ -75,7 +193,9 @@ TEST_F(EventManagerTest, GetDefaultTest) { EXPECT_EQ(EventCount(), 0); } -// Test get with a size limit +/** + * Checks that get() with a size param only flushes and returns the desired amount, even when requesting too many. + */ TEST_F(EventManagerTest, GetSizeTest) { // Add 10 events @@ -128,8 +248,9 @@ TEST_F(EventManagerTest, GetSizeTest) { EXPECT_EQ(EventCount(), 0); } -// Test get with a filter (type, severity) -// Doesn't test with device! +/** + * Checks that get() with a filter param only flushes and returns the events matching the filter. + */ TEST_F(EventManagerTest, GetFilterTest) { // Add 20 events for(int i = 0; i < 5; i++) { @@ -189,8 +310,9 @@ TEST_F(EventManagerTest, GetFilterTest) { EXPECT_EQ(EventCount(), 0); } -// Test get with both size limit and filter -// Doesn't test with devices +/** + * Checks that get() with both a size and filter param only flushes and returns the desired amount of events matching the filter. + */ TEST_F(EventManagerTest, GetSizeFilterTest) { // Add 20 events for(int i = 0; i < 5; i++) { @@ -264,31 +386,9 @@ TEST_F(EventManagerTest, GetSizeFilterTest) { EXPECT_EQ(EventCount(), 0); } -// Multithreaded test of GetLastError() -TEST_F(EventManagerTest, GetLastErrorMultiThreaded) { - std::thread t1( []() { - EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error)); - EXPECT_EQ(GetLastError().getType(), APIEvent::Type::OutputTruncated); - auto err = GetLastError(); - EXPECT_EQ(err.getType(), APIEvent::Type::NoErrorFound); - EXPECT_EQ(err.getSeverity(), APIEvent::Severity::EventInfo); - }); - - std::thread t2( []() { - EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error)); - EventManager::GetInstance().add(APIEvent(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error)); - EventManager::GetInstance().add(APIEvent(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error)); - EXPECT_EQ(GetLastError().getType(), APIEvent::Type::SettingsNotAvailable); - auto err = GetLastError(); - EXPECT_EQ(err.getType(), APIEvent::Type::NoErrorFound); - EXPECT_EQ(err.getSeverity(), APIEvent::Severity::EventInfo); - }); - - t1.join(); - t2.join(); -} - -// Tests that adding 1 error and calling GetLastError() twice will first return the error then return a NoErrorFound info message. Singlethreaded. +/** + * Checks that adding 1 error and calling GetLastError() twice will first return the error then return a NoErrorFound info message. Singlethreaded. + */ TEST_F(EventManagerTest, GetLastErrorSingleTest) { EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error)); EXPECT_EQ(GetLastError().getType(), APIEvent::Type::OutputTruncated); @@ -297,7 +397,9 @@ TEST_F(EventManagerTest, GetLastErrorSingleTest) { EXPECT_EQ(err.getSeverity(), APIEvent::Severity::EventInfo); } -// Tests that adding multiple errors and calling GetLastError() twice will first return the last error then return a NoErrorFound info message. Singlethreaded. +/** + * Checks that adding multiple errors and calling GetLastError() twice will first return the last error then return a NoErrorFound info message. Singlethreaded. + */ TEST_F(EventManagerTest, GetLastErrorMultipleTest) { EventManager::GetInstance().add(APIEvent(APIEvent::Type::OutputTruncated, APIEvent::Severity::Error)); EventManager::GetInstance().add(APIEvent(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error)); @@ -308,7 +410,10 @@ TEST_F(EventManagerTest, GetLastErrorMultipleTest) { EXPECT_EQ(err.getSeverity(), APIEvent::Severity::EventInfo); } -// Tests the case where too many warnings are added +/** + * Adds 52 events when the limit is 50 (49 normal, 1 reserved) + * Checks that only the latest 49 are kept, and a TooManyEvents warning exists at the end. + */ TEST_F(EventManagerTest, TestAddWarningsOverflow) { // space for 49 normal events, 1 reserved for TooManyEvents @@ -339,7 +444,10 @@ TEST_F(EventManagerTest, TestAddWarningsOverflow) { EXPECT_EQ(events.at(49).getSeverity(), APIEvent::Severity::EventWarning); } -// Tests the case where too many warnings and info are added +/** + * Adds 1 warning, 3 info, and 47 warning events, in that order, when the limit is 50 (49 normal, 1 reserved) + * Checks that only the latest 49 are kept, and a TOoManyEvents warning exists at the end. + */ TEST_F(EventManagerTest, TestAddWarningsInfoOverflow) { // space for 49 normal events, 1 reserved for TooManyEvents @@ -370,7 +478,51 @@ TEST_F(EventManagerTest, TestAddWarningsInfoOverflow) { EXPECT_EQ(events.at(49).getType(), APIEvent::Type::TooManyEvents); } -// Tests that setting the event limit works in normal conditions, if the new limit is too small, and if the list needs truncating +/** + * Checks that discarding with no params flushes every event. + */ +TEST_F(EventManagerTest, DiscardDefault) { + for(int i = 0; i < 3000; i++) { + EventManager::GetInstance().add(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::EventInfo); + EventManager::GetInstance().add(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::EventWarning); + EventManager::GetInstance().add(APIEvent::Type::BufferInsufficient, APIEvent::Severity::EventWarning); + } + + EXPECT_EQ(EventCount(), 9000); + + DiscardEvents(); + + EXPECT_EQ(EventCount(), 0); +} + +/** + * Checks that discarding with a filter only flushes events matching the filter. + */ +TEST_F(EventManagerTest, DiscardFilter) { + for(int i = 0; i < 3000; i++) { + EventManager::GetInstance().add(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::EventInfo); + EventManager::GetInstance().add(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::EventWarning); + EventManager::GetInstance().add(APIEvent::Type::BufferInsufficient, APIEvent::Severity::EventWarning); + } + + EXPECT_EQ(EventCount(), 9000); + + DiscardEvents(EventFilter(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::EventInfo)); + + EXPECT_EQ(EventCount(), 6000); + + DiscardEvents(EventFilter(APIEvent::Type::BufferInsufficient, APIEvent::Severity::EventInfo)); + + EXPECT_EQ(EventCount(), 6000); + + DiscardEvents(EventFilter(APIEvent::Severity::EventWarning)); + + EXPECT_EQ(EventCount(), 0); +} + +/** + * Checks setting the event limit when truncating is not required, when the new limit is < 10, and when the new limit < num events. + */ TEST_F(EventManagerTest, SetEventLimitTest) { // Test if event limit too low to be set EventManager::GetInstance().setEventLimit(9); @@ -393,6 +545,7 @@ TEST_F(EventManagerTest, SetEventLimitTest) { EXPECT_EQ(GetEventLimit(), 9001); EXPECT_EQ(EventCount(), 9001); + // Truncate a lot SetEventLimit(5000); EXPECT_EQ(GetEventLimit(), 5000); EXPECT_EQ(EventCount(), 5000);