From c33741ba5e5d7dc11f4708a33582e73451808d19 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Wed, 1 May 2024 14:04:53 +0000 Subject: [PATCH 01/35] [Tests/unit/core] : Fix build 'test_message_unit.cpp' Includes a workaround for a unresponsive child process. --- Tests/unit/core/CMakeLists.txt | 6 +- Tests/unit/core/test_message_unit.cpp | 932 ++++++++++++++++++-------- 2 files changed, 639 insertions(+), 299 deletions(-) diff --git a/Tests/unit/core/CMakeLists.txt b/Tests/unit/core/CMakeLists.txt index cfc0082fe..6ef9e76c0 100644 --- a/Tests/unit/core/CMakeLists.txt +++ b/Tests/unit/core/CMakeLists.txt @@ -81,8 +81,8 @@ add_executable(${TEST_RUNNER_NAME} test_xgetopt.cpp #test_message_dispatcher.cpp ) - -#[[ if(MESSAGING) + +if(MESSAGING) target_sources(${TEST_RUNNER_NAME} PRIVATE test_message_unit.cpp) target_link_libraries(${TEST_RUNNER_NAME} WPEFrameworkMessaging @@ -92,7 +92,7 @@ else() target_link_libraries(${TEST_RUNNER_NAME} WPEFrameworkTracing ) -endif() ]] +endif() set_source_files_properties(test_systeminfo.cpp PROPERTIES COMPILE_OPTIONS "-fexceptions") diff --git a/Tests/unit/core/test_message_unit.cpp b/Tests/unit/core/test_message_unit.cpp index abdcf0d87..df5a0c7c1 100644 --- a/Tests/unit/core/test_message_unit.cpp +++ b/Tests/unit/core/test_message_unit.cpp @@ -26,7 +26,7 @@ using namespace WPEFramework; class Control : public Core::Messaging::IControl { public: - Control(const Core::Messaging::MetaData& metaData) + Control(const Core::Messaging::Metadata& metaData) : _metaData(metaData) { } @@ -46,72 +46,105 @@ class Control : public Core::Messaging::IControl { { _isEnabled = false; } - const Core::Messaging::MetaData& MessageMetaData() const override + const Core::Messaging::Metadata& Metadata() const override { return _metaData; } private: bool _isEnabled; - Core::Messaging::MetaData _metaData; + Core::Messaging::Metadata _metaData; }; class Core_Messaging_MessageUnit : public testing::Test { protected: Core_Messaging_MessageUnit() { - _controls.emplace_back(new Control({ Core::Messaging::MetaData::MessageType::TRACING, _T("Test_Category_1"), EXPAND_AND_QUOTE(MODULE_NAME) })); - _controls.emplace_back(new Control({ Core::Messaging::MetaData::MessageType::TRACING, _T("Test_Category_2"), EXPAND_AND_QUOTE(MODULE_NAME) })); - _controls.emplace_back(new Control({ Core::Messaging::MetaData::MessageType::TRACING, _T("Test_Category_3"), EXPAND_AND_QUOTE(MODULE_NAME) })); - _controls.emplace_back(new Control({ Core::Messaging::MetaData::MessageType::TRACING, _T("Test_Category_4"), EXPAND_AND_QUOTE(MODULE_NAME) })); - _controls.emplace_back(new Control({ Core::Messaging::MetaData::MessageType::TRACING, _T("Test_Category_1"), _T("Test_Module2") })); - _controls.emplace_back(new Control({ Core::Messaging::MetaData::MessageType::LOGGING, _T("Test_Category_5"), _T("SysLog") })); + _controls.emplace_back(new Control({ Core::Messaging::Metadata::type::TRACING, _T("Test_Category_1"), EXPAND_AND_QUOTE(MODULE_NAME) })); + _controls.emplace_back(new Control({ Core::Messaging::Metadata::type::TRACING, _T("Test_Category_2"), EXPAND_AND_QUOTE(MODULE_NAME) })); + _controls.emplace_back(new Control({ Core::Messaging::Metadata::type::TRACING, _T("Test_Category_3"), EXPAND_AND_QUOTE(MODULE_NAME) })); + _controls.emplace_back(new Control({ Core::Messaging::Metadata::type::TRACING, _T("Test_Category_4"), EXPAND_AND_QUOTE(MODULE_NAME) })); + _controls.emplace_back(new Control({ Core::Messaging::Metadata::type::TRACING, _T("Test_Category_1"), _T("Test_Module2") })); + _controls.emplace_back(new Control({ Core::Messaging::Metadata::type::LOGGING, _T("Test_Category_5"), _T("SysLog") })); + + _activeConfig = false; } ~Core_Messaging_MessageUnit() = default; static void SetUpTestSuite() { - Core::Messaging::MessageUnit::Instance().IsBackground(_background); - Core::Messaging::MessageUnit::Instance().Open(_basePath); } static void TearDownTestSuite() { - Core::Messaging::MessageUnit::Instance().Close(); Core::Singleton::Dispose(); } + void SetUp() override { - for (const auto& control : _controls) { - Core::Messaging::MessageUnit::Instance().Announce(control.get()); - } + AnnounceAllControls(); + + ToggleDefaultConfig(true); + + _activeConfig = true; } void TearDown() override { - Core::Messaging::MessageUnit::Instance().Defaults(_T("")); - for (const auto& control : _controls) { - Core::Messaging::MessageUnit::Instance().Revoke(control.get()); - } + RevokeAllControls(); + + ToggleDefaultConfig(false); + + _activeConfig = false; } string DispatcherIdentifier() { - string result; - Core::SystemInfo::GetEnvironment(Core::Messaging::MessageUnit::MESSAGE_DISPACTHER_IDENTIFIER_ENV, result); - return result; + return Messaging::MessageUnit::Instance().Identifier(); } string DispatcherBasePath() { string result; - Core::SystemInfo::GetEnvironment(Core::Messaging::MessageUnit::MESSAGE_DISPATCHER_PATH_ENV, result); - return result; + return Messaging::MessageUnit::Instance().BasePath(); + } + + void AnnounceAllControls() + { + for (const auto& control : _controls) { + // Only for 'controls' enabled in configuration + Core::Messaging::IControl::Announce(control.get()); + } + } + + void RevokeAllControls() + { + for (const auto& control : _controls) { + Core::Messaging::IControl::Revoke(control.get()); + } + } + + void ToggleDefaultConfig(bool activate) + { + ASSERT(_activeConfig != activate); + + if (!_activeConfig && activate) { + Messaging::MessageUnit::Settings::Config configuration; + Messaging::MessageUnit::Instance().Open(Core_Messaging_MessageUnit::_basePath, configuration, Core_Messaging_MessageUnit::_background, Messaging::MessageUnit::OFF); + } + + if (_activeConfig && !activate) { + Messaging::MessageUnit::Instance().Close(); + } + + _activeConfig = !_activeConfig; } static bool _background; static string _basePath; std::list> _controls; + + bool _activeConfig; }; bool Core_Messaging_MessageUnit::_background = false; @@ -119,455 +152,762 @@ string Core_Messaging_MessageUnit::_basePath = _T("/tmp/"); TEST_F(Core_Messaging_MessageUnit, TraceMessageIsEnabledByDefaultWhenConfigFullySpecified) { - const string config = R"({"tracing":{"messages":[{"category":"Information","module":"Plugin_DeviceInfo","enabled":true}]}})"; + Messaging::MessageUnit::Settings::Config configuration; + configuration.FromString(R"({"tracing":{"settings":[{"category":"Information","module":"Plugin_DeviceInfo","enabled":true}]}})"); - Core::Messaging::MessageUnit::Instance().Defaults(config); - ASSERT_TRUE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ Core::Messaging::MetaData::MessageType::TRACING, _T("Information"), _T("Plugin_DeviceInfo") })); - ASSERT_FALSE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ Core::Messaging::MetaData::MessageType::TRACING, _T("Information"), _T("Some_Module") })); - ASSERT_FALSE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ Core::Messaging::MetaData::MessageType::TRACING, _T("SomeCategory"), _T("Plugin_DeviceInfo") })); + Messaging::MessageUnit::Settings settings; + settings.Configure(Core_Messaging_MessageUnit::_basePath, "SomeIdentifier", configuration, Core_Messaging_MessageUnit::_background, Messaging::MessageUnit::OFF); + + Core::Messaging::Metadata metaData(Core::Messaging::Metadata::type::TRACING, _T("Information"), _T("Plugin_DeviceInfo")); + EXPECT_TRUE(settings.IsEnabled(metaData)); + + metaData = Core::Messaging::Metadata(Core::Messaging::Metadata::type::TRACING, _T("Information"), _T("Some_Module")); + EXPECT_FALSE(settings.IsEnabled(metaData)); + + metaData = Core::Messaging::Metadata(Core::Messaging::Metadata::type::TRACING, _T("SomeCategory"), _T("Plugin_DeviceInfo")); + EXPECT_FALSE(settings.IsEnabled(metaData)); } TEST_F(Core_Messaging_MessageUnit, TraceMessageIsDisabledByDefaultWhenConfigFullySpecified) { - const string config = R"({"tracing":{"messages":[{"category":"Information","module":"Plugin_DeviceInfo","enabled":false}]}})"; + Messaging::MessageUnit::Settings::Config configuration; + configuration.FromString(R"({"tracing":{"settings":[{"category":"Information","module":"Plugin_DeviceInfo","enabled":false}]}})"); + + Messaging::MessageUnit::Settings settings; + settings.Configure(Core_Messaging_MessageUnit::_basePath, "SomeIdentifier", configuration, Core_Messaging_MessageUnit::_background, Messaging::MessageUnit::OFF); - Core::Messaging::MessageUnit::Instance().Defaults(config); - ASSERT_FALSE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ Core::Messaging::MetaData::MessageType::TRACING, _T("Information"), _T("Plugin_DeviceInfo") })); - ASSERT_FALSE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ Core::Messaging::MetaData::MessageType::TRACING, _T("Information"), _T("Some_Module") })); - ASSERT_FALSE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ Core::Messaging::MetaData::MessageType::TRACING, _T("SomeCategory"), _T("Plugin_DeviceInfo") })); + Core::Messaging::Metadata metaData(Core::Messaging::Metadata::type::TRACING, _T("Information"), _T("Plugin_DeviceInfo")); + EXPECT_FALSE(settings.IsEnabled(metaData)); + + metaData = Core::Messaging::Metadata(Core::Messaging::Metadata::type::TRACING, _T("Information"), _T("Some_Module")); + EXPECT_FALSE(settings.IsEnabled(metaData)); + + metaData = Core::Messaging::Metadata(Core::Messaging::Metadata::type::TRACING, _T("SomeCategory"), _T("Plugin_DeviceInfo")); + EXPECT_FALSE(settings.IsEnabled(metaData)); } TEST_F(Core_Messaging_MessageUnit, TraceMessagesAreEnabledWhenModuleNotSpecified) { - const string config = R"({"tracing":{"messages":[{"category":"Information","enabled":true}]}})"; + Messaging::MessageUnit::Settings::Config configuration; + configuration.FromString(R"({"tracing":{"settings":[{"category":"Information","enabled":true}]}})"); + + Messaging::MessageUnit::Settings settings; + settings.Configure(Core_Messaging_MessageUnit::_basePath, "SomeIdentifier", configuration, Core_Messaging_MessageUnit::_background, Messaging::MessageUnit::OFF); + + Core::Messaging::Metadata metaData(Core::Messaging::Metadata::type::TRACING, _T("Information"), _T("Plugin_DeviceInfo")); + EXPECT_TRUE(settings.IsEnabled(metaData)); - Core::Messaging::MessageUnit::Instance().Defaults(config); - ASSERT_TRUE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ Core::Messaging::MetaData::MessageType::TRACING, _T("Information"), _T("Plugin_DeviceInfo") })); - ASSERT_TRUE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ Core::Messaging::MetaData::MessageType::TRACING, _T("Information"), _T("Some_Module") })); - ASSERT_FALSE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ Core::Messaging::MetaData::MessageType::TRACING, _T("SomeCategory"), _T("Plugin_DeviceInfo") })); + metaData = Core::Messaging::Metadata(Core::Messaging::Metadata::type::TRACING, _T("Information"), _T("Some_Module")); + EXPECT_TRUE(settings.IsEnabled(metaData)); + + metaData = Core::Messaging::Metadata(Core::Messaging::Metadata::type::TRACING, _T("SomeCategory"), _T("Plugin_DeviceInfo")); + EXPECT_FALSE(settings.IsEnabled(metaData)); } TEST_F(Core_Messaging_MessageUnit, TraceMessagesAreDisabledWhenModuleNotSpecified) { - const string config = R"({"tracing":{"messages":[{"category":"Information","enabled":false}]}})"; + Messaging::MessageUnit::Settings::Config configuration; + configuration.FromString(R"({"tracing":{"messages":[{"category":"Information","enabled":false}]}})"); + + Messaging::MessageUnit::Settings settings; + settings.Configure(Core_Messaging_MessageUnit::_basePath, "SomeIdentifier", configuration, Core_Messaging_MessageUnit::_background, Messaging::MessageUnit::OFF); + + Core::Messaging::Metadata metaData(Core::Messaging::Metadata::type::TRACING, _T("Information"), _T("Plugin_DeviceInfo")); + EXPECT_FALSE(settings.IsEnabled(metaData)); + + metaData = Core::Messaging::Metadata(Core::Messaging::Metadata::type::TRACING, _T("Information"), _T("Some_Module")); + EXPECT_FALSE(settings.IsEnabled(metaData)); - Core::Messaging::MessageUnit::Instance().Defaults(config); - ASSERT_FALSE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ Core::Messaging::MetaData::MessageType::TRACING, _T("Information"), _T("Plugin_DeviceInfo") })); - ASSERT_FALSE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ Core::Messaging::MetaData::MessageType::TRACING, _T("Information"), _T("Some_Module") })); - ASSERT_FALSE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ Core::Messaging::MetaData::MessageType::TRACING, _T("SomeCategory"), _T("Plugin_DeviceInfo") })); + metaData = Core::Messaging::Metadata(Core::Messaging::Metadata::type::TRACING, _T("SomeCategory"), _T("Plugin_DeviceInfo")); + EXPECT_FALSE(settings.IsEnabled(metaData)); } TEST_F(Core_Messaging_MessageUnit, LoggingMessageIsEnabledIfNotConfigured) { - //logging messages are enabled by default (if not specified otherwise in the config) - const string config = R"({"logging":{"messages":[{"category":"Startup","module":"SysLog","enabled":false}]}})"; - Core::Messaging::MessageUnit::Instance().Defaults(config); - ASSERT_FALSE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ Core::Messaging::MetaData::MessageType::LOGGING, _T("Startup"), _T("SysLog") })); - ASSERT_TRUE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ Core::Messaging::MetaData::MessageType::LOGGING, _T("Notification"), _T("SysLog") })); + Messaging::MessageUnit::Settings::Config configuration; + configuration.FromString(R"({"logging":{"settings":[{"category":"Startup","module":"SysLog","enabled":false}]}})"); + + Messaging::MessageUnit::Settings settings; + settings.Configure(Core_Messaging_MessageUnit::_basePath, "SomeIdentifier", configuration, Core_Messaging_MessageUnit::_background, Messaging::MessageUnit::OFF); + + Core::Messaging::Metadata metaData(Core::Messaging::Metadata::type::LOGGING, _T("Startup"), _T("SysLog")); + // Internal Metadata::Default() is true for LOGGING but here overwritten because of element of config + EXPECT_FALSE(settings.IsEnabled(metaData)); + + metaData = Core::Messaging::Metadata(Core::Messaging::Metadata::type::LOGGING, _T("Notification"), _T("SysLog")); + // Internal Metadata::Default() is true for LOGGING and not overwritten because of no element of config + EXPECT_TRUE(settings.IsEnabled(metaData)); } TEST_F(Core_Messaging_MessageUnit, MessageClientWillReturnListOfControls) { //this test is using metadata (IPC) passing, so no other proces tests for now - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); - client.AddInstance(0); //we are in framework - auto it = client.Enabled(); + Messaging::MessageClient client(Messaging::MessageUnit::Instance().Identifier(), Messaging::MessageUnit::Instance().BasePath()); + + client.AddInstance(0 /*id*/); //we are in framework + + Messaging::MessageUnit::Iterator it; + + client.Controls(it); int matches = 0; int count = 0; while (it.Next()) { - auto info = it.Current(); - if (info.first.Module() == EXPAND_AND_QUOTE(MODULE_NAME)) { + if (it.Module() == EXPAND_AND_QUOTE(MODULE_NAME)) { ++matches; } ++count; } - ASSERT_GE(count, 4); - ASSERT_EQ(matches, 4); + client.RemoveInstance(0); + + EXPECT_GE(count, 4); + EXPECT_EQ(matches, 4); } TEST_F(Core_Messaging_MessageUnit, EnablingMessagesShouldUpdateExistingDefaultConfig) { - const string config = R"({"tracing":{"messages":[{"category":"ExampleCategory","module":"ExampleModule","enabled":false}]}})"; - Core::Messaging::MessageUnit::Instance().Defaults(config); - const Core::Messaging::MetaData toBeUpdated(Core::Messaging::MetaData::MessageType::TRACING, _T("ExampleCategory"), _T("ExampleModule")); - ASSERT_FALSE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault(toBeUpdated)); + // Reload with new configuration + ToggleDefaultConfig(false); + + Messaging::MessageUnit::Settings::Config configuration; + + // If 'enabled' equals false the entry is not added to 'Settings' + configuration.FromString(R"({"tracing":{"settings":[{"category":"ExampleCategory","module":"ExampleModule","enabled":false}]}})"); + + // Populate settings with specified configuration + Messaging::MessageUnit::Instance().Open(Core_Messaging_MessageUnit::_basePath, configuration, Core_Messaging_MessageUnit::_background, Messaging::MessageUnit::OFF); - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); + const Core::Messaging::Metadata toBeUpdated(Core::Messaging::Metadata::type::TRACING, _T("ExampleCategory"), _T("ExampleModule")); + + Control control(toBeUpdated); + // Add to the internal list if it is not already + Core::Messaging::IControl::Announce(&control); + + Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + + // Creates a MessageUnit::Client internally with the id passed in client.AddInstance(0); //we are in framework + + // Get the system 'status' + Messaging::MessageUnit::Iterator it; + client.Controls(it); + + bool enabled = false; + + while (it.Next()) { + enabled = enabled + || + ( toBeUpdated.Type() == it.Type() + && toBeUpdated.Category() == it.Category() + && toBeUpdated.Module() == it.Module() + && it.Enabled() + ) + ; + } + + EXPECT_FALSE(enabled); + + // Enable message via metadata, eg, set enable for the previously added Control, eg, enable category client.Enable(toBeUpdated, true); - ASSERT_TRUE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault(toBeUpdated)); + client.Controls(it); + + /* bool */ enabled = false; + + while (it.Next()) { + enabled = enabled + || + ( toBeUpdated.Type() == it.Type() + && toBeUpdated.Category() == it.Category() + && toBeUpdated.Module() == it.Module() + && it.Enabled() + ) + ; + } + + EXPECT_TRUE(enabled); + + client.RemoveInstance(0); + + Core::Messaging::IControl::Revoke(&control); + + Messaging::MessageUnit::Instance().Close(); + + ToggleDefaultConfig(true); } TEST_F(Core_Messaging_MessageUnit, EnablingMessagesShouldAddToDefaultConfigListIfNotPresent) { - const Core::Messaging::MetaData toBeAdded(Core::Messaging::MetaData::MessageType::TRACING, _T("ExampleCategory"), _T("ExampleModule")); + const Core::Messaging::Metadata toBeAdded(Core::Messaging::Metadata::type::TRACING, _T("ExampleCategory"), _T("ExampleModule")); - ASSERT_FALSE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault(toBeAdded)); + Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); client.AddInstance(0); //we are in framework - client.Enable(toBeAdded, true); - ASSERT_TRUE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault(toBeAdded)); - auto defaultsString = Core::Messaging::MessageUnit::Instance().Defaults(); - Core::Messaging::Settings settings; - settings.FromString(defaultsString); + Messaging::MessageUnit::Iterator it; + client.Controls(it); + + bool enabled = false; + + while (it.Next()) { + enabled = enabled + || + ( toBeAdded.Type() == it.Type() + && toBeAdded.Category() == it.Category() + && toBeAdded.Module() == it.Module() + && it.Enabled() + ) + ; + } + + EXPECT_FALSE(enabled); + + Control control(toBeAdded); + + Core::Messaging::IControl::Announce(&control); - ASSERT_EQ(settings.Tracing.Entries.Length(), 1); - auto entriesIt = settings.Tracing.Entries.Elements(); - while (entriesIt.Next()) { - ASSERT_STREQ(entriesIt.Current().Category.Value().c_str(), toBeAdded.Category().c_str()); - ASSERT_STREQ(entriesIt.Current().Module.Value().c_str(), toBeAdded.Module().c_str()); + client.Controls(it); + + enabled = false; + + while (it.Next()) { + enabled = enabled + || + ( toBeAdded.Type() == it.Type() + && toBeAdded.Category() == it.Category() + && toBeAdded.Module() == it.Module() + ) + ; } + + EXPECT_TRUE(enabled); + + client.RemoveInstance(0); + + Core::Messaging::IControl::Revoke(&control); } TEST_F(Core_Messaging_MessageUnit, EnablingMessagesByTypeShouldEnableEverything) { - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); + Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + client.AddInstance(0); //we are in framework - auto itBeforeUpdate = client.Enabled(); - int matches = 0; - while (itBeforeUpdate.Next()) { - auto info = itBeforeUpdate.Current(); - if (info.first.Type() == Core::Messaging::MetaData::MessageType::TRACING && info.second == true) { - ++matches; - } + Messaging::MessageUnit::Iterator it; + client.Controls(it); + + bool enabled = true; + + while (it.Next()) { + enabled = enabled + && it.Enabled() + ; } - ASSERT_EQ(matches, 0); - matches = 0; - client.Enable({ Core::Messaging::MetaData::MessageType::TRACING, _T(""), _T("") }, true); - auto itAfterUpdate = client.Enabled(); - while (itAfterUpdate.Next()) { - auto info = itAfterUpdate.Current(); - if (info.first.Type() == Core::Messaging::MetaData::MessageType::TRACING && info.second == true) { - ++matches; - } + // Controls from the default are disabled by default, except a few + EXPECT_FALSE(enabled); + + // Enable message via metadata, eg, set enable for the previously added Control, eg, enable category + client.Enable({Core::Messaging::Metadata::type::TRACING, _T(""), _T("")}, true); + + client.Controls(it); + + enabled = true; + + while (it.Next()) { + enabled = enabled + && it.Enabled() + ; } - ASSERT_GE(matches, 5); + + EXPECT_TRUE(enabled); + + client.RemoveInstance(0); } TEST_F(Core_Messaging_MessageUnit, LogMessagesCanToggledWhenLogModuleSpecified) { - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); + Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + client.AddInstance(0); //we are in framework - auto itBeforeUpdate = client.Enabled(); - Core::Messaging::MetaData messageToToggle(Core::Messaging::MetaData::MessageType::LOGGING, _T("Test_Category_5"), _T("SysLog")); + + Core::Messaging::Metadata messageToToggle(Core::Messaging::Metadata::type::LOGGING, _T("Test_Category_5"), _T("SysLog")); + + Messaging::MessageUnit::Iterator it; + client.Controls(it); int matches = 0; - while (itBeforeUpdate.Next()) { - auto info = itBeforeUpdate.Current(); - if (info.first == messageToToggle && info.second == true) { + while (it.Next()) { + if ( it.Type() == messageToToggle.Type() + && it.Category() == messageToToggle.Category() + && it.Module() == messageToToggle.Module() + && it.Enabled() + ) { ++matches; } } - ASSERT_EQ(matches, 1); - matches = 0; + EXPECT_EQ(matches, 1); + client.Enable(messageToToggle, false); - auto itAfterUpdate = client.Enabled(); - while (itAfterUpdate.Next()) { - auto info = itAfterUpdate.Current(); - if (info.first == messageToToggle && info.second == false) { + + client.Controls(it); + + matches = 0; + + while (it.Next()) { + if ( it.Type() == messageToToggle.Type() + && it.Category() == messageToToggle.Category() + && it.Module() == messageToToggle.Module() + && !it.Enabled() + ) { ++matches; } } - ASSERT_EQ(matches, 1); + + EXPECT_EQ(matches, 1); + + client.RemoveInstance(0); } TEST_F(Core_Messaging_MessageUnit, LogEnablingMessagesShouldAddToDefaultConfigListIfNotPresent) { - const Core::Messaging::MetaData tobeAdded(Core::Messaging::MetaData::MessageType::LOGGING, _T("Test_Category_5"), _T("SysLog")); - ASSERT_TRUE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault(tobeAdded)); + const Core::Messaging::Metadata toBeAdded(Core::Messaging::Metadata::type::LOGGING, _T("Test_Category_5"), _T("SysLog")); + + Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); client.AddInstance(0); //we are in framework - client.Enable(tobeAdded, false); - ASSERT_FALSE(Core::Messaging::MessageUnit::Instance().IsEnabledByDefault(tobeAdded)); - auto defaultsString = Core::Messaging::MessageUnit::Instance().Defaults(); - Core::Messaging::Settings settings; - settings.FromString(defaultsString); + // LOGGING is enabled and available by default + + Messaging::MessageUnit::Iterator it; - ASSERT_EQ(settings.Logging.Entries.Length(), 1); - auto entriesIt = settings.Logging.Entries.Elements(); - while (entriesIt.Next()) { - ASSERT_STREQ(entriesIt.Current().Category.Value().c_str(), tobeAdded.Category().c_str()); - ASSERT_STREQ(entriesIt.Current().Module.Value().c_str(), tobeAdded.Module().c_str()); + client.Controls(it); + + bool enabled = false; + + while (it.Next()) { + enabled = enabled + || + ( toBeAdded.Type() == it.Type() + && toBeAdded.Category() == it.Category() + && toBeAdded.Module() == it.Module() + && it.Enabled() + ) + ; } + + EXPECT_TRUE(enabled); + + client.RemoveInstance(0); } TEST_F(Core_Messaging_MessageUnit, EnablingFullySpecifiedMessageUpdateOnlyThisOne) { - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); + Core::Messaging::Metadata message(Core::Messaging::Metadata::type::TRACING, _T("Test_Category_1"), EXPAND_AND_QUOTE(MODULE_NAME)); + + Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + client.AddInstance(0); //we are in framework - auto itBeforeUpdate = client.Enabled(); - Core::Messaging::MetaData message(Core::Messaging::MetaData::MessageType::TRACING, _T("Test_Category_1"), EXPAND_AND_QUOTE(MODULE_NAME)); - int matches = 0; - while (itBeforeUpdate.Next()) { - auto info = itBeforeUpdate.Current(); - if (info.first == message && info.second == false) { - ++matches; - } + // TRACING is not enabled but available by default + + Messaging::MessageUnit::Iterator it; + + client.Controls(it); + + bool enabled = false; + + while (it.Next()) { + enabled = enabled + || + ( message.Type() == it.Type() + && message.Category() == it.Category() + && message.Module() == it.Module() + && it.Enabled() + ) + ; } - ASSERT_EQ(matches, 1); - matches = 0; + EXPECT_FALSE(enabled); + client.Enable(message, true); - auto itAfterUpdate = client.Enabled(); - while (itAfterUpdate.Next()) { - auto info = itAfterUpdate.Current(); - if (info.first == message && info.second == true) { - ++matches; - } + + client.Enable(message, true); + + client.Controls(it); + + enabled = false; + + while (it.Next()) { + enabled = enabled + || + ( message.Type() == it.Type() + && message.Category() == it.Category() + && message.Module() == it.Module() + && it.Enabled() + ) + ; } - ASSERT_EQ(matches, 1); + + EXPECT_TRUE(enabled); + + client.RemoveInstance(0); } TEST_F(Core_Messaging_MessageUnit, EnablingMessageSpecifiedByModuleShouldEnableAllCategoriesInsideIt) { - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); + const Core::Messaging::Metadata message(Core::Messaging::Metadata::type::TRACING, _T(""), EXPAND_AND_QUOTE(MODULE_NAME)); + + Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + client.AddInstance(0); //we are in framework - auto itBeforeUpdate = client.Enabled(); - - int enabled = 0; - while (itBeforeUpdate.Next()) { - auto info = itBeforeUpdate.Current(); - if (info.first.Type() == Core::Messaging::MetaData::MessageType::TRACING && info.first.Module() == EXPAND_AND_QUOTE(MODULE_NAME)) { - if (info.second == true) { - ++enabled; - } + + Messaging::MessageUnit::Iterator it; + client.Controls(it); + + bool enabled = true; + + while (it.Next()) { + if ( message.Type() == it.Type() + && message.Module() == it.Module() + ) { + enabled = enabled + && it.Enabled() + ; } } - ASSERT_EQ(enabled, 0); - enabled = 0; - client.Enable({ Core::Messaging::MetaData::MessageType::TRACING, _T(""), EXPAND_AND_QUOTE(MODULE_NAME) }, true); - auto itAfterUpdate = client.Enabled(); - while (itAfterUpdate.Next()) { - auto info = itAfterUpdate.Current(); - if (info.first.Type() == Core::Messaging::MetaData::MessageType::TRACING && info.first.Module() == EXPAND_AND_QUOTE(MODULE_NAME)) { - if (info.second == true) { - ++enabled; - } + EXPECT_FALSE(enabled); + + client.Enable(message, true); + + client.Controls(it); + + enabled = true; + + while (it.Next()) { + if ( message.Type() == it.Type() + && message.Module() == it.Module() + ) { + enabled = enabled + && it.Enabled() + ; } } - ASSERT_EQ(enabled, 4); + EXPECT_TRUE(enabled); + + client.RemoveInstance(0); } TEST_F(Core_Messaging_MessageUnit, EnablingMessageSpecifiedByCategoryShouldEnableItInAllModules) { - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); + const Core::Messaging::Metadata message(Core::Messaging::Metadata::type::TRACING, _T("Test_Category_1"), _T("")); + + Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + client.AddInstance(0); //we are in framework - auto itBeforeUpdate = client.Enabled(); - - int enabled = 0; - while (itBeforeUpdate.Next()) { - auto info = itBeforeUpdate.Current(); - if (info.first.Type() == Core::Messaging::MetaData::MessageType::TRACING && info.first.Category() == _T("Test_Category_1")) { - if (info.second == true) { - ++enabled; - } + + Messaging::MessageUnit::Iterator it; + client.Controls(it); + + bool enabled = true; + + while (it.Next()) { + if ( message.Type() == it.Type() + && message.Category() == it.Category() + ) { + enabled = enabled + && it.Enabled() + ; } } - ASSERT_EQ(enabled, 0); - enabled = 0; - client.Enable({ Core::Messaging::MetaData::MessageType::TRACING, _T("Test_Category_1"), _T("") }, true); - auto itAfterUpdate = client.Enabled(); - while (itAfterUpdate.Next()) { - auto info = itAfterUpdate.Current(); - if (info.first.Type() == Core::Messaging::MetaData::MessageType::TRACING && info.first.Category() == _T("Test_Category_1")) { - if (info.second == true) { - ++enabled; - } + EXPECT_FALSE(enabled); + + client.Enable(message, true); + + client.Controls(it); + + enabled = true; + + while (it.Next()) { + if ( message.Type() == it.Type() + && message.Category() == it.Category() + ) { + enabled = enabled + && it.Enabled() + ; } } - ASSERT_EQ(enabled, 2); + EXPECT_TRUE(enabled); + + client.RemoveInstance(0); } TEST_F(Core_Messaging_MessageUnit, TextMessageEventIsProperlySerializedIfBufferBigEnough) { - uint8_t buffer[1 * 1024]; + constexpr string::size_type bufferSize = 1024; + + uint8_t buffer[bufferSize]; const string testTextMessage = _T("TEST MESSAGE"); + EXPECT_GT(bufferSize, sizeof(testTextMessage.size())); + Messaging::TextMessage tm(testTextMessage); auto serialized = tm.Serialize(buffer, sizeof(buffer)); - ASSERT_GT(serialized, 0); + EXPECT_GT(serialized, 0); auto deserialized = tm.Deserialize(buffer, sizeof(buffer)); - ASSERT_EQ(serialized, deserialized); + EXPECT_EQ(serialized, deserialized); - string result; - tm.ToString(result); - ASSERT_STREQ(result.c_str(), testTextMessage.c_str()); + string result = tm.Data(); + EXPECT_STREQ(result.c_str(), testTextMessage.c_str()); } TEST_F(Core_Messaging_MessageUnit, TextMessageEventIsProperlySerializedAndCutIfBufferNotBigEnough) { - uint8_t buffer[5]; + constexpr string::size_type bufferSize = 5; + + uint8_t buffer[bufferSize]; const string testTextMessage = _T("abcdefghi"); + EXPECT_LT(bufferSize, sizeof(testTextMessage.size())); + Messaging::TextMessage tm(testTextMessage); auto serialized = tm.Serialize(buffer, sizeof(buffer)); - ASSERT_GT(serialized, 0); + EXPECT_GT(serialized, 0); auto deserialized = tm.Deserialize(buffer, serialized); - ASSERT_EQ(serialized, deserialized); + EXPECT_EQ(serialized, deserialized); + + string result = tm.Data(); - string result; - tm.ToString(result); - //last byte reserved for null termination - ASSERT_STREQ(result.c_str(), _T("abcd")); + EXPECT_STREQ(result.c_str(), testTextMessage.substr(0, bufferSize - 1).c_str()); } TEST_F(Core_Messaging_MessageUnit, ControlListIsProperlySerializedIfBufferBigEnough) { - uint8_t buffer[1 * 1024]; + constexpr string::size_type bufferSize = 1024; - Core::Messaging::ControlList cl; - for (const auto& control : _controls) { - cl.Announce(control.get()); - } + uint8_t buffer[bufferSize]; - auto serialized = cl.Serialize(buffer, sizeof(buffer)); - ASSERT_GT(serialized, 0); - ASSERT_EQ(buffer[0], _controls.size()); + Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); - auto deserialized = cl.Deserialize(buffer, serialized); - ASSERT_EQ(serialized, deserialized); + client.AddInstance(0); //we are in framework + + Messaging::MessageUnit::Iterator it; + client.Controls(it); + + while (it.Next()) { + Messaging::MessageUnit::Control control({it.Type(), it.Category(), it.Module()}, it.Enabled()); + auto serialized = control.Serialize(buffer, sizeof(buffer)); - auto informationIt = cl.Information(); - auto controlsIt = _controls.cbegin(); - while (informationIt.Next()) { - ASSERT_EQ(informationIt.Current().first, controlsIt->get()->MessageMetaData()); - ++controlsIt; + EXPECT_GT(serialized, 0); + + auto deserialized = control.Deserialize(buffer, serialized); + + EXPECT_EQ(serialized, deserialized); } + + client.RemoveInstance(0); } TEST_F(Core_Messaging_MessageUnit, ControlListIsProperlySerializedIfBufferNotBigEnough) { - const int controlsThatShouldFit = 2; - uint16_t maxBufferSize = 0; - auto it = _controls.cbegin(); - for (int i = 0; i < controlsThatShouldFit; ++i, ++it) { - maxBufferSize += sizeof(it->get()->MessageMetaData().Type()); - maxBufferSize += it->get()->MessageMetaData().Category().size() + 1; - maxBufferSize += it->get()->MessageMetaData().Module().size() + 1; - maxBufferSize += sizeof(bool); - } + Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + + client.AddInstance(0); //we are in framework + + Messaging::MessageUnit::Iterator it; + client.Controls(it); std::vector buffer; - buffer.resize(maxBufferSize + 1); - Core::Messaging::ControlList cl; - for (const auto& control : _controls) { - cl.Announce(control.get()); + while (it.Next()) { + buffer.resize(buffer.size() + sizeof(it.Type()), Core::Messaging::Metadata::type::INVALID); + buffer.resize(buffer.size() + it.Category().size() + 1, Core::Messaging::Metadata::type::INVALID); + buffer.resize(buffer.size() + it.Module().size() + 1, Core::Messaging::Metadata::type::INVALID); + buffer.resize(buffer.size() + sizeof(bool), Core::Messaging::Metadata::type::INVALID); } - auto serialized = cl.Serialize(buffer.data(), buffer.size()); - ASSERT_GT(serialized, 0); - ASSERT_EQ(buffer[0], controlsThatShouldFit); + buffer.resize(buffer.size() + 1); + + uint16_t index = 0; + + client.Controls(it); + + while (it.Next()) { + Messaging::MessageUnit::Control control({it.Type(), it.Category(), it.Module()}, it.Enabled()); + auto serialized = control.Serialize(&(buffer.data()[index]), buffer.size()); + + EXPECT_GT(serialized, 0); + + EXPECT_GT(buffer.size(), serialized); + + auto deserialized = control.Deserialize(&buffer.data()[index], serialized); - auto deserialized = cl.Deserialize(buffer.data(), serialized); - ASSERT_EQ(serialized, deserialized); + index += serialized; - auto informationIt = cl.Information(); - auto controlsIt = _controls.cbegin(); - while (informationIt.Next()) { - ASSERT_EQ(informationIt.Current().first, controlsIt->get()->MessageMetaData()); - ++controlsIt; + EXPECT_EQ(serialized, deserialized); } + + EXPECT_LT(index, buffer.size()); + + client.RemoveInstance(0); } TEST_F(Core_Messaging_MessageUnit, PopMessageShouldReturnLastPushedMessage) { - const string traceMessage = _T("some trace"); - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); + Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + client.AddInstance(0); //we are in framework //factory should be added before attempting to pop data - Messaging::TraceFactory factory; - client.AddFactory(Core::Messaging::MetaData::MessageType::TRACING, &factory); + Messaging::TraceFactoryType factory; + client.AddFactory(Core::Messaging::Metadata::type::TRACING, &factory); + Core::Messaging::Metadata metadata(Core::Messaging::Metadata::type::TRACING, _T("some_category"), EXPAND_AND_QUOTE(MODULE_NAME)); + + client.Enable(metadata, true); + + const string traceMessage = _T("some trace"); Messaging::TextMessage tm(traceMessage); - Core::Messaging::Information info(Core::Messaging::MetaData::MessageType::TRACING, - _T("some_category"), - EXPAND_AND_QUOTE(MODULE_NAME), - _T("some_file.cpp"), - 1337, - Core::Time::Now().Ticks()); - - Core::Messaging::MessageUnit::Instance().Push(info, &tm); - - auto messages = client.PopMessagesAsList(); - ASSERT_EQ(messages.size(), 1); - auto message = messages.front(); - - ASSERT_NE(message.first.MessageMetaData().Type(), Core::Messaging::MetaData::MessageType::INVALID); - ASSERT_EQ(message.first.MessageMetaData(), info.MessageMetaData()); - - string result; - message.second->ToString(result); - ASSERT_STREQ(message.first.FileName().c_str(), info.FileName().c_str()); - ASSERT_EQ(message.first.LineNumber(), info.LineNumber()); - ASSERT_EQ(message.first.TimeStamp(), info.TimeStamp()); - ASSERT_STREQ(traceMessage.c_str(), result.c_str()); + + Core::Messaging::IStore::Tracing info(Core::Messaging::MessageInfo(metadata, Core::Time::Now().Ticks()), _T("some_file"), 1337, EXPAND_AND_QUOTE(MODULE_NAME)); + + Messaging::MessageUnit::Instance().Push(info, &tm); + + // Risk of blocking or unknown suitable 'waittime' + //client.WaitForUpdates(Core::infinite); + // Instead 'flush' and continue + client.SkipWaiting(); + + bool present = false; + + client.PopMessagesAndCall( + [&](const Core::ProxyType& metadata, const Core::ProxyType& message) { + //(*metadata).TimeStamp(); + //(*metadata).Module(); + //(*metadata).Category(); + + if ((*metadata).Type() == Core::Messaging::Metadata::type::TRACING) { + TRACE_L1( + _T("PopMessagesAndCall : Tracing message -> Filename : %s, Linenumber : %d, Classname : %s") + , static_cast(*metadata).FileName().c_str() + , static_cast(*metadata).LineNumber() + , static_cast(*metadata).ClassName().c_str() + ); + + present = present || (*message).Data() == traceMessage; + } else { + TRACE_L1(_T("PopMessagesAndCall : Unknown message")); + } + + // By defining a callback data could be further processed + } + ); + + EXPECT_TRUE(present); + + client.RemoveInstance(0); } TEST_F(Core_Messaging_MessageUnit, PopMessageShouldReturnLastPushedMessageInOtherProcess) { const string traceMessage = _T("some trace"); - Messaging::TextMessage tm(traceMessage); - Core::Messaging::Information info(Core::Messaging::MetaData::MessageType::TRACING, - _T("some_category"), - EXPAND_AND_QUOTE(MODULE_NAME), - _T("some_file.cpp"), - 1337, - Core::Time::Now().Ticks()); - - auto lambdaFunc = [&](IPTestAdministrator& testAdmin) { - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); - client.AddInstance(0); - Messaging::TraceFactory factory; - client.AddFactory(Core::Messaging::MetaData::MessageType::TRACING, &factory); - testAdmin.Sync("setup"); - testAdmin.Sync("writer wrote"); - auto messages = client.PopMessagesAsList(); - - ASSERT_EQ(messages.size(), 1); - auto message = messages.front(); - - ASSERT_NE(message.first.MessageMetaData().Type(), Core::Messaging::MetaData::MessageType::INVALID); - ASSERT_EQ(message.first.MessageMetaData(), info.MessageMetaData()); - string result; - message.second->ToString(result); - ASSERT_STREQ(message.first.FileName().c_str(), info.FileName().c_str()); - ASSERT_EQ(message.first.LineNumber(), info.LineNumber()); - ASSERT_EQ(message.first.TimeStamp(), info.TimeStamp()); - ASSERT_STREQ(traceMessage.c_str(), result.c_str()); + Core::Messaging::Metadata metadata(Core::Messaging::Metadata::type::TRACING, _T("some_category"), EXPAND_AND_QUOTE(MODULE_NAME)); - testAdmin.Sync("reader read"); - testAdmin.Sync("done"); - }; + // Make sure the parent does not miss out on the signal if the child completes prematurely + sigset_t sigset; - static std::function lambdaVar = lambdaFunc; - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin) { lambdaVar(testAdmin); }; - IPTestAdministrator testAdmin(otherSide); + sigemptyset(&sigset); + sigaddset(&sigset, SIGCHLD); - { - testAdmin.Sync("setup"); - testAdmin.Sync("writer wrote"); - Core::Messaging::MessageUnit::Instance().Push(info, &tm); - testAdmin.Sync("reader read"); + // Do not continue if it is not guaranteed a child can be killed / ended + ASSERT_FALSE(sigprocmask(SIG_BLOCK, &sigset, nullptr) == -1); + + pid_t pid = fork(); + + switch(pid) { + case -1 : // error + { + EXPECT_TRUE(pid != -1); + break; + } + case 0 : // child + { + ASSERT_FALSE(sigprocmask(SIG_UNBLOCK, &sigset, nullptr) == -1); + + Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + + client.AddInstance(0); + + Messaging::TraceFactoryType factory; + client.AddFactory(Core::Messaging::Metadata::type::TRACING, &factory); + + client.Enable(metadata, true); + + client.WaitForUpdates(Core::infinite); +// client.SkipWaiting(); + + client.PopMessagesAndCall( + [&](const Core::ProxyType& metadata, const Core::ProxyType& message) { + if ((*metadata).Type() == Core::Messaging::Metadata::type::TRACING) { + TRACE_L1( + _T("PopMessagesAndCall : Tracing message -> Filename : %s, Linenumber : %d, Classname : %s") + , static_cast(*metadata).FileName().c_str() + , static_cast(*metadata).LineNumber() + , static_cast(*metadata).ClassName().c_str() + ); + + EXPECT_TRUE((*message).Data() == traceMessage); + } + } + ); + + client.RemoveFactory(Core::Messaging::Metadata::TRACING); + + client.RemoveInstance(0); + + break; + } + default : // parent + { + ASSERT_FALSE(sigprocmask(SIG_UNBLOCK, &sigset, nullptr) == -1); + + Messaging::TextMessage tm(traceMessage); + + Core::Messaging::IStore::Tracing info(Core::Messaging::MessageInfo(metadata, Core::Time::Now().Ticks()), _T("some_file"), 1337, EXPAND_AND_QUOTE(MODULE_NAME)); + + Messaging::MessageUnit::Instance().Push(info, &tm); + + struct timespec timeout; + timeout.tv_sec = 60; // Arbitrary value + timeout.tv_nsec = 0; + + do { + if (sigtimedwait(&sigset, nullptr, &timeout) == -1) { + int err = errno; + if (err == EINTR) { + // Signal other than SIGCHLD + continue; + } else if (err == EAGAIN) { + // Timeout and no SIGCHLD received + // Kill the child + EXPECT_FALSE(kill(pid, SIGKILL) == -1); + } else { + // Error in executing sigtimedwait, 'abort' + EXPECT_FALSE(err == 0); + } + } + + break; + } while(waitpid(-1, nullptr, WNOHANG) <= 0); + } } - testAdmin.Sync("done"); } From 3793120cbcb6be91ef2e0a9bbd865650cf0c3785 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Thu, 20 Jun 2024 19:22:17 +0000 Subject: [PATCH 02/35] [Tests/unit] : Do not depend on 'IPTestAdministrator' if not used --- Tests/unit/IPTestAdministrator.h | 4 +--- Tests/unit/Module.h | 24 +++++++++++++++++++ Tests/unit/core/test_cyclicbuffer.cpp | 12 ++++++---- Tests/unit/core/test_databuffer.cpp | 7 ++++-- Tests/unit/core/test_dataelement.cpp | 7 ++++-- Tests/unit/core/test_dataelementfile.cpp | 7 ++++-- Tests/unit/core/test_doorbell.cpp | 8 ++++++- Tests/unit/core/test_enumerate.cpp | 8 +++++-- Tests/unit/core/test_event.cpp | 8 +++++-- Tests/unit/core/test_filesystem.cpp | 7 ++++-- Tests/unit/core/test_frametype.cpp | 7 ++++-- Tests/unit/core/test_hash.cpp | 8 +++++-- Tests/unit/core/test_hex2strserialization.cpp | 7 +++++- Tests/unit/core/test_ipc.cpp | 9 +++++-- Tests/unit/core/test_ipcclient.cpp | 9 +++++-- Tests/unit/core/test_iso639.cpp | 7 ++++-- Tests/unit/core/test_iterator.cpp | 7 ++++-- Tests/unit/core/test_jsonparser.cpp | 8 ++++--- Tests/unit/core/test_keyvalue.cpp | 7 ++++-- Tests/unit/core/test_library.cpp | 7 ++++-- Tests/unit/core/test_lockablecontainer.cpp | 7 ++++-- Tests/unit/core/test_measurementtype.cpp | 7 ++++-- Tests/unit/core/test_memberavailability.cpp | 8 +++++-- Tests/unit/core/test_messageException.cpp | 7 ++++-- Tests/unit/core/test_message_dispatcher.cpp | 12 ++++++---- Tests/unit/core/test_message_unit.cpp | 11 ++++++--- Tests/unit/core/test_networkinfo.cpp | 7 ++++-- Tests/unit/core/test_nodeid.cpp | 7 ++++-- Tests/unit/core/test_numbertype.cpp | 7 ++++-- Tests/unit/core/test_optional.cpp | 7 ++++-- Tests/unit/core/test_parser.cpp | 7 ++++-- Tests/unit/core/test_portability.cpp | 8 +++++-- Tests/unit/core/test_processinfo.cpp | 7 ++++-- Tests/unit/core/test_queue.cpp | 7 ++++-- Tests/unit/core/test_rangetype.cpp | 7 ++++-- Tests/unit/core/test_readwritelock.cpp | 7 ++++-- Tests/unit/core/test_rectangle.cpp | 7 ++++-- Tests/unit/core/test_rpc.cpp | 9 ++++--- Tests/unit/core/test_semaphore.cpp | 8 +++++-- Tests/unit/core/test_sharedbuffer.cpp | 9 +++++-- Tests/unit/core/test_singleton.cpp | 7 ++++-- Tests/unit/core/test_socketstreamjson.cpp | 15 ++++++++---- Tests/unit/core/test_socketstreamtext.cpp | 13 ++++++---- Tests/unit/core/test_statetrigger.cpp | 6 ++++- Tests/unit/core/test_stopwatch.cpp | 7 ++++-- Tests/unit/core/test_synchronize.cpp | 7 ++++-- Tests/unit/core/test_synchronous.cpp | 9 +++++-- Tests/unit/core/test_systeminfo.cpp | 13 ++++++---- Tests/unit/core/test_textfragment.cpp | 7 ++++-- Tests/unit/core/test_textreader.cpp | 7 ++++-- Tests/unit/core/test_thread.cpp | 10 +++++--- Tests/unit/core/test_threadpool.cpp | 8 +++++-- Tests/unit/core/test_time.cpp | 8 +++++-- Tests/unit/core/test_timer.cpp | 10 +++++--- Tests/unit/core/test_tracing.cpp | 15 +++++++----- Tests/unit/core/test_tristate.cpp | 7 ++++-- Tests/unit/core/test_valuerecorder.cpp | 7 ++++-- Tests/unit/core/test_weblinkjson.cpp | 9 +++++-- Tests/unit/core/test_weblinktext.cpp | 9 +++++-- Tests/unit/core/test_websocketjson.cpp | 12 +++++++--- Tests/unit/core/test_websockettext.cpp | 12 +++++++--- Tests/unit/core/test_workerpool.cpp | 8 +++++-- Tests/unit/core/test_xgetopt.cpp | 9 ++++--- 63 files changed, 392 insertions(+), 147 deletions(-) create mode 100644 Tests/unit/Module.h diff --git a/Tests/unit/IPTestAdministrator.h b/Tests/unit/IPTestAdministrator.h index 270442e23..ef749723f 100644 --- a/Tests/unit/IPTestAdministrator.h +++ b/Tests/unit/IPTestAdministrator.h @@ -19,12 +19,10 @@ #pragma once -#define MODULE_NAME ThunderUnitTests - #include #include -class IPTestAdministrator; +#include "Module.h" class IPTestAdministrator { diff --git a/Tests/unit/Module.h b/Tests/unit/Module.h new file mode 100644 index 000000000..cb547a8ea --- /dev/null +++ b/Tests/unit/Module.h @@ -0,0 +1,24 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2020 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifndef MODULE_NAME +#define MODULE_NAME ThunderUnitTests +#endif diff --git a/Tests/unit/core/test_cyclicbuffer.cpp b/Tests/unit/core/test_cyclicbuffer.cpp index f0caa777e..79d4eebb6 100644 --- a/Tests/unit/core/test_cyclicbuffer.cpp +++ b/Tests/unit/core/test_cyclicbuffer.cpp @@ -17,13 +17,15 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include -#include -#include -#include + +#include "../IPTestAdministrator.h" namespace Thunder { namespace Core { diff --git a/Tests/unit/core/test_databuffer.cpp b/Tests/unit/core/test_databuffer.cpp index 01542ecbf..cf8daf999 100644 --- a/Tests/unit/core/test_databuffer.cpp +++ b/Tests/unit/core/test_databuffer.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include namespace Thunder { diff --git a/Tests/unit/core/test_dataelement.cpp b/Tests/unit/core/test_dataelement.cpp index 88dc1c5d9..358527739 100644 --- a/Tests/unit/core/test_dataelement.cpp +++ b/Tests/unit/core/test_dataelement.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_dataelementfile.cpp b/Tests/unit/core/test_dataelementfile.cpp index 35a61980d..1dffb9607 100644 --- a/Tests/unit/core/test_dataelementfile.cpp +++ b/Tests/unit/core/test_dataelementfile.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_doorbell.cpp b/Tests/unit/core/test_doorbell.cpp index 56990a424..ecc6cca21 100644 --- a/Tests/unit/core/test_doorbell.cpp +++ b/Tests/unit/core/test_doorbell.cpp @@ -16,11 +16,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "../IPTestAdministrator.h" #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include +#include "../IPTestAdministrator.h" + namespace Thunder { namespace Tests { diff --git a/Tests/unit/core/test_enumerate.cpp b/Tests/unit/core/test_enumerate.cpp index aacec7d66..8b53bd78f 100644 --- a/Tests/unit/core/test_enumerate.cpp +++ b/Tests/unit/core/test_enumerate.cpp @@ -17,9 +17,13 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME + +#include "../Module.h" +#endif + #include namespace Thunder { diff --git a/Tests/unit/core/test_event.cpp b/Tests/unit/core/test_event.cpp index 06fe9e25f..26c75096d 100644 --- a/Tests/unit/core/test_event.cpp +++ b/Tests/unit/core/test_event.cpp @@ -17,11 +17,15 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" +#include #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include -#include using namespace Thunder; using namespace Thunder::Core; diff --git a/Tests/unit/core/test_filesystem.cpp b/Tests/unit/core/test_filesystem.cpp index 2dea5b4e5..b51eb51d1 100644 --- a/Tests/unit/core/test_filesystem.cpp +++ b/Tests/unit/core/test_filesystem.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_frametype.cpp b/Tests/unit/core/test_frametype.cpp index 22252e01e..d79c8a358 100644 --- a/Tests/unit/core/test_frametype.cpp +++ b/Tests/unit/core/test_frametype.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_hash.cpp b/Tests/unit/core/test_hash.cpp index 58c588c65..0ff9d7db8 100644 --- a/Tests/unit/core/test_hash.cpp +++ b/Tests/unit/core/test_hash.cpp @@ -17,12 +17,16 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" +#include #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include #include -#include namespace Thunder { namespace Tests { diff --git a/Tests/unit/core/test_hex2strserialization.cpp b/Tests/unit/core/test_hex2strserialization.cpp index 03d5dc45a..6b9075a01 100644 --- a/Tests/unit/core/test_hex2strserialization.cpp +++ b/Tests/unit/core/test_hex2strserialization.cpp @@ -16,11 +16,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "../IPTestAdministrator.h" + #include #include #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include "core/core.h" namespace Thunder { diff --git a/Tests/unit/core/test_ipc.cpp b/Tests/unit/core/test_ipc.cpp index 4a8217ce3..4bfea2226 100644 --- a/Tests/unit/core/test_ipc.cpp +++ b/Tests/unit/core/test_ipc.cpp @@ -17,11 +17,16 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include +#include "../IPTestAdministrator.h" + namespace Thunder { namespace Tests { diff --git a/Tests/unit/core/test_ipcclient.cpp b/Tests/unit/core/test_ipcclient.cpp index 016dfdc96..9edd7ae49 100644 --- a/Tests/unit/core/test_ipcclient.cpp +++ b/Tests/unit/core/test_ipcclient.cpp @@ -17,11 +17,16 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include +#include "../IPTestAdministrator.h" + namespace Thunder { namespace Tests { diff --git a/Tests/unit/core/test_iso639.cpp b/Tests/unit/core/test_iso639.cpp index 2d38cd393..71f1446a1 100644 --- a/Tests/unit/core/test_iso639.cpp +++ b/Tests/unit/core/test_iso639.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_iterator.cpp b/Tests/unit/core/test_iterator.cpp index be26042cf..8d656ecd7 100644 --- a/Tests/unit/core/test_iterator.cpp +++ b/Tests/unit/core/test_iterator.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include namespace Thunder { diff --git a/Tests/unit/core/test_jsonparser.cpp b/Tests/unit/core/test_jsonparser.cpp index 684a33090..8cccbf459 100644 --- a/Tests/unit/core/test_jsonparser.cpp +++ b/Tests/unit/core/test_jsonparser.cpp @@ -19,14 +19,16 @@ #include #include +#include #include -#include "../IPTestAdministrator.h" +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include -#include - namespace Thunder { enum class JSONTestEnum { ENUM_1, diff --git a/Tests/unit/core/test_keyvalue.cpp b/Tests/unit/core/test_keyvalue.cpp index 12089ab7f..e60b8ac6b 100644 --- a/Tests/unit/core/test_keyvalue.cpp +++ b/Tests/unit/core/test_keyvalue.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_library.cpp b/Tests/unit/core/test_library.cpp index dc2aa207c..b6aa99ae5 100644 --- a/Tests/unit/core/test_library.cpp +++ b/Tests/unit/core/test_library.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_lockablecontainer.cpp b/Tests/unit/core/test_lockablecontainer.cpp index 76a42faa7..634d19757 100644 --- a/Tests/unit/core/test_lockablecontainer.cpp +++ b/Tests/unit/core/test_lockablecontainer.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_measurementtype.cpp b/Tests/unit/core/test_measurementtype.cpp index bcd96f2f1..fed7764b6 100644 --- a/Tests/unit/core/test_measurementtype.cpp +++ b/Tests/unit/core/test_measurementtype.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include namespace Thunder { diff --git a/Tests/unit/core/test_memberavailability.cpp b/Tests/unit/core/test_memberavailability.cpp index df8306414..0b437afd8 100644 --- a/Tests/unit/core/test_memberavailability.cpp +++ b/Tests/unit/core/test_memberavailability.cpp @@ -17,11 +17,15 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" +#include #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include -#include namespace Thunder { namespace Tests { diff --git a/Tests/unit/core/test_messageException.cpp b/Tests/unit/core/test_messageException.cpp index 377d17d2f..86180ddbd 100644 --- a/Tests/unit/core/test_messageException.cpp +++ b/Tests/unit/core/test_messageException.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_message_dispatcher.cpp b/Tests/unit/core/test_message_dispatcher.cpp index e3419552d..c741e4844 100644 --- a/Tests/unit/core/test_message_dispatcher.cpp +++ b/Tests/unit/core/test_message_dispatcher.cpp @@ -17,13 +17,17 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" +#include -#include #include -#include -#include +#ifndef MODULE_NAME +#include "../Module.h" +#endif + +#include + +#include "../IPTestAdministrator.h" namespace Thunder { namespace Tests { diff --git a/Tests/unit/core/test_message_unit.cpp b/Tests/unit/core/test_message_unit.cpp index 7610a8cc4..ff3e3bfda 100644 --- a/Tests/unit/core/test_message_unit.cpp +++ b/Tests/unit/core/test_message_unit.cpp @@ -17,11 +17,16 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include -#include +#ifndef MODULE_NAME +#include "../Module.h" +#endif + +#include + +#include "../IPTestAdministrator.h" + using namespace Thunder; class Control : public Core::Messaging::IControl { diff --git a/Tests/unit/core/test_networkinfo.cpp b/Tests/unit/core/test_networkinfo.cpp index 96892dfb4..b09b5d70c 100644 --- a/Tests/unit/core/test_networkinfo.cpp +++ b/Tests/unit/core/test_networkinfo.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_nodeid.cpp b/Tests/unit/core/test_nodeid.cpp index 026264e4f..7ff22fccc 100644 --- a/Tests/unit/core/test_nodeid.cpp +++ b/Tests/unit/core/test_nodeid.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_numbertype.cpp b/Tests/unit/core/test_numbertype.cpp index 05d3f4682..5bc5a658b 100644 --- a/Tests/unit/core/test_numbertype.cpp +++ b/Tests/unit/core/test_numbertype.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include namespace Thunder { diff --git a/Tests/unit/core/test_optional.cpp b/Tests/unit/core/test_optional.cpp index ba0961cc0..c802dbeea 100644 --- a/Tests/unit/core/test_optional.cpp +++ b/Tests/unit/core/test_optional.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_parser.cpp b/Tests/unit/core/test_parser.cpp index e0d367269..9ba705362 100644 --- a/Tests/unit/core/test_parser.cpp +++ b/Tests/unit/core/test_parser.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_portability.cpp b/Tests/unit/core/test_portability.cpp index a4c706522..24e448615 100644 --- a/Tests/unit/core/test_portability.cpp +++ b/Tests/unit/core/test_portability.cpp @@ -17,11 +17,15 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" +#include #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include -#include using namespace Thunder; using namespace Thunder::Core; diff --git a/Tests/unit/core/test_processinfo.cpp b/Tests/unit/core/test_processinfo.cpp index a3b10e97d..5ab22f4a9 100644 --- a/Tests/unit/core/test_processinfo.cpp +++ b/Tests/unit/core/test_processinfo.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_queue.cpp b/Tests/unit/core/test_queue.cpp index 80a765e3a..80c5e237a 100644 --- a/Tests/unit/core/test_queue.cpp +++ b/Tests/unit/core/test_queue.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_rangetype.cpp b/Tests/unit/core/test_rangetype.cpp index 0da321e63..d5aa74709 100644 --- a/Tests/unit/core/test_rangetype.cpp +++ b/Tests/unit/core/test_rangetype.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include namespace Thunder { diff --git a/Tests/unit/core/test_readwritelock.cpp b/Tests/unit/core/test_readwritelock.cpp index 80725dd85..18c72583b 100644 --- a/Tests/unit/core/test_readwritelock.cpp +++ b/Tests/unit/core/test_readwritelock.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_rectangle.cpp b/Tests/unit/core/test_rectangle.cpp index 27faeef08..2900036b8 100644 --- a/Tests/unit/core/test_rectangle.cpp +++ b/Tests/unit/core/test_rectangle.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_rpc.cpp b/Tests/unit/core/test_rpc.cpp index de3ce2a1f..bac4cd4d6 100644 --- a/Tests/unit/core/test_rpc.cpp +++ b/Tests/unit/core/test_rpc.cpp @@ -17,13 +17,16 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include #include -#include + +#include "../IPTestAdministrator.h" namespace Thunder { namespace Exchange { diff --git a/Tests/unit/core/test_semaphore.cpp b/Tests/unit/core/test_semaphore.cpp index 556fba1bc..356aaf710 100644 --- a/Tests/unit/core/test_semaphore.cpp +++ b/Tests/unit/core/test_semaphore.cpp @@ -17,11 +17,15 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" +#include #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include -#include using namespace Thunder; using namespace Thunder::Core; diff --git a/Tests/unit/core/test_sharedbuffer.cpp b/Tests/unit/core/test_sharedbuffer.cpp index df4650ca9..c3577700f 100644 --- a/Tests/unit/core/test_sharedbuffer.cpp +++ b/Tests/unit/core/test_sharedbuffer.cpp @@ -17,11 +17,16 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include +#include "../IPTestAdministrator.h" + namespace Thunder { namespace Tests { diff --git a/Tests/unit/core/test_singleton.cpp b/Tests/unit/core/test_singleton.cpp index b9d42e74e..26a1acf18 100644 --- a/Tests/unit/core/test_singleton.cpp +++ b/Tests/unit/core/test_singleton.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_socketstreamjson.cpp b/Tests/unit/core/test_socketstreamjson.cpp index 23afc4ab3..337491e46 100644 --- a/Tests/unit/core/test_socketstreamjson.cpp +++ b/Tests/unit/core/test_socketstreamjson.cpp @@ -17,13 +17,18 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - -#include -#include -#include #include #include + +#include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + +#include + +#include "../IPTestAdministrator.h" namespace Thunder { namespace Tests { diff --git a/Tests/unit/core/test_socketstreamtext.cpp b/Tests/unit/core/test_socketstreamtext.cpp index 7272f421a..6a613e876 100644 --- a/Tests/unit/core/test_socketstreamtext.cpp +++ b/Tests/unit/core/test_socketstreamtext.cpp @@ -17,13 +17,18 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" +#include +#include #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include -#include -#include -#include + +#include "../IPTestAdministrator.h" namespace Thunder { namespace Tests { diff --git a/Tests/unit/core/test_statetrigger.cpp b/Tests/unit/core/test_statetrigger.cpp index 6c92bf06d..48d514df3 100644 --- a/Tests/unit/core/test_statetrigger.cpp +++ b/Tests/unit/core/test_statetrigger.cpp @@ -16,9 +16,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "../IPTestAdministrator.h" #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_stopwatch.cpp b/Tests/unit/core/test_stopwatch.cpp index 48a6b9479..97b11a508 100644 --- a/Tests/unit/core/test_stopwatch.cpp +++ b/Tests/unit/core/test_stopwatch.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_synchronize.cpp b/Tests/unit/core/test_synchronize.cpp index 2cb5f57d6..8fcec033f 100644 --- a/Tests/unit/core/test_synchronize.cpp +++ b/Tests/unit/core/test_synchronize.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_synchronous.cpp b/Tests/unit/core/test_synchronous.cpp index 70083770f..700aab9aa 100644 --- a/Tests/unit/core/test_synchronous.cpp +++ b/Tests/unit/core/test_synchronous.cpp @@ -17,11 +17,16 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include +#include "../IPTestAdministrator.h" + using namespace Thunder; using namespace Thunder::Core; diff --git a/Tests/unit/core/test_systeminfo.cpp b/Tests/unit/core/test_systeminfo.cpp index 56e517e96..b1784f72d 100644 --- a/Tests/unit/core/test_systeminfo.cpp +++ b/Tests/unit/core/test_systeminfo.cpp @@ -17,17 +17,20 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include - -#include -#include #include #include #include #include +#include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + +#include + namespace Thunder { namespace Tests { diff --git a/Tests/unit/core/test_textfragment.cpp b/Tests/unit/core/test_textfragment.cpp index fde006b6c..ff2e979ef 100644 --- a/Tests/unit/core/test_textfragment.cpp +++ b/Tests/unit/core/test_textfragment.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_textreader.cpp b/Tests/unit/core/test_textreader.cpp index 864c000ee..f075fb3cc 100644 --- a/Tests/unit/core/test_textreader.cpp +++ b/Tests/unit/core/test_textreader.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_thread.cpp b/Tests/unit/core/test_thread.cpp index defbf2502..2ef0e2aaf 100644 --- a/Tests/unit/core/test_thread.cpp +++ b/Tests/unit/core/test_thread.cpp @@ -17,12 +17,16 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" +#include +#include #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include -#include -#include namespace Thunder { namespace Tests { diff --git a/Tests/unit/core/test_threadpool.cpp b/Tests/unit/core/test_threadpool.cpp index 42443a27b..29295cf00 100644 --- a/Tests/unit/core/test_threadpool.cpp +++ b/Tests/unit/core/test_threadpool.cpp @@ -17,11 +17,15 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" +#include #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include -#include using namespace Thunder; using namespace Thunder::Core; diff --git a/Tests/unit/core/test_time.cpp b/Tests/unit/core/test_time.cpp index 0e193ba55..3a3ca588e 100644 --- a/Tests/unit/core/test_time.cpp +++ b/Tests/unit/core/test_time.cpp @@ -17,11 +17,15 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" +#include #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include -#include using namespace Thunder; using namespace Thunder::Core; diff --git a/Tests/unit/core/test_timer.cpp b/Tests/unit/core/test_timer.cpp index a919d792d..0e91402e2 100644 --- a/Tests/unit/core/test_timer.cpp +++ b/Tests/unit/core/test_timer.cpp @@ -17,12 +17,16 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" +#include +#include #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include -#include -#include namespace Thunder { namespace Tests { diff --git a/Tests/unit/core/test_tracing.cpp b/Tests/unit/core/test_tracing.cpp index 0d32cb406..b85ff04c7 100644 --- a/Tests/unit/core/test_tracing.cpp +++ b/Tests/unit/core/test_tracing.cpp @@ -17,13 +17,16 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include -#include -#include -#include +#ifndef MODULE_NAME +#include "../Module.h" +#endif + +#include + +#include "../IPTestAdministrator.h" + using namespace Thunder; using namespace Thunder::Core; @@ -348,4 +351,4 @@ TEST(Core_tracing, simpleTracingReversed) testAdmin.WaitForChildCompletion(); Singleton::Dispose(); -} \ No newline at end of file +} diff --git a/Tests/unit/core/test_tristate.cpp b/Tests/unit/core/test_tristate.cpp index 2d71c0c52..7067c5591 100644 --- a/Tests/unit/core/test_tristate.cpp +++ b/Tests/unit/core/test_tristate.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include using namespace Thunder; diff --git a/Tests/unit/core/test_valuerecorder.cpp b/Tests/unit/core/test_valuerecorder.cpp index ac939d8fe..f7e8446fb 100644 --- a/Tests/unit/core/test_valuerecorder.cpp +++ b/Tests/unit/core/test_valuerecorder.cpp @@ -17,9 +17,12 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include "gtest/gtest.h" + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include "core/core.h" using namespace Thunder; diff --git a/Tests/unit/core/test_weblinkjson.cpp b/Tests/unit/core/test_weblinkjson.cpp index f811a24ab..a9821292c 100644 --- a/Tests/unit/core/test_weblinkjson.cpp +++ b/Tests/unit/core/test_weblinkjson.cpp @@ -17,12 +17,17 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include #include +#include "../IPTestAdministrator.h" + namespace Thunder { namespace Tests { diff --git a/Tests/unit/core/test_weblinktext.cpp b/Tests/unit/core/test_weblinktext.cpp index 49d135c0a..fcf37dcca 100644 --- a/Tests/unit/core/test_weblinktext.cpp +++ b/Tests/unit/core/test_weblinktext.cpp @@ -17,12 +17,17 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include #include +#include "../IPTestAdministrator.h" + namespace Thunder { namespace Tests { diff --git a/Tests/unit/core/test_websocketjson.cpp b/Tests/unit/core/test_websocketjson.cpp index 4f9e19c19..54809313e 100644 --- a/Tests/unit/core/test_websocketjson.cpp +++ b/Tests/unit/core/test_websocketjson.cpp @@ -17,13 +17,19 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" +#include +#include #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include #include -#include -#include + +#include "../IPTestAdministrator.h" namespace Thunder { namespace Tests { diff --git a/Tests/unit/core/test_websockettext.cpp b/Tests/unit/core/test_websockettext.cpp index 6753e9ab5..c118e7e53 100644 --- a/Tests/unit/core/test_websockettext.cpp +++ b/Tests/unit/core/test_websockettext.cpp @@ -17,13 +17,19 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" +#include +#include #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include #include -#include -#include + +#include "../IPTestAdministrator.h" namespace Thunder { namespace Tests { diff --git a/Tests/unit/core/test_workerpool.cpp b/Tests/unit/core/test_workerpool.cpp index 5a6a9dd33..bffeac19e 100644 --- a/Tests/unit/core/test_workerpool.cpp +++ b/Tests/unit/core/test_workerpool.cpp @@ -17,11 +17,15 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" +#include #include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + #include -#include using namespace Thunder; using namespace Thunder::Core; diff --git a/Tests/unit/core/test_xgetopt.cpp b/Tests/unit/core/test_xgetopt.cpp index 27feec7c8..320411080 100644 --- a/Tests/unit/core/test_xgetopt.cpp +++ b/Tests/unit/core/test_xgetopt.cpp @@ -17,10 +17,13 @@ * limitations under the License. */ -#include "../IPTestAdministrator.h" - #include -#include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + +#include int argumentCount = 3; char* arguments[]= {(char*)"-c", (char*)"-h", (char*)"-b"}; From 5e55df67665d40e3afd2ec574b63db845a4b4c15 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:26:49 +0000 Subject: [PATCH 03/35] [Tests/unit/tests] : Cherry pick 'test_iptestmanager' from development/namespaces --- Tests/unit/tests/test_iptestmanager.cpp | 39 ++++++++++++++++--------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/Tests/unit/tests/test_iptestmanager.cpp b/Tests/unit/tests/test_iptestmanager.cpp index 557d16cd4..894448c5b 100644 --- a/Tests/unit/tests/test_iptestmanager.cpp +++ b/Tests/unit/tests/test_iptestmanager.cpp @@ -17,24 +17,37 @@ * limitations under the License. */ +#include + +#ifndef MODULE_NAME +#include "../Module.h" +#endif + +#include + #include "../IPTestAdministrator.h" -#include +namespace Thunder { +namespace Tests { +namespace Core { -TEST(Test_IPTestAdministrator, sync) -{ - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator & testAdmin) { - testAdmin.Sync("str01"); + TEST(Test_IPTestAdministrator, sync) + { + IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator & testAdmin) { + testAdmin.Sync("str01"); - testAdmin.Sync("str02_a"); - }; + testAdmin.Sync("str02_a"); + }; - IPTestAdministrator testAdmin(otherSide); + IPTestAdministrator testAdmin(otherSide); - bool result = testAdmin.Sync("str01"); - ASSERT_TRUE(result); + bool result = testAdmin.Sync("str01"); + ASSERT_TRUE(result); - result = testAdmin.Sync("str02_b"); - ASSERT_FALSE(result); -} + result = testAdmin.Sync("str02_b"); + ASSERT_FALSE(result); + } +} // Core +} // Tests +} // Thunder From 957977381dfa8137f1475131622390ebed2bdcf7 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:36:59 +0000 Subject: [PATCH 04/35] [Tests/unit / Tests/unit/tests] : Improve synchronization usage of 'IPTestAdministrator' --- Tests/unit/IPTestAdministrator.cpp | 348 ++++++++++-------------- Tests/unit/IPTestAdministrator.h | 62 ++--- Tests/unit/tests/CMakeLists.txt | 3 + Tests/unit/tests/test_iptestmanager.cpp | 28 +- 4 files changed, 192 insertions(+), 249 deletions(-) diff --git a/Tests/unit/IPTestAdministrator.cpp b/Tests/unit/IPTestAdministrator.cpp index a231d62d0..d2d807ce1 100644 --- a/Tests/unit/IPTestAdministrator.cpp +++ b/Tests/unit/IPTestAdministrator.cpp @@ -17,234 +17,176 @@ * limitations under the License. */ -#include "IPTestAdministrator.h" - -#include -#include -#include -#include -#include -#include -#include - -MODULE_NAME_DECLARATION(BUILD_REFERENCE); +#include -#ifdef WITH_CODE_COVERAGE -extern "C" void __gcov_flush(); +#ifdef __cplusplus +extern "C" { #endif - -IPTestAdministrator::IPTestAdministrator(OtherSideMain otherSideMain, void* data, const uint32_t waitTime) - : m_sharedData(nullptr) - , m_childPid(0) - , m_data(data) - , m_maxWaitTime(waitTime) -{ - ForkChildProcess(otherSideMain); -} -IPTestAdministrator::IPTestAdministrator(OtherSideMain otherSideMain, const uint32_t waitTime) - : m_sharedData(nullptr) - , m_childPid(0) - , m_data(nullptr) - , m_maxWaitTime(waitTime) -{ - ForkChildProcess(otherSideMain); -} - -void IPTestAdministrator::ForkChildProcess(OtherSideMain otherSideMain) -{ - m_sharedData = static_cast(mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0)); - - pthread_mutexattr_t mutexAttr; - pthread_mutexattr_init(&mutexAttr); - pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED); - pthread_mutex_init(&m_sharedData->m_stateMutex, &mutexAttr); - pthread_mutex_init(&m_sharedData->m_waitingForSecondCondMutex, &mutexAttr); - pthread_mutex_init(&m_sharedData->m_waitingForNormalCondMutex, &mutexAttr); - pthread_mutexattr_destroy(&mutexAttr); - - pthread_condattr_t condAttr; - pthread_condattr_init(&condAttr); - pthread_condattr_setpshared(&condAttr, PTHREAD_PROCESS_SHARED); - pthread_cond_init(&m_sharedData->m_waitingForSecondCond, &condAttr); - pthread_cond_init(&m_sharedData->m_waitingForNormalCond, &condAttr); - pthread_condattr_destroy(&condAttr); - - pid_t childProcess = fork(); - - if (childProcess == 0) { - // In child process - otherSideMain(*this); - - // TODO: should we clean up stuff here or not? - //Thunder::Core::Singleton::Dispose(); - - // Make sure no gtest cleanup code is called (summary etc). - #ifdef WITH_CODE_COVERAGE - __gcov_flush(); - #endif - - abort(); - } else { - // In parent process, store child pid, so we can kill it later. - m_childPid = childProcess; - } -} - -IPTestAdministrator::~IPTestAdministrator() -{ - waitpid(m_childPid, 0, 0); +#include // FUTEX_* constants +#include // SYS_* constants +#include +#ifdef __cplusplus } +#endif -void IPTestAdministrator::WaitForChildCompletion() -{ - waitpid(m_childPid, 0, 0); -} - -bool IPTestAdministrator::Sync(const std::string & str) -{ - bool result = false; - - // Get hold of mutex guarding state. - TimedLock(&m_sharedData->m_stateMutex, str); - - if (!m_sharedData->m_waitingForOther) { - // We are the first. - if (str.length() >= m_messageBufferSize) { - fprintf(stderr, "Warning: sync string is too long: \"%s\"\n", str.c_str()); - } - - strncpy(m_sharedData->m_message, str.c_str(), m_messageBufferSize); - - // Get hold of mutex of "waiting for second" cond var. - TimedLock(&m_sharedData->m_waitingForSecondCondMutex, str); - - m_sharedData->m_waitingForOther = true; - - // Release state mutex, because we set "waiting for other". - pthread_mutex_unlock(&m_sharedData->m_stateMutex); - - // Wait for other side to arrive and set "m_messageTheSame" - while (m_sharedData->m_waitingForOther) { - TimedWait(&m_sharedData->m_waitingForSecondCond, &m_sharedData->m_waitingForSecondCondMutex, str); - } - - // Now other side if waiting for us to set everything to normal situation. - - // Cond var was triggered, release mutex we now hold. - pthread_mutex_unlock(&m_sharedData->m_waitingForSecondCondMutex); - - // Other side arrived and set m_messageTheSame - result = m_sharedData->m_messageTheSame; +#include +#include - // Unset "waiting for other" bool - m_sharedData->m_waitingForOther = false; +#include "IPTestAdministrator.h" - // Get hold of mutex guarding "back to normal" cond var - TimedLock(&m_sharedData->m_waitingForNormalCondMutex, str); +#include - m_sharedData->m_backToNormal = true; +MODULE_NAME_DECLARATION(BUILD_REFERENCE); - // Signal other side everything is back to normal. - pthread_cond_signal(&m_sharedData->m_waitingForNormalCond); +IPTestAdministrator::IPTestAdministrator(Callback parent, Callback child, const uint32_t initHandShakeValue, const uint32_t waitTime) + : _sharedData{nullptr} + , _pid{-1} + , _waitTime(waitTime) +{ + ASSERT(waitTime > 0 && waitTime < ::Thunder::Core::infinite); - // Unlock mutex belonging to this cond var. - pthread_mutex_unlock(&m_sharedData->m_waitingForNormalCondMutex); - } else { - if (str.length() >= m_messageBufferSize) { - fprintf(stderr, "Warning: sync string is too long: \"%s\"\n", str.c_str()); - } + int shm_id = shmget(IPC_PRIVATE, sizeof(struct SharedData) /* size */, IPC_CREAT | 0666 /* read and write for user, group and others */); - // Other side came first and set "m_message", compare. - result = (strcmp(m_sharedData->m_message, str.c_str()) == 0); + ASSERT(shm_id >= 0); - // Straight away we can unlock state mutex - pthread_mutex_unlock(&m_sharedData->m_stateMutex); + _sharedData = reinterpret_cast(shmat(shm_id, nullptr, 0 /* attach for reading and writing */)); - // Store result, so other side will also return it. - m_sharedData->m_messageTheSame = result; + ASSERT(_sharedData != nullptr); - // We will have to wait for other side to set everything back to normal. - // For this we need to lock the mutex with the cond var, and wait for it. - TimedLock(&m_sharedData->m_waitingForNormalCondMutex, str); + _sharedData->handshakeValue.exchange(initHandShakeValue); - // We have to mutex, so now safe to unset this variable. - m_sharedData->m_backToNormal = false; + _pid = fork(); - // We ("other side") are done, tell other process about it. - TimedLock(&m_sharedData->m_waitingForSecondCondMutex, str); - m_sharedData->m_waitingForOther = false; - pthread_cond_signal(&m_sharedData->m_waitingForSecondCond); - pthread_mutex_unlock(&m_sharedData->m_waitingForSecondCondMutex); + ASSERT(_pid != -1); - // Wait until other process tells us all is back to normal. - while (!m_sharedData->m_backToNormal) { - TimedWait(&m_sharedData->m_waitingForNormalCond, &m_sharedData->m_waitingForNormalCondMutex, str); - } + if (_pid == 0) { + // Child process - // We hold that mutex now, unlock it. - pthread_mutex_unlock(&m_sharedData->m_waitingForNormalCondMutex); - } + ASSERT(child != nullptr); + child(*this); - return result; + std::exit(0); // Avoid multiple / repeated test runs + } else { + ASSERT(parent != nullptr); + parent(*this); + } } -const char * IPTestAdministrator::GetProcessName() const +IPTestAdministrator::~IPTestAdministrator() { - if (m_childPid != 0) { - return "parent"; - } else { - return "child"; - } + if (_pid > 0) { + // Is the child still alive? + + int pid_fd = syscall(SYS_pidfd_open, _pid, 0); + + if (pid_fd != -1) { + struct pollfd fds = { pid_fd, POLLIN, 0 }; + + switch (poll(&fds, sizeof(fds) / sizeof(struct pollfd), _waitTime >= std::numeric_limits::max() ? std::numeric_limits::max() : _waitTime /* timeout in milliseconds */)) { + case -1 : // error + switch(errno) { + case EFAULT : // fds is not within address space + do {} while(false); + case EINTR : // Signal occured before any requested event + do {} while(false); + case EINVAL : // Number of descriptors too large or invalid timeout value + do {} while(false); + case ENOMEM : // Unable to allocated supported memory + do {} while(false); + default :; + } + do {} while(false); + case 0 : // Timeout expired before events are available + { + int result = syscall(SYS_kill, _pid, SIGKILL); + + ASSERT(result == 0); + } + do {} while(false); + default : // Number of events set because the descriptor is readable, eg, the process has terminated + ; + } + + /* int */ close(pid_fd); + } + } + + if(shmdt(_sharedData) == -1) { + switch(errno) { + case EINVAL : // The shared data is not the start address of the sahred segment + do {} while(false); + default : // Uninpsected or unknown error + ; + } + } } -void IPTestAdministrator::TimedLock(pthread_mutex_t * mutex, const std::string & str) -{ - timespec timeSpec; - FillTimeOut(timeSpec); -#ifdef __APPLE__ - int result; - do { - result = pthread_mutex_trylock(mutex); - if (result == EBUSY) { - int wait = -1; - timespec ts; - ts.tv_sec = 1000; - if (timeSpec.tv_sec > 1000) { - timeSpec.tv_sec -= ts.tv_sec; - } else if (timeSpec.tv_sec != -1) { - ts.tv_sec = timeSpec.tv_sec; - timeSpec.tv_sec = 0; - } - - while (wait == -1) { - wait = nanosleep(&ts, &ts); - } - } else { - break; - } - } while (result != 0); - -#else - int result = pthread_mutex_timedlock(mutex, &timeSpec); - if (result == ETIMEDOUT) { - fprintf(stderr, "While locking mutex, time out expired for \"%s\" in %s.\n", str.c_str(), GetProcessName()); - abort(); - } -#endif -} -void IPTestAdministrator::TimedWait(pthread_cond_t * cond, pthread_mutex_t * mutex, const std::string & str) +uint32_t IPTestAdministrator::Wait(uint32_t expectedHandshakeValue) const { - timespec timeSpec; - FillTimeOut(timeSpec); - int result = pthread_cond_timedwait(cond, mutex, &timeSpec); - if (result == ETIMEDOUT) { - fprintf(stderr, "While waiting on cond var, time out expired for \"%s\" in %s (%u).\n", str.c_str(), GetProcessName(), getpid()); - abort(); - } + uint32_t result = ::Thunder::Core::ERROR_GENERAL; + + // Never wait infinite amount of time + const struct timespec timeout { _waitTime /* seconds */, 0 /* nanoseconds */}; + + constexpr bool stop = { false }; + + do { + long futex_result = syscall(SYS_futex, reinterpret_cast(&(_sharedData->handshakeValue)), FUTEX_WAIT, expectedHandshakeValue, &timeout, nullptr, 0); + + switch(futex_result) { + case 0 : if (_sharedData->handshakeValue == expectedHandshakeValue) { + // True wake-up + result = ::Thunder::Core::ERROR_NONE; + break; + } + + // Spurious wake-up + // TODO: continue with remaining time + continue; + case -1 : // + switch(errno) { + case EAGAIN : + // Value mismatch + result = ::Thunder::Core::ERROR_INVALID_RANGE; + break; + case ETIMEDOUT : // Value has not changed within the specified timeout + result = ::Thunder::Core::ERROR_TIMEDOUT; + break; + default : // Uninspected conditions like EINTR and EINVAL + ; + } + break; + default : // Serious error + ; + } + + break; + + } while(!stop); + + return result; } -void IPTestAdministrator::FillTimeOut(timespec & timeSpec) +uint32_t IPTestAdministrator::Signal(uint32_t expectedNextHandshakeValue) { - clock_gettime(CLOCK_REALTIME, &timeSpec); - timeSpec.tv_sec += m_maxWaitTime; + uint32_t result = ::Thunder::Core::ERROR_GENERAL; + + long futex_result = syscall(SYS_futex, &(_sharedData->handshakeValue), FUTEX_WAKE, INT_MAX /* number of waiters to wake-up */, nullptr, nullptr, 0); + + switch(futex_result) { + case -1 : // Error + switch(errno) { + case EINVAL : // Inconsistent state + do {} while (false); + default : // Uninspected // unknown conditions + ; + } + case 0 : // No waiters + do {} while (false); + default : result = ::Thunder::Core::ERROR_NONE; + // Atomically replaces the current value by the expected value + bool oldHandshakeValue = _sharedData->handshakeValue.exchange(expectedNextHandshakeValue); + } + + return result; } diff --git a/Tests/unit/IPTestAdministrator.h b/Tests/unit/IPTestAdministrator.h index ef749723f..95939bfaf 100644 --- a/Tests/unit/IPTestAdministrator.h +++ b/Tests/unit/IPTestAdministrator.h @@ -21,51 +21,39 @@ #include #include +#include +#include #include "Module.h" +#ifndef __LINUX__ +static_assert(false, "Only LINUX is supported"); +#endif + class IPTestAdministrator { -private: - static constexpr uint32_t MaxWaitTime = 2; // In seconds - -public: - typedef void (*OtherSideMain)(IPTestAdministrator & testAdmin); +public : + using Callback = std::function; - IPTestAdministrator(OtherSideMain otherSideMain, const uint32_t waitTime = MaxWaitTime); - IPTestAdministrator(OtherSideMain otherSideMain, void* data, const uint32_t waitTime = MaxWaitTime); - ~IPTestAdministrator(); + IPTestAdministrator(Callback /* executed by parent */, Callback /* executed by child */, const uint32_t initHandshakeValue, const uint32_t waitTime); + ~IPTestAdministrator(); - void ForkChildProcess(OtherSideMain otherSideMain); - // Method to sync the two test processes. - bool Sync(const std::string & str); - void WaitForChildCompletion(); + IPTestAdministrator(const IPTestAdministrator&) = delete; + const IPTestAdministrator& operator=(const IPTestAdministrator&) = delete; - void* Data() { return m_data; } -private: - static const uint32_t m_messageBufferSize = 1024; + uint32_t Wait(uint32_t expectedHandshakeValue) const; + uint32_t Signal(uint32_t expectedNextHandshakeValue); - struct SharedData - { - pthread_mutex_t m_stateMutex; // Guards state (are we first or second?) - pthread_cond_t m_waitingForSecondCond; // Used to wait for second - pthread_mutex_t m_waitingForSecondCondMutex; - bool m_waitingForOther; // whether we are waiting for the other side or not - bool m_messageTheSame; // whether message comparison was a success - char m_message[m_messageBufferSize]; // Expected message string - bool m_backToNormal; - pthread_cond_t m_waitingForNormalCond; // To wait for first to restore state to normal - pthread_mutex_t m_waitingForNormalCondMutex; - }; +private : - SharedData * m_sharedData; - pid_t m_childPid; // Set if we are parent processs. - void* m_data; - uint32_t m_maxWaitTime; // In seconds. - - const char * GetProcessName() const; - void TimedLock(pthread_mutex_t * mutex, const std::string & str); - void TimedWait(pthread_cond_t * cond, pthread_mutex_t * mutex, const std::string & str); - - void FillTimeOut(timespec & timeSpec); + struct SharedData + { + // std::atomic integral> has standard layout! + // A pointer may be converted to a pointer of the first non-static data element with reinterpret_cast + std::atomic handshakeValue; + }; +public: + SharedData* _sharedData; + pid_t _pid; + uint32_t _waitTime; // In seconds }; diff --git a/Tests/unit/tests/CMakeLists.txt b/Tests/unit/tests/CMakeLists.txt index 766c13346..aae8d8fb9 100644 --- a/Tests/unit/tests/CMakeLists.txt +++ b/Tests/unit/tests/CMakeLists.txt @@ -15,6 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +if(LINUX) set(TEST_RUNNER_NAME "Thunder_test_tests") add_executable(${TEST_RUNNER_NAME} @@ -36,3 +37,5 @@ install( DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${NAMESPACE}_Test) add_test(${TEST_RUNNER_NAME} ${TEST_RUNNER_NAME}) + +endif() diff --git a/Tests/unit/tests/test_iptestmanager.cpp b/Tests/unit/tests/test_iptestmanager.cpp index 894448c5b..b92611214 100644 --- a/Tests/unit/tests/test_iptestmanager.cpp +++ b/Tests/unit/tests/test_iptestmanager.cpp @@ -33,19 +33,29 @@ namespace Core { TEST(Test_IPTestAdministrator, sync) { - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator & testAdmin) { - testAdmin.Sync("str01"); + // Do not change the signal handshake value unless you use a timed loop and repeatedly check. + // Wait may return early with an error if it expect a different value. - testAdmin.Sync("str02_a"); - }; + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4; - IPTestAdministrator testAdmin(otherSide); + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + }; - bool result = testAdmin.Sync("str01"); - ASSERT_TRUE(result); + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + // A small delay so the child can be set up + SleepMs(1000); + // The child is awaiting the signal for this value to produce no error and continue. If the values mismatch the child continues with an error. + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + }; - result = testAdmin.Sync("str02_b"); - ASSERT_FALSE(result); + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); + + // Code after this line is executed by both parent and child + + ::Thunder::Core::Singleton::Dispose(); } } // Core From 8bc4c8a8711729fa9e9a7f12bb4bf7d0eeb78610 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Tue, 16 Jul 2024 10:57:27 +0000 Subject: [PATCH 05/35] [core/IPCChannel] : cherry-pick from 'development/ipcchannel_dangling_handlers' --- Source/core/IPCChannel.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Source/core/IPCChannel.h b/Source/core/IPCChannel.h index e948cdc65..fc0064908 100644 --- a/Source/core/IPCChannel.h +++ b/Source/core/IPCChannel.h @@ -333,6 +333,11 @@ namespace Core { ASSERT(index != _handlers.end()); if (index != _handlers.end()) { + for(auto it = _clients.begin(), tail = _clients.end(); it != tail; it++) { + Core::ProxyType element(it->second); + element->Unregister(index->first); + } + _handlers.erase(index); } From 22e7e3b7447a67c42d578e56abc75b604aed9d0b Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Tue, 16 Jul 2024 13:23:29 +0000 Subject: [PATCH 06/35] Tests/unit/core] : align tests with '957977381dfa8137f1475131622390ebed2bdcf7' --- Tests/unit/IPTestAdministrator.cpp | 2 - Tests/unit/IPTestAdministrator.h | 4 + Tests/unit/core/CMakeLists.txt | 70 ++- Tests/unit/core/test_doorbell.cpp | 102 ++-- Tests/unit/core/test_ipc.cpp | 663 +++++++++++----------- Tests/unit/core/test_ipcclient.cpp | 64 ++- Tests/unit/core/test_rpc.cpp | 76 +-- Tests/unit/core/test_socketstreamjson.cpp | 62 +- Tests/unit/core/test_socketstreamtext.cpp | 54 +- Tests/unit/core/test_statetrigger.cpp | 3 - Tests/unit/core/test_synchronous.cpp | 54 +- Tests/unit/core/test_systeminfo.cpp | 8 - Tests/unit/core/test_threadpool.cpp | 3 - Tests/unit/core/test_valuerecorder.cpp | 3 - Tests/unit/core/test_weblinktext.cpp | 1 - 15 files changed, 655 insertions(+), 514 deletions(-) diff --git a/Tests/unit/IPTestAdministrator.cpp b/Tests/unit/IPTestAdministrator.cpp index d2d807ce1..7ce30c550 100644 --- a/Tests/unit/IPTestAdministrator.cpp +++ b/Tests/unit/IPTestAdministrator.cpp @@ -34,8 +34,6 @@ extern "C" { #include "IPTestAdministrator.h" -#include - MODULE_NAME_DECLARATION(BUILD_REFERENCE); IPTestAdministrator::IPTestAdministrator(Callback parent, Callback child, const uint32_t initHandShakeValue, const uint32_t waitTime) diff --git a/Tests/unit/IPTestAdministrator.h b/Tests/unit/IPTestAdministrator.h index 95939bfaf..3421998b0 100644 --- a/Tests/unit/IPTestAdministrator.h +++ b/Tests/unit/IPTestAdministrator.h @@ -24,7 +24,11 @@ #include #include +#ifndef MODULE_NAME #include "Module.h" +#endif + +#include #ifndef __LINUX__ static_assert(false, "Only LINUX is supported"); diff --git a/Tests/unit/core/CMakeLists.txt b/Tests/unit/core/CMakeLists.txt index b18982d77..6a2e64dda 100644 --- a/Tests/unit/core/CMakeLists.txt +++ b/Tests/unit/core/CMakeLists.txt @@ -17,8 +17,8 @@ set(TEST_RUNNER_NAME "Thunder_test_core") - - +if(LINUX) + # IPTestAdministrator only supprt LINUX platform add_executable(${TEST_RUNNER_NAME} ../IPTestAdministrator.cpp #test_cyclicbuffer.cpp @@ -28,12 +28,12 @@ add_executable(${TEST_RUNNER_NAME} test_doorbell.cpp test_enumerate.cpp test_event.cpp - test_hex2strserialization.cpp test_filesystem.cpp test_frametype.cpp test_hash.cpp - test_ipcclient.cpp + test_hex2strserialization.cpp test_ipc.cpp + test_ipcclient.cpp test_iso639.cpp test_iterator.cpp test_jsonparser.cpp @@ -68,20 +68,70 @@ add_executable(${TEST_RUNNER_NAME} test_textfragment.cpp test_textreader.cpp test_thread.cpp +##### test_threadpool.cpp + test_time.cpp + test_timer.cpp + test_tristate.cpp + #test_valuerecorder.cpp +# test_weblinkjson.cpp +# test_weblinktext.cpp +# test_websocketjson.cpp +# test_websockettext.cpp +#### test_workerpool.cpp + test_xgetopt.cpp +) +else() +add_executable(${TEST_RUNNER_NAME} + test_databuffer.cpp + test_dataelement.cpp + test_dataelementfile.cpp + test_enumerate.cpp + test_event.cpp + test_filesystem.cpp + test_frametype.cpp + test_hash.cpp + test_hex2strserialization.cpp + test_iso639.cpp + test_iterator.cpp + test_jsonparser.cpp + test_keyvalue.cpp + test_library.cpp + test_lockablecontainer.cpp + test_measurementtype.cpp + test_memberavailability.cpp +# test_message_dispatcher.cpp + test_messageException.cpp + test_networkinfo.cpp + test_nodeid.cpp + test_numbertype.cpp + test_optional.cpp + test_parser.cpp + test_portability.cpp + test_processinfo.cpp + test_queue.cpp + test_rangetype.cpp + test_readwritelock.cpp + test_rectangle.cpp + test_semaphore.cpp + test_singleton.cpp + test_statetrigger.cpp + test_stopwatch.cpp + test_synchronize.cpp + test_systeminfo.cpp + test_textfragment.cpp + test_textreader.cpp + test_thread.cpp test_threadpool.cpp test_time.cpp test_timer.cpp test_tristate.cpp #test_valuerecorder.cpp - test_weblinkjson.cpp - test_weblinktext.cpp - test_websocketjson.cpp - test_websockettext.cpp test_workerpool.cpp test_xgetopt.cpp - test_message_dispatcher.cpp ) - +endif() + + #[[ if(MESSAGING) target_sources(${TEST_RUNNER_NAME} PRIVATE test_message_unit.cpp) target_link_libraries(${TEST_RUNNER_NAME} diff --git a/Tests/unit/core/test_doorbell.cpp b/Tests/unit/core/test_doorbell.cpp index 4b8aed5de..b1ff6f4d1 100644 --- a/Tests/unit/core/test_doorbell.cpp +++ b/Tests/unit/core/test_doorbell.cpp @@ -33,74 +33,86 @@ namespace Core { TEST(Core_DoorBell, simpleSet) { - std::string fileName {"/tmp/doorbell01"}; - auto lambdaFunc = [fileName] (IPTestAdministrator & testAdmin) { + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + + const std::string fileName {"/tmp/doorbell01"}; + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { ::Thunder::Core::DoorBell doorBell(fileName.c_str()); - EXPECT_EQ(doorBell.Wait(::Thunder::Core::infinite), ::Thunder::Core::ERROR_NONE); - if (doorBell.Wait(::Thunder::Core::infinite) == ::Thunder::Core::ERROR_NONE) { - doorBell.Acknowledge(); - testAdmin.Sync("First ring"); - } - - EXPECT_EQ(doorBell.Wait(::Thunder::Core::infinite), ::Thunder::Core::ERROR_NONE); - if (doorBell.Wait(::Thunder::Core::infinite) == ::Thunder::Core::ERROR_NONE) { - doorBell.Acknowledge(); - testAdmin.Sync("Second ring"); - } + ASSERT_EQ(doorBell.Wait(::Thunder::Core::infinite), ::Thunder::Core::ERROR_NONE); + + doorBell.Acknowledge(); + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(doorBell.Wait(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + doorBell.Acknowledge(); + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + doorBell.Relinquish(); }; - static std::function lambdaVar = lambdaFunc; + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + // a small delay so the child can be set up + SleepMs(maxInitTime); - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; - - IPTestAdministrator testAdmin(otherSide); - { ::Thunder::Core::DoorBell doorBell(fileName.c_str()); - ::SleepMs(10); + doorBell.Ring(); - testAdmin.Sync("First ring"); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + doorBell.Ring(); - testAdmin.Sync("Second ring"); - } + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); + + // Code after this line is executed by both parent and child + ::Thunder::Core::Singleton::Dispose(); } TEST(Core_DoorBell, simpleSetReversed) { - + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; - std::string fileName {"/tmp/doorbell02"}; - auto lambdaFunc = [fileName] (IPTestAdministrator & testAdmin) { + const std::string fileName {"/tmp/doorbell02"}; + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { ::Thunder::Core::DoorBell doorBell(fileName.c_str()); - ::SleepMs(10); + + // A small delay so the child can be set up + SleepMs(maxInitTime); + doorBell.Ring(); - testAdmin.Sync("First ring"); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + doorBell.Ring(); - testAdmin.Sync("Second ring"); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); }; - static std::function lambdaVar = lambdaFunc; + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + ::Thunder::Core::DoorBell doorBell(fileName.c_str()); - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; + ASSERT_EQ(doorBell.Wait(::Thunder::Core::infinite), ::Thunder::Core::ERROR_NONE); + doorBell.Acknowledge(); + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(doorBell.Wait(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + doorBell.Acknowledge(); + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - IPTestAdministrator testAdmin(otherSide); - { - ::Thunder::Core::DoorBell doorBell(fileName.c_str()); - EXPECT_EQ(doorBell.Wait(::Thunder::Core::infinite), ::Thunder::Core::ERROR_NONE); - if (doorBell.Wait(::Thunder::Core::infinite) == ::Thunder::Core::ERROR_NONE) { - doorBell.Acknowledge(); - testAdmin.Sync("First ring"); - } - - EXPECT_EQ(doorBell.Wait(::Thunder::Core::infinite), ::Thunder::Core::ERROR_NONE); - if (doorBell.Wait(::Thunder::Core::infinite) == ::Thunder::Core::ERROR_NONE) { - doorBell.Acknowledge(); - testAdmin.Sync("Second ring"); - } doorBell.Relinquish(); - } + }; + + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); + + // Code after this line is executed by both parent and child + ::Thunder::Core::Singleton::Dispose(); } diff --git a/Tests/unit/core/test_ipc.cpp b/Tests/unit/core/test_ipc.cpp index 52299d591..d8c1cc941 100644 --- a/Tests/unit/core/test_ipc.cpp +++ b/Tests/unit/core/test_ipc.cpp @@ -205,12 +205,14 @@ namespace Core { } }; - TEST(DISABLED_Core_IPC, ContinuousChannel) + TEST(Core_IPC, ContinuousChannel) { - std::string connector = _T("/tmp/testserver0"); - auto lambdaFunc = [connector](IPTestAdministrator & testAdmin) { + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + + const std::string connector = _T("/tmp/testserver0"); + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { ::Thunder::Core::NodeId continousNode(connector.c_str()); - uint32_t error; ::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> > factory(::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> >::Create()); @@ -218,6 +220,7 @@ namespace Core { factory->CreateFactory(2); factory->CreateFactory(2); + // Listening with no internal factory ::Thunder::Core::IPCChannelClientType<::Thunder::Core::Void, true, false> continousChannel(continousNode, 32, factory); ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler1(::Thunder::Core::ProxyType::Create()); @@ -228,32 +231,35 @@ namespace Core { continousChannel.Register(VoidTriplet::Id(), handler2); continousChannel.Register(TextText::Id(), handler3); - error = continousChannel.Source().Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(continousChannel.Source().Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); - testAdmin.Sync("setup server"); - testAdmin.Sync("setup client"); - testAdmin.Sync("done testing"); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - error = continousChannel.Source().Close(1000); // Wait for 1 second - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); continousChannel.Unregister(TripletResponse::Id()); continousChannel.Unregister(VoidTriplet::Id()); continousChannel.Unregister(TextText::Id()); - factory->DestroyFactories(); - }; + handler1.Release(); + handler2.Release(); + handler3.Release(); - static std::function lambdaVar = lambdaFunc; + factory->DestroyFactory(); + factory->DestroyFactory(); + factory->DestroyFactory(); + + // Only for internal factories +// factory->DestroyFactories(); + + EXPECT_EQ(continousChannel.Source().Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + }; - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + // A small delay so the child can be set up + SleepMs(maxInitTime); - IPTestAdministrator testAdmin(otherSide); - { ::Thunder::Core::NodeId continousNode(connector.c_str()); - uint32_t error; - - testAdmin.Sync("setup server"); ::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> > factory(::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> >::Create()); @@ -261,59 +267,64 @@ namespace Core { factory->CreateFactory(2); factory->CreateFactory(2); + // NOT listening with no internal factory ::Thunder::Core::IPCChannelClientType<::Thunder::Core::Void, false, false> continousChannel(continousNode, 32, factory); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler1(::Thunder::Core::ProxyType::Create()); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler2(::Thunder::Core::ProxyType::Create()); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler3(::Thunder::Core::ProxyType::Create()); - - error = continousChannel.Source().Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - - testAdmin.Sync("setup client"); + ASSERT_EQ(continousChannel.Source().Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); ::Thunder::Core::ProxyType tripletResponseData(::Thunder::Core::ProxyType::Create(Triplet(1, 2, 3))); ::Thunder::Core::ProxyType voidTripletData(::Thunder::Core::ProxyType::Create()); - string text = "test text"; + + const string text = "test text"; ::Thunder::Core::ProxyType textTextData(::Thunder::Core::ProxyType::Create(::Thunder::Core::IPC::Text<2048>(text))); - uint16_t display = 1;; - uint32_t surface = 2; - uint64_t context = 3; - uint32_t result = 6; + constexpr uint16_t display = 1;; + constexpr uint32_t surface = 2; + constexpr uint64_t context = 3; + constexpr uint32_t result = 6; - error = continousChannel.Invoke(tripletResponseData, 2000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + EXPECT_EQ(continousChannel.Invoke(tripletResponseData, maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(tripletResponseData->Response().Result(), result); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - error = continousChannel.Invoke(voidTripletData, 2000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + EXPECT_EQ(continousChannel.Invoke(voidTripletData, maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(voidTripletData->Response().Display(), display); EXPECT_EQ(voidTripletData->Response().Surface(), surface); EXPECT_EQ(voidTripletData->Response().Context(), context); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - error = continousChannel.Invoke(textTextData, 2000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + EXPECT_EQ(continousChannel.Invoke(textTextData, maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); EXPECT_STREQ(textTextData->Response().Value(), text.c_str()); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - error = continousChannel.Source().Close(1000); // Wait for 1 second - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + factory->DestroyFactory(); + factory->DestroyFactory(); + factory->DestroyFactory(); + + // Only for internal factories +// factory->DestroyFactories(); + + ASSERT_EQ(continousChannel.Source().Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + }; - factory->DestroyFactories(); + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); - ::Thunder::Core::Singleton::Dispose(); - } - testAdmin.Sync("done testing"); + // Code after this line is executed by both parent and child + + ::Thunder::Core::Singleton::Dispose(); } TEST(Core_IPC, ContinuousChannelReversed) { - std::string connector = _T("/tmp/testserver1"); - auto lambdaFunc = [connector](IPTestAdministrator & testAdmin) { - ::Thunder::Core::NodeId continousNode(connector.c_str()); - uint32_t error; + const std::string connector = _T("/tmp/testserver1"); + + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; - testAdmin.Sync("setup client"); + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { + // A small delay so the parent can be set up + SleepMs(maxInitTime); + + ::Thunder::Core::NodeId continousNode(connector.c_str()); ::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> > factory(::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> >::Create()); @@ -321,60 +332,48 @@ namespace Core { factory->CreateFactory(2); factory->CreateFactory(2); + // NOT listening with no factory ::Thunder::Core::IPCChannelClientType<::Thunder::Core::Void, false, false> continousChannel(continousNode, 32, factory); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler1(::Thunder::Core::ProxyType::Create()); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler2(::Thunder::Core::ProxyType::Create()); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler3(::Thunder::Core::ProxyType::Create()); - - error = continousChannel.Source().Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - - - testAdmin.Sync("setup server"); + ASSERT_EQ(continousChannel.Source().Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); ::Thunder::Core::ProxyType tripletResponseData(::Thunder::Core::ProxyType::Create(Triplet(1, 2, 3))); ::Thunder::Core::ProxyType voidTripletData(::Thunder::Core::ProxyType::Create()); - string text = "test text"; + + const string text = "test text"; ::Thunder::Core::ProxyType textTextData(::Thunder::Core::ProxyType::Create(::Thunder::Core::IPC::Text<2048>(text))); - uint16_t display = 1;; - uint32_t surface = 2; - uint64_t context = 3; - uint32_t result = 6; + constexpr uint16_t display = 1;; + constexpr uint32_t surface = 2; + constexpr uint64_t context = 3; + constexpr uint32_t result = 6; - error = continousChannel.Invoke(tripletResponseData, 5000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + EXPECT_EQ(continousChannel.Invoke(tripletResponseData, maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(tripletResponseData->Response().Result(), result); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - error = continousChannel.Invoke(voidTripletData, 2000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + EXPECT_EQ(continousChannel.Invoke(voidTripletData, maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(voidTripletData->Response().Display(), display); EXPECT_EQ(voidTripletData->Response().Surface(), surface); EXPECT_EQ(voidTripletData->Response().Context(), context); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - error = continousChannel.Invoke(textTextData, 2000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + EXPECT_EQ(continousChannel.Invoke(textTextData, maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); EXPECT_STREQ(textTextData->Response().Value(), text.c_str()); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - error = continousChannel.Source().Close(1000); // Wait for 1 second - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - - factory->DestroyFactories(); + factory->DestroyFactory(); + factory->DestroyFactory(); + factory->DestroyFactory(); - ::Thunder::Core::Singleton::Dispose(); + // Only for internal factories +// factory->DestroyFactories(); - testAdmin.Sync("done testing"); + EXPECT_EQ(continousChannel.Source().Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); }; - static std::function lambdaVar = lambdaFunc; - - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; - - IPTestAdministrator testAdmin(otherSide); - { + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { ::Thunder::Core::NodeId continousNode(connector.c_str()); - uint32_t error; ::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> > factory(::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> >::Create()); @@ -382,6 +381,7 @@ namespace Core { factory->CreateFactory(2); factory->CreateFactory(2); + // Listening with no internal factory ::Thunder::Core::IPCChannelClientType<::Thunder::Core::Void, true, false> continousChannel(continousNode, 32, factory); ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler1(::Thunder::Core::ProxyType::Create()); @@ -392,32 +392,45 @@ namespace Core { continousChannel.Register(VoidTriplet::Id(), handler2); continousChannel.Register(TextText::Id(), handler3); - error = continousChannel.Source().Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - - testAdmin.Sync("setup client"); - testAdmin.Sync("setup server"); - testAdmin.Sync("done testing"); + EXPECT_EQ(continousChannel.Source().Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); - error = continousChannel.Source().Close(1000); // Wait for 1 second - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); continousChannel.Unregister(TripletResponse::Id()); continousChannel.Unregister(VoidTriplet::Id()); continousChannel.Unregister(TextText::Id()); - factory->DestroyFactories(); + handler1.Release(); + handler2.Release(); + handler3.Release(); - ::Thunder::Core::Singleton::Dispose(); - } + factory->DestroyFactory(); + factory->DestroyFactory(); + factory->DestroyFactory(); + + // Only for internal factories +// factory->DestroyFactories(); + + EXPECT_EQ(continousChannel.Source().Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); + + // Code after this line is executed by both parent and child + + ::Thunder::Core::Singleton::Dispose(); } - TEST(DISABLED_Core_IPC, FlashChannel) + TEST(Core_IPC, FlashChannel) { - std::string connector = _T("/tmp/testserver2"); - auto lambdaFunc = [connector](IPTestAdministrator & testAdmin) { + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxInitTime = 2000; + + const std::string connector = _T("/tmp/testserver2"); + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { ::Thunder::Core::NodeId flashNode(connector.c_str()); - uint32_t error; ::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> > factory(::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> >::Create()); @@ -425,6 +438,7 @@ namespace Core { factory->CreateFactory(2); factory->CreateFactory(2); + // Listening with no internal factory ::Thunder::Core::IPCChannelClientType<::Thunder::Core::Void, true, false> flashChannel(flashNode, 512, factory); ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler1(::Thunder::Core::ProxyType::Create()); @@ -435,32 +449,35 @@ namespace Core { flashChannel.Register(VoidTriplet::Id(), handler2); flashChannel.Register(TextText::Id(), handler3); - error = flashChannel.Source().Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(flashChannel.Source().Open(maxWaitTime), ::Thunder::Core::ERROR_NONE); - testAdmin.Sync("setup server"); - testAdmin.Sync("setup client"); - testAdmin.Sync("done testing"); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - error = flashChannel.Source().Close(1000); // Wait for 1 Second - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); flashChannel.Unregister(TripletResponse::Id()); flashChannel.Unregister(VoidTriplet::Id()); flashChannel.Unregister(TextText::Id()); - factory->DestroyFactories(); - }; + handler1.Release(); + handler2.Release(); + handler3.Release(); + + factory->DestroyFactory(); + factory->DestroyFactory(); + factory->DestroyFactory(); - static std::function lambdaVar = lambdaFunc; + // Only for internal factories +// factory->DestroyFactories(); - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; + EXPECT_EQ(flashChannel.Source().Close(maxWaitTime), ::Thunder::Core::ERROR_NONE); + }; - IPTestAdministrator testAdmin(otherSide); - { - ::Thunder::Core::NodeId flashNode(connector.c_str()); - uint32_t error; + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + // A small delay so the child can be set up + SleepMs(maxInitTime); - testAdmin.Sync("setup server"); + ::Thunder::Core::NodeId flashNode(connector.c_str()); ::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> > factory(::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> >::Create()); @@ -468,63 +485,64 @@ namespace Core { factory->CreateFactory(2); factory->CreateFactory(2); + // NOT listening with no internal factory ::Thunder::Core::IPCChannelClientType<::Thunder::Core::Void, false, false> flashChannel(flashNode, 512, factory); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler1(::Thunder::Core::ProxyType::Create()); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler2(::Thunder::Core::ProxyType::Create()); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler3(::Thunder::Core::ProxyType::Create()); - - testAdmin.Sync("setup client"); + ASSERT_EQ(flashChannel.Source().Open(maxWaitTime), ::Thunder::Core::ERROR_NONE); ::Thunder::Core::ProxyType tripletResponseData(::Thunder::Core::ProxyType::Create(Triplet(1, 2, 3))); ::Thunder::Core::ProxyType voidTripletData(::Thunder::Core::ProxyType::Create()); - string text = "test text"; + + const string text = "test text"; ::Thunder::Core::ProxyType textTextData(::Thunder::Core::ProxyType::Create(::Thunder::Core::IPC::Text<2048>(text))); - uint16_t display = 1;; - uint32_t surface = 2; - uint64_t context = 3; - uint32_t result = 6; + constexpr uint16_t display = 1;; + constexpr uint32_t surface = 2; + constexpr uint64_t context = 3; + constexpr uint32_t result = 6; - error = flashChannel.Source().Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - error = flashChannel.Invoke(tripletResponseData, 2000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + EXPECT_EQ(flashChannel.Invoke(tripletResponseData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(tripletResponseData->Response().Result(), result); - error = flashChannel.Source().Close(1000); // Wait for 1 Second - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - error = flashChannel.Source().Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - error = flashChannel.Invoke(voidTripletData, 2000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + EXPECT_EQ(flashChannel.Invoke(voidTripletData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(voidTripletData->Response().Display(), display); EXPECT_EQ(voidTripletData->Response().Surface(), surface); EXPECT_EQ(voidTripletData->Response().Context(), context); - error = flashChannel.Source().Close(1000); // Wait for 1 Second - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - error = flashChannel.Source().Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - error = flashChannel.Invoke(textTextData, 2000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + EXPECT_EQ(flashChannel.Invoke(textTextData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_STREQ(textTextData->Response().Value(), text.c_str()); - error = flashChannel.Source().Close(1000); // Wait for 1 Second - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - factory->DestroyFactories(); - ::Thunder::Core::Singleton::Dispose(); - } + factory->DestroyFactory(); + factory->DestroyFactory(); + factory->DestroyFactory(); + + // Only for internal factories +// factory->DestroyFactories(); + + ASSERT_EQ(flashChannel.Source().Close(maxWaitTime), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); - testAdmin.Sync("done testing"); + // Code after this line is executed by both parent and child + + ::Thunder::Core::Singleton::Dispose(); } - TEST(DISABLED_Core_IPC, FlashChannelReversed) + TEST(Core_IPC, FlashChannelReversed) { - std::string connector = _T("/tmp/testserver3"); - auto lambdaFunc = [connector](IPTestAdministrator & testAdmin) { + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxInitTime = 2000; + + const std::string connector = _T("/tmp/testserver3"); + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { + // A small delay so the parent can be set up + SleepMs(maxInitTime); + ::Thunder::Core::NodeId flashNode(connector.c_str()); - uint32_t error; ::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> > factory(::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> >::Create()); @@ -532,42 +550,48 @@ namespace Core { factory->CreateFactory(2); factory->CreateFactory(2); - ::Thunder::Core::IPCChannelClientType<::Thunder::Core::Void, true, false> flashChannel(flashNode, 512, factory); + // NOT listening with no internal factory + ::Thunder::Core::IPCChannelClientType<::Thunder::Core::Void, false, false> flashChannel(flashNode, 512, factory); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler1(::Thunder::Core::ProxyType::Create()); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler2(::Thunder::Core::ProxyType::Create()); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler3(::Thunder::Core::ProxyType::Create()); + ASSERT_EQ(flashChannel.Source().Open(maxWaitTime), ::Thunder::Core::ERROR_NONE); - flashChannel.Register(TripletResponse::Id(), handler1); - flashChannel.Register(VoidTriplet::Id(), handler2); - flashChannel.Register(TextText::Id(), handler3); + ::Thunder::Core::ProxyType tripletResponseData(::Thunder::Core::ProxyType::Create(Triplet(1, 2, 3))); + ::Thunder::Core::ProxyType voidTripletData(::Thunder::Core::ProxyType::Create()); - error = flashChannel.Source().Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + const string text = "test text"; + ::Thunder::Core::ProxyType textTextData(::Thunder::Core::ProxyType::Create(::Thunder::Core::IPC::Text<2048>(text))); - testAdmin.Sync("setup server"); - testAdmin.Sync("setup client"); - testAdmin.Sync("done testing"); + constexpr uint16_t display = 1;; + constexpr uint32_t surface = 2; + constexpr uint64_t context = 3; + constexpr uint32_t result = 6; - error = flashChannel.Source().Close(1000); // Wait for 1 Second - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - flashChannel.Unregister(TripletResponse::Id()); - flashChannel.Unregister(VoidTriplet::Id()); - flashChannel.Unregister(TextText::Id()); + EXPECT_EQ(flashChannel.Invoke(tripletResponseData, maxWaitTime), ::Thunder::Core::ERROR_NONE); + EXPECT_EQ(tripletResponseData->Response().Result(), result); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - factory->DestroyFactories(); - }; + EXPECT_EQ(flashChannel.Invoke(voidTripletData, maxWaitTime), ::Thunder::Core::ERROR_NONE); + EXPECT_EQ(voidTripletData->Response().Display(), display); + EXPECT_EQ(voidTripletData->Response().Surface(), surface); + EXPECT_EQ(voidTripletData->Response().Context(), context); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - static std::function lambdaVar = lambdaFunc; + EXPECT_EQ(flashChannel.Invoke(textTextData, maxWaitTime), ::Thunder::Core::ERROR_NONE); + EXPECT_STREQ(textTextData->Response().Value(), text.c_str()); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; + factory->DestroyFactory(); + factory->DestroyFactory(); + factory->DestroyFactory(); - IPTestAdministrator testAdmin(otherSide); - { - ::Thunder::Core::NodeId flashNode(connector.c_str()); - uint32_t error; + // Only for internal factories +// factory->DestroyFactories(); - testAdmin.Sync("setup server"); + ASSERT_EQ(flashChannel.Source().Close(maxWaitTime), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + ::Thunder::Core::NodeId flashNode(connector.c_str()); ::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> > factory(::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> >::Create()); @@ -575,62 +599,56 @@ namespace Core { factory->CreateFactory(2); factory->CreateFactory(2); - ::Thunder::Core::IPCChannelClientType<::Thunder::Core::Void, false, false> flashChannel(flashNode, 512, factory); + // Listening with no internal factory + ::Thunder::Core::IPCChannelClientType<::Thunder::Core::Void, true, false> flashChannel(flashNode, 512, factory); ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler1(::Thunder::Core::ProxyType::Create()); ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler2(::Thunder::Core::ProxyType::Create()); ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler3(::Thunder::Core::ProxyType::Create()); - testAdmin.Sync("setup client"); + flashChannel.Register(TripletResponse::Id(), handler1); + flashChannel.Register(VoidTriplet::Id(), handler2); + flashChannel.Register(TextText::Id(), handler3); - ::Thunder::Core::ProxyType tripletResponseData(::Thunder::Core::ProxyType::Create(Triplet(1, 2, 3))); - ::Thunder::Core::ProxyType voidTripletData(::Thunder::Core::ProxyType::Create()); - string text = "test text"; - ::Thunder::Core::ProxyType textTextData(::Thunder::Core::ProxyType::Create(::Thunder::Core::IPC::Text<2048>(text))); + ASSERT_EQ(flashChannel.Source().Open(maxWaitTime), ::Thunder::Core::ERROR_NONE); - uint16_t display = 1;; - uint32_t surface = 2; - uint64_t context = 3; - uint32_t result = 6; + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - error = flashChannel.Source().Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - error = flashChannel.Invoke(tripletResponseData, 2000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - EXPECT_EQ(tripletResponseData->Response().Result(), result); - error = flashChannel.Source().Close(1000); // Wait for 1 Second - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + flashChannel.Unregister(TripletResponse::Id()); + flashChannel.Unregister(VoidTriplet::Id()); + flashChannel.Unregister(TextText::Id()); - error = flashChannel.Source().Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - error = flashChannel.Invoke(voidTripletData, 2000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - EXPECT_EQ(voidTripletData->Response().Display(), display); - EXPECT_EQ(voidTripletData->Response().Surface(), surface); - EXPECT_EQ(voidTripletData->Response().Context(), context); - error = flashChannel.Source().Close(1000); // Wait for 1 Second - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + handler1.Release(); + handler2.Release(); + handler3.Release(); - error = flashChannel.Source().Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - error = flashChannel.Invoke(textTextData, 2000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - EXPECT_STREQ(textTextData->Response().Value(), text.c_str()); - error = flashChannel.Source().Close(1000); // Wait for 1 Second - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + factory->DestroyFactory(); + factory->DestroyFactory(); + factory->DestroyFactory(); - factory->DestroyFactories(); - ::Thunder::Core::Singleton::Dispose(); - } - testAdmin.Sync("done testing"); + // Only for internal factories +// factory->DestroyFactories(); + + EXPECT_EQ(flashChannel.Source().Close(maxWaitTime), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); + + // Code after this line is executed by both parent and child + + ::Thunder::Core::Singleton::Dispose(); } TEST(Core_IPC, MultiChannel) { - std::string connector = _T("/tmp/testserver4"); - auto lambdaFunc = [connector](IPTestAdministrator & testAdmin) { + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxInitTime = 2000; + + const std::string connector = _T("/tmp/testserver4"); + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { ::Thunder::Core::NodeId multiNode(connector.c_str()); - uint32_t error; ::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> > factory(::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> >::Create()); @@ -638,6 +656,7 @@ namespace Core { factory->CreateFactory(2); factory->CreateFactory(2); + // Server (always listening) with no internal factory ::Thunder::Core::IPCChannelServerType<::Thunder::Core::Void, false> multiChannel(multiNode, 512, factory); ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler1(::Thunder::Core::ProxyType::Create()); @@ -648,31 +667,41 @@ namespace Core { multiChannel.Register(VoidTriplet::Id(), handler2); multiChannel.Register(TextText::Id(), handler3); - error = multiChannel.Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(multiChannel.Open(maxWaitTime), ::Thunder::Core::ERROR_NONE); - testAdmin.Sync("setup server"); - testAdmin.Sync("setup client"); - testAdmin.Sync("done testing"); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - error = multiChannel.Close(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + multiChannel.Unregister(TripletResponse::Id()); + multiChannel.Unregister(VoidTriplet::Id()); + multiChannel.Unregister(TextText::Id()); - factory->DestroyFactories(); + handler1.Release(); + handler2.Release(); + handler3.Release(); - ::Thunder::Core::Singleton::Dispose(); - }; + factory->DestroyFactory(); + factory->DestroyFactory(); + factory->DestroyFactory(); - static std::function lambdaVar = lambdaFunc; + // Only for internal factories +// factory->DestroyFactories(); + + // A server cannot 'end' its life if clients are connected + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; + // Do not unregister any / the last handler prior the call of cleanup + multiChannel.Cleanup(); - IPTestAdministrator testAdmin(otherSide); - { - ::Thunder::Core::NodeId multiNode(connector.c_str()); - uint32_t error; + ASSERT_EQ(multiChannel.Close(maxWaitTime), ::Thunder::Core::ERROR_NONE); + }; - testAdmin.Sync("setup server"); + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + // A small delay so the child can be set up + SleepMs(maxInitTime); + + ::Thunder::Core::NodeId multiNode(connector.c_str()); ::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> > factory(::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> >::Create()); @@ -680,171 +709,171 @@ namespace Core { factory->CreateFactory(2); factory->CreateFactory(2); + // (Server client) NOT listening with no internal factory ::Thunder::Core::IPCChannelClientType<::Thunder::Core::Void, false, false> multiChannel(multiNode, 512, factory); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler1(::Thunder::Core::ProxyType::Create()); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler2(::Thunder::Core::ProxyType::Create()); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler3(::Thunder::Core::ProxyType::Create()); - - error = multiChannel.Source().Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - - testAdmin.Sync("setup client"); + ASSERT_EQ(multiChannel.Source().Open(maxWaitTime), ::Thunder::Core::ERROR_NONE); ::Thunder::Core::ProxyType tripletResponseData(::Thunder::Core::ProxyType::Create(Triplet(1, 2, 3))); ::Thunder::Core::ProxyType voidTripletData(::Thunder::Core::ProxyType::Create()); - string text = "test text"; + + const string text = "test text"; ::Thunder::Core::ProxyType textTextData(::Thunder::Core::ProxyType::Create(::Thunder::Core::IPC::Text<2048>(text))); - uint16_t display = 1;; - uint32_t surface = 2; - uint64_t context = 3; - uint32_t result = 6; + constexpr uint16_t display = 1;; + constexpr uint32_t surface = 2; + constexpr uint64_t context = 3; + constexpr uint32_t result = 6; - error = multiChannel.Invoke(tripletResponseData, 2000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + EXPECT_EQ(multiChannel.Invoke(tripletResponseData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(tripletResponseData->Response().Result(), result); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - error = multiChannel.Invoke(voidTripletData, 2000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + EXPECT_EQ(multiChannel.Invoke(voidTripletData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(voidTripletData->Response().Display(), display); EXPECT_EQ(voidTripletData->Response().Surface(), surface); EXPECT_EQ(voidTripletData->Response().Context(), context); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - error = multiChannel.Invoke(textTextData, 2000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + EXPECT_EQ(multiChannel.Invoke(textTextData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_STREQ(textTextData->Response().Value(), text.c_str()); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + + factory->DestroyFactory(); + factory->DestroyFactory(); + factory->DestroyFactory(); - error = multiChannel.Source().Close(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + // Only for internal factories +// factory->DestroyFactories(); - factory->DestroyFactories(); + ASSERT_EQ(multiChannel.Source().Close(maxWaitTime), ::Thunder::Core::ERROR_NONE); - ::Thunder::Core::Singleton::Dispose(); - } -// testAdmin.Sync("done testing"); + // Signal the server it can 'end' its life + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); + + // Code after this line is executed by both parent and child + + ::Thunder::Core::Singleton::Dispose(); } TEST(Core_IPC, MultiChannelReversed) { - std::string connector = _T("/tmp/testserver5"); - auto lambdaFunc = [connector](IPTestAdministrator & testAdmin) { - ::Thunder::Core::NodeId multiNode(connector.c_str()); - uint32_t error; + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxInitTime = 2000; - testAdmin.Sync("setup client"); + const std::string connector = _T("/tmp/testserver5"); + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { + // A small delay so the parent can be set up + SleepMs(maxInitTime); + + ::Thunder::Core::NodeId multiNode(connector.c_str()); ::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> > factory(::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> >::Create()); + factory->CreateFactory(2); factory->CreateFactory(2); factory->CreateFactory(2); + // (Server client) NOT listening with no internal factory ::Thunder::Core::IPCChannelClientType<::Thunder::Core::Void, false, false> multiChannel(multiNode, 512, factory); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler1(::Thunder::Core::ProxyType::Create()); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler2(::Thunder::Core::ProxyType::Create()); - ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler3(::Thunder::Core::ProxyType::Create()); - - error = multiChannel.Source().Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - - testAdmin.Sync("setup server"); + ASSERT_EQ(multiChannel.Source().Open(maxWaitTime), ::Thunder::Core::ERROR_NONE); ::Thunder::Core::ProxyType tripletResponseData(::Thunder::Core::ProxyType::Create(Triplet(1, 2, 3))); ::Thunder::Core::ProxyType voidTripletData(::Thunder::Core::ProxyType::Create()); - string text = "test text"; + + const string text = "test text"; ::Thunder::Core::ProxyType textTextData(::Thunder::Core::ProxyType::Create(::Thunder::Core::IPC::Text<2048>(text))); - uint16_t display = 1;; - uint32_t surface = 2; - uint64_t context = 3; - uint32_t result = 6; - error = multiChannel.Invoke(tripletResponseData, 5000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + constexpr uint16_t display = 1;; + constexpr uint32_t surface = 2; + constexpr uint64_t context = 3; + constexpr uint32_t result = 6; + + EXPECT_EQ(multiChannel.Invoke(tripletResponseData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(tripletResponseData->Response().Result(), result); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - error = multiChannel.Invoke(voidTripletData, 2000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + EXPECT_EQ(multiChannel.Invoke(voidTripletData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(voidTripletData->Response().Display(), display); EXPECT_EQ(voidTripletData->Response().Surface(), surface); EXPECT_EQ(voidTripletData->Response().Context(), context); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - error = multiChannel.Invoke(textTextData, 2000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + EXPECT_EQ(multiChannel.Invoke(textTextData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_STREQ(textTextData->Response().Value(), text.c_str()); - - tripletResponseData.Release(); - voidTripletData.Release(); - textTextData.Release(); - - error = multiChannel.Source().Close(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - - handler1.Release(); - handler2.Release(); - handler3.Release(); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); factory->DestroyFactory(); factory->DestroyFactory(); factory->DestroyFactory(); - factory->DestroyFactories(); + // Only for internal factories +// factory->DestroyFactories(); - ::Thunder::Core::Singleton::Dispose(); + ASSERT_EQ(multiChannel.Source().Close(maxWaitTime), ::Thunder::Core::ERROR_NONE); - testAdmin.Sync("done testing"); + // Signal the server it can 'end' its life + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); }; - static std::function lambdaVar = lambdaFunc; - - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; - - IPTestAdministrator testAdmin(otherSide); - { + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { ::Thunder::Core::NodeId multiNode(connector.c_str()); - uint32_t error; ::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> > factory(::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> >::Create()); + factory->CreateFactory(2); factory->CreateFactory(2); factory->CreateFactory(2); + // Server (always listening) with no internal factory ::Thunder::Core::IPCChannelServerType<::Thunder::Core::Void, false> multiChannel(multiNode, 512, factory); ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler1(::Thunder::Core::ProxyType::Create()); ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler2(::Thunder::Core::ProxyType::Create()); ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer> handler3(::Thunder::Core::ProxyType::Create()); + ASSERT_EQ(multiChannel.Open(maxWaitTime), ::Thunder::Core::ERROR_NONE); + multiChannel.Register(TripletResponse::Id(), handler1); multiChannel.Register(VoidTriplet::Id(), handler2); multiChannel.Register(TextText::Id(), handler3); - error = multiChannel.Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - - testAdmin.Sync("setup client"); - testAdmin.Sync("setup server"); - testAdmin.Sync("done testing"); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - error = multiChannel.Close(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + multiChannel.Unregister(TripletResponse::Id()); + multiChannel.Unregister(VoidTriplet::Id()); + multiChannel.Unregister(TextText::Id()); handler1.Release(); handler2.Release(); handler3.Release(); - multiChannel.Cleanup(); - factory->DestroyFactory(); factory->DestroyFactory(); factory->DestroyFactory(); - factory->DestroyFactories(); + // Only for internal factories +// factory->DestroyFactories(); - ::Thunder::Core::Singleton::Dispose(); + // A server cannot 'end' its life if clients are connected + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); -// testAdmin.Sync("done testing"); - } + multiChannel.Cleanup(); + + ASSERT_EQ(multiChannel.Close(maxWaitTime), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); + + // Code after this line is executed by both parent and child + + ::Thunder::Core::Singleton::Dispose(); } } // Core diff --git a/Tests/unit/core/test_ipcclient.cpp b/Tests/unit/core/test_ipcclient.cpp index 66298e695..fa7a4a91b 100644 --- a/Tests/unit/core/test_ipcclient.cpp +++ b/Tests/unit/core/test_ipcclient.cpp @@ -33,53 +33,57 @@ namespace Core { TEST(Core_IPC, IPCClientConnection) { - std::string connector = _T("/tmp/testserver"); + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; - auto lambdaFunc = [connector](IPTestAdministrator & testAdmin) { - ::Thunder::Core::NodeId serverNode(connector.c_str()); + const std::string connector = _T("/tmp/testserver"); - uint32_t error; + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { + ::Thunder::Core::NodeId serverNode(connector.c_str()); ::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> > factory(::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> >::Create()); + ::Thunder::Core::IPCChannelServerType<::Thunder::Core::Void, false> serverChannel(serverNode, 512, factory); - error = serverChannel.Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - testAdmin.Sync("setup server"); - testAdmin.Sync("setup client"); - testAdmin.Sync("done testing"); + ASSERT_EQ(serverChannel.Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + // Only for internal factories +// factory->DestroyFactories(); - error = serverChannel.Close(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); + // A server cannot 'end' its life if clients are connected + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + // Do not unregister any / the last handler prior the call of cleanup serverChannel.Cleanup(); - factory->DestroyFactories(); + ASSERT_EQ(serverChannel.Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); }; - static std::function lambdaVar = lambdaFunc; + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + // A small delay so the child can be set up + SleepMs(maxInitTime); - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; - - IPTestAdministrator testAdmin(otherSide); - { ::Thunder::Core::NodeId clientNode(connector.c_str()); - uint32_t error; - - testAdmin.Sync("setup server"); ::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> > factory(::Thunder::Core::ProxyType<::Thunder::Core::FactoryType<::Thunder::Core::IIPC, uint32_t> >::Create()); + ::Thunder::Core::IPCChannelClientType<::Thunder::Core::Void, false, false> clientChannel(clientNode, 512, factory); - error = clientChannel.Source().Open(1000); // Wait for 1 Second. - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - testAdmin.Sync("setup client"); - - error = clientChannel.Close(1000); - EXPECT_EQ(error, ::Thunder::Core::ERROR_NONE); - factory->DestroyFactories(); - ::Thunder::Core::Singleton::Dispose(); - } - testAdmin.Sync("done testing"); + + ASSERT_EQ(clientChannel.Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + // Only for internal factories +// factory->DestroyFactories(); + + ASSERT_EQ(clientChannel.Source().Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + // Signal the server it can 'end' its life + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); + + // Code after this line is executed by both parent and child + + ::Thunder::Core::Singleton::Dispose(); } } // Core diff --git a/Tests/unit/core/test_rpc.cpp b/Tests/unit/core/test_rpc.cpp index c2fdf2d9e..b1dc737bc 100644 --- a/Tests/unit/core/test_rpc.cpp +++ b/Tests/unit/core/test_rpc.cpp @@ -221,7 +221,7 @@ namespace Exchange { public: ExternalAccess() = delete; ExternalAccess(const ExternalAccess &) = delete; - ExternalAccess & operator=(const ExternalAccess &) = delete; + ExternalAccess& operator=(const ExternalAccess &) = delete; ExternalAccess(const ::Thunder::Core::NodeId & source) : ::Thunder::RPC::Communicator(source, _T("")) @@ -251,59 +251,61 @@ namespace Exchange { TEST(Core_RPC, adder) { -#ifndef __APPLE__ - std::string connector{"/tmp/wperpc01"}; - auto lambdaFunc = [connector](IPTestAdministrator & testAdmin) { - ::Thunder::Core::NodeId remoteNode(connector.c_str()); + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; - ExternalAccess communicator(remoteNode); + const std::string connector{"/tmp/wperpc01"}; - testAdmin.Sync("setup server"); + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { + ::Thunder::Core::NodeId remoteNode(connector.c_str()); - testAdmin.Sync("done testing"); + ExternalAccess communicator(remoteNode); - communicator.Close(::Thunder::Core::infinite); - }; + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - static std::function lambdaVar = lambdaFunc; + EXPECT_EQ(communicator.Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + }; - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + // A small delay so the child can be set up + SleepMs(maxInitTime); - IPTestAdministrator testAdmin(otherSide); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - testAdmin.Sync("setup server"); + ::Thunder::Core::NodeId remoteNode(connector.c_str()); - { - ::Thunder::Core::NodeId remoteNode(connector.c_str()); + ::Thunder::Core::ProxyType<::Thunder::RPC::InvokeServerType<4, 0, 1>> engine = ::Thunder::Core::ProxyType<::Thunder::RPC::InvokeServerType<4, 0, 1>>::Create(); + ASSERT_TRUE(engine.IsValid()); - ::Thunder::Core::ProxyType<::Thunder::RPC::InvokeServerType<4, 0, 1>> engine = ::Thunder::Core::ProxyType<::Thunder::RPC::InvokeServerType<4, 0, 1>>::Create(); - EXPECT_TRUE(engine.IsValid()); - ::Thunder::Core::ProxyType<::Thunder::RPC::CommunicatorClient> client = ::Thunder::Core::ProxyType<::Thunder::RPC::CommunicatorClient>::Create(remoteNode, ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer>(engine)); - EXPECT_TRUE(client.IsValid()); + ::Thunder::Core::ProxyType<::Thunder::RPC::CommunicatorClient> client = ::Thunder::Core::ProxyType<::Thunder::RPC::CommunicatorClient>::Create(remoteNode, ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer>(engine)); + ASSERT_TRUE(client.IsValid()); - // Create remote instance of "Thunder::Tests::Core::Exchange::IAdder". - Thunder::Tests::Core::Exchange::IAdder * adder = client->Open(_T("Adder")); + // Create remote instance of "Thunder::Tests::Core::Exchange::IAdder". + Thunder::Tests::Core::Exchange::IAdder* adder = client->Open(_T("Adder")); + ASSERT_TRUE(adder != nullptr); - ASSERT_TRUE(adder != nullptr); + // Perform some arithmatic. + EXPECT_EQ(adder->GetValue(), static_cast(0)); + adder->Add(20); + EXPECT_EQ(adder->GetValue(), static_cast(20)); + adder->Add(22); + EXPECT_EQ(adder->GetValue(), static_cast(42)); - // Perform some arithmatic. - EXPECT_EQ(adder->GetValue(), static_cast(0)); - adder->Add(20); - EXPECT_EQ(adder->GetValue(), static_cast(20)); - adder->Add(22); - EXPECT_EQ(adder->GetValue(), static_cast(42)); + // Make sure other side is indeed running in other process. + EXPECT_NE(adder->GetPid(), static_cast(getpid())); - // Make sure other side is indeed running in other process. - EXPECT_NE(adder->GetPid(), (uint32_t)getpid()); + EXPECT_EQ(adder->Release(), ::Thunder::Core::ERROR_DESTRUCTION_SUCCEEDED); - adder->Release(); + ASSERT_EQ(client->Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); - client->Close(::Thunder::Core::infinite); - } + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + }; - testAdmin.Sync("done testing"); - ::Thunder::Core::Singleton::Dispose(); -#endif + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); + + // Code after this line is executed by both parent and child + + ::Thunder::Core::Singleton::Dispose(); } } // Core diff --git a/Tests/unit/core/test_socketstreamjson.cpp b/Tests/unit/core/test_socketstreamjson.cpp index 6441a3054..f1fd86cf3 100644 --- a/Tests/unit/core/test_socketstreamjson.cpp +++ b/Tests/unit/core/test_socketstreamjson.cpp @@ -224,46 +224,70 @@ namespace Core { TEST(Core_Socket, StreamJSON) { - std::string connector = "/tmp/wpestreamjson0"; - auto lambdaFunc = [connector](IPTestAdministrator & testAdmin) { + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + + const std::string connector = "/tmp/wpestreamjson0"; + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { ::Thunder::Core::SocketServerType> jsonSocketServer(::Thunder::Core::NodeId(connector.c_str())); - jsonSocketServer.Open(::Thunder::Core::infinite); - testAdmin.Sync("setup server"); + + ASSERT_EQ(jsonSocketServer.Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + std::unique_lock lk(JSONConnector<::Thunder::Core::JSON::IElement>::_mutex); + while (!JSONConnector<::Thunder::Core::JSON::IElement>::GetState()) { JSONConnector<::Thunder::Core::JSON::IElement>::_cv.wait(lk); } - testAdmin.Sync("client open"); - testAdmin.Sync("client done"); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(jsonSocketServer.Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); }; - static std::function lambdaVar = lambdaFunc; + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + // a small delay so the child can be set up + SleepMs(maxInitTime); - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - IPTestAdministrator testAdmin(otherSide); - testAdmin.Sync("setup server"); - { ::Thunder::Core::ProxyType sendObject = ::Thunder::Core::ProxyType::Create(); + ASSERT_TRUE(sendObject.IsValid()); + sendObject->Identifier = 1; sendObject->Name = _T("TestCase"); sendObject->Params.Duration = 100; + std::string sendString; - sendObject->ToString(sendString); + EXPECT_TRUE(sendObject->ToString(sendString)); JSONConnector<::Thunder::Core::JSON::IElement> jsonSocketClient(::Thunder::Core::NodeId(connector.c_str())); - jsonSocketClient.Open(::Thunder::Core::infinite); - testAdmin.Sync("client open"); + + ASSERT_EQ(jsonSocketClient.Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + jsonSocketClient.Submit(::Thunder::Core::ProxyType<::Thunder::Core::JSON::IElement>(sendObject)); - jsonSocketClient.Wait(); + + EXPECT_EQ(jsonSocketClient.Wait(), ::Thunder::Core::ERROR_NONE); + string received; jsonSocketClient.Retrieve(received); + EXPECT_STREQ(sendString.c_str(), received.c_str()); - jsonSocketClient.Close(::Thunder::Core::infinite); - testAdmin.Sync("client done"); - } - ::Thunder::Core::Singleton::Dispose(); + + EXPECT_EQ(jsonSocketClient.Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); + + // Code after this line is executed by both parent and child + + ::Thunder::Core::Singleton::Dispose(); } } // Core diff --git a/Tests/unit/core/test_socketstreamtext.cpp b/Tests/unit/core/test_socketstreamtext.cpp index 59fe3ed64..f0fd5f081 100644 --- a/Tests/unit/core/test_socketstreamtext.cpp +++ b/Tests/unit/core/test_socketstreamtext.cpp @@ -120,39 +120,57 @@ namespace Core { TEST(Core_Socket, StreamText) { - std::string connector {"/tmp/wpestreamtext0"}; + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; - auto lambdaFunc = [connector](IPTestAdministrator & testAdmin) { + const std::string connector {"/tmp/wpestreamtext0"}; + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { ::Thunder::Core::SocketServerType textSocketServer(::Thunder::Core::NodeId(connector.c_str())); - textSocketServer.Open(::Thunder::Core::infinite); - testAdmin.Sync("setup server"); + + ASSERT_EQ(textSocketServer.Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + std::unique_lock lk(TextConnector::_mutex); + while (!TextConnector::GetState()) { TextConnector::_cv.wait(lk); } - testAdmin.Sync("server open"); - testAdmin.Sync("client done"); + + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(textSocketServer.Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); }; - static std::function lambdaVar = lambdaFunc; + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + // a small delay so the child can be set up + SleepMs(maxInitTime); - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - IPTestAdministrator testAdmin(otherSide); - testAdmin.Sync("setup server"); - { TextConnector textSocketClient(::Thunder::Core::NodeId(connector.c_str())); - textSocketClient.Open(::Thunder::Core::infinite); - testAdmin.Sync("server open"); - string message = "hello"; + + ASSERT_EQ(textSocketClient.Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + const string message = "hello"; textSocketClient.Submit(message); - textSocketClient.Wait(); + EXPECT_EQ(textSocketClient.Wait(), ::Thunder::Core::ERROR_NONE); + string received; textSocketClient.Retrieve(received); + EXPECT_STREQ(message.c_str(), received.c_str()); - textSocketClient.Close(::Thunder::Core::infinite); - testAdmin.Sync("client done"); - } + + ASSERT_EQ(textSocketClient.Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); + + // Code after this line is executed by both parent and child + ::Thunder::Core::Singleton::Dispose(); } diff --git a/Tests/unit/core/test_statetrigger.cpp b/Tests/unit/core/test_statetrigger.cpp index 4af677dec..5fd152885 100644 --- a/Tests/unit/core/test_statetrigger.cpp +++ b/Tests/unit/core/test_statetrigger.cpp @@ -29,9 +29,6 @@ namespace Thunder { namespace Tests { namespace Core { - - - enum class TestState { TEST_INIT = 0x00, TEST_MESSAGE = 0x01, diff --git a/Tests/unit/core/test_synchronous.cpp b/Tests/unit/core/test_synchronous.cpp index abd8623e5..dc1972472 100644 --- a/Tests/unit/core/test_synchronous.cpp +++ b/Tests/unit/core/test_synchronous.cpp @@ -162,34 +162,52 @@ namespace Core { TEST(test_synchronous, simple_synchronous) { - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin) { + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { SynchronousSocket synchronousServerSocket(true); - testAdmin.Sync("setup server"); - testAdmin.Sync("connect client"); - testAdmin.Sync("client msg"); - testAdmin.Sync("client newmsg"); - testAdmin.Sync("client revokemsg"); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); }; - IPTestAdministrator testAdmin(otherSide); - { - testAdmin.Sync("setup server"); + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + // a small delay so the child can be set up + SleepMs(maxInitTime); + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + SynchronousSocket synchronousClientSocket(false); - testAdmin.Sync("connect client"); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + uint8_t buffer[] = "Hello"; - Message message(5,buffer); - EXPECT_EQ(synchronousClientSocket.Exchange(500, message),0u); - testAdmin.Sync("client msg"); + Message message(sizeof(buffer), buffer); + // Outbound + EXPECT_EQ(synchronousClientSocket.Exchange(maxWaitTimeMs, message), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); InMessage response; - Message newmessage(5,buffer); - synchronousClientSocket.Exchange(500, newmessage, response);//TODO Output verification is pending. - testAdmin.Sync("client newmsg"); + Message newmessage(sizeof(buffer), buffer); + // Inbound + EXPECT_EQ(synchronousClientSocket.Exchange(maxWaitTimeMs, newmessage, response), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + synchronousClientSocket.Revoke(message); - testAdmin.Sync("client revokemsg"); - } + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); + + // Code after this line is executed by both parent and child + ::Thunder::Core::Singleton::Dispose(); } diff --git a/Tests/unit/core/test_systeminfo.cpp b/Tests/unit/core/test_systeminfo.cpp index 63c24a2bb..28a627f68 100644 --- a/Tests/unit/core/test_systeminfo.cpp +++ b/Tests/unit/core/test_systeminfo.cpp @@ -33,14 +33,6 @@ #include -#include - -#ifndef MODULE_NAME -#include "../Module.h" -#endif - -#include - namespace Thunder { namespace Tests { namespace Core { diff --git a/Tests/unit/core/test_threadpool.cpp b/Tests/unit/core/test_threadpool.cpp index ea9211fa9..31d022ca3 100644 --- a/Tests/unit/core/test_threadpool.cpp +++ b/Tests/unit/core/test_threadpool.cpp @@ -31,9 +31,6 @@ namespace Thunder { namespace Tests { namespace Core { - - - static constexpr uint32_t MaxJobWaitTime = 1000; // In milliseconds static constexpr uint8_t MaxAdditionalWorker = 5; diff --git a/Tests/unit/core/test_valuerecorder.cpp b/Tests/unit/core/test_valuerecorder.cpp index 86f0dad72..db51c7226 100644 --- a/Tests/unit/core/test_valuerecorder.cpp +++ b/Tests/unit/core/test_valuerecorder.cpp @@ -29,9 +29,6 @@ namespace Thunder { namespace Tests { namespace Core { - - - const unsigned int BLOCKSIZE = 20; class WriterClass : public RecorderType::Writer diff --git a/Tests/unit/core/test_weblinktext.cpp b/Tests/unit/core/test_weblinktext.cpp index 0d8f2d3f3..30c24879b 100644 --- a/Tests/unit/core/test_weblinktext.cpp +++ b/Tests/unit/core/test_weblinktext.cpp @@ -23,7 +23,6 @@ #include "../Module.h" #endif -#include #include #include "../IPTestAdministrator.h" From 346fb6ec2a0da5058f7a581190e63c7cb61d929c Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Mon, 22 Jul 2024 14:23:28 +0000 Subject: [PATCH 07/35] [Tests/unit] : Improve synchronization with premature signalling --- Tests/unit/IPTestAdministrator.cpp | 25 +++++++++++++++++++------ Tests/unit/IPTestAdministrator.h | 15 +++++++++++---- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/Tests/unit/IPTestAdministrator.cpp b/Tests/unit/IPTestAdministrator.cpp index 7ce30c550..1d77b6e19 100644 --- a/Tests/unit/IPTestAdministrator.cpp +++ b/Tests/unit/IPTestAdministrator.cpp @@ -139,12 +139,11 @@ uint32_t IPTestAdministrator::Wait(uint32_t expectedHandshakeValue) const } // Spurious wake-up - // TODO: continue with remaining time +// TODO: continue with remaining time continue; case -1 : // switch(errno) { - case EAGAIN : - // Value mismatch + case EAGAIN : // Value mismatch result = ::Thunder::Core::ERROR_INVALID_RANGE; break; case ETIMEDOUT : // Value has not changed within the specified timeout @@ -165,8 +164,10 @@ uint32_t IPTestAdministrator::Wait(uint32_t expectedHandshakeValue) const return result; } -uint32_t IPTestAdministrator::Signal(uint32_t expectedNextHandshakeValue) +uint32_t IPTestAdministrator::Signal(uint32_t expectedNextHandshakeValue, uint8_t maxRetries) { + constexpr std::chrono::seconds s {0}; + uint32_t result = ::Thunder::Core::ERROR_GENERAL; long futex_result = syscall(SYS_futex, &(_sharedData->handshakeValue), FUTEX_WAKE, INT_MAX /* number of waiters to wake-up */, nullptr, nullptr, 0); @@ -179,8 +180,20 @@ uint32_t IPTestAdministrator::Signal(uint32_t expectedNextHandshakeValue) default : // Uninspected // unknown conditions ; } - case 0 : // No waiters - do {} while (false); + break; + case 0 : { + // No waiters + constexpr auto seconds2milliseconds = std::chrono::duration_cast(std::chrono::seconds(1)).count(); + + if (maxRetries > 0) { + std::this_thread::yield(); // Hopefully the scheduler plays nice + std::this_thread::sleep_for(std::chrono::milliseconds(_waitTime * seconds2milliseconds / _waitTimeDivisor)); // Sleep a fraction of the maximum specified waiting time + result = Signal(expectedNextHandshakeValue, maxRetries - 1); + } else { + result = ::Thunder::Core::ERROR_BAD_REQUEST; + } + } + break; default : result = ::Thunder::Core::ERROR_NONE; // Atomically replaces the current value by the expected value bool oldHandshakeValue = _sharedData->handshakeValue.exchange(expectedNextHandshakeValue); diff --git a/Tests/unit/IPTestAdministrator.h b/Tests/unit/IPTestAdministrator.h index 3421998b0..dd95c94c7 100644 --- a/Tests/unit/IPTestAdministrator.h +++ b/Tests/unit/IPTestAdministrator.h @@ -37,16 +37,21 @@ static_assert(false, "Only LINUX is supported"); class IPTestAdministrator { public : + using Callback = std::function; - IPTestAdministrator(Callback /* executed by parent */, Callback /* executed by child */, const uint32_t initHandshakeValue, const uint32_t waitTime); + IPTestAdministrator(Callback /* executed by parent */, Callback /* executed by child */, const uint32_t initHandshakeValue, const uint32_t waitTime /* seconds */); ~IPTestAdministrator(); IPTestAdministrator(const IPTestAdministrator&) = delete; const IPTestAdministrator& operator=(const IPTestAdministrator&) = delete; uint32_t Wait(uint32_t expectedHandshakeValue) const; - uint32_t Signal(uint32_t expectedNextHandshakeValue); + uint32_t Signal(uint32_t expectedNextHandshakeValue, uint8_t maxRetries = 0); + + uint32_t WaitTimeDivisor() const { + return _waitTimeDivisor; + } private : @@ -56,8 +61,10 @@ private : // A pointer may be converted to a pointer of the first non-static data element with reinterpret_cast std::atomic handshakeValue; }; -public: + + constexpr static uint32_t _waitTimeDivisor = 10; + SharedData* _sharedData; pid_t _pid; - uint32_t _waitTime; // In seconds + uint32_t _waitTime; // Seconds }; From 3696efa7282151cdc44ce8f7797097614dc82ffd Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Mon, 22 Jul 2024 14:24:41 +0000 Subject: [PATCH 08/35] [Tests/unit] : Add test cases to 'Tests/unit/tests/test_iptestmanager.cpp' --- Tests/unit/tests/test_iptestmanager.cpp | 124 +++++++++++++++++++++++- 1 file changed, 119 insertions(+), 5 deletions(-) diff --git a/Tests/unit/tests/test_iptestmanager.cpp b/Tests/unit/tests/test_iptestmanager.cpp index b92611214..f51cc5929 100644 --- a/Tests/unit/tests/test_iptestmanager.cpp +++ b/Tests/unit/tests/test_iptestmanager.cpp @@ -31,23 +31,137 @@ namespace Thunder { namespace Tests { namespace Core { - TEST(Test_IPTestAdministrator, sync) + TEST(Test_IPTestAdministrator, BasicSync) { // Do not change the signal handshake value unless you use a timed loop and repeatedly check. // Wait may return early with an error if it expect a different value. - constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4; + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 0; IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); }; IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { // A small delay so the child can be set up - SleepMs(1000); + SleepMs(maxInitTime); + + // The child is awaiting the signal for this value to produce no error and continue. If the values mismatch the child continues with an error. + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); + + // Code after this line is executed by both parent and child + + ::Thunder::Core::Singleton::Dispose(); + } + + TEST(Test_IPTestAdministrator, SignalBeforeWait) + { + // Do not change the signal handshake value unless you use a timed loop and repeatedly check. + // Wait may return early with an error if it expect a different value. + + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 15; // Approximately 150% maxWaitTimePeriod + + constexpr auto seconds2milliseconds = std::chrono::duration_cast(std::chrono::seconds(1)).count(); + + static_assert((maxWaitTime * seconds2milliseconds * maxRetries) > (maxWaitTimeMs + maxInitTime), "Scheduling is unpredicatable. Keep a safe margin."); + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { + // A small delay so the signal comes first + SleepMs(maxInitTime); + + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + // The child is awaiting the signal for this value to produce no error and continue. If the values mismatch the child continues with an error. + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); + + // Code after this line is executed by both parent and child + + ::Thunder::Core::Singleton::Dispose(); + } + + TEST(Test_IPTestAdministrator, SuccessiveSignalWait) + { + // Do not change the signal handshake value unless you use a timed loop and repeatedly check. + // Wait may return early with an error if it expect a different value. + + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 2; + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + // A small delay so the child can be set up + SleepMs(maxInitTime); + // The child is awaiting the signal for this value to produce no error and continue. If the values mismatch the child continues with an error. - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); + + // Code after this line is executed by both parent and child + + ::Thunder::Core::Singleton::Dispose(); + } + + TEST(Test_IPTestAdministrator, SuccessiveSignalWaitInterleavedDelay) + { + // Do not change the signal handshake value unless you use a timed loop and repeatedly check. + // Wait may return early with an error if it expect a different value. + + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 15; // Approximately 150% maxWaitTimePeriod + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + + SleepMs(maxInitTime); + + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + // A small delay so the child can be set up + SleepMs(maxInitTime); + // The child is awaiting the signal for this value to produce no error and continue. If the values mismatch the child continues with an error. + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + + SleepMs(maxInitTime); + + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); }; From 7c9a286d1398de9f2b470b02bb58596120f0d8c9 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Mon, 22 Jul 2024 14:33:06 +0000 Subject: [PATCH 09/35] [Tests/unit/core] : align tests with '346fb6ec2a0da5058f7a581190e63c7cb61d929c' Including various improvements for some test. --- Tests/unit/core/CMakeLists.txt | 38 +++++----- Tests/unit/core/test_doorbell.cpp | 15 ++-- Tests/unit/core/test_ipc.cpp | 44 +++++++----- Tests/unit/core/test_ipcclient.cpp | 3 +- Tests/unit/core/test_rpc.cpp | 7 +- Tests/unit/core/test_socketstreamjson.cpp | 7 +- Tests/unit/core/test_socketstreamtext.cpp | 9 +-- Tests/unit/core/test_synchronous.cpp | 49 +++++++------ Tests/unit/core/test_weblinkjson.cpp | 84 ++++++++++++++++------- Tests/unit/core/test_weblinktext.cpp | 73 ++++++++++++++------ Tests/unit/core/test_websocketjson.cpp | 71 +++++++++++++------ Tests/unit/core/test_websockettext.cpp | 65 ++++++++++++------ 12 files changed, 296 insertions(+), 169 deletions(-) diff --git a/Tests/unit/core/CMakeLists.txt b/Tests/unit/core/CMakeLists.txt index 6a2e64dda..ca60da0a8 100644 --- a/Tests/unit/core/CMakeLists.txt +++ b/Tests/unit/core/CMakeLists.txt @@ -18,7 +18,7 @@ set(TEST_RUNNER_NAME "Thunder_test_core") if(LINUX) - # IPTestAdministrator only supprt LINUX platform + # IPTestAdministrator only supported on LINUX platform add_executable(${TEST_RUNNER_NAME} ../IPTestAdministrator.cpp #test_cyclicbuffer.cpp @@ -68,18 +68,29 @@ add_executable(${TEST_RUNNER_NAME} test_textfragment.cpp test_textreader.cpp test_thread.cpp -##### test_threadpool.cpp + test_threadpool.cpp test_time.cpp test_timer.cpp test_tristate.cpp #test_valuerecorder.cpp -# test_weblinkjson.cpp -# test_weblinktext.cpp -# test_websocketjson.cpp -# test_websockettext.cpp -#### test_workerpool.cpp + test_weblinkjson.cpp + test_weblinktext.cpp + test_websocketjson.cpp + test_websockettext.cpp + test_workerpool.cpp test_xgetopt.cpp ) +#[[ if(MESSAGING) + target_sources(${TEST_RUNNER_NAME} PRIVATE test_message_unit.cpp) + target_link_libraries(${TEST_RUNNER_NAME} + ThunderMessaging + ) +else() + target_sources(${TEST_RUNNER_NAME} PRIVATE test_tracing.cpp) + target_link_libraries(${TEST_RUNNER_NAME} + ThunderTracing + ) +endif() ]] else() add_executable(${TEST_RUNNER_NAME} test_databuffer.cpp @@ -131,19 +142,6 @@ add_executable(${TEST_RUNNER_NAME} ) endif() - -#[[ if(MESSAGING) - target_sources(${TEST_RUNNER_NAME} PRIVATE test_message_unit.cpp) - target_link_libraries(${TEST_RUNNER_NAME} - ThunderMessaging - ) -else() - target_sources(${TEST_RUNNER_NAME} PRIVATE test_tracing.cpp) - target_link_libraries(${TEST_RUNNER_NAME} - ThunderTracing - ) -endif() ]] - set_source_files_properties(test_systeminfo.cpp PROPERTIES COMPILE_OPTIONS "-fexceptions") target_compile_definitions(${TEST_RUNNER_NAME} diff --git a/Tests/unit/core/test_doorbell.cpp b/Tests/unit/core/test_doorbell.cpp index b1ff6f4d1..2bcccf3cc 100644 --- a/Tests/unit/core/test_doorbell.cpp +++ b/Tests/unit/core/test_doorbell.cpp @@ -34,22 +34,22 @@ namespace Core { TEST(Core_DoorBell, simpleSet) { constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 1; const std::string fileName {"/tmp/doorbell01"}; IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { ::Thunder::Core::DoorBell doorBell(fileName.c_str()); - ASSERT_EQ(doorBell.Wait(::Thunder::Core::infinite), ::Thunder::Core::ERROR_NONE); - + ASSERT_EQ(doorBell.Wait(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); doorBell.Acknowledge(); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); ASSERT_EQ(doorBell.Wait(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); doorBell.Acknowledge(); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); doorBell.Relinquish(); }; @@ -77,6 +77,7 @@ namespace Core { TEST(Core_DoorBell, simpleSetReversed) { constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 1; const std::string fileName {"/tmp/doorbell02"}; @@ -96,15 +97,15 @@ namespace Core { IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { ::Thunder::Core::DoorBell doorBell(fileName.c_str()); - ASSERT_EQ(doorBell.Wait(::Thunder::Core::infinite), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(doorBell.Wait(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); doorBell.Acknowledge(); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); ASSERT_EQ(doorBell.Wait(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); doorBell.Acknowledge(); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); doorBell.Relinquish(); }; diff --git a/Tests/unit/core/test_ipc.cpp b/Tests/unit/core/test_ipc.cpp index d8c1cc941..51d9e9baf 100644 --- a/Tests/unit/core/test_ipc.cpp +++ b/Tests/unit/core/test_ipc.cpp @@ -208,6 +208,7 @@ namespace Core { TEST(Core_IPC, ContinuousChannel) { constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 1; const std::string connector = _T("/tmp/testserver0"); @@ -291,11 +292,11 @@ namespace Core { EXPECT_EQ(voidTripletData->Response().Display(), display); EXPECT_EQ(voidTripletData->Response().Surface(), surface); EXPECT_EQ(voidTripletData->Response().Context(), context); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(continousChannel.Invoke(textTextData, maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); EXPECT_STREQ(textTextData->Response().Value(), text.c_str()); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); factory->DestroyFactory(); factory->DestroyFactory(); @@ -316,9 +317,10 @@ namespace Core { TEST(Core_IPC, ContinuousChannelReversed) { - const std::string connector = _T("/tmp/testserver1"); - constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 1; + + const std::string connector = _T("/tmp/testserver1"); IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { // A small delay so the parent can be set up @@ -350,17 +352,17 @@ namespace Core { EXPECT_EQ(continousChannel.Invoke(tripletResponseData, maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(tripletResponseData->Response().Result(), result); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(continousChannel.Invoke(voidTripletData, maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(voidTripletData->Response().Display(), display); EXPECT_EQ(voidTripletData->Response().Surface(), surface); EXPECT_EQ(voidTripletData->Response().Context(), context); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(continousChannel.Invoke(textTextData, maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); EXPECT_STREQ(textTextData->Response().Value(), text.c_str()); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); factory->DestroyFactory(); factory->DestroyFactory(); @@ -426,6 +428,7 @@ namespace Core { TEST(Core_IPC, FlashChannel) { constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxInitTime = 2000; + constexpr uint8_t maxRetries = 1; const std::string connector = _T("/tmp/testserver2"); @@ -503,17 +506,17 @@ namespace Core { EXPECT_EQ(flashChannel.Invoke(tripletResponseData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(tripletResponseData->Response().Result(), result); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(flashChannel.Invoke(voidTripletData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(voidTripletData->Response().Display(), display); EXPECT_EQ(voidTripletData->Response().Surface(), surface); EXPECT_EQ(voidTripletData->Response().Context(), context); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(flashChannel.Invoke(textTextData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_STREQ(textTextData->Response().Value(), text.c_str()); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); factory->DestroyFactory(); factory->DestroyFactory(); @@ -535,6 +538,7 @@ namespace Core { TEST(Core_IPC, FlashChannelReversed) { constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxInitTime = 2000; + constexpr uint8_t maxRetries = 1; const std::string connector = _T("/tmp/testserver3"); @@ -568,17 +572,17 @@ namespace Core { EXPECT_EQ(flashChannel.Invoke(tripletResponseData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(tripletResponseData->Response().Result(), result); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(flashChannel.Invoke(voidTripletData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(voidTripletData->Response().Display(), display); EXPECT_EQ(voidTripletData->Response().Surface(), surface); EXPECT_EQ(voidTripletData->Response().Context(), context); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(flashChannel.Invoke(textTextData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_STREQ(textTextData->Response().Value(), text.c_str()); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); factory->DestroyFactory(); factory->DestroyFactory(); @@ -644,6 +648,7 @@ namespace Core { TEST(Core_IPC, MultiChannel) { constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxInitTime = 2000; + constexpr uint8_t maxRetries = 1; const std::string connector = _T("/tmp/testserver4"); @@ -727,17 +732,17 @@ namespace Core { EXPECT_EQ(multiChannel.Invoke(tripletResponseData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(tripletResponseData->Response().Result(), result); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(multiChannel.Invoke(voidTripletData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(voidTripletData->Response().Display(), display); EXPECT_EQ(voidTripletData->Response().Surface(), surface); EXPECT_EQ(voidTripletData->Response().Context(), context); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(multiChannel.Invoke(textTextData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_STREQ(textTextData->Response().Value(), text.c_str()); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); factory->DestroyFactory(); factory->DestroyFactory(); @@ -762,6 +767,7 @@ namespace Core { TEST(Core_IPC, MultiChannelReversed) { constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxInitTime = 2000; + constexpr uint8_t maxRetries = 1; const std::string connector = _T("/tmp/testserver5"); @@ -795,17 +801,17 @@ namespace Core { EXPECT_EQ(multiChannel.Invoke(tripletResponseData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(tripletResponseData->Response().Result(), result); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(multiChannel.Invoke(voidTripletData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(voidTripletData->Response().Display(), display); EXPECT_EQ(voidTripletData->Response().Surface(), surface); EXPECT_EQ(voidTripletData->Response().Context(), context); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); EXPECT_EQ(multiChannel.Invoke(textTextData, maxWaitTime), ::Thunder::Core::ERROR_NONE); EXPECT_STREQ(textTextData->Response().Value(), text.c_str()); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); factory->DestroyFactory(); factory->DestroyFactory(); diff --git a/Tests/unit/core/test_ipcclient.cpp b/Tests/unit/core/test_ipcclient.cpp index fa7a4a91b..04bf53a83 100644 --- a/Tests/unit/core/test_ipcclient.cpp +++ b/Tests/unit/core/test_ipcclient.cpp @@ -34,6 +34,7 @@ namespace Core { TEST(Core_IPC, IPCClientConnection) { constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 1; const std::string connector = _T("/tmp/testserver"); @@ -76,7 +77,7 @@ namespace Core { ASSERT_EQ(clientChannel.Source().Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); // Signal the server it can 'end' its life - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); }; IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); diff --git a/Tests/unit/core/test_rpc.cpp b/Tests/unit/core/test_rpc.cpp index b1dc737bc..83cd7c632 100644 --- a/Tests/unit/core/test_rpc.cpp +++ b/Tests/unit/core/test_rpc.cpp @@ -252,6 +252,7 @@ namespace Exchange { TEST(Core_RPC, adder) { constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 1; const std::string connector{"/tmp/wperpc01"}; @@ -270,8 +271,6 @@ namespace Exchange { // A small delay so the child can be set up SleepMs(maxInitTime); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - ::Thunder::Core::NodeId remoteNode(connector.c_str()); ::Thunder::Core::ProxyType<::Thunder::RPC::InvokeServerType<4, 0, 1>> engine = ::Thunder::Core::ProxyType<::Thunder::RPC::InvokeServerType<4, 0, 1>>::Create(); @@ -280,6 +279,8 @@ namespace Exchange { ::Thunder::Core::ProxyType<::Thunder::RPC::CommunicatorClient> client = ::Thunder::Core::ProxyType<::Thunder::RPC::CommunicatorClient>::Create(remoteNode, ::Thunder::Core::ProxyType<::Thunder::Core::IIPCServer>(engine)); ASSERT_TRUE(client.IsValid()); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + // Create remote instance of "Thunder::Tests::Core::Exchange::IAdder". Thunder::Tests::Core::Exchange::IAdder* adder = client->Open(_T("Adder")); ASSERT_TRUE(adder != nullptr); @@ -298,7 +299,7 @@ namespace Exchange { ASSERT_EQ(client->Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); }; IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); diff --git a/Tests/unit/core/test_socketstreamjson.cpp b/Tests/unit/core/test_socketstreamjson.cpp index f1fd86cf3..57762452d 100644 --- a/Tests/unit/core/test_socketstreamjson.cpp +++ b/Tests/unit/core/test_socketstreamjson.cpp @@ -187,7 +187,7 @@ namespace Core { return (true); } - int Wait() const + uint32_t Wait() const { return _dataPending.Lock(); } @@ -225,6 +225,7 @@ namespace Core { TEST(Core_Socket, StreamJSON) { constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 1; const std::string connector = "/tmp/wpestreamjson0"; @@ -267,7 +268,7 @@ namespace Core { ASSERT_EQ(jsonSocketClient.Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); jsonSocketClient.Submit(::Thunder::Core::ProxyType<::Thunder::Core::JSON::IElement>(sendObject)); @@ -280,7 +281,7 @@ namespace Core { EXPECT_EQ(jsonSocketClient.Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); }; IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); diff --git a/Tests/unit/core/test_socketstreamtext.cpp b/Tests/unit/core/test_socketstreamtext.cpp index f0fd5f081..a91165873 100644 --- a/Tests/unit/core/test_socketstreamtext.cpp +++ b/Tests/unit/core/test_socketstreamtext.cpp @@ -72,7 +72,7 @@ namespace Core { } } - int Wait() const + uint32_t Wait() const { return _dataPending.Lock(); } @@ -121,6 +121,7 @@ namespace Core { TEST(Core_Socket, StreamText) { constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 1; const std::string connector {"/tmp/wpestreamtext0"}; @@ -147,10 +148,10 @@ namespace Core { // a small delay so the child can be set up SleepMs(maxInitTime); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - TextConnector textSocketClient(::Thunder::Core::NodeId(connector.c_str())); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(textSocketClient.Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); const string message = "hello"; @@ -164,7 +165,7 @@ namespace Core { ASSERT_EQ(textSocketClient.Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); }; IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); diff --git a/Tests/unit/core/test_synchronous.cpp b/Tests/unit/core/test_synchronous.cpp index dc1972472..ae78a1e6c 100644 --- a/Tests/unit/core/test_synchronous.cpp +++ b/Tests/unit/core/test_synchronous.cpp @@ -130,6 +130,8 @@ namespace Core { class SynchronousSocket : public ::Thunder::Core::SynchronousChannelType<::Thunder::Core::SocketPort> { public: + static constexpr uint32_t maxWaitTimeMs = 4000; + SynchronousSocket(const SynchronousSocket&) = delete; SynchronousSocket& operator=(const SynchronousSocket&) = delete; SynchronousSocket() = delete; @@ -146,12 +148,12 @@ namespace Core { , bufferSize, bufferSize ) { - EXPECT_FALSE(::Thunder::Core::SynchronousChannelType<::Thunder::Core::SocketPort>::Open(::Thunder::Core::infinite) != ::Thunder::Core::ERROR_NONE); + EXPECT_EQ(::Thunder::Core::SynchronousChannelType<::Thunder::Core::SocketPort>::Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); } virtual ~SynchronousSocket() { - ::Thunder::Core::SynchronousChannelType<::Thunder::Core::SocketPort>::Close(::Thunder::Core::infinite); + EXPECT_EQ(::Thunder::Core::SynchronousChannelType<::Thunder::Core::SocketPort>::Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); } virtual uint16_t Deserialize(const uint8_t* dataFrame, const uint16_t availableData) @@ -162,46 +164,43 @@ namespace Core { TEST(test_synchronous, simple_synchronous) { - constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 8, maxWaitTimeMs = 6000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 15; // Approximately 150% maxWaitTime IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { SynchronousSocket synchronousServerSocket(true); - ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + // a small delay so the parent can be set up + SleepMs(maxInitTime); + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); }; IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { - // a small delay so the child can be set up - SleepMs(maxInitTime); - - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); SynchronousSocket synchronousClientSocket(false); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - - uint8_t buffer[] = "Hello"; - Message message(sizeof(buffer), buffer); + uint8_t buffer1[] = "Hello"; + Message message(sizeof(buffer1), buffer1); // Outbound EXPECT_EQ(synchronousClientSocket.Exchange(maxWaitTimeMs, message), ::Thunder::Core::ERROR_NONE); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - + synchronousClientSocket.Revoke(message); + + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + InMessage response; - Message newmessage(sizeof(buffer), buffer); + uint8_t buffer2[] = "olleH"; + Message newmessage(sizeof(buffer2), buffer2); // Inbound - EXPECT_EQ(synchronousClientSocket.Exchange(maxWaitTimeMs, newmessage, response), ::Thunder::Core::ERROR_NONE); - - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); +// EXPECT_EQ(synchronousClientSocket.Exchange(maxWaitTimeMs, newmessage, response), ::Thunder::Core::ERROR_NONE); - synchronousClientSocket.Revoke(message); + synchronousClientSocket.Revoke(newmessage); - ASSERT_EQ(testAdmin.Signal(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); }; IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); diff --git a/Tests/unit/core/test_weblinkjson.cpp b/Tests/unit/core/test_weblinkjson.cpp index 8a52afec3..2e4c1bf86 100644 --- a/Tests/unit/core/test_weblinkjson.cpp +++ b/Tests/unit/core/test_weblinkjson.cpp @@ -106,6 +106,8 @@ namespace Core { private: typedef Web::WebLinkType<::Thunder::Core::SocketStream, Web::Request, Web::Response, ::Thunder::Core::ProxyPoolType&> BaseClass; + constexpr static uint32_t maxWaitTimeMs = 4000; + public: JSONWebServer() = delete; JSONWebServer(const JSONWebServer& copy) = delete; @@ -120,7 +122,7 @@ namespace Core { virtual ~JSONWebServer() { - Close(::Thunder::Core::infinite); + EXPECT_EQ(Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); } public: @@ -142,7 +144,8 @@ namespace Core { ::Thunder::Core::ProxyType response(::Thunder::Core::ProxyType::Create()); response->ErrorCode = 200; response->Body(request->Body()); - Submit(response); + + EXPECT_TRUE(Submit(response)); } virtual void Send(const ::Thunder::Core::ProxyType& response) @@ -164,6 +167,8 @@ namespace Core { private: typedef Web::WebLinkType<::Thunder::Core::SocketStream, Web::Response, Web::Request, ::Thunder::Core::ProxyPoolType&> BaseClass; + static constexpr uint32_t maxWaitTimeMs = 4000; + public: JSONWebClient() = delete; JSONWebClient(const JSONWebClient& copy) = delete; @@ -179,7 +184,7 @@ namespace Core { virtual ~JSONWebClient() { - Close(::Thunder::Core::infinite); + EXPECT_EQ(Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); } public: @@ -199,8 +204,9 @@ namespace Core { EXPECT_TRUE(response->HasBody()); EXPECT_EQ(response->ContentLength.Value(), 60u); - response->Body()->ToString(_dataReceived); - _dataPending.Unlock(); + EXPECT_TRUE(response->Body()->ToString(_dataReceived)); + + EXPECT_EQ(_dataPending.Unlock(), ::Thunder::Core::ERROR_NONE); } virtual void Send(const ::Thunder::Core::ProxyType& request) @@ -213,7 +219,7 @@ namespace Core { { } - int Wait() const + uint32_t Wait() const { return _dataPending.Lock(); } @@ -233,42 +239,72 @@ namespace Core { TEST(WebLink, Json) { - std::string connector {"0.0.0.0"}; - auto lambdaFunc = [connector](IPTestAdministrator & testAdmin) { + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 1; + + const std::string connector {"0.0.0.0"}; + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { ::Thunder::Core::SocketServerType webServer(::Thunder::Core::NodeId(connector.c_str(), 12341)); - webServer.Open(::Thunder::Core::infinite); - testAdmin.Sync("setup server"); - testAdmin.Sync("client done"); + + ASSERT_EQ(webServer.Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(webServer.Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); }; - static std::function lambdaVar = lambdaFunc; + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + SleepMs(maxInitTime); - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); - IPTestAdministrator testAdmin(otherSide); - testAdmin.Sync("setup server"); - { JSONWebClient jsonWebConnector(::Thunder::Core::NodeId(connector.c_str(), 12341)); + ::Thunder::Core::ProxyType jsonRequest(::Thunder::Core::ProxyType::Create()); ::Thunder::Core::ProxyType jsonRequestBody(::Thunder::Core::ProxyType::Create()); + + // ProxyType + ASSERT_TRUE(jsonRequest.IsValid()); + // ProxyType + ASSERT_TRUE(jsonRequestBody.IsValid()); + jsonRequest->Body(jsonRequestBody); - jsonWebConnector.Open(::Thunder::Core::infinite); - while (!jsonWebConnector.IsOpen()); + + ASSERT_EQ(jsonWebConnector.Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + ASSERT_TRUE(jsonWebConnector.IsOpen()); + jsonRequest->Verb = Web::Request::HTTP_GET; jsonRequestBody->Identifier = 123; jsonRequestBody->Name = _T("TestCase"); jsonRequestBody->Params.Speed = 4321; + + // True object + ASSERT_TRUE(jsonRequest->IsValid()); + string sent; - jsonRequestBody->ToString(sent); - jsonWebConnector.Submit(jsonRequest); + EXPECT_TRUE(jsonRequestBody->ToString(sent)); + + EXPECT_TRUE(jsonWebConnector.Submit(jsonRequest)); + + EXPECT_EQ(jsonWebConnector.Wait(), ::Thunder::Core::ERROR_NONE); - jsonWebConnector.Wait(); string received; + jsonWebConnector.Retrieve(received); + EXPECT_STREQ(received.c_str(), sent.c_str()); - testAdmin.Sync("client done"); - } - ::Thunder::Core::Singleton::Dispose(); + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + }; + + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); + + // Code after this line is executed by both parent and child + + ::Thunder::Core::Singleton::Dispose(); } } // Core diff --git a/Tests/unit/core/test_weblinktext.cpp b/Tests/unit/core/test_weblinktext.cpp index 30c24879b..090d45f9f 100644 --- a/Tests/unit/core/test_weblinktext.cpp +++ b/Tests/unit/core/test_weblinktext.cpp @@ -35,6 +35,8 @@ namespace Core { private: typedef Web::WebLinkType<::Thunder::Core::SocketStream, Web::Request, Web::Response, ::Thunder::Core::ProxyPoolType > BaseClass; + constexpr static uint32_t maxWaitTimeMs = 4000; + public: WebServer() = delete; WebServer(const WebServer& copy) = delete; @@ -47,7 +49,7 @@ namespace Core { virtual ~WebServer() { - Close(::Thunder::Core::infinite); + EXPECT_EQ(Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); } public: @@ -69,7 +71,8 @@ namespace Core { ::Thunder::Core::ProxyType response(::Thunder::Core::ProxyType::Create()); response->ErrorCode = 200; response->Body(request->Body()); - Submit(response); + + EXPECT_TRUE(Submit(response)); } virtual void Send(const ::Thunder::Core::ProxyType<::Thunder::Web::Response>& response) @@ -92,6 +95,8 @@ namespace Core { private: typedef Web::WebLinkType<::Thunder::Core::SocketStream, Web::Response, Web::Request, ::Thunder::Core::ProxyPoolType&> BaseClass; + static constexpr uint32_t maxWaitTimeMs = 4000; + public: WebClient() = delete; WebClient(const WebClient& copy) = delete; @@ -105,7 +110,7 @@ namespace Core { virtual ~WebClient() { - Close(::Thunder::Core::infinite); + EXPECT_EQ(Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); } public: @@ -126,7 +131,8 @@ namespace Core { EXPECT_EQ(response->ContentLength.Value(), 19u); _dataReceived = *(response->Body()); - _dataPending.Unlock(); + + EXPECT_EQ(_dataPending.Unlock(), ::Thunder::Core::ERROR_NONE); } virtual void Send(const ::Thunder::Core::ProxyType<::Thunder::Web::Request>& request) @@ -139,7 +145,7 @@ namespace Core { { } - int Wait() const + uint32_t Wait() const { return _dataPending.Lock(); } @@ -162,38 +168,63 @@ namespace Core { TEST(WebLink, Text) { - std::string connector {"127.0.0.1"}; - auto lambdaFunc = [connector](IPTestAdministrator & testAdmin) { + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 1; + + const std::string connector {"127.0.0.1"}; + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { ::Thunder::Core::SocketServerType _webServer(::Thunder::Core::NodeId(connector.c_str(), 12343)); - _webServer.Open(::Thunder::Core::infinite); - testAdmin.Sync("setup server"); - testAdmin.Sync("client done"); + + ASSERT_EQ(_webServer.Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(_webServer.Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); }; - static std::function lambdaVar = lambdaFunc; + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + // a small delay so the child can be set up + SleepMs(maxInitTime); - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); - IPTestAdministrator testAdmin(otherSide); - testAdmin.Sync("setup server"); - { WebClient webConnector(::Thunder::Core::NodeId(connector.c_str(), 12343)); + ::Thunder::Core::ProxyType webRequest(::Thunder::Core::ProxyType::Create()); ::Thunder::Core::ProxyType webRequestBody(::Thunder::Core::ProxyType::Create()); + webRequest->Body(webRequestBody); - webConnector.Open(::Thunder::Core::infinite); - while (!webConnector.IsOpen()); + + ASSERT_EQ(webConnector.Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + ASSERT_TRUE(webConnector.IsOpen()); + webRequest->Verb = Web::Request::HTTP_GET; + + // True object + ASSERT_TRUE(webRequest->IsValid()); + string sent = "Just a body to send"; + *webRequestBody = sent; - webConnector.Submit(webRequest); - webConnector.Wait(); + EXPECT_TRUE(webConnector.Submit(webRequest)); + + ASSERT_EQ(webConnector.Wait(), ::Thunder::Core::ERROR_NONE); + string received; + webConnector.Retrieve(received); + EXPECT_STREQ(received.c_str(), sent.c_str()); - testAdmin.Sync("client done"); - } + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + }; + + // Code after this line is executed by both parent and child + ::Thunder::Core::Singleton::Dispose(); } diff --git a/Tests/unit/core/test_websocketjson.cpp b/Tests/unit/core/test_websocketjson.cpp index 744df0ac5..3b83157ea 100644 --- a/Tests/unit/core/test_websocketjson.cpp +++ b/Tests/unit/core/test_websocketjson.cpp @@ -174,9 +174,12 @@ namespace Core { virtual void Received(::Thunder::Core::ProxyType<::Thunder::Core::JSON::IElement>& jsonObject) { string textElement; - jsonObject->ToString(textElement); + + EXPECT_TRUE(jsonObject->ToString(textElement)); + _dataReceived = textElement; - _dataPending.Unlock(); + + EXPECT_EQ(_dataPending.Unlock(), ::Thunder::Core::ERROR_NONE); } virtual void Send(::Thunder::Core::ProxyType<::Thunder::Core::JSON::IElement>& jsonObject) @@ -197,7 +200,7 @@ namespace Core { return _objectFactory.Element(""); } - int Wait() const + uint32_t Wait() const { return _dataPending.Lock(); } @@ -214,46 +217,70 @@ namespace Core { mutable ::Thunder::Core::Event _dataPending; }; - TEST(WebSocket, DISABLED_Json) + TEST(WebSocket, Json) { - std::string connector {"/tmp/wpewebsocketjson0"}; - auto lambdaFunc = [connector](IPTestAdministrator & testAdmin) { + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 1; + + const std::string connector {"/tmp/wpewebsocketjson0"}; + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { ::Thunder::Core::SocketServerType> jsonWebSocketServer(::Thunder::Core::NodeId(connector.c_str())); - jsonWebSocketServer.Open(::Thunder::Core::infinite); - testAdmin.Sync("setup server"); + + ASSERT_EQ(jsonWebSocketServer.Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); std::unique_lock lk(JsonSocketServer<::Thunder::Core::JSON::IElement>::_mutex); + while (!JsonSocketServer<::Thunder::Core::JSON::IElement>::GetState()) { JsonSocketServer<::Thunder::Core::JSON::IElement>::_cv.wait(lk); } - testAdmin.Sync("server open"); - testAdmin.Sync("client done"); + + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); }; - static std::function lambdaVar = lambdaFunc; + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + // a small delay so the child can be set up + SleepMs(maxInitTime); - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); - IPTestAdministrator testAdmin(otherSide); - testAdmin.Sync("setup server"); - { ::Thunder::Core::ProxyType sendObject = ::Thunder::Core::ProxyType::Create(); + sendObject->EventType = _T("Test"); sendObject->Event = _T("TestSend"); + std::string sendString; - sendObject->ToString(sendString); + + EXPECT_TRUE(sendObject->ToString(sendString)); JsonSocketClient<::Thunder::Core::JSON::IElement> jsonWebSocketClient(::Thunder::Core::NodeId(connector.c_str())); - jsonWebSocketClient.Open(::Thunder::Core::infinite); - testAdmin.Sync("server open"); + + ASSERT_EQ(jsonWebSocketClient.Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + ASSERT_TRUE(jsonWebSocketClient.IsOpen()); + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + jsonWebSocketClient.Submit(::Thunder::Core::ProxyType<::Thunder::Core::JSON::IElement>(sendObject)); - jsonWebSocketClient.Wait(); + + ASSERT_EQ(jsonWebSocketClient.Wait(), ::Thunder::Core::ERROR_NONE); + string received; + jsonWebSocketClient.Retrieve(received); + EXPECT_STREQ(sendString.c_str(), received.c_str()); - jsonWebSocketClient.Close(::Thunder::Core::infinite); - testAdmin.Sync("client done"); - } + + EXPECT_EQ(jsonWebSocketClient.Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + }; + + // Code after this line is executed by both parent and child + ::Thunder::Core::Singleton::Dispose(); } diff --git a/Tests/unit/core/test_websockettext.cpp b/Tests/unit/core/test_websockettext.cpp index 27deafab9..583f1b83e 100644 --- a/Tests/unit/core/test_websockettext.cpp +++ b/Tests/unit/core/test_websockettext.cpp @@ -112,7 +112,8 @@ namespace Core { virtual void Received(string& text) { _dataReceived = text; - _dataPending.Unlock(); + + EXPECT_EQ(_dataPending.Unlock(), ::Thunder::Core::ERROR_NONE); } virtual void Send(const string& text) @@ -123,7 +124,7 @@ namespace Core { { } - int Wait() const + uint32_t Wait() const { return _dataPending.Lock(); } @@ -139,41 +140,65 @@ namespace Core { mutable ::Thunder::Core::Event _dataPending; }; - TEST(WebSocket, DISABLED_Text) + TEST(WebSocket, Text) { - std::string connector {"/tmp/wpewebsockettext0"}; - auto lambdaFunc = [connector](IPTestAdministrator & testAdmin) { + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 1; + + const std::string connector {"/tmp/wpewebsockettext0"}; + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { ::Thunder::Core::SocketServerType textWebSocketServer(::Thunder::Core::NodeId(connector.c_str())); - textWebSocketServer.Open(::Thunder::Core::infinite); - testAdmin.Sync("setup server"); + + ASSERT_EQ(textWebSocketServer.Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + std::unique_lock lk(TextSocketServer::_mutex); + while (!TextSocketServer::GetState()) { TextSocketServer::_cv.wait(lk); } - testAdmin.Sync("server open"); - testAdmin.Sync("client done"); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(textWebSocketServer.Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); }; - static std::function lambdaVar = lambdaFunc; + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + // a small delay so the child can be set up + SleepMs(maxInitTime); - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); - IPTestAdministrator testAdmin(otherSide); - testAdmin.Sync("setup server"); - { TextSocketClient textWebSocketClient(::Thunder::Core::NodeId(connector.c_str())); - textWebSocketClient.Open(::Thunder::Core::infinite); - testAdmin.Sync("server open"); + + ASSERT_EQ(textWebSocketClient.Open(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + ASSERT_TRUE(textWebSocketClient.IsOpen()); + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + string sentString = "Test String"; + textWebSocketClient.Submit(sentString); - textWebSocketClient.Wait(); + + EXPECT_EQ(textWebSocketClient.Wait(), ::Thunder::Core::ERROR_NONE); + string received; + textWebSocketClient.Retrieve(received); + EXPECT_STREQ(sentString.c_str(), received.c_str()); - textWebSocketClient.Close(::Thunder::Core::infinite); - testAdmin.Sync("client done"); - } + + EXPECT_EQ(textWebSocketClient.Close(maxWaitTimeMs), ::Thunder::Core::ERROR_NONE); + + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + }; + + // Code after this line is executed by both parent and child + ::Thunder::Core::Singleton::Dispose(); } From 373734371b8fb2fd30cfc47fc39fe86f6a1e3d8c Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Thu, 25 Jul 2024 07:46:17 +0000 Subject: [PATCH 10/35] [Tests/unit/core] : amend '7c9a286d1398de9f2b470b02bb58596120f0d8c9' --- Tests/unit/core/CMakeLists.txt | 17 +- Tests/unit/core/test_synchronous.cpp | 2 +- Tests/unit/core/test_tracing.cpp | 359 --------------------------- 3 files changed, 7 insertions(+), 371 deletions(-) delete mode 100644 Tests/unit/core/test_tracing.cpp diff --git a/Tests/unit/core/CMakeLists.txt b/Tests/unit/core/CMakeLists.txt index ca60da0a8..813e68ac8 100644 --- a/Tests/unit/core/CMakeLists.txt +++ b/Tests/unit/core/CMakeLists.txt @@ -80,17 +80,12 @@ add_executable(${TEST_RUNNER_NAME} test_workerpool.cpp test_xgetopt.cpp ) -#[[ if(MESSAGING) - target_sources(${TEST_RUNNER_NAME} PRIVATE test_message_unit.cpp) - target_link_libraries(${TEST_RUNNER_NAME} - ThunderMessaging - ) -else() - target_sources(${TEST_RUNNER_NAME} PRIVATE test_tracing.cpp) - target_link_libraries(${TEST_RUNNER_NAME} - ThunderTracing - ) -endif() ]] +#[[ +target_sources(${TEST_RUNNER_NAME} PRIVATE test_message_unit.cpp) +target_link_libraries(${TEST_RUNNER_NAME} + ThunderMessaging +) +]] else() add_executable(${TEST_RUNNER_NAME} test_databuffer.cpp diff --git a/Tests/unit/core/test_synchronous.cpp b/Tests/unit/core/test_synchronous.cpp index ae78a1e6c..0126ebf62 100644 --- a/Tests/unit/core/test_synchronous.cpp +++ b/Tests/unit/core/test_synchronous.cpp @@ -164,7 +164,7 @@ namespace Core { TEST(test_synchronous, simple_synchronous) { - constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 8, maxWaitTimeMs = 6000, maxInitTime = 2000; + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; constexpr uint8_t maxRetries = 15; // Approximately 150% maxWaitTime IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { diff --git a/Tests/unit/core/test_tracing.cpp b/Tests/unit/core/test_tracing.cpp deleted file mode 100644 index c0b67e3c9..000000000 --- a/Tests/unit/core/test_tracing.cpp +++ /dev/null @@ -1,359 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#ifndef MODULE_NAME -#include "../Module.h" -#endif - -#include - -#include "../IPTestAdministrator.h" - -namespace Thunder { -namespace Tests { -namespace Core { - -#pragma pack(push) -#pragma pack(1) - struct TraceHeader - { - uint16_t _Length; - uint64_t _ClockTicks; - uint32_t _LineNumber; - }; -#pragma pack(pop) - - struct TraceData - { - TraceHeader _Header; - string _File; - string _Module; - string _Category; - string _Class; - string _Text; - - string ToString() - { - std::stringstream output; - output << _File << "(" << _Header._LineNumber << "): " << _Text; - return output.str(); - } - }; - - class ServerCyclicBuffer01 : public CyclicBuffer - { - public: - ServerCyclicBuffer01(const string& fileName, uint32_t size) - : CyclicBuffer(fileName, File::USER_WRITE|File::USER_READ|File::SHAREABLE, size, true) - { - } - - virtual uint32_t GetReadSize(Cursor& cursor) override - { - uint16_t entrySize = 0; - cursor.Peek(entrySize); - return entrySize; - } - }; - - bool ReadTraceString(const uint8_t buffer[], uint32_t length, uint32_t& offset, string& output) - { - output = ""; - - const char * charBuffer = reinterpret_cast(buffer); - - while (true) { - char c = charBuffer[offset]; - - if (c == '\0') { - // Found the end - offset++; - return true; - } - - output += string(1, c); - offset++; - - if (offset >= length) { - // Buffer overrun - return false; - } - } - - return true; - } - - bool ParseTraceData(const uint8_t buffer[], uint32_t length, uint32_t& offset, TraceData& traceData, uint32_t bufferSize) - { - uint32_t startOffset = offset; - - const TraceHeader * header = reinterpret_cast(buffer + offset); - offset += sizeof(TraceHeader); - - if (offset > length) { - std::cerr << "Offset " << offset << " is larger than length " << length << std::endl; - return false; - } - - traceData._Header = *header; - uint16_t entrySize = traceData._Header._Length; - EXPECT_TRUE(entrySize <= bufferSize); - - if (!ReadTraceString(buffer, length, offset, traceData._File)) { - std::cerr << "Failed to read file name" << std::endl; - return false; - } - - if (!ReadTraceString(buffer, length, offset, traceData._Module)) { - std::cerr << "Failed to read module name" << std::endl; - return false; - } - - if (!ReadTraceString(buffer, length, offset, traceData._Category)) { - std::cerr << "Failed to read category" << std::endl; - return false; - } - if (!ReadTraceString(buffer, length, offset, traceData._Class)) { - std::cerr << "Failed to read class name" << std::endl; - return false; - } - - uint16_t totalHeaderLength = offset - startOffset; - uint16_t textLength = entrySize - totalHeaderLength; - uint16_t textBufferLength = textLength + 1; - char textBuffer[textBufferLength]; - - memcpy(textBuffer, buffer + offset, textLength); - textBuffer[textLength] = '\0'; - traceData._Text = string(textBuffer); - - offset += textLength; - - EXPECT_TRUE(offset == (startOffset + entrySize)); - - return true; - } - - void DebugCheckIfConsistent(const uint8_t * buffer, int length, CyclicBuffer& cycBuffer, uint32_t bufferSize) - { - uint entryCount = 0; - - int index = 0; - while (index < length) { - uint16_t entrySize = 0; - entrySize += static_cast(buffer[index]); - index++; - entrySize += static_cast(buffer[index]) << 8; - - EXPECT_TRUE(entrySize < bufferSize); - index += entrySize - 1; - - entryCount++; - } - - EXPECT_TRUE(index == length); - } - - void CreateTraceBuffer(string tracePath) - { - char systemCmd[1024]; - string command = "mkdir -p "; - snprintf(systemCmd, command.size()+tracePath.size()+1, "%s%s", command.c_str(),tracePath.c_str()); - system(systemCmd); - } - - TEST(Core_tracing, simpleTracing) - { - // Call dispose to ensure there is no any resource handler registered to - // avoid hang on the poll - ::Thunder::Core::Singleton::Dispose(); - - std::string tracePath = "/tmp/tracebuffer01"; - auto lambdaFunc = [tracePath](IPTestAdministrator & testAdmin) { - std::string db = (tracePath + "/tracebuffer.doorbell"); - string cycBufferName = (tracePath + "/tracebuffer"); - - testAdmin.Sync("client start"); - DoorBell doorBell(db.c_str()); - constexpr uint32_t bufferSize = ((8 * 1024) - (sizeof(struct CyclicBuffer::control))); /* 8Kb */ - ServerCyclicBuffer01 cycBuffer(cycBufferName, bufferSize); - - // Note: this test case is forking a child process with parent process space. - // In such case, signalfd:poll of parent will not get signal from pthread_kill(SIGUSR2) from child - // process. Hence please ensure parent process cleared all resource registration - // using Singleton::Dispose() call from parent context. - // https://lore.kernel.org/linux-man/20190923222413.5c79b179@kappa.digital-domain.net/T/ - - // TODO: maximum running time? - if (doorBell.Wait(infinite) == ERROR_NONE) { - doorBell.Acknowledge(); - uint32_t bufferLength = bufferSize; - uint8_t buffer[bufferLength]; - uint32_t actuallyRead = cycBuffer.Read(buffer, sizeof(buffer)); - testAdmin.Sync("server done"); - - EXPECT_TRUE(actuallyRead < cycBuffer.Size()); - - DebugCheckIfConsistent(buffer, actuallyRead, cycBuffer, bufferSize); - - uint32_t offset = 0; - int traceCount = 0; - while (offset < actuallyRead) { - TraceData traceData; - EXPECT_TRUE(ParseTraceData(buffer, actuallyRead, offset, traceData, bufferSize)); - string time(Time::Now().ToRFC1123(true)); - - EXPECT_STREQ(traceData._File.c_str(), "test_tracing.cpp"); - EXPECT_STREQ(traceData._Class.c_str(), "TestBody"); - EXPECT_STREQ(traceData._Category.c_str(), "Information"); - EXPECT_STREQ(traceData._Text.c_str(), "Trace Log"); - - traceCount++; - } - } - doorBell.Relinquish(); - }; - - static std::function lambdaVar = lambdaFunc; - - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; - - // This side (tested) acts as client. - IPTestAdministrator testAdmin(otherSide); - { - CreateTraceBuffer(tracePath); - Trace::TraceUnit::Instance().Open(tracePath); - testAdmin.Sync("client start"); - sleep(2); - Trace::TraceType::Enable(true); - - TRACE_GLOBAL(Trace::Information, (_T("Trace Log"))); - testAdmin.Sync("server done"); - - Trace::TraceUnit::Instance().SetCategories(true,"Tracing", reinterpret_cast("Information")); - Trace::TraceUnit::Iterator index = Trace::TraceUnit::Instance().GetCategories(); - - while (index.Next() == true) - if ((*index)->Enabled() == true) { - if ((strcmp((*index)->Module(), "Tracing")) == 0 ) { - EXPECT_STREQ((*index)->Category(), "Information"); - } - } - - bool enabled = false; - Trace::TraceUnit::Instance().IsDefaultCategory("Tracing", reinterpret_cast("Information"), enabled); - TRACE(Trace::Information,(Trace::Format(_T("Checking the Format() with 1 parameter")))); - std::string text = "Hello"; - TRACE(Trace::Information,(Trace::Format(text.c_str(), _T("Checking the Format() with 2 parameter")))); - Trace::TraceUnit::Instance().Close(); - Trace::TraceUnit::Instance().Open(1); - } - - testAdmin. WaitForChildCompletion(); - Singleton::Dispose(); - } - - TEST(Core_tracing, simpleTracingReversed) - { - std::string tracePath = "/tmp/tracebuffer02"; - auto lambdaFunc = [&](IPTestAdministrator & testAdmin) { - CreateTraceBuffer(tracePath); - Trace::TraceUnit::Instance().Open(tracePath); - testAdmin.Sync("client start"); - sleep(2); - Trace::TraceType::Enable(true); - - TRACE_GLOBAL(Trace::Information, (_T("Trace Log"))); - testAdmin.Sync("server done"); - - Trace::TraceUnit::Instance().SetCategories(true,"Tracing", reinterpret_cast("Information")); - Trace::TraceUnit::Iterator index = Trace::TraceUnit::Instance().GetCategories(); - - while (index.Next() == true) - if ((*index)->Enabled() == true) { - if ((strcmp((*index)->Module(), "Tracing")) == 0 ) { - EXPECT_STREQ((*index)->Category(), "Information"); - } - } - - bool enabled = false; - Trace::TraceUnit::Instance().IsDefaultCategory("Tracing", reinterpret_cast("Information"), enabled); - TRACE(Trace::Information,(Trace::Format(_T("Checking the Format() with 1 parameter")))); - std::string text = "Hello"; - TRACE(Trace::Information,(Trace::Format(text.c_str(), _T("Checking the Format() with 2 parameter")))); - Trace::TraceUnit::Instance().Close(); - Trace::TraceUnit::Instance().Open(1); - - Singleton::Dispose(); - }; - - static std::function lambdaVar = lambdaFunc; - - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin ) { lambdaVar(testAdmin); }; - - // This side (tested) acts as client. - IPTestAdministrator testAdmin(otherSide); - { - std::string db = (tracePath + "/tracebuffer.doorbell"); - string cycBufferName = (tracePath + "/tracebuffer"); - - testAdmin.Sync("server start"); - DoorBell doorBell(db.c_str()); - constexpr uint32_t bufferSize = ((8 * 1024) - (sizeof(struct CyclicBuffer::control))); /* 8Kb */ - ServerCyclicBuffer01 cycBuffer(cycBufferName, bufferSize); - - // TODO: maximum running time? - if (doorBell.Wait(infinite) == ERROR_NONE) { - doorBell.Acknowledge(); - uint32_t bufferLength = bufferSize; - uint8_t buffer[bufferLength]; - uint32_t actuallyRead = cycBuffer.Read(buffer, sizeof(buffer)); - testAdmin.Sync("client done"); - - EXPECT_TRUE(actuallyRead < cycBuffer.Size()); - - DebugCheckIfConsistent(buffer, actuallyRead, cycBuffer, bufferSize); - - uint32_t offset = 0; - int traceCount = 0; - while (offset < actuallyRead) { - TraceData traceData; - EXPECT_TRUE(ParseTraceData(buffer, actuallyRead, offset, traceData, bufferSize)); - string time(Time::Now().ToRFC1123(true)); - - EXPECT_STREQ(traceData._File.c_str(), "test_tracing.cpp"); - EXPECT_STREQ(traceData._Class.c_str(), "operator()"); - EXPECT_STREQ(traceData._Category.c_str(), "Information"); - EXPECT_STREQ(traceData._Text.c_str(), "Trace Log"); - - traceCount++; - } - } - doorBell.Relinquish(); - } - - testAdmin.WaitForChildCompletion(); - Singleton::Dispose(); - } - -} // Core -} // Tests -} // Thunder From da8760ca536ea8df1511fcb0714ebb52fc98a76e Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Fri, 26 Jul 2024 07:41:30 +0000 Subject: [PATCH 11/35] [Tests/core/unit] : align 'test_message_unit' with recent changes --- Tests/unit/core/test_message_unit.cpp | 110 ++++++++++++++++++++++---- 1 file changed, 94 insertions(+), 16 deletions(-) diff --git a/Tests/unit/core/test_message_unit.cpp b/Tests/unit/core/test_message_unit.cpp index 8556b680f..1001e657c 100644 --- a/Tests/unit/core/test_message_unit.cpp +++ b/Tests/unit/core/test_message_unit.cpp @@ -239,13 +239,14 @@ namespace Core { TEST_F(Core_Messaging_MessageUnit, MessageClientWillReturnListOfControls) { + ToggleDefaultConfig(true); + //this test is using metadata (IPC) passing, so no other proces tests for now - ::Thunder::Messaging::MessageClient client(::Thunder::Messaging::MessageUnit::Instance().Identifier(), ::Thunder::Messaging::MessageUnit::Instance().BasePath().empty() ? Core_Messaging_MessageUnit::_basePath : ::Thunder::Messaging::MessageUnit::Instance().BasePath()); + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); client.AddInstance(0 /*id*/); //we are in framework std::vector modules; - client.Modules(modules); int matches = 0; @@ -260,15 +261,14 @@ namespace Core { client.RemoveInstance(0); - EXPECT_GE(count, 4); - EXPECT_EQ(matches, 4); + EXPECT_GE(count, 2); + EXPECT_EQ(matches, 0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, EnablingMessagesShouldUpdateExistingDefaultConfig) { - // Reload with new configuration - ToggleDefaultConfig(false); - ::Thunder::Messaging::MessageUnit::Settings::Config configuration; // If 'enabled' equals false the entry is not added to 'Settings' @@ -300,7 +300,9 @@ namespace Core { for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; - + + client.Controls(item, *it); + while (item.Next()) { enabled = enabled || @@ -321,9 +323,13 @@ namespace Core { modules.clear(); client.Modules(modules); + /* bool */ enabled = false; + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; + client.Controls(item, *it); + while (item.Next()) { enabled = enabled || @@ -336,21 +342,19 @@ namespace Core { } } - /* bool */ enabled = false; - EXPECT_TRUE(enabled); - client.RemoveInstance(0); - ::Thunder::Core::Messaging::IControl::Revoke(&control); - ::Thunder::Messaging::MessageUnit::Instance().Close(); + client.RemoveInstance(0); - ToggleDefaultConfig(true); + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, EnablingMessagesShouldAddToDefaultConfigListIfNotPresent) { + ToggleDefaultConfig(true); + const ::Thunder::Core::Messaging::Metadata toBeAdded(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("ExampleCategory"), _T("ExampleModule")); ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); @@ -359,12 +363,14 @@ namespace Core { std::vector modules; client.Modules(modules); - +//missing operational stream bool enabled = false; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; + client.Controls(item, *it); + while (item.Next()) { enabled = enabled || @@ -391,6 +397,8 @@ namespace Core { for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; + client.Controls(item, *it); + while (item.Next()) { enabled = enabled || @@ -407,22 +415,28 @@ namespace Core { client.RemoveInstance(0); ::Thunder::Core::Messaging::IControl::Revoke(&control); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, EnablingMessagesByTypeShouldEnableEverything) { + ToggleDefaultConfig(true); + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); client.AddInstance(0); //we are in framework std::vector modules; client.Modules(modules); - +//empty bool enabled = true; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; + client.Controls(item, *it); + while (item.Next()) { enabled = enabled && item.Enabled() @@ -444,6 +458,8 @@ namespace Core { for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; + client.Controls(item, *it); + while (item.Next()) { enabled = enabled && item.Enabled() @@ -454,10 +470,14 @@ namespace Core { EXPECT_TRUE(enabled); client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, LogMessagesCanToggledWhenLogModuleSpecified) { + ToggleDefaultConfig(true); + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); client.AddInstance(0); //we are in framework @@ -472,6 +492,8 @@ namespace Core { for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; + client.Controls(item, *it); + while (item.Next()) { if ( item.Type() == messageToToggle.Type() && item.Category() == messageToToggle.Category() @@ -495,6 +517,8 @@ namespace Core { for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; + client.Controls(item, *it); + while (item.Next()) { if ( item.Type() == messageToToggle.Type() && item.Category() == messageToToggle.Category() @@ -509,10 +533,14 @@ namespace Core { EXPECT_EQ(matches, 1); client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, LogEnablingMessagesShouldAddToDefaultConfigListIfNotPresent) { + ToggleDefaultConfig(true); + const ::Thunder::Core::Messaging::Metadata toBeAdded(::Thunder::Core::Messaging::Metadata::type::LOGGING, _T("Test_Category_5"), _T("SysLog")); ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); @@ -529,6 +557,8 @@ namespace Core { for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; + client.Controls(item, *it); + while (item.Next()) { enabled = enabled || @@ -544,10 +574,14 @@ namespace Core { EXPECT_TRUE(enabled); client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, EnablingFullySpecifiedMessageUpdateOnlyThisOne) { + ToggleDefaultConfig(true); + ::Thunder::Core::Messaging::Metadata message(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_1"), EXPAND_AND_QUOTE(MODULE_NAME)); ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); @@ -564,6 +598,8 @@ namespace Core { for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; + client.Controls(item, *it); + while (item.Next()) { enabled = enabled || @@ -590,6 +626,8 @@ namespace Core { for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; + client.Controls(item, *it); + while (item.Next()) { enabled = enabled || @@ -605,10 +643,14 @@ namespace Core { EXPECT_TRUE(enabled); client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, EnablingMessageSpecifiedByModuleShouldEnableAllCategoriesInsideIt) { + ToggleDefaultConfig(false); + const ::Thunder::Core::Messaging::Metadata message(::Thunder::Core::Messaging::Metadata::type::TRACING, _T(""), EXPAND_AND_QUOTE(MODULE_NAME)); ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); @@ -623,6 +665,8 @@ namespace Core { for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; + client.Controls(item, *it); + while (item.Next()) { if ( message.Type() == item.Type() && message.Module() == item.Module() @@ -646,6 +690,8 @@ namespace Core { for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; + client.Controls(item, *it); + while (item.Next()) { if ( message.Type() == item.Type() && message.Module() == item.Module() @@ -660,10 +706,14 @@ namespace Core { EXPECT_TRUE(enabled); client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, EnablingMessageSpecifiedByCategoryShouldEnableItInAllModules) { + ToggleDefaultConfig(true); + const ::Thunder::Core::Messaging::Metadata message(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_1"), _T("")); ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); @@ -678,6 +728,8 @@ namespace Core { for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; + client.Controls(item, *it); + while (item.Next()) { if ( message.Type() == item.Type() && message.Category() == item.Category() @@ -701,6 +753,8 @@ namespace Core { for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; + client.Controls(item, *it); + while (item.Next()) { if ( message.Type() == item.Type() && message.Category() == item.Category() @@ -715,6 +769,8 @@ namespace Core { EXPECT_TRUE(enabled); client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, TextMessageEventIsProperlySerializedIfBufferBigEnough) @@ -760,6 +816,8 @@ namespace Core { TEST_F(Core_Messaging_MessageUnit, ControlListIsProperlySerializedIfBufferBigEnough) { + ToggleDefaultConfig(true); + constexpr string::size_type bufferSize = 1024; uint8_t buffer[bufferSize]; @@ -774,6 +832,8 @@ namespace Core { for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; + client.Controls(item, *it); + while (item.Next()) { ::Thunder::Messaging::MessageUnit::Control control({item.Type(), item.Category(), item.Module()}, item.Enabled()); auto serialized = control.Serialize(buffer, sizeof(buffer)); @@ -787,10 +847,14 @@ namespace Core { } client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, ControlListIsProperlySerializedIfBufferNotBigEnough) { + ToggleDefaultConfig(true); + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); client.AddInstance(0); //we are in framework @@ -803,6 +867,8 @@ namespace Core { for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; + client.Controls(item, *it); + while (item.Next()) { buffer.resize(buffer.size() + sizeof(item.Type()), ::Thunder::Core::Messaging::Metadata::type::INVALID); buffer.resize(buffer.size() + item.Category().size() + 1, ::Thunder::Core::Messaging::Metadata::type::INVALID); @@ -821,6 +887,8 @@ namespace Core { for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; + client.Controls(item, *it); + while (item.Next()) { ::Thunder::Messaging::MessageUnit::Control control({item.Type(), item.Category(), item.Module()}, item.Enabled()); auto serialized = control.Serialize(&(buffer.data()[index]), buffer.size()); @@ -840,10 +908,14 @@ namespace Core { EXPECT_LT(index, buffer.size()); client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, PopMessageShouldReturnLastPushedMessage) { + ToggleDefaultConfig(true); + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); client.AddInstance(0); //we are in framework @@ -896,6 +968,8 @@ namespace Core { EXPECT_TRUE(present); client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, PopMessageShouldReturnLastPushedMessageInOtherProcess) @@ -962,6 +1036,8 @@ TEST_F(Core_Messaging_MessageUnit, PopMessageShouldReturnLastPushedMessageInOthe { ASSERT_FALSE(sigprocmask(SIG_UNBLOCK, &sigset, nullptr) == -1); + ToggleDefaultConfig(true); + ::Thunder::Messaging::TextMessage tm(traceMessage); ::Thunder::Core::Messaging::IStore::Tracing info(::Thunder::Core::Messaging::MessageInfo(metadata, ::Thunder::Core::Time::Now().Ticks()), _T("some_file"), 1337, EXPAND_AND_QUOTE(MODULE_NAME)); @@ -990,6 +1066,8 @@ TEST_F(Core_Messaging_MessageUnit, PopMessageShouldReturnLastPushedMessageInOthe break; } while(waitpid(-1, nullptr, WNOHANG) <= 0); + + ToggleDefaultConfig(false); } } } From c84512fc7bbcb42f4ebbdea5b1915f4648c0e9d3 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Fri, 26 Jul 2024 07:50:33 +0000 Subject: [PATCH 12/35] [Tests/core/unit] : 'test_message_unit' does not use 'IPTestAdministrator' --- Tests/unit/core/test_message_unit.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/unit/core/test_message_unit.cpp b/Tests/unit/core/test_message_unit.cpp index 1001e657c..94181e790 100644 --- a/Tests/unit/core/test_message_unit.cpp +++ b/Tests/unit/core/test_message_unit.cpp @@ -27,7 +27,7 @@ #include -#include "../IPTestAdministrator.h" +//#include "../IPTestAdministrator.h" namespace Thunder { namespace Tests { @@ -363,7 +363,7 @@ namespace Core { std::vector modules; client.Modules(modules); -//missing operational stream + bool enabled = false; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -429,7 +429,7 @@ namespace Core { std::vector modules; client.Modules(modules); -//empty + bool enabled = true; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { From 9c470c7cfea211bd1035d8ccbe5012d773328ddd Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Fri, 26 Jul 2024 08:45:16 +0000 Subject: [PATCH 13/35] [Tests/core/unit] : cherry pick from 'development/messageunit' --- Tests/unit/core/test_message_unit.cpp | 1093 ++++++++++++++++++------- 1 file changed, 793 insertions(+), 300 deletions(-) diff --git a/Tests/unit/core/test_message_unit.cpp b/Tests/unit/core/test_message_unit.cpp index a4966c0a3..94181e790 100644 --- a/Tests/unit/core/test_message_unit.cpp +++ b/Tests/unit/core/test_message_unit.cpp @@ -25,7 +25,9 @@ #include -#include "../IPTestAdministrator.h" +#include + +//#include "../IPTestAdministrator.h" namespace Thunder { namespace Tests { @@ -33,7 +35,7 @@ namespace Core { class Control : public ::Thunder::Core::Messaging::IControl { public: - Control(const ::Thunder::Core::Messaging::MetaData& metaData) + Control(const ::Thunder::Core::Messaging::Metadata& metaData) : _metaData(metaData) { } @@ -53,72 +55,94 @@ namespace Core { { _isEnabled = false; } - const ::Thunder::Core::Messaging::MetaData& MessageMetaData() const override + const ::Thunder::Core::Messaging::Metadata& Metadata() const override { return _metaData; } private: bool _isEnabled; - ::Thunder::Core::Messaging::MetaData _metaData; + ::Thunder::Core::Messaging::Metadata _metaData; }; class Core_Messaging_MessageUnit : public testing::Test { protected: Core_Messaging_MessageUnit() { - _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("Test_Category_1"), EXPAND_AND_QUOTE(MODULE_NAME) })); - _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("Test_Category_2"), EXPAND_AND_QUOTE(MODULE_NAME) })); - _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("Test_Category_3"), EXPAND_AND_QUOTE(MODULE_NAME) })); - _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("Test_Category_4"), EXPAND_AND_QUOTE(MODULE_NAME) })); - _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("Test_Category_1"), _T("Test_Module2") })); - _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::MetaData::MessageType::LOGGING, _T("Test_Category_5"), _T("SysLog") })); + _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_1"), EXPAND_AND_QUOTE(MODULE_NAME) })); + _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_2"), EXPAND_AND_QUOTE(MODULE_NAME) })); + _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_3"), EXPAND_AND_QUOTE(MODULE_NAME) })); + _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_4"), EXPAND_AND_QUOTE(MODULE_NAME) })); + _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_1"), _T("Test_Module2") })); + _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::Metadata::type::LOGGING, _T("Test_Category_5"), _T("SysLog") })); + } ~Core_Messaging_MessageUnit() = default; static void SetUpTestSuite() { - ::Thunder::Core::Messaging::MessageUnit::Instance().IsBackground(_background); - ::Thunder::Core::Messaging::MessageUnit::Instance().Open(_basePath); } static void TearDownTestSuite() { - ::Thunder::Core::Messaging::MessageUnit::Instance().Close(); ::Thunder::Core::Singleton::Dispose(); } + void SetUp() override { - for (const auto& control : _controls) { - ::Thunder::Core::Messaging::MessageUnit::Instance().Announce(control.get()); - } } void TearDown() override { - ::Thunder::Core::Messaging::MessageUnit::Instance().Defaults(_T("")); - for (const auto& control : _controls) { - ::Thunder::Core::Messaging::MessageUnit::Instance().Revoke(control.get()); - } } string DispatcherIdentifier() { - string result; - ::Thunder::Core::SystemInfo::GetEnvironment(::Thunder::Core::Messaging::MessageUnit::MESSAGE_DISPACTHER_IDENTIFIER_ENV, result); - return result; + return ::Thunder::Messaging::MessageUnit::Instance().Identifier(); } string DispatcherBasePath() { string result; - ::Thunder::Core::SystemInfo::GetEnvironment(::Thunder::Core::Messaging::MessageUnit::MESSAGE_DISPATCHER_PATH_ENV, result); - return result; + return ::Thunder::Messaging::MessageUnit::Instance().BasePath(); + } + + void AnnounceAllControls() + { + for (const auto& control : _controls) { + // Only for 'controls' enabled in configuration + ::Thunder::Core::Messaging::IControl::Announce(control.get()); + } + } + + void RevokeAllControls() + { + for (const auto& control : _controls) { + ::Thunder::Core::Messaging::IControl::Revoke(control.get()); + } + } + + void ToggleDefaultConfig(bool activate) + { + ASSERT(_activeConfig != activate); + + if (!_activeConfig && activate) { + ::Thunder::Messaging::MessageUnit::Settings::Config configuration; + ::Thunder::Messaging::MessageUnit::Instance().Open(Core_Messaging_MessageUnit::_basePath, configuration, Core_Messaging_MessageUnit::_background, ::Thunder::Messaging::MessageUnit::OFF); + } + + if (_activeConfig && !activate) { + ::Thunder::Messaging::MessageUnit::Instance().Close(); + } + + _activeConfig = !_activeConfig; } static bool _background; static string _basePath; std::list> _controls; + + bool _activeConfig; }; bool Core_Messaging_MessageUnit::_background = false; @@ -126,458 +150,927 @@ namespace Core { TEST_F(Core_Messaging_MessageUnit, TraceMessageIsEnabledByDefaultWhenConfigFullySpecified) { - const string config = R"({"tracing":{"messages":[{"category":"Information","module":"Plugin_DeviceInfo","enabled":true}]}})"; + ::Thunder::Messaging::MessageUnit::Settings::Config configuration; + configuration.FromString(R"({"tracing":{"settings":[{"category":"Information","module":"Plugin_DeviceInfo","enabled":true}]}})"); - ::Thunder::Core::Messaging::MessageUnit::Instance().Defaults(config); - ASSERT_TRUE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("Information"), _T("Plugin_DeviceInfo") })); - ASSERT_FALSE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("Information"), _T("Some_Module") })); - ASSERT_FALSE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("SomeCategory"), _T("Plugin_DeviceInfo") })); + ::Thunder::Messaging::MessageUnit::Settings settings; + settings.Configure(Core_Messaging_MessageUnit::_basePath, "SomeIdentifier", configuration, Core_Messaging_MessageUnit::_background, ::Thunder::Messaging::MessageUnit::OFF); + + ::Thunder::Core::Messaging::Metadata metaData(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Information"), _T("Plugin_DeviceInfo")); + EXPECT_TRUE(settings.IsEnabled(metaData)); + + metaData = ::Thunder::Core::Messaging::Metadata(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Information"), _T("Some_Module")); + EXPECT_FALSE(settings.IsEnabled(metaData)); + + metaData = ::Thunder::Core::Messaging::Metadata(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("SomeCategory"), _T("Plugin_DeviceInfo")); + EXPECT_FALSE(settings.IsEnabled(metaData)); } TEST_F(Core_Messaging_MessageUnit, TraceMessageIsDisabledByDefaultWhenConfigFullySpecified) { - const string config = R"({"tracing":{"messages":[{"category":"Information","module":"Plugin_DeviceInfo","enabled":false}]}})"; + ::Thunder::Messaging::MessageUnit::Settings::Config configuration; + configuration.FromString(R"({"tracing":{"settings":[{"category":"Information","module":"Plugin_DeviceInfo","enabled":false}]}})"); + + ::Thunder::Messaging::MessageUnit::Settings settings; + settings.Configure(Core_Messaging_MessageUnit::_basePath, "SomeIdentifier", configuration, Core_Messaging_MessageUnit::_background, ::Thunder::Messaging::MessageUnit::OFF); - ::Thunder::Core::Messaging::MessageUnit::Instance().Defaults(config); - ASSERT_FALSE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("Information"), _T("Plugin_DeviceInfo") })); - ASSERT_FALSE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("Information"), _T("Some_Module") })); - ASSERT_FALSE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("SomeCategory"), _T("Plugin_DeviceInfo") })); + ::Thunder::Core::Messaging::Metadata metaData(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Information"), _T("Plugin_DeviceInfo")); + EXPECT_FALSE(settings.IsEnabled(metaData)); + + metaData = ::Thunder::Core::Messaging::Metadata(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Information"), _T("Some_Module")); + EXPECT_FALSE(settings.IsEnabled(metaData)); + + metaData = ::Thunder::Core::Messaging::Metadata(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("SomeCategory"), _T("Plugin_DeviceInfo")); + EXPECT_FALSE(settings.IsEnabled(metaData)); } TEST_F(Core_Messaging_MessageUnit, TraceMessagesAreEnabledWhenModuleNotSpecified) { - const string config = R"({"tracing":{"messages":[{"category":"Information","enabled":true}]}})"; + ::Thunder::Messaging::MessageUnit::Settings::Config configuration; + configuration.FromString(R"({"tracing":{"settings":[{"category":"Information","enabled":true}]}})"); + + ::Thunder::Messaging::MessageUnit::Settings settings; + settings.Configure(Core_Messaging_MessageUnit::_basePath, "SomeIdentifier", configuration, Core_Messaging_MessageUnit::_background, ::Thunder::Messaging::MessageUnit::OFF); + + ::Thunder::Core::Messaging::Metadata metaData(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Information"), _T("Plugin_DeviceInfo")); + EXPECT_TRUE(settings.IsEnabled(metaData)); - ::Thunder::Core::Messaging::MessageUnit::Instance().Defaults(config); - ASSERT_TRUE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("Information"), _T("Plugin_DeviceInfo") })); - ASSERT_TRUE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("Information"), _T("Some_Module") })); - ASSERT_FALSE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("SomeCategory"), _T("Plugin_DeviceInfo") })); + metaData = ::Thunder::Core::Messaging::Metadata(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Information"), _T("Some_Module")); + EXPECT_TRUE(settings.IsEnabled(metaData)); + + metaData = ::Thunder::Core::Messaging::Metadata(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("SomeCategory"), _T("Plugin_DeviceInfo")); + EXPECT_FALSE(settings.IsEnabled(metaData)); } TEST_F(Core_Messaging_MessageUnit, TraceMessagesAreDisabledWhenModuleNotSpecified) { - const string config = R"({"tracing":{"messages":[{"category":"Information","enabled":false}]}})"; + ::Thunder::Messaging::MessageUnit::Settings::Config configuration; + configuration.FromString(R"({"tracing":{"messages":[{"category":"Information","enabled":false}]}})"); + + ::Thunder::Messaging::MessageUnit::Settings settings; + settings.Configure(Core_Messaging_MessageUnit::_basePath, "SomeIdentifier", configuration, Core_Messaging_MessageUnit::_background, ::Thunder::Messaging::MessageUnit::OFF); + + ::Thunder::Core::Messaging::Metadata metaData(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Information"), _T("Plugin_DeviceInfo")); + EXPECT_FALSE(settings.IsEnabled(metaData)); - ::Thunder::Core::Messaging::MessageUnit::Instance().Defaults(config); - ASSERT_FALSE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("Information"), _T("Plugin_DeviceInfo") })); - ASSERT_FALSE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("Information"), _T("Some_Module") })); - ASSERT_FALSE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("SomeCategory"), _T("Plugin_DeviceInfo") })); + metaData = ::Thunder::Core::Messaging::Metadata(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Information"), _T("Some_Module")); + EXPECT_FALSE(settings.IsEnabled(metaData)); + + metaData = ::Thunder::Core::Messaging::Metadata(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("SomeCategory"), _T("Plugin_DeviceInfo")); + EXPECT_FALSE(settings.IsEnabled(metaData)); } TEST_F(Core_Messaging_MessageUnit, LoggingMessageIsEnabledIfNotConfigured) { - //logging messages are enabled by default (if not specified otherwise in the config) - const string config = R"({"logging":{"messages":[{"category":"Startup","module":"SysLog","enabled":false}]}})"; - ::Thunder::Core::Messaging::MessageUnit::Instance().Defaults(config); - ASSERT_FALSE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ ::Thunder::Core::Messaging::MetaData::MessageType::LOGGING, _T("Startup"), _T("SysLog") })); - ASSERT_TRUE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault({ ::Thunder::Core::Messaging::MetaData::MessageType::LOGGING, _T("Notification"), _T("SysLog") })); + ::Thunder::Messaging::MessageUnit::Settings::Config configuration; + configuration.FromString(R"({"logging":{"settings":[{"category":"Startup","module":"SysLog","enabled":false}]}})"); + + ::Thunder::Messaging::MessageUnit::Settings settings; + settings.Configure(Core_Messaging_MessageUnit::_basePath, "SomeIdentifier", configuration, Core_Messaging_MessageUnit::_background, ::Thunder::Messaging::MessageUnit::OFF); + + ::Thunder::Core::Messaging::Metadata metaData(::Thunder::Core::Messaging::Metadata::type::LOGGING, _T("Startup"), _T("SysLog")); + // Internal Metadata::Default() is true for LOGGING but here overwritten because of element of config + EXPECT_FALSE(settings.IsEnabled(metaData)); + + metaData = ::Thunder::Core::Messaging::Metadata(::Thunder::Core::Messaging::Metadata::type::LOGGING, _T("Notification"), _T("SysLog")); + // Internal Metadata::Default() is true for LOGGING and not overwritten because of no element of config + EXPECT_TRUE(settings.IsEnabled(metaData)); } TEST_F(Core_Messaging_MessageUnit, MessageClientWillReturnListOfControls) { + ToggleDefaultConfig(true); + //this test is using metadata (IPC) passing, so no other proces tests for now - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); - client.AddInstance(0); //we are in framework - auto it = client.Enabled(); + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); + + client.AddInstance(0 /*id*/); //we are in framework + + std::vector modules; + client.Modules(modules); int matches = 0; int count = 0; - while (it.Next()) { - auto info = it.Current(); - if (info.first.Module() == EXPAND_AND_QUOTE(MODULE_NAME)) { + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + if (*it == EXPAND_AND_QUOTE(MODULE_NAME)) { ++matches; } ++count; } - ASSERT_GE(count, 4); - ASSERT_EQ(matches, 4); + client.RemoveInstance(0); + + EXPECT_GE(count, 2); + EXPECT_EQ(matches, 0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, EnablingMessagesShouldUpdateExistingDefaultConfig) { - const string config = R"({"tracing":{"messages":[{"category":"ExampleCategory","module":"ExampleModule","enabled":false}]}})"; - ::Thunder::Core::Messaging::MessageUnit::Instance().Defaults(config); - const ::Thunder::Core::Messaging::MetaData toBeUpdated(::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("ExampleCategory"), _T("ExampleModule")); - ASSERT_FALSE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault(toBeUpdated)); + ::Thunder::Messaging::MessageUnit::Settings::Config configuration; + + // If 'enabled' equals false the entry is not added to 'Settings' + configuration.FromString(R"({"tracing":{"settings":[{"category":"ExampleCategory","module":"ExampleModule","enabled":false}]}})"); + + // Populate settings with specified configuration + ::Thunder::Messaging::MessageUnit::Instance().Open(Core_Messaging_MessageUnit::_basePath, configuration, Core_Messaging_MessageUnit::_background, ::Thunder::Messaging::MessageUnit::OFF); + + const ::Thunder::Core::Messaging::Metadata toBeUpdated(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("ExampleCategory"), _T("ExampleModule")); + + Control control(toBeUpdated); + // Add to the internal list if it is not already + ::Thunder::Core::Messaging::IControl::Announce(&control); - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + + // Creates a MessageUnit::Client internally with the id passed in client.AddInstance(0); //we are in framework + + // Get the system 'status' + + bool enabled = false; + + std::vector modules; + client.Modules(modules); + + int matches = 0; + int count = 0; + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + enabled = enabled + || + ( toBeUpdated.Type() == item.Type() + && toBeUpdated.Category() == item.Category() + && toBeUpdated.Module() == item.Module() + && item.Enabled() + ) + ; + } + } + + EXPECT_FALSE(enabled); + + // Enable message via metadata, eg, set enable for the previously added Control, eg, enable category client.Enable(toBeUpdated, true); - ASSERT_TRUE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault(toBeUpdated)); + modules.clear(); + client.Modules(modules); + + /* bool */ enabled = false; + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + enabled = enabled + || + ( toBeUpdated.Type() == item.Type() + && toBeUpdated.Category() == item.Category() + && toBeUpdated.Module() == item.Module() + && item.Enabled() + ) + ; + } + } + + EXPECT_TRUE(enabled); + + ::Thunder::Core::Messaging::IControl::Revoke(&control); + + client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, EnablingMessagesShouldAddToDefaultConfigListIfNotPresent) { - const ::Thunder::Core::Messaging::MetaData toBeAdded(::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("ExampleCategory"), _T("ExampleModule")); + ToggleDefaultConfig(true); - ASSERT_FALSE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault(toBeAdded)); + const ::Thunder::Core::Messaging::Metadata toBeAdded(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("ExampleCategory"), _T("ExampleModule")); + + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); client.AddInstance(0); //we are in framework - client.Enable(toBeAdded, true); - ASSERT_TRUE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault(toBeAdded)); - auto defaultsString = ::Thunder::Core::Messaging::MessageUnit::Instance().Defaults(); - ::Thunder::Core::Messaging::Settings settings; - settings.FromString(defaultsString); + std::vector modules; + client.Modules(modules); + + bool enabled = false; + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + enabled = enabled + || + ( toBeAdded.Type() == item.Type() + && toBeAdded.Category() == item.Category() + && toBeAdded.Module() == item.Module() + && item.Enabled() + ) + ; + } + } + + EXPECT_FALSE(enabled); + + Control control(toBeAdded); + + ::Thunder::Core::Messaging::IControl::Announce(&control); - ASSERT_EQ(settings.Tracing.Entries.Length(), 1); - auto entriesIt = settings.Tracing.Entries.Elements(); - while (entriesIt.Next()) { - ASSERT_STREQ(entriesIt.Current().Category.Value().c_str(), toBeAdded.Category().c_str()); - ASSERT_STREQ(entriesIt.Current().Module.Value().c_str(), toBeAdded.Module().c_str()); + modules.clear(); + client.Modules(modules); + + enabled = false; + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + enabled = enabled + || + ( toBeAdded.Type() == item.Type() + && toBeAdded.Category() == item.Category() + && toBeAdded.Module() == item.Module() + ) + ; + } } + + EXPECT_TRUE(enabled); + + client.RemoveInstance(0); + + ::Thunder::Core::Messaging::IControl::Revoke(&control); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, EnablingMessagesByTypeShouldEnableEverything) { - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); + ToggleDefaultConfig(true); + + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + client.AddInstance(0); //we are in framework - auto itBeforeUpdate = client.Enabled(); - int matches = 0; - while (itBeforeUpdate.Next()) { - auto info = itBeforeUpdate.Current(); - if (info.first.Type() == ::Thunder::Core::Messaging::MetaData::MessageType::TRACING && info.second == true) { - ++matches; + std::vector modules; + client.Modules(modules); + + bool enabled = true; + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + enabled = enabled + && item.Enabled() + ; } } - ASSERT_EQ(matches, 0); - matches = 0; - client.Enable({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T(""), _T("") }, true); - auto itAfterUpdate = client.Enabled(); - while (itAfterUpdate.Next()) { - auto info = itAfterUpdate.Current(); - if (info.first.Type() == ::Thunder::Core::Messaging::MetaData::MessageType::TRACING && info.second == true) { - ++matches; + // Controls from the default are disabled by default, except a few + EXPECT_FALSE(enabled); + + // Enable message via metadata, eg, set enable for the previously added Control, eg, enable category + client.Enable({::Thunder::Core::Messaging::Metadata::type::TRACING, _T(""), _T("")}, true); + + modules.clear(); + client.Modules(modules); + + enabled = true; + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + enabled = enabled + && item.Enabled() + ; } } - ASSERT_GE(matches, 5); + + EXPECT_TRUE(enabled); + + client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, LogMessagesCanToggledWhenLogModuleSpecified) { - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); + ToggleDefaultConfig(true); + + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + client.AddInstance(0); //we are in framework - auto itBeforeUpdate = client.Enabled(); - ::Thunder::Core::Messaging::MetaData messageToToggle(::Thunder::Core::Messaging::MetaData::MessageType::LOGGING, _T("Test_Category_5"), _T("SysLog")); + + ::Thunder::Core::Messaging::Metadata messageToToggle(::Thunder::Core::Messaging::Metadata::type::LOGGING, _T("Test_Category_5"), _T("SysLog")); + + std::vector modules; + client.Modules(modules); int matches = 0; - while (itBeforeUpdate.Next()) { - auto info = itBeforeUpdate.Current(); - if (info.first == messageToToggle && info.second == true) { - ++matches; + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + if ( item.Type() == messageToToggle.Type() + && item.Category() == messageToToggle.Category() + && item.Module() == messageToToggle.Module() + && item.Enabled() + ) { + ++matches; + } } } - ASSERT_EQ(matches, 1); - matches = 0; + EXPECT_EQ(matches, 1); + client.Enable(messageToToggle, false); - auto itAfterUpdate = client.Enabled(); - while (itAfterUpdate.Next()) { - auto info = itAfterUpdate.Current(); - if (info.first == messageToToggle && info.second == false) { - ++matches; + + modules.clear(); + client.Modules(modules); + + matches = 0; + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + if ( item.Type() == messageToToggle.Type() + && item.Category() == messageToToggle.Category() + && item.Module() == messageToToggle.Module() + && !item.Enabled() + ) { + ++matches; + } } } - ASSERT_EQ(matches, 1); + + EXPECT_EQ(matches, 1); + + client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, LogEnablingMessagesShouldAddToDefaultConfigListIfNotPresent) { - const ::Thunder::Core::Messaging::MetaData tobeAdded(::Thunder::Core::Messaging::MetaData::MessageType::LOGGING, _T("Test_Category_5"), _T("SysLog")); - ASSERT_TRUE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault(tobeAdded)); + ToggleDefaultConfig(true); + + const ::Thunder::Core::Messaging::Metadata toBeAdded(::Thunder::Core::Messaging::Metadata::type::LOGGING, _T("Test_Category_5"), _T("SysLog")); + + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); client.AddInstance(0); //we are in framework - client.Enable(tobeAdded, false); - ASSERT_FALSE(::Thunder::Core::Messaging::MessageUnit::Instance().IsEnabledByDefault(tobeAdded)); - auto defaultsString = ::Thunder::Core::Messaging::MessageUnit::Instance().Defaults(); - ::Thunder::Core::Messaging::Settings settings; - settings.FromString(defaultsString); + // LOGGING is enabled and available by default + + std::vector modules; + client.Modules(modules); - ASSERT_EQ(settings.Logging.Entries.Length(), 1); - auto entriesIt = settings.Logging.Entries.Elements(); - while (entriesIt.Next()) { - ASSERT_STREQ(entriesIt.Current().Category.Value().c_str(), tobeAdded.Category().c_str()); - ASSERT_STREQ(entriesIt.Current().Module.Value().c_str(), tobeAdded.Module().c_str()); + bool enabled = false; + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + enabled = enabled + || + ( toBeAdded.Type() == item.Type() + && toBeAdded.Category() == item.Category() + && toBeAdded.Module() == item.Module() + && item.Enabled() + ) + ; + } } + + EXPECT_TRUE(enabled); + + client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, EnablingFullySpecifiedMessageUpdateOnlyThisOne) { - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); + ToggleDefaultConfig(true); + + ::Thunder::Core::Messaging::Metadata message(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_1"), EXPAND_AND_QUOTE(MODULE_NAME)); + + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + client.AddInstance(0); //we are in framework - auto itBeforeUpdate = client.Enabled(); - ::Thunder::Core::Messaging::MetaData message(::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("Test_Category_1"), EXPAND_AND_QUOTE(MODULE_NAME)); - int matches = 0; - while (itBeforeUpdate.Next()) { - auto info = itBeforeUpdate.Current(); - if (info.first == message && info.second == false) { - ++matches; + // TRACING is not enabled but available by default + + std::vector modules; + client.Modules(modules); + + bool enabled = false; + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + enabled = enabled + || + ( message.Type() == item.Type() + && message.Category() == item.Category() + && message.Module() == item.Module() + && item.Enabled() + ) + ; } } - ASSERT_EQ(matches, 1); - matches = 0; + EXPECT_FALSE(enabled); + client.Enable(message, true); - auto itAfterUpdate = client.Enabled(); - while (itAfterUpdate.Next()) { - auto info = itAfterUpdate.Current(); - if (info.first == message && info.second == true) { - ++matches; + + client.Enable(message, true); + + modules.clear(); + client.Modules(modules); + + enabled = false; + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + enabled = enabled + || + ( message.Type() == item.Type() + && message.Category() == item.Category() + && message.Module() == item.Module() + && item.Enabled() + ) + ; } } - ASSERT_EQ(matches, 1); + + EXPECT_TRUE(enabled); + + client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, EnablingMessageSpecifiedByModuleShouldEnableAllCategoriesInsideIt) { - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); + ToggleDefaultConfig(false); + + const ::Thunder::Core::Messaging::Metadata message(::Thunder::Core::Messaging::Metadata::type::TRACING, _T(""), EXPAND_AND_QUOTE(MODULE_NAME)); + + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + client.AddInstance(0); //we are in framework - auto itBeforeUpdate = client.Enabled(); - - int enabled = 0; - while (itBeforeUpdate.Next()) { - auto info = itBeforeUpdate.Current(); - if (info.first.Type() == ::Thunder::Core::Messaging::MetaData::MessageType::TRACING && info.first.Module() == EXPAND_AND_QUOTE(MODULE_NAME)) { - if (info.second == true) { - ++enabled; + + std::vector modules; + client.Modules(modules); + + bool enabled = true; + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + if ( message.Type() == item.Type() + && message.Module() == item.Module() + ) { + enabled = enabled + && item.Enabled() + ; } } } - ASSERT_EQ(enabled, 0); - enabled = 0; - client.Enable({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T(""), EXPAND_AND_QUOTE(MODULE_NAME) }, true); - auto itAfterUpdate = client.Enabled(); - while (itAfterUpdate.Next()) { - auto info = itAfterUpdate.Current(); - if (info.first.Type() == ::Thunder::Core::Messaging::MetaData::MessageType::TRACING && info.first.Module() == EXPAND_AND_QUOTE(MODULE_NAME)) { - if (info.second == true) { - ++enabled; + EXPECT_FALSE(enabled); + + client.Enable(message, true); + + modules.clear(); + client.Modules(modules); + + enabled = true; + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + if ( message.Type() == item.Type() + && message.Module() == item.Module() + ) { + enabled = enabled + && item.Enabled() + ; } } } - ASSERT_EQ(enabled, 4); + EXPECT_TRUE(enabled); + + client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, EnablingMessageSpecifiedByCategoryShouldEnableItInAllModules) { - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); + ToggleDefaultConfig(true); + + const ::Thunder::Core::Messaging::Metadata message(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_1"), _T("")); + + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + client.AddInstance(0); //we are in framework - auto itBeforeUpdate = client.Enabled(); - - int enabled = 0; - while (itBeforeUpdate.Next()) { - auto info = itBeforeUpdate.Current(); - if (info.first.Type() == ::Thunder::Core::Messaging::MetaData::MessageType::TRACING && info.first.Category() == _T("Test_Category_1")) { - if (info.second == true) { - ++enabled; + + std::vector modules; + client.Modules(modules); + + bool enabled = true; + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + if ( message.Type() == item.Type() + && message.Category() == item.Category() + ) { + enabled = enabled + && item.Enabled() + ; } } } - ASSERT_EQ(enabled, 0); - enabled = 0; - client.Enable({ ::Thunder::Core::Messaging::MetaData::MessageType::TRACING, _T("Test_Category_1"), _T("") }, true); - auto itAfterUpdate = client.Enabled(); - while (itAfterUpdate.Next()) { - auto info = itAfterUpdate.Current(); - if (info.first.Type() == ::Thunder::Core::Messaging::MetaData::MessageType::TRACING && info.first.Category() == _T("Test_Category_1")) { - if (info.second == true) { - ++enabled; + EXPECT_FALSE(enabled); + + client.Enable(message, true); + + modules.clear(); + client.Modules(modules); + + enabled = true; + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + if ( message.Type() == item.Type() + && message.Category() == item.Category() + ) { + enabled = enabled + && item.Enabled() + ; } } } - ASSERT_EQ(enabled, 2); + EXPECT_TRUE(enabled); + + client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, TextMessageEventIsProperlySerializedIfBufferBigEnough) { - uint8_t buffer[1 * 1024]; + constexpr string::size_type bufferSize = 1024; + + uint8_t buffer[bufferSize]; const string testTextMessage = _T("TEST MESSAGE"); - Messaging::TextMessage tm(testTextMessage); + EXPECT_GT(bufferSize, sizeof(testTextMessage.size())); + + ::Thunder::Messaging::TextMessage tm(testTextMessage); auto serialized = tm.Serialize(buffer, sizeof(buffer)); - ASSERT_GT(serialized, 0); + EXPECT_GT(serialized, 0); auto deserialized = tm.Deserialize(buffer, sizeof(buffer)); - ASSERT_EQ(serialized, deserialized); + EXPECT_EQ(serialized, deserialized); - string result; - tm.ToString(result); - ASSERT_STREQ(result.c_str(), testTextMessage.c_str()); + string result = tm.Data(); + EXPECT_STREQ(result.c_str(), testTextMessage.c_str()); } TEST_F(Core_Messaging_MessageUnit, TextMessageEventIsProperlySerializedAndCutIfBufferNotBigEnough) { - uint8_t buffer[5]; + constexpr string::size_type bufferSize = 5; + + uint8_t buffer[bufferSize]; const string testTextMessage = _T("abcdefghi"); - Messaging::TextMessage tm(testTextMessage); + EXPECT_LT(bufferSize, sizeof(testTextMessage.size())); + + ::Thunder::Messaging::TextMessage tm(testTextMessage); auto serialized = tm.Serialize(buffer, sizeof(buffer)); - ASSERT_GT(serialized, 0); + EXPECT_GT(serialized, 0); auto deserialized = tm.Deserialize(buffer, serialized); - ASSERT_EQ(serialized, deserialized); + EXPECT_EQ(serialized, deserialized); + + string result = tm.Data(); - string result; - tm.ToString(result); - //last byte reserved for null termination - ASSERT_STREQ(result.c_str(), _T("abcd")); + EXPECT_STREQ(result.c_str(), testTextMessage.substr(0, bufferSize - 1).c_str()); } TEST_F(Core_Messaging_MessageUnit, ControlListIsProperlySerializedIfBufferBigEnough) { - uint8_t buffer[1 * 1024]; + ToggleDefaultConfig(true); - ::Thunder::Core::Messaging::ControlList cl; - for (const auto& control : _controls) { - cl.Announce(control.get()); - } + constexpr string::size_type bufferSize = 1024; + + uint8_t buffer[bufferSize]; + + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + + client.AddInstance(0); //we are in framework + + std::vector modules; + client.Modules(modules); + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); - auto serialized = cl.Serialize(buffer, sizeof(buffer)); - ASSERT_GT(serialized, 0); - ASSERT_EQ(buffer[0], _controls.size()); + while (item.Next()) { + ::Thunder::Messaging::MessageUnit::Control control({item.Type(), item.Category(), item.Module()}, item.Enabled()); + auto serialized = control.Serialize(buffer, sizeof(buffer)); - auto deserialized = cl.Deserialize(buffer, serialized); - ASSERT_EQ(serialized, deserialized); + EXPECT_GT(serialized, 0); - auto informationIt = cl.Information(); - auto controlsIt = _controls.cbegin(); - while (informationIt.Next()) { - ASSERT_EQ(informationIt.Current().first, controlsIt->get()->MessageMetaData()); - ++controlsIt; + auto deserialized = control.Deserialize(buffer, serialized); + + EXPECT_EQ(serialized, deserialized); + } } + + client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, ControlListIsProperlySerializedIfBufferNotBigEnough) { - const int controlsThatShouldFit = 2; - uint16_t maxBufferSize = 0; - auto it = _controls.cbegin(); - for (int i = 0; i < controlsThatShouldFit; ++i, ++it) { - maxBufferSize += sizeof(it->get()->MessageMetaData().Type()); - maxBufferSize += it->get()->MessageMetaData().Category().size() + 1; - maxBufferSize += it->get()->MessageMetaData().Module().size() + 1; - maxBufferSize += sizeof(bool); - } + ToggleDefaultConfig(true); + + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + + client.AddInstance(0); //we are in framework + + std::vector modules; + client.Modules(modules); std::vector buffer; - buffer.resize(maxBufferSize + 1); - ::Thunder::Core::Messaging::ControlList cl; - for (const auto& control : _controls) { - cl.Announce(control.get()); + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + buffer.resize(buffer.size() + sizeof(item.Type()), ::Thunder::Core::Messaging::Metadata::type::INVALID); + buffer.resize(buffer.size() + item.Category().size() + 1, ::Thunder::Core::Messaging::Metadata::type::INVALID); + buffer.resize(buffer.size() + item.Module().size() + 1, ::Thunder::Core::Messaging::Metadata::type::INVALID); + buffer.resize(buffer.size() + sizeof(bool), ::Thunder::Core::Messaging::Metadata::type::INVALID); + } } - auto serialized = cl.Serialize(buffer.data(), buffer.size()); - ASSERT_GT(serialized, 0); - ASSERT_EQ(buffer[0], controlsThatShouldFit); + buffer.resize(buffer.size() + 1); + + uint16_t index = 0; + + modules.clear(); + client.Modules(modules); + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + ::Thunder::Messaging::MessageUnit::Control control({item.Type(), item.Category(), item.Module()}, item.Enabled()); + auto serialized = control.Serialize(&(buffer.data()[index]), buffer.size()); + + EXPECT_GT(serialized, 0); - auto deserialized = cl.Deserialize(buffer.data(), serialized); - ASSERT_EQ(serialized, deserialized); + EXPECT_GT(buffer.size(), serialized); - auto informationIt = cl.Information(); - auto controlsIt = _controls.cbegin(); - while (informationIt.Next()) { - ASSERT_EQ(informationIt.Current().first, controlsIt->get()->MessageMetaData()); - ++controlsIt; + auto deserialized = control.Deserialize(&buffer.data()[index], serialized); + + index += serialized; + + EXPECT_EQ(serialized, deserialized); + } } + + EXPECT_LT(index, buffer.size()); + + client.RemoveInstance(0); + + ToggleDefaultConfig(false); } TEST_F(Core_Messaging_MessageUnit, PopMessageShouldReturnLastPushedMessage) { - const string traceMessage = _T("some trace"); - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); + ToggleDefaultConfig(true); + + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + client.AddInstance(0); //we are in framework //factory should be added before attempting to pop data - Messaging::TraceFactory factory; - client.AddFactory(::Thunder::Core::Messaging::MetaData::MessageType::TRACING, &factory); - - Messaging::TextMessage tm(traceMessage); - ::Thunder::Core::Messaging::Information info(::Thunder::Core::Messaging::MetaData::MessageType::TRACING, - _T("some_category"), - EXPAND_AND_QUOTE(MODULE_NAME), - _T("some_file.cpp"), - 1337, - ::Thunder::Core::Time::Now().Ticks()); - - ::Thunder::Core::Messaging::MessageUnit::Instance().Push(info, &tm); - - auto messages = client.PopMessagesAsList(); - ASSERT_EQ(messages.size(), 1); - auto message = messages.front(); - - ASSERT_NE(message.first.MessageMetaData().Type(), ::Thunder::Core::Messaging::MetaData::MessageType::INVALID); - ASSERT_EQ(message.first.MessageMetaData(), info.MessageMetaData()); - - string result; - message.second->ToString(result); - ASSERT_STREQ(message.first.FileName().c_str(), info.FileName().c_str()); - ASSERT_EQ(message.first.LineNumber(), info.LineNumber()); - ASSERT_EQ(message.first.TimeStamp(), info.TimeStamp()); - ASSERT_STREQ(traceMessage.c_str(), result.c_str()); - } + ::Thunder::Messaging::TraceFactoryType<::Thunder::Core::Messaging::IStore::Tracing, ::Thunder::Messaging::TextMessage> factory; + client.AddFactory(::Thunder::Core::Messaging::Metadata::type::TRACING, &factory); + + ::Thunder::Core::Messaging::Metadata metadata(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("some_category"), EXPAND_AND_QUOTE(MODULE_NAME)); + + client.Enable(metadata, true); - TEST_F(Core_Messaging_MessageUnit, PopMessageShouldReturnLastPushedMessageInOtherProcess) - { const string traceMessage = _T("some trace"); - Messaging::TextMessage tm(traceMessage); - ::Thunder::Core::Messaging::Information info(::Thunder::Core::Messaging::MetaData::MessageType::TRACING, - _T("some_category"), - EXPAND_AND_QUOTE(MODULE_NAME), - _T("some_file.cpp"), - 1337, - ::Thunder::Core::Time::Now().Ticks()); - - auto lambdaFunc = [&](IPTestAdministrator& testAdmin) { - Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath()); - client.AddInstance(0); - Messaging::TraceFactory factory; - client.AddFactory(::Thunder::Core::Messaging::MetaData::MessageType::TRACING, &factory); - testAdmin.Sync("setup"); - testAdmin.Sync("writer wrote"); - auto messages = client.PopMessagesAsList(); - - ASSERT_EQ(messages.size(), 1); - auto message = messages.front(); - - ASSERT_NE(message.first.MessageMetaData().Type(), ::Thunder::Core::Messaging::MetaData::MessageType::INVALID); - ASSERT_EQ(message.first.MessageMetaData(), info.MessageMetaData()); + ::Thunder::Messaging::TextMessage tm(traceMessage); - string result; - message.second->ToString(result); - ASSERT_STREQ(message.first.FileName().c_str(), info.FileName().c_str()); - ASSERT_EQ(message.first.LineNumber(), info.LineNumber()); - ASSERT_EQ(message.first.TimeStamp(), info.TimeStamp()); - ASSERT_STREQ(traceMessage.c_str(), result.c_str()); + ::Thunder::Core::Messaging::IStore::Tracing info(::Thunder::Core::Messaging::MessageInfo(metadata, ::Thunder::Core::Time::Now().Ticks()), _T("some_file"), 1337, EXPAND_AND_QUOTE(MODULE_NAME)); - testAdmin.Sync("reader read"); - testAdmin.Sync("done"); - }; + ::Thunder::Messaging::MessageUnit::Instance().Push(info, &tm); - static std::function lambdaVar = lambdaFunc; - IPTestAdministrator::OtherSideMain otherSide = [](IPTestAdministrator& testAdmin) { lambdaVar(testAdmin); }; - IPTestAdministrator testAdmin(otherSide); + // Risk of blocking or unknown suitable 'waittime' + //client.WaitForUpdates(::Thunder::Core::infinite); + // Instead 'flush' and continue + client.SkipWaiting(); - { - testAdmin.Sync("setup"); - testAdmin.Sync("writer wrote"); - ::Thunder::Core::Messaging::MessageUnit::Instance().Push(info, &tm); - testAdmin.Sync("reader read"); - } - testAdmin.Sync("done"); + bool present = false; + + client.PopMessagesAndCall( + [&](const ::Thunder::Core::ProxyType<::Thunder::Core::Messaging::MessageInfo>& metadata, const ::Thunder::Core::ProxyType<::Thunder::Core::Messaging::IEvent>& message) { + //(*metadata).TimeStamp(); + //(*metadata).Module(); + //(*metadata).Category(); + + if ((*metadata).Type() == ::Thunder::Core::Messaging::Metadata::type::TRACING) { + TRACE_L1( + _T("PopMessagesAndCall : Tracing message -> Filename : %s, Linenumber : %d, Classname : %s") + , static_cast<::Thunder::Core::Messaging::IStore::Tracing&>(*metadata).FileName().c_str() + , static_cast<::Thunder::Core::Messaging::IStore::Tracing&>(*metadata).LineNumber() + , static_cast<::Thunder::Core::Messaging::IStore::Tracing&>(*metadata).ClassName().c_str() + ); + + present = present || (*message).Data() == traceMessage; + } else { + TRACE_L1(_T("PopMessagesAndCall : Unknown message")); + } + + // By defining a callback data could be further processed + } + ); + + EXPECT_TRUE(present); + + client.RemoveInstance(0); + + ToggleDefaultConfig(false); + } + +TEST_F(Core_Messaging_MessageUnit, PopMessageShouldReturnLastPushedMessageInOtherProcess) +{ + const string traceMessage = _T("some trace"); + + ::Thunder::Core::Messaging::Metadata metadata(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("some_category"), EXPAND_AND_QUOTE(MODULE_NAME)); + + // Make sure the parent does not miss out on the signal if the child completes prematurely + sigset_t sigset; + + sigemptyset(&sigset); + sigaddset(&sigset, SIGCHLD); + + // Do not continue if it is not guaranteed a child can be killed / ended + ASSERT_FALSE(sigprocmask(SIG_BLOCK, &sigset, nullptr) == -1); + + pid_t pid = fork(); + + switch(pid) { + case -1 : // error + { + EXPECT_TRUE(pid != -1); + break; + } + case 0 : // child + { + ASSERT_FALSE(sigprocmask(SIG_UNBLOCK, &sigset, nullptr) == -1); + + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + + client.AddInstance(0); + + ::Thunder::Messaging::TraceFactoryType<::Thunder::Core::Messaging::IStore::Tracing, ::Thunder::Messaging::TextMessage> factory; + client.AddFactory(::Thunder::Core::Messaging::Metadata::type::TRACING, &factory); + + client.Enable(metadata, true); + + client.WaitForUpdates(::Thunder::Core::infinite); +// client.SkipWaiting(); + + client.PopMessagesAndCall( + [&](const ::Thunder::Core::ProxyType<::Thunder::Core::Messaging::MessageInfo>& metadata, const ::Thunder::Core::ProxyType<::Thunder::Core::Messaging::IEvent>& message) { + if ((*metadata).Type() == ::Thunder::Core::Messaging::Metadata::type::TRACING) { + TRACE_L1( + _T("PopMessagesAndCall : Tracing message -> Filename : %s, Linenumber : %d, Classname : %s") + , static_cast<::Thunder::Core::Messaging::IStore::Tracing&>(*metadata).FileName().c_str() + , static_cast<::Thunder::Core::Messaging::IStore::Tracing&>(*metadata).LineNumber() + , static_cast<::Thunder::Core::Messaging::IStore::Tracing&>(*metadata).ClassName().c_str() + ); + + EXPECT_TRUE((*message).Data() == traceMessage); + } + } + ); + + client.RemoveFactory(::Thunder::Core::Messaging::Metadata::TRACING); + + client.RemoveInstance(0); + + break; + } + default : // parent + { + ASSERT_FALSE(sigprocmask(SIG_UNBLOCK, &sigset, nullptr) == -1); + + ToggleDefaultConfig(true); + + ::Thunder::Messaging::TextMessage tm(traceMessage); + + ::Thunder::Core::Messaging::IStore::Tracing info(::Thunder::Core::Messaging::MessageInfo(metadata, ::Thunder::Core::Time::Now().Ticks()), _T("some_file"), 1337, EXPAND_AND_QUOTE(MODULE_NAME)); + + ::Thunder::Messaging::MessageUnit::Instance().Push(info, &tm); + + struct timespec timeout; + timeout.tv_sec = 60; // Arbitrary value + timeout.tv_nsec = 0; + + do { + if (sigtimedwait(&sigset, nullptr, &timeout) == -1) { + int err = errno; + if (err == EINTR) { + // Signal other than SIGCHLD + continue; + } else if (err == EAGAIN) { + // Timeout and no SIGCHLD received + // Kill the child + EXPECT_FALSE(kill(pid, SIGKILL) == -1); + } else { + // Error in executing sigtimedwait, 'abort' + EXPECT_FALSE(err == 0); + } + } + + break; + } while(waitpid(-1, nullptr, WNOHANG) <= 0); + + ToggleDefaultConfig(false); + } } +} } // Core } // Tests From be5e514261b86a447a23255b5635703f63143cad Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Fri, 26 Jul 2024 09:32:01 +0000 Subject: [PATCH 14/35] [Tests/unit/core] : Use 'IPTestAdministrator' for 'PopMessageShouldReturnLastPushedMessageInOtherProcess' in test_message_unit' --- Tests/unit/core/test_message_unit.cpp | 135 ++++++++++---------------- 1 file changed, 51 insertions(+), 84 deletions(-) diff --git a/Tests/unit/core/test_message_unit.cpp b/Tests/unit/core/test_message_unit.cpp index 94181e790..6a5121ef4 100644 --- a/Tests/unit/core/test_message_unit.cpp +++ b/Tests/unit/core/test_message_unit.cpp @@ -27,7 +27,7 @@ #include -//#include "../IPTestAdministrator.h" +#include "../IPTestAdministrator.h" namespace Thunder { namespace Tests { @@ -935,8 +935,6 @@ namespace Core { ::Thunder::Messaging::MessageUnit::Instance().Push(info, &tm); - // Risk of blocking or unknown suitable 'waittime' - //client.WaitForUpdates(::Thunder::Core::infinite); // Instead 'flush' and continue client.SkipWaiting(); @@ -972,105 +970,74 @@ namespace Core { ToggleDefaultConfig(false); } -TEST_F(Core_Messaging_MessageUnit, PopMessageShouldReturnLastPushedMessageInOtherProcess) -{ - const string traceMessage = _T("some trace"); + TEST_F(Core_Messaging_MessageUnit, PopMessageShouldReturnLastPushedMessageInOtherProcess) + { + constexpr uint32_t initHandshakeValue = 0, maxWaitTime = 4, maxWaitTimeMs = 4000, maxInitTime = 2000; + constexpr uint8_t maxRetries = 15; + + const string traceMessage = _T("some trace"); + + ::Thunder::Core::Messaging::Metadata metadata(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("some_category"), EXPAND_AND_QUOTE(MODULE_NAME)); + + IPTestAdministrator::Callback callback_child = [&](IPTestAdministrator& testAdmin) { + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); - ::Thunder::Core::Messaging::Metadata metadata(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("some_category"), EXPAND_AND_QUOTE(MODULE_NAME)); + ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); - // Make sure the parent does not miss out on the signal if the child completes prematurely - sigset_t sigset; + client.AddInstance(0); - sigemptyset(&sigset); - sigaddset(&sigset, SIGCHLD); + ::Thunder::Messaging::TraceFactoryType<::Thunder::Core::Messaging::IStore::Tracing, ::Thunder::Messaging::TextMessage> factory; + client.AddFactory(::Thunder::Core::Messaging::Metadata::type::TRACING, &factory); - // Do not continue if it is not guaranteed a child can be killed / ended - ASSERT_FALSE(sigprocmask(SIG_BLOCK, &sigset, nullptr) == -1); + client.Enable(metadata, true); - pid_t pid = fork(); + client.WaitForUpdates(maxWaitTimeMs); + + client.PopMessagesAndCall( + [&](const ::Thunder::Core::ProxyType<::Thunder::Core::Messaging::MessageInfo>& metadata, const ::Thunder::Core::ProxyType<::Thunder::Core::Messaging::IEvent>& message) { + if ((*metadata).Type() == ::Thunder::Core::Messaging::Metadata::type::TRACING) { + TRACE_L1( + _T("PopMessagesAndCall : Tracing message -> Filename : %s, Linenumber : %d, Classname : %s") + , static_cast<::Thunder::Core::Messaging::IStore::Tracing&>(*metadata).FileName().c_str() + , static_cast<::Thunder::Core::Messaging::IStore::Tracing&>(*metadata).LineNumber() + , static_cast<::Thunder::Core::Messaging::IStore::Tracing&>(*metadata).ClassName().c_str() + ); - switch(pid) { - case -1 : // error - { - EXPECT_TRUE(pid != -1); - break; + EXPECT_TRUE((*message).Data() == traceMessage); } - case 0 : // child - { - ASSERT_FALSE(sigprocmask(SIG_UNBLOCK, &sigset, nullptr) == -1); + } + ); - ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + client.RemoveFactory(::Thunder::Core::Messaging::Metadata::TRACING); - client.AddInstance(0); + client.RemoveInstance(0); - ::Thunder::Messaging::TraceFactoryType<::Thunder::Core::Messaging::IStore::Tracing, ::Thunder::Messaging::TextMessage> factory; - client.AddFactory(::Thunder::Core::Messaging::Metadata::type::TRACING, &factory); + ASSERT_EQ(testAdmin.Signal(initHandshakeValue, maxRetries), ::Thunder::Core::ERROR_NONE); + }; - client.Enable(metadata, true); + IPTestAdministrator::Callback callback_parent = [&](IPTestAdministrator& testAdmin) { + ToggleDefaultConfig(true); - client.WaitForUpdates(::Thunder::Core::infinite); -// client.SkipWaiting(); + // a small delay so the child can be set up + SleepMs(maxInitTime); - client.PopMessagesAndCall( - [&](const ::Thunder::Core::ProxyType<::Thunder::Core::Messaging::MessageInfo>& metadata, const ::Thunder::Core::ProxyType<::Thunder::Core::Messaging::IEvent>& message) { - if ((*metadata).Type() == ::Thunder::Core::Messaging::Metadata::type::TRACING) { - TRACE_L1( - _T("PopMessagesAndCall : Tracing message -> Filename : %s, Linenumber : %d, Classname : %s") - , static_cast<::Thunder::Core::Messaging::IStore::Tracing&>(*metadata).FileName().c_str() - , static_cast<::Thunder::Core::Messaging::IStore::Tracing&>(*metadata).LineNumber() - , static_cast<::Thunder::Core::Messaging::IStore::Tracing&>(*metadata).ClassName().c_str() - ); + ::Thunder::Messaging::TextMessage tm(traceMessage); - EXPECT_TRUE((*message).Data() == traceMessage); - } - } - ); + ::Thunder::Core::Messaging::IStore::Tracing info(::Thunder::Core::Messaging::MessageInfo(metadata, ::Thunder::Core::Time::Now().Ticks()), _T("some_file"), 1337, EXPAND_AND_QUOTE(MODULE_NAME)); - client.RemoveFactory(::Thunder::Core::Messaging::Metadata::TRACING); + ::Thunder::Messaging::MessageUnit::Instance().Push(info, &tm); - client.RemoveInstance(0); + ASSERT_EQ(testAdmin.Wait(initHandshakeValue), ::Thunder::Core::ERROR_NONE); - break; - } - default : // parent - { - ASSERT_FALSE(sigprocmask(SIG_UNBLOCK, &sigset, nullptr) == -1); - - ToggleDefaultConfig(true); - - ::Thunder::Messaging::TextMessage tm(traceMessage); - - ::Thunder::Core::Messaging::IStore::Tracing info(::Thunder::Core::Messaging::MessageInfo(metadata, ::Thunder::Core::Time::Now().Ticks()), _T("some_file"), 1337, EXPAND_AND_QUOTE(MODULE_NAME)); - - ::Thunder::Messaging::MessageUnit::Instance().Push(info, &tm); - - struct timespec timeout; - timeout.tv_sec = 60; // Arbitrary value - timeout.tv_nsec = 0; - - do { - if (sigtimedwait(&sigset, nullptr, &timeout) == -1) { - int err = errno; - if (err == EINTR) { - // Signal other than SIGCHLD - continue; - } else if (err == EAGAIN) { - // Timeout and no SIGCHLD received - // Kill the child - EXPECT_FALSE(kill(pid, SIGKILL) == -1); - } else { - // Error in executing sigtimedwait, 'abort' - EXPECT_FALSE(err == 0); - } - } - - break; - } while(waitpid(-1, nullptr, WNOHANG) <= 0); - - ToggleDefaultConfig(false); - } + ToggleDefaultConfig(false); + }; + + IPTestAdministrator testAdmin(callback_parent, callback_child, initHandshakeValue, maxWaitTime); + + // Code after this line is executed by both parent and child + +// ::Thunder::Core::Singleton::Dispose(); } -} } // Core } // Tests From 7a25695488e7c74e56c839079fd065a345ef8d2f Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Mon, 29 Jul 2024 16:06:52 +0000 Subject: [PATCH 15/35] [Tests/unit/core] : Print modules in 'test_message_unit' to support debugging --- Tests/unit/core/test_message_unit.cpp | 42 +++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/Tests/unit/core/test_message_unit.cpp b/Tests/unit/core/test_message_unit.cpp index bfaf884f2..99839669a 100644 --- a/Tests/unit/core/test_message_unit.cpp +++ b/Tests/unit/core/test_message_unit.cpp @@ -17,6 +17,8 @@ * limitations under the License. */ +#include + #include #ifndef MODULE_NAME @@ -29,6 +31,8 @@ #include "../IPTestAdministrator.h" +#define PRINT_MODULES(NAME, MODULES) {std::cout << NAME << " ---> "; std::for_each(MODULES.begin(), MODULES.end(), [](std::string MODULE){std::cout << " " << MODULE;}); std::cout << std::endl;}; + namespace Thunder { namespace Tests { namespace Core { @@ -249,6 +253,8 @@ namespace Core { std::vector modules; client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + int matches = 0; int count = 0; @@ -295,6 +301,8 @@ namespace Core { std::vector modules; client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + int matches = 0; int count = 0; @@ -323,6 +331,8 @@ namespace Core { modules.clear(); client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + /* bool */ enabled = false; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -364,6 +374,8 @@ namespace Core { std::vector modules; client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + bool enabled = false; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -392,6 +404,8 @@ namespace Core { modules.clear(); client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + enabled = false; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -430,6 +444,8 @@ namespace Core { std::vector modules; client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + bool enabled = true; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -453,6 +469,8 @@ namespace Core { modules.clear(); client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + enabled = true; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -487,6 +505,8 @@ namespace Core { std::vector modules; client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + int matches = 0; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -512,6 +532,8 @@ namespace Core { modules.clear(); client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + matches = 0; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -552,6 +574,8 @@ namespace Core { std::vector modules; client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + bool enabled = false; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -593,6 +617,8 @@ namespace Core { std::vector modules; client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + bool enabled = false; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -621,6 +647,8 @@ namespace Core { modules.clear(); client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + enabled = false; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -660,6 +688,8 @@ namespace Core { std::vector modules; client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + bool enabled = true; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -685,6 +715,8 @@ namespace Core { modules.clear(); client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + enabled = true; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -723,6 +755,8 @@ namespace Core { std::vector modules; client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + bool enabled = true; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -748,6 +782,8 @@ namespace Core { modules.clear(); client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + enabled = true; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -829,6 +865,8 @@ namespace Core { std::vector modules; client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; @@ -862,6 +900,8 @@ namespace Core { std::vector modules; client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + std::vector buffer; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -884,6 +924,8 @@ namespace Core { modules.clear(); client.Modules(modules); +PRINT_MODULES(__PRETTY_FUNCTION__, modules); + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; From d34ded12efc4417bdc4224256fbc76710c9e42f0 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Tue, 30 Jul 2024 09:50:31 +0000 Subject: [PATCH 16/35] [Tests/unit/core] : Match 'MessageUnit::Open' with 'MessageUnit::Close' in 'test_message_unit' --- Tests/unit/core/test_message_unit.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tests/unit/core/test_message_unit.cpp b/Tests/unit/core/test_message_unit.cpp index 99839669a..446f05f09 100644 --- a/Tests/unit/core/test_message_unit.cpp +++ b/Tests/unit/core/test_message_unit.cpp @@ -358,7 +358,8 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); client.RemoveInstance(0); - ToggleDefaultConfig(false); + // Direct call required + ::Thunder::Messaging::MessageUnit::Instance().Close(); } TEST_F(Core_Messaging_MessageUnit, EnablingMessagesShouldAddToDefaultConfigListIfNotPresent) From da02a32291757c26374062ec9e07c84a49bf9c43 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Tue, 30 Jul 2024 14:45:16 +0000 Subject: [PATCH 17/35] [core/TextStreamRedirectType / core/MessageUnit] : improve (return) value checks --- Source/core/TextStreamRedirectType.h | 112 +++++++++++++++++++++++---- Source/messaging/MessageUnit.cpp | 2 + 2 files changed, 98 insertions(+), 16 deletions(-) diff --git a/Source/core/TextStreamRedirectType.h b/Source/core/TextStreamRedirectType.h index 6f214caea..6fc9c1579 100644 --- a/Source/core/TextStreamRedirectType.h +++ b/Source/core/TextStreamRedirectType.h @@ -394,41 +394,121 @@ namespace Core { _handle[1] = Core::IResource::INVALID; } ~ReaderImplementation() override { - Close(); + ASSERT(_handle[0] == Core::IResource::INVALID); + ASSERT(_handle[1] == Core::IResource::INVALID); + ASSERT(_index != Core::IResource::INVALID); + ASSERT(_copy == Core::IResource::INVALID); + + // The original owner of replacing (_index) is responsible for cleaning it up _index = Core::IResource::INVALID; } public: bool Open() { + // Create a pipe only once ASSERT(_index != Core::IResource::INVALID); + ASSERT(_handle[0] == Core::IResource::INVALID); + ASSERT(_handle[1] == Core::IResource::INVALID); - if ((_handle[0] == Core::IResource::INVALID) && (::pipe(_handle) == 0)) { + if ((_handle[0] == Core::IResource::INVALID) && (::pipe(_handle) != -1)) { _copy = ::dup(_index); - ::fsync(_index); + + ASSERT(_copy != -1); + + // A copy of some valid file descriptior represented by _index + + switch(_index) { + case STDERR_FILENO : do {} while(false); + case STDIN_FILENO : // no sync + break; + case STDOUT_FILENO : do {} while(false); + default : { + int result = ::fsync(_index); + ASSERT(result != 1); + } + } + + // Get flags associated with _handle[0] int flags = ::fcntl(_handle[0], F_GETFL); - ::fcntl(_handle[0], F_SETFL, (flags | O_NONBLOCK)); - ::dup2(_handle[1], _index); - ::close(_handle[1]); + + ASSERT(flags >= 0); + + // Set 'old' flags to _handle[0], with one extra flag + int result = ::fcntl(_handle[0], F_SETFL, (flags | O_NONBLOCK)); + + ASSERT(result != -1); + + ASSERT(_handle[1] != Core::IResource::INVALID); + ASSERT(_handle[1] != _index); + + // For invalid handle _index remains open + // Identical handles have no effect and returns _index, otherwise _index closed, and then _index becomes a copy of _handle[1] + result = ::dup2(_handle[1], _index); + + ASSERT(result != -1); + + result = ::close(_handle[1]); + + ASSERT(result != -1); + _handle[1] = Core::IResource::INVALID; - ResourceMonitor::Instance().Register(*this); } + + ResourceMonitor::Instance().Register(*this); + + ASSERT(_handle[0] != Core::IResource::INVALID); + ASSERT(_handle[1] == Core::IResource::INVALID); + ASSERT(_index != Core::IResource::INVALID); + ASSERT(_copy != Core::IResource::INVALID); + return (_handle[0] != Core::IResource::INVALID); } bool Close() { + ASSERT(_handle[0] != Core::IResource::INVALID); + ASSERT(_handle[1] == Core::IResource::INVALID); + ASSERT(_index != Core::IResource::INVALID); + ASSERT(_copy != Core::IResource::INVALID); + if (_handle[0] != Core::IResource::INVALID) { + switch(_handle[0]) { + case STDERR_FILENO : do {} while(false); + case STDIN_FILENO : // no sync + break; + case STDOUT_FILENO : do {} while(false); + default : { + int result = ::fsync(_index); + ASSERT(result != 1); + } + } - ::fsync(_handle[0]); + int result = ::close(_handle[0]); - if (::dup2(_copy, _index) != -1) { - ::close(_handle[0]); - ::close(_copy); - ResourceMonitor::Instance().Unregister(*this); - _handle[0] = Core::IResource::INVALID; - _copy = Core::IResource::INVALID; - Reader::Flush(); - } + ASSERT(result != -1); + + _handle[0] = Core::IResource::INVALID; } + + if (_copy != Core::IResource::INVALID) { + ASSERT(_copy != _index); + + int result = ::dup2(_copy, _index); + + ASSERT(result != -1); + + result = ::close(_copy); + + ASSERT(result != -1); + + _copy = Core::IResource::INVALID; + } + + ResourceMonitor::Instance().Unregister(*this); + + Reader::Flush(); + + ASSERT(_handle[0] == Core::IResource::INVALID); + return (_handle[0] == Core::IResource::INVALID); } Core::IResource::handle Origin() const { diff --git a/Source/messaging/MessageUnit.cpp b/Source/messaging/MessageUnit.cpp index 429412f69..81e9e62aa 100644 --- a/Source/messaging/MessageUnit.cpp +++ b/Source/messaging/MessageUnit.cpp @@ -97,6 +97,8 @@ namespace Thunder { public: void Handle(Core::Messaging::IControl* control) override { + ASSERT(control != nullptr); + const string& module = control->Metadata().Module(); if (std::find(_modules.begin(), _modules.end(), module) == _modules.end()) { _modules.push_back(module); From f07568159e36f1694407c02e42843010bf40b47c Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Tue, 30 Jul 2024 21:14:14 +0000 Subject: [PATCH 18/35] [core/MessageUnit] : add a comment on the available modules --- Source/messaging/MessageUnit.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/messaging/MessageUnit.cpp b/Source/messaging/MessageUnit.cpp index 81e9e62aa..40b25e39c 100644 --- a/Source/messaging/MessageUnit.cpp +++ b/Source/messaging/MessageUnit.cpp @@ -314,6 +314,10 @@ namespace Thunder { Messaging::ConsoleStandardOut::Instance().Close(); } Core::Messaging::IStore::Set(nullptr); + + // Loop of the entire list including those added via the announce macros like + // SYSLOG_ANNOUNCE, OPERATIONAL_STREAM_ANNOUNCE, ANNOUNCE_WARNING + // Re-opening MessageUnit does not restore // anounces them Core::Messaging::IControl::Iterate(handler); _adminLock.Lock(); From 5248a4b3d0864ce7e3c343fb55f7b9234f61a9cf Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Thu, 1 Aug 2024 11:58:25 +0000 Subject: [PATCH 19/35] [core/messaging/Control] : Unconditionally revoke ourself if we unconditionally annnounce ourself --- Source/messaging/Control.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Source/messaging/Control.h b/Source/messaging/Control.h index 9b40d469d..e682ab25d 100644 --- a/Source/messaging/Control.h +++ b/Source/messaging/Control.h @@ -44,7 +44,7 @@ namespace Messaging { Core::Messaging::IControl::Announce(this); } ~ControlType() override { - Destroy(); + Core::Messaging::IControl::Revoke(this); } public: @@ -67,10 +67,6 @@ namespace Messaging { void Destroy() override { - if ((_enabled & 0x02) != 0) { - Core::Messaging::IControl::Revoke(this); - _enabled = 0; - } } private: From ce9ead13a4e6171e37b69daa3ae64e7b8163acad Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Fri, 2 Aug 2024 07:15:39 +0000 Subject: [PATCH 20/35] [core/MessageStore] : match 'Serialize' length --- Source/core/MessageStore.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/core/MessageStore.cpp b/Source/core/MessageStore.cpp index d42bc63aa..f79ee204c 100644 --- a/Source/core/MessageStore.cpp +++ b/Source/core/MessageStore.cpp @@ -157,9 +157,9 @@ namespace Core { { uint16_t length = 0; - ASSERT(bufferSize > (sizeof(_type) + (sizeof(_category[0]) * 2))); + ASSERT(bufferSize > (sizeof(_type) + _category.size() + 1)); - if (bufferSize > (sizeof(_type) + (sizeof(_category[0]) * 2))) { + if (bufferSize > (sizeof(_type) + _category.size() + 1)) { Core::FrameType<0> frame(const_cast(buffer), bufferSize, bufferSize); Core::FrameType<0>::Reader frameReader(frame, 0); _type = frameReader.Number(); From 93ada9a67018a0cfdaa65f5c64b5182e055d63ed Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Mon, 5 Aug 2024 07:41:11 +0000 Subject: [PATCH 21/35] Revert "[core/messaging/Control] : Unconditionally revoke ourself if we unconditionally annnounce ourself" This reverts commit 5248a4b3d0864ce7e3c343fb55f7b9234f61a9cf. --- Source/messaging/Control.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/messaging/Control.h b/Source/messaging/Control.h index e682ab25d..9b40d469d 100644 --- a/Source/messaging/Control.h +++ b/Source/messaging/Control.h @@ -44,7 +44,7 @@ namespace Messaging { Core::Messaging::IControl::Announce(this); } ~ControlType() override { - Core::Messaging::IControl::Revoke(this); + Destroy(); } public: @@ -67,6 +67,10 @@ namespace Messaging { void Destroy() override { + if ((_enabled & 0x02) != 0) { + Core::Messaging::IControl::Revoke(this); + _enabled = 0; + } } private: From cdc50b28ec2c975472662643ddf091c66d6bce36 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Mon, 5 Aug 2024 08:07:20 +0000 Subject: [PATCH 22/35] [core/MessageStore / messaging/MessageUnit] : Cleaning up is responsibility of the user of 'Announce' - Avoid pure virtual call - MessageUnit should not clean up / destroy (I)Controls announced via the SYSLOG_ANNOUNCE, OPERATIONAL_STREAM_ANNOUNCE and ANNOUNCE_WARNING --- Source/core/MessageStore.cpp | 5 ++--- Source/messaging/MessageUnit.cpp | 5 ----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Source/core/MessageStore.cpp b/Source/core/MessageStore.cpp index f79ee204c..50bee1d23 100644 --- a/Source/core/MessageStore.cpp +++ b/Source/core/MessageStore.cpp @@ -51,11 +51,10 @@ ENUM_CONVERSION_END(Core::Messaging::Metadata::type) { _adminLock.Lock(); - while (_controlList.size() > 0) { - VARIABLE_IS_NOT_USED auto& control = *_controlList.front(); + for_each (_controlList.begin(), _controlList.end(), [](Core::Messaging::IControl* const & control) { TRACE_L1(_T("MessageControl %s, size = %u was not disposed before"), typeid(control).name(), static_cast(_controlList.size())); - _controlList.front()->Destroy(); } + ); _adminLock.Unlock(); } diff --git a/Source/messaging/MessageUnit.cpp b/Source/messaging/MessageUnit.cpp index 40b25e39c..5a970a293 100644 --- a/Source/messaging/MessageUnit.cpp +++ b/Source/messaging/MessageUnit.cpp @@ -315,11 +315,6 @@ namespace Thunder { } Core::Messaging::IStore::Set(nullptr); - // Loop of the entire list including those added via the announce macros like - // SYSLOG_ANNOUNCE, OPERATIONAL_STREAM_ANNOUNCE, ANNOUNCE_WARNING - // Re-opening MessageUnit does not restore // anounces them - Core::Messaging::IControl::Iterate(handler); - _adminLock.Lock(); _dispatcher.reset(nullptr); _adminLock.Unlock(); From 3e16646bee7d567235571aed283d293ef8515565 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Mon, 5 Aug 2024 11:56:49 +0000 Subject: [PATCH 23/35] [Tests/unit/IPTestAdministrator] : Cherry pick 'a9f67288fc51d43a7cc52e4572b292d8ecb575dc' from 'development/iptestadministrator' --- Tests/unit/IPTestAdministrator.cpp | 19 +++++++++++++++---- Tests/unit/IPTestAdministrator.h | 1 + 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Tests/unit/IPTestAdministrator.cpp b/Tests/unit/IPTestAdministrator.cpp index 1d77b6e19..31435c865 100644 --- a/Tests/unit/IPTestAdministrator.cpp +++ b/Tests/unit/IPTestAdministrator.cpp @@ -43,11 +43,11 @@ IPTestAdministrator::IPTestAdministrator(Callback parent, Callback child, const { ASSERT(waitTime > 0 && waitTime < ::Thunder::Core::infinite); - int shm_id = shmget(IPC_PRIVATE, sizeof(struct SharedData) /* size */, IPC_CREAT | 0666 /* read and write for user, group and others */); + _shm_id = shmget(IPC_PRIVATE, sizeof(struct SharedData) /* size */, IPC_CREAT | 0666 /* read and write for user, group and others */); - ASSERT(shm_id >= 0); + ASSERT(_shm_id >= 0); - _sharedData = reinterpret_cast(shmat(shm_id, nullptr, 0 /* attach for reading and writing */)); + _sharedData = reinterpret_cast(shmat(_shm_id, nullptr, 0 /* attach for reading and writing */)); ASSERT(_sharedData != nullptr); @@ -96,6 +96,7 @@ IPTestAdministrator::~IPTestAdministrator() do {} while(false); case 0 : // Timeout expired before events are available { + // Potential leak of shared memory descriptor int result = syscall(SYS_kill, _pid, SIGKILL); ASSERT(result == 0); @@ -111,12 +112,22 @@ IPTestAdministrator::~IPTestAdministrator() if(shmdt(_sharedData) == -1) { switch(errno) { - case EINVAL : // The shared data is not the start address of the sahred segment + case EINVAL : // The shared data is not the start address of the shared segment do {} while(false); default : // Uninpsected or unknown error ; } } + + if (shmctl(_shm_id, IPC_RMID, nullptr) == -1) { + switch(errno) { + case EPERM : // User ID is not that of the creator, owner or insufficient privileges + do {} while(false); + default : // Uninpsected or unknown error + ; + } + + } } uint32_t IPTestAdministrator::Wait(uint32_t expectedHandshakeValue) const diff --git a/Tests/unit/IPTestAdministrator.h b/Tests/unit/IPTestAdministrator.h index dd95c94c7..01bab4724 100644 --- a/Tests/unit/IPTestAdministrator.h +++ b/Tests/unit/IPTestAdministrator.h @@ -65,6 +65,7 @@ private : constexpr static uint32_t _waitTimeDivisor = 10; SharedData* _sharedData; + int _shm_id; pid_t _pid; uint32_t _waitTime; // Seconds }; From 798b280580871087dfb6c31ffa875086213e3f69 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Mon, 5 Aug 2024 12:53:42 +0000 Subject: [PATCH 24/35] [Tests/unit/core] : fix 'test_message_unit' build and improves tests --- Tests/unit/core/test_message_unit.cpp | 325 +++++++++++++++++--------- 1 file changed, 217 insertions(+), 108 deletions(-) diff --git a/Tests/unit/core/test_message_unit.cpp b/Tests/unit/core/test_message_unit.cpp index 446f05f09..e2586d622 100644 --- a/Tests/unit/core/test_message_unit.cpp +++ b/Tests/unit/core/test_message_unit.cpp @@ -31,8 +31,6 @@ #include "../IPTestAdministrator.h" -#define PRINT_MODULES(NAME, MODULES) {std::cout << NAME << " ---> "; std::for_each(MODULES.begin(), MODULES.end(), [](std::string MODULE){std::cout << " " << MODULE;}); std::cout << std::endl;}; - namespace Thunder { namespace Tests { namespace Core { @@ -77,6 +75,7 @@ namespace Core { _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_2"), EXPAND_AND_QUOTE(MODULE_NAME) })); _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_3"), EXPAND_AND_QUOTE(MODULE_NAME) })); _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_4"), EXPAND_AND_QUOTE(MODULE_NAME) })); + _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_5"), EXPAND_AND_QUOTE(MODULE_NAME) })); _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_1"), _T("Test_Module2") })); _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::Metadata::type::LOGGING, _T("Test_Category_5"), _T("SysLog") })); @@ -253,8 +252,6 @@ namespace Core { std::vector modules; client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); - int matches = 0; int count = 0; @@ -301,8 +298,6 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); std::vector modules; client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); - int matches = 0; int count = 0; @@ -331,13 +326,11 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); modules.clear(); client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); - /* bool */ enabled = false; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; - + client.Controls(item, *it); while (item.Next()) { @@ -375,13 +368,11 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); std::vector modules; client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); - bool enabled = false; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; - + client.Controls(item, *it); while (item.Next()) { @@ -405,13 +396,11 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); modules.clear(); client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); - enabled = false; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; - + client.Controls(item, *it); while (item.Next()) { @@ -445,7 +434,7 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); std::vector modules; client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); + // Controls from the default are disabled by default, except a few, like the once announce with the ANNOUNCE-macros bool enabled = true; @@ -461,17 +450,49 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); } } - // Controls from the default are disabled by default, except a few + if (modules.size() > 0) { + EXPECT_TRUE(enabled); + } else { + EXPECT_FALSE(enabled); + } + + // Effective only for exsting modules / controls for this category + // Disable all controls within a category via metadata + client.Enable({::Thunder::Core::Messaging::Metadata::type::LOGGING, _T(""), _T("")}, false); + client.Enable({::Thunder::Core::Messaging::Metadata::type::TRACING, _T(""), _T("")}, false); + client.Enable({::Thunder::Core::Messaging::Metadata::type::REPORTING, _T(""), _T("")}, false); + client.Enable({::Thunder::Core::Messaging::Metadata::type::OPERATIONAL_STREAM, _T(""), _T("")}, false); + + modules.clear(); + client.Modules(modules); + + enabled = false; + + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + enabled = enabled + || item.Enabled() + ; + } + } + + // All categories are disabled EXPECT_FALSE(enabled); - // Enable message via metadata, eg, set enable for the previously added Control, eg, enable category + // WARNING: This effects all successive tests as it can differ from the defaults + + client.Enable({::Thunder::Core::Messaging::Metadata::type::LOGGING, _T(""), _T("")}, true); client.Enable({::Thunder::Core::Messaging::Metadata::type::TRACING, _T(""), _T("")}, true); + client.Enable({::Thunder::Core::Messaging::Metadata::type::REPORTING, _T(""), _T("")}, true); + client.Enable({::Thunder::Core::Messaging::Metadata::type::OPERATIONAL_STREAM, _T(""), _T("")}, true); modules.clear(); client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); - enabled = true; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -501,14 +522,12 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); client.AddInstance(0); //we are in framework - ::Thunder::Core::Messaging::Metadata messageToToggle(::Thunder::Core::Messaging::Metadata::type::LOGGING, _T("Test_Category_5"), _T("SysLog")); - std::vector modules; client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); + // Controls from the default are disabled by default, except a few, like the once announce with the ANNOUNCE-macros - int matches = 0; + bool enabled = true; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; @@ -516,26 +535,55 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); client.Controls(item, *it); while (item.Next()) { - if ( item.Type() == messageToToggle.Type() - && item.Category() == messageToToggle.Category() - && item.Module() == messageToToggle.Module() - && item.Enabled() - ) { - ++matches; - } + enabled = enabled + && item.Enabled() + ; } } - EXPECT_EQ(matches, 1); + if (modules.size() > 0) { + EXPECT_TRUE(enabled); + } else { + EXPECT_FALSE(enabled); + } - client.Enable(messageToToggle, false); + // Effective only for exsting modules / controls for this category + // Disable all controls within a category via metadata + client.Enable({::Thunder::Core::Messaging::Metadata::type::LOGGING, _T(""), _T("")}, false); + client.Enable({::Thunder::Core::Messaging::Metadata::type::TRACING, _T(""), _T("")}, false); + client.Enable({::Thunder::Core::Messaging::Metadata::type::REPORTING, _T(""), _T("")}, false); + client.Enable({::Thunder::Core::Messaging::Metadata::type::OPERATIONAL_STREAM, _T(""), _T("")}, false); modules.clear(); client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); + enabled = false; - matches = 0; + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + enabled = enabled + || item.Enabled() + ; + } + } + + // All categories are disabled + EXPECT_FALSE(enabled); + + // WARNING: This effects all successive tests as it can differ from the defaults + + client.Enable({::Thunder::Core::Messaging::Metadata::type::LOGGING, _T(""), _T("SysLog")}, true); + + modules.clear(); + client.Modules(modules); + + enabled = true; + + int matches = 0; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; @@ -543,17 +591,23 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); client.Controls(item, *it); while (item.Next()) { - if ( item.Type() == messageToToggle.Type() - && item.Category() == messageToToggle.Category() - && item.Module() == messageToToggle.Module() - && !item.Enabled() - ) { + if (item.Module() == "SysLog") { + enabled = enabled + && item.Enabled() + ; ++matches; } } } - EXPECT_EQ(matches, 1); + EXPECT_TRUE(enabled); + EXPECT_GT(matches, 0); + + // Re-enable all + client.Enable({::Thunder::Core::Messaging::Metadata::type::LOGGING, _T(""), _T("")}, true); + client.Enable({::Thunder::Core::Messaging::Metadata::type::TRACING, _T(""), _T("")}, true); + client.Enable({::Thunder::Core::Messaging::Metadata::type::REPORTING, _T(""), _T("")}, true); + client.Enable({::Thunder::Core::Messaging::Metadata::type::OPERATIONAL_STREAM, _T(""), _T("")}, true); client.RemoveInstance(0); @@ -565,19 +619,37 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); ToggleDefaultConfig(true); const ::Thunder::Core::Messaging::Metadata toBeAdded(::Thunder::Core::Messaging::Metadata::type::LOGGING, _T("Test_Category_5"), _T("SysLog")); + Control control(toBeAdded); ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); client.AddInstance(0); //we are in framework - // LOGGING is enabled and available by default - std::vector modules; client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); + int matches = 0; - bool enabled = false; + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { + ::Thunder::Messaging::MessageUnit::Iterator item; + + client.Controls(item, *it); + + while (item.Next()) { + if ( toBeAdded.Type() == item.Type() + && toBeAdded.Category() == item.Category() + && toBeAdded.Module() == item.Module() + ) { + ++matches; + } + } + } + + EXPECT_EQ(matches, 0); + + matches = 0; + + ::Thunder::Core::Messaging::IControl::Announce(&control); for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; @@ -585,18 +657,19 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); client.Controls(item, *it); while (item.Next()) { - enabled = enabled - || - ( toBeAdded.Type() == item.Type() - && toBeAdded.Category() == item.Category() - && toBeAdded.Module() == item.Module() - && item.Enabled() - ) - ; + if ( toBeAdded.Type() == item.Type() + && toBeAdded.Category() == item.Category() + && toBeAdded.Module() == item.Module() + ) { + ++matches; + } } } - EXPECT_TRUE(enabled); + EXPECT_EQ(matches, 1); + + // The control goes out of scope + ::Thunder::Core::Messaging::IControl::Revoke(&control); client.RemoveInstance(0); @@ -608,18 +681,23 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); ToggleDefaultConfig(true); ::Thunder::Core::Messaging::Metadata message(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_1"), EXPAND_AND_QUOTE(MODULE_NAME)); + Control control(message); ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); client.AddInstance(0); //we are in framework - // TRACING is not enabled but available by default + ::Thunder::Core::Messaging::IControl::Announce(&control); + + // Disable all controls within a category via metadata + client.Enable({::Thunder::Core::Messaging::Metadata::type::LOGGING, _T(""), _T("")}, false); + client.Enable({::Thunder::Core::Messaging::Metadata::type::TRACING, _T(""), _T("")}, false); + client.Enable({::Thunder::Core::Messaging::Metadata::type::REPORTING, _T(""), _T("")}, false); + client.Enable({::Thunder::Core::Messaging::Metadata::type::OPERATIONAL_STREAM, _T(""), _T("")}, false); std::vector modules; client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); - bool enabled = false; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -643,13 +721,9 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); client.Enable(message, true); - client.Enable(message, true); - modules.clear(); client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); - enabled = false; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -671,6 +745,13 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); EXPECT_TRUE(enabled); + ::Thunder::Core::Messaging::IControl::Revoke(&control); + + client.Enable({::Thunder::Core::Messaging::Metadata::type::LOGGING, _T(""), _T("")}, true); + client.Enable({::Thunder::Core::Messaging::Metadata::type::TRACING, _T(""), _T("")}, true); + client.Enable({::Thunder::Core::Messaging::Metadata::type::REPORTING, _T(""), _T("")}, true); + client.Enable({::Thunder::Core::Messaging::Metadata::type::OPERATIONAL_STREAM, _T(""), _T("")}, true); + client.RemoveInstance(0); ToggleDefaultConfig(false); @@ -678,20 +759,28 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); TEST_F(Core_Messaging_MessageUnit, EnablingMessageSpecifiedByModuleShouldEnableAllCategoriesInsideIt) { - ToggleDefaultConfig(false); - - const ::Thunder::Core::Messaging::Metadata message(::Thunder::Core::Messaging::Metadata::type::TRACING, _T(""), EXPAND_AND_QUOTE(MODULE_NAME)); + ToggleDefaultConfig(true); ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + const ::Thunder::Core::Messaging::Metadata toBeAdded(::Thunder::Core::Messaging::Metadata::type::LOGGING, _T("Test_Category_5"), _T("SysLog")); + Control control(toBeAdded); + client.AddInstance(0); //we are in framework + ::Thunder::Core::Messaging::IControl::Announce(&control); + + // Effective only for exsting modules / controls for this category + // Disable all controls within a category via metadata + client.Enable({::Thunder::Core::Messaging::Metadata::type::LOGGING, _T(""), _T("")}, false); + client.Enable({::Thunder::Core::Messaging::Metadata::type::TRACING, _T(""), _T("")}, false); + client.Enable({::Thunder::Core::Messaging::Metadata::type::REPORTING, _T(""), _T("")}, false); + client.Enable({::Thunder::Core::Messaging::Metadata::type::OPERATIONAL_STREAM, _T(""), _T("")}, false); + std::vector modules; client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); - - bool enabled = true; + bool enabled = false; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; @@ -699,44 +788,51 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); client.Controls(item, *it); while (item.Next()) { - if ( message.Type() == item.Type() - && message.Module() == item.Module() - ) { - enabled = enabled - && item.Enabled() - ; - } + enabled = enabled + || item.Enabled() + ; } } + // All categories are disabled EXPECT_FALSE(enabled); - client.Enable(message, true); + // WARNING: This effects all successive tests as it can differ from the defaults + + client.Enable({::Thunder::Core::Messaging::Metadata::type::LOGGING, _T(""), _T("SysLog")}, true); modules.clear(); client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); - enabled = true; + int matches = 0; + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; client.Controls(item, *it); while (item.Next()) { - if ( message.Type() == item.Type() - && message.Module() == item.Module() + if ( item.Module() == "SysLog" + && item.Category() == "Test_Category_5" + && item.Enabled() ) { - enabled = enabled - && item.Enabled() - ; + ++matches; } } } EXPECT_TRUE(enabled); + EXPECT_EQ(matches, 1); + + ::Thunder::Core::Messaging::IControl::Revoke(&control); + + // Re-enable all + client.Enable({::Thunder::Core::Messaging::Metadata::type::LOGGING, _T(""), _T("")}, true); + client.Enable({::Thunder::Core::Messaging::Metadata::type::TRACING, _T(""), _T("")}, true); + client.Enable({::Thunder::Core::Messaging::Metadata::type::REPORTING, _T(""), _T("")}, true); + client.Enable({::Thunder::Core::Messaging::Metadata::type::OPERATIONAL_STREAM, _T(""), _T("")}, true); client.RemoveInstance(0); @@ -747,18 +843,30 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); { ToggleDefaultConfig(true); - const ::Thunder::Core::Messaging::Metadata message(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_1"), _T("")); - ::Thunder::Messaging::MessageClient client(DispatcherIdentifier(), DispatcherBasePath() /*, socketPort not specified, domain socket used instead */); + const ::Thunder::Core::Messaging::Metadata moduleMessage(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_5"), EXPAND_AND_QUOTE(MODULE_NAME)); + Control moduleControl(moduleMessage); + + const ::Thunder::Core::Messaging::Metadata syslogMessage(::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_5"), _T("SysLog")); + Control syslogControl(syslogMessage); + client.AddInstance(0); //we are in framework + ::Thunder::Core::Messaging::IControl::Announce(&moduleControl); + ::Thunder::Core::Messaging::IControl::Announce(&syslogControl); + + // Effective only for exsting modules / controls for this category + // Disable all controls within a category via metadata + client.Enable({::Thunder::Core::Messaging::Metadata::type::LOGGING, _T(""), _T("")}, false); + client.Enable({::Thunder::Core::Messaging::Metadata::type::TRACING, _T(""), _T("")}, false); + client.Enable({::Thunder::Core::Messaging::Metadata::type::REPORTING, _T(""), _T("")}, false); + client.Enable({::Thunder::Core::Messaging::Metadata::type::OPERATIONAL_STREAM, _T(""), _T("")}, false); + std::vector modules; client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); - - bool enabled = true; + bool enabled = false; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; @@ -766,44 +874,51 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); client.Controls(item, *it); while (item.Next()) { - if ( message.Type() == item.Type() - && message.Category() == item.Category() - ) { - enabled = enabled - && item.Enabled() - ; - } + enabled = enabled + || item.Enabled() + ; } } + // All categories are disabled EXPECT_FALSE(enabled); - client.Enable(message, true); + // WARNING: This effects all successive tests as it can differ from the defaults + + client.Enable({::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_5"), _T("")}, true); modules.clear(); client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); - enabled = true; + int matches = 0; + for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; client.Controls(item, *it); while (item.Next()) { - if ( message.Type() == item.Type() - && message.Category() == item.Category() + if ( item.Category() == "Test_Category_5" + && item.Enabled() ) { - enabled = enabled - && item.Enabled() - ; + ++matches; } } } EXPECT_TRUE(enabled); + EXPECT_EQ(matches, 2); // 'all' within the same TYPE, ie, TRACING + + ::Thunder::Core::Messaging::IControl::Revoke(&moduleControl); + ::Thunder::Core::Messaging::IControl::Revoke(&syslogControl); + + // Re-enable all + client.Enable({::Thunder::Core::Messaging::Metadata::type::LOGGING, _T(""), _T("")}, true); + client.Enable({::Thunder::Core::Messaging::Metadata::type::TRACING, _T(""), _T("")}, true); + client.Enable({::Thunder::Core::Messaging::Metadata::type::REPORTING, _T(""), _T("")}, true); + client.Enable({::Thunder::Core::Messaging::Metadata::type::OPERATIONAL_STREAM, _T(""), _T("")}, true); client.RemoveInstance(0); @@ -866,8 +981,6 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); std::vector modules; client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); - for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; @@ -901,8 +1014,6 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); std::vector modules; client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); - std::vector buffer; for (auto it = modules.begin(), end = modules.end(); it != end; it++) { @@ -925,8 +1036,6 @@ PRINT_MODULES(__PRETTY_FUNCTION__, modules); modules.clear(); client.Modules(modules); -PRINT_MODULES(__PRETTY_FUNCTION__, modules); - for (auto it = modules.begin(), end = modules.end(); it != end; it++) { ::Thunder::Messaging::MessageUnit::Iterator item; From 71fec8a327854684518ea006d7aa7ac2b20ea826 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Mon, 5 Aug 2024 13:01:12 +0000 Subject: [PATCH 25/35] [Tests/unit/core] : add 'test_message_unit' to build --- Tests/unit/core/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/Tests/unit/core/CMakeLists.txt b/Tests/unit/core/CMakeLists.txt index 813e68ac8..e955a2f88 100644 --- a/Tests/unit/core/CMakeLists.txt +++ b/Tests/unit/core/CMakeLists.txt @@ -80,12 +80,10 @@ add_executable(${TEST_RUNNER_NAME} test_workerpool.cpp test_xgetopt.cpp ) -#[[ target_sources(${TEST_RUNNER_NAME} PRIVATE test_message_unit.cpp) target_link_libraries(${TEST_RUNNER_NAME} ThunderMessaging ) -]] else() add_executable(${TEST_RUNNER_NAME} test_databuffer.cpp From 90f3519bc2089c735f2486a559b1bc38f40ef352 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Mon, 5 Aug 2024 14:13:13 +0000 Subject: [PATCH 26/35] [core/MessageStore] : avoid 'variable not used' compiler warning if TRACE_L1 is NOP --- Source/core/MessageStore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/core/MessageStore.cpp b/Source/core/MessageStore.cpp index 50bee1d23..ed5a696cd 100644 --- a/Source/core/MessageStore.cpp +++ b/Source/core/MessageStore.cpp @@ -51,7 +51,7 @@ ENUM_CONVERSION_END(Core::Messaging::Metadata::type) { _adminLock.Lock(); - for_each (_controlList.begin(), _controlList.end(), [](Core::Messaging::IControl* const & control) { + for_each (_controlList.begin(), _controlList.end(), [](VARIABLE_IS_NOT_USED Core::Messaging::IControl* const & control) { TRACE_L1(_T("MessageControl %s, size = %u was not disposed before"), typeid(control).name(), static_cast(_controlList.size())); } ); From 9154bdd7a08777d2065c38c61261d4e9babced54 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Tue, 6 Aug 2024 08:07:55 +0000 Subject: [PATCH 27/35] [core/TextStreamRedirectType] : Introduced variables in 'da02a32291757c26374062ec9e07c84a49bf9c43' may not be used --- Source/core/TextStreamRedirectType.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/core/TextStreamRedirectType.h b/Source/core/TextStreamRedirectType.h index 6fc9c1579..fd9fa14f4 100644 --- a/Source/core/TextStreamRedirectType.h +++ b/Source/core/TextStreamRedirectType.h @@ -424,7 +424,7 @@ namespace Core { break; case STDOUT_FILENO : do {} while(false); default : { - int result = ::fsync(_index); + VARIABLE_IS_NOT_USED int result = ::fsync(_index); ASSERT(result != 1); } } @@ -435,7 +435,7 @@ namespace Core { ASSERT(flags >= 0); // Set 'old' flags to _handle[0], with one extra flag - int result = ::fcntl(_handle[0], F_SETFL, (flags | O_NONBLOCK)); + VARIABLE_IS_NOT_USED int result = ::fcntl(_handle[0], F_SETFL, (flags | O_NONBLOCK)); ASSERT(result != -1); @@ -477,12 +477,12 @@ namespace Core { break; case STDOUT_FILENO : do {} while(false); default : { - int result = ::fsync(_index); + VARIABLE_IS_NOT_USED int result = ::fsync(_index); ASSERT(result != 1); } } - int result = ::close(_handle[0]); + VARIABLE_IS_NOT_USED int result = ::close(_handle[0]); ASSERT(result != -1); @@ -492,7 +492,7 @@ namespace Core { if (_copy != Core::IResource::INVALID) { ASSERT(_copy != _index); - int result = ::dup2(_copy, _index); + VARIABLE_IS_NOT_USED int result = ::dup2(_copy, _index); ASSERT(result != -1); From 6fc8f74d6af6c3b38f5878c5af298b16d10ad7d5 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Tue, 6 Aug 2024 08:52:41 +0000 Subject: [PATCH 28/35] [ [core/MessageStore] : capture 'this' --- Source/core/MessageStore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/core/MessageStore.cpp b/Source/core/MessageStore.cpp index ed5a696cd..5f7d54b27 100644 --- a/Source/core/MessageStore.cpp +++ b/Source/core/MessageStore.cpp @@ -51,7 +51,7 @@ ENUM_CONVERSION_END(Core::Messaging::Metadata::type) { _adminLock.Lock(); - for_each (_controlList.begin(), _controlList.end(), [](VARIABLE_IS_NOT_USED Core::Messaging::IControl* const & control) { + for_each (_controlList.begin(), _controlList.end(), [this](VARIABLE_IS_NOT_USED Core::Messaging::IControl* const & control) { TRACE_L1(_T("MessageControl %s, size = %u was not disposed before"), typeid(control).name(), static_cast(_controlList.size())); } ); From b4f620e509513b1b48a4d679667d06c16803ece2 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Tue, 6 Aug 2024 09:42:28 +0000 Subject: [PATCH 29/35] [Tests/unit/core] : expect modules activated in default for 'test_message_unit' --- Tests/unit/core/test_message_unit.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Tests/unit/core/test_message_unit.cpp b/Tests/unit/core/test_message_unit.cpp index e2586d622..12e4a5d54 100644 --- a/Tests/unit/core/test_message_unit.cpp +++ b/Tests/unit/core/test_message_unit.cpp @@ -450,11 +450,8 @@ namespace Core { } } - if (modules.size() > 0) { - EXPECT_TRUE(enabled); - } else { - EXPECT_FALSE(enabled); - } + EXPECT_GT(modules.size(), 0); + EXPECT_TRUE(enabled); // Effective only for exsting modules / controls for this category // Disable all controls within a category via metadata @@ -541,11 +538,8 @@ namespace Core { } } - if (modules.size() > 0) { - EXPECT_TRUE(enabled); - } else { - EXPECT_FALSE(enabled); - } + EXPECT_GT(modules.size(), 0); + EXPECT_TRUE(enabled); // Effective only for exsting modules / controls for this category // Disable all controls within a category via metadata From a746f7b686dda18fa4a9ca0ad11717302839cd0b Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Wed, 7 Aug 2024 12:15:59 +0000 Subject: [PATCH 30/35] [Tests/unit/core] : enable 'test_threadpool' and 'test_workerpool --- Tests/unit/core/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/unit/core/CMakeLists.txt b/Tests/unit/core/CMakeLists.txt index e955a2f88..248cda826 100644 --- a/Tests/unit/core/CMakeLists.txt +++ b/Tests/unit/core/CMakeLists.txt @@ -125,12 +125,12 @@ add_executable(${TEST_RUNNER_NAME} test_textfragment.cpp test_textreader.cpp test_thread.cpp - test_threadpool.cpp +# test_threadpool.cpp test_time.cpp test_timer.cpp test_tristate.cpp #test_valuerecorder.cpp - test_workerpool.cpp +# test_workerpool.cpp test_xgetopt.cpp ) endif() From 7c19e8f45b20edbc710d7a97a8520fcdd4d30625 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Wed, 7 Aug 2024 12:16:36 +0000 Subject: [PATCH 31/35] [Tests/unit/core] : properly initialize variable for 'test_message_unit' --- Tests/unit/core/test_message_unit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/unit/core/test_message_unit.cpp b/Tests/unit/core/test_message_unit.cpp index 12e4a5d54..cd17b8757 100644 --- a/Tests/unit/core/test_message_unit.cpp +++ b/Tests/unit/core/test_message_unit.cpp @@ -78,7 +78,6 @@ namespace Core { _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_5"), EXPAND_AND_QUOTE(MODULE_NAME) })); _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::Metadata::type::TRACING, _T("Test_Category_1"), _T("Test_Module2") })); _controls.emplace_back(new Control({ ::Thunder::Core::Messaging::Metadata::type::LOGGING, _T("Test_Category_5"), _T("SysLog") })); - } ~Core_Messaging_MessageUnit() = default; @@ -93,6 +92,7 @@ namespace Core { void SetUp() override { + _activeConfig = false; } void TearDown() override From 1a53ac87842246fa452197a684f7f73dcdd3a8de Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Wed, 7 Aug 2024 12:38:05 +0000 Subject: [PATCH 32/35] Revert "[core/IPCChannel] : cherry-pick from 'development/ipcchannel_dangling_handlers'" This reverts commit 8bc4c8a8711729fa9e9a7f12bb4bf7d0eeb78610. --- Source/core/IPCChannel.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Source/core/IPCChannel.h b/Source/core/IPCChannel.h index fc0064908..e948cdc65 100644 --- a/Source/core/IPCChannel.h +++ b/Source/core/IPCChannel.h @@ -333,11 +333,6 @@ namespace Core { ASSERT(index != _handlers.end()); if (index != _handlers.end()) { - for(auto it = _clients.begin(), tail = _clients.end(); it != tail; it++) { - Core::ProxyType element(it->second); - element->Unregister(index->first); - } - _handlers.erase(index); } From 8790fb87959d5c6d3aed9bedaf4a9bfc0884f83f Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Wed, 7 Aug 2024 12:39:54 +0000 Subject: [PATCH 33/35] Revert "[core/TextStreamRedirectType] : Introduced variables in 'da02a32291757c26374062ec9e07c84a49bf9c43' may not be used" This reverts commit 9154bdd7a08777d2065c38c61261d4e9babced54. --- Source/core/TextStreamRedirectType.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/core/TextStreamRedirectType.h b/Source/core/TextStreamRedirectType.h index fd9fa14f4..6fc9c1579 100644 --- a/Source/core/TextStreamRedirectType.h +++ b/Source/core/TextStreamRedirectType.h @@ -424,7 +424,7 @@ namespace Core { break; case STDOUT_FILENO : do {} while(false); default : { - VARIABLE_IS_NOT_USED int result = ::fsync(_index); + int result = ::fsync(_index); ASSERT(result != 1); } } @@ -435,7 +435,7 @@ namespace Core { ASSERT(flags >= 0); // Set 'old' flags to _handle[0], with one extra flag - VARIABLE_IS_NOT_USED int result = ::fcntl(_handle[0], F_SETFL, (flags | O_NONBLOCK)); + int result = ::fcntl(_handle[0], F_SETFL, (flags | O_NONBLOCK)); ASSERT(result != -1); @@ -477,12 +477,12 @@ namespace Core { break; case STDOUT_FILENO : do {} while(false); default : { - VARIABLE_IS_NOT_USED int result = ::fsync(_index); + int result = ::fsync(_index); ASSERT(result != 1); } } - VARIABLE_IS_NOT_USED int result = ::close(_handle[0]); + int result = ::close(_handle[0]); ASSERT(result != -1); @@ -492,7 +492,7 @@ namespace Core { if (_copy != Core::IResource::INVALID) { ASSERT(_copy != _index); - VARIABLE_IS_NOT_USED int result = ::dup2(_copy, _index); + int result = ::dup2(_copy, _index); ASSERT(result != -1); From 45c1a99cde6266599937d51ba68acf2c33f3a1d5 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Wed, 7 Aug 2024 12:42:37 +0000 Subject: [PATCH 34/35] Partly revert "[core/TextStreamRedirectType / core/MessageUnit] : improve (return) value checks" This partly reverts commit da02a32291757c26374062ec9e07c84a49bf9c43. --- Source/core/TextStreamRedirectType.h | 112 ++++----------------------- 1 file changed, 16 insertions(+), 96 deletions(-) diff --git a/Source/core/TextStreamRedirectType.h b/Source/core/TextStreamRedirectType.h index 6fc9c1579..6f214caea 100644 --- a/Source/core/TextStreamRedirectType.h +++ b/Source/core/TextStreamRedirectType.h @@ -394,121 +394,41 @@ namespace Core { _handle[1] = Core::IResource::INVALID; } ~ReaderImplementation() override { - ASSERT(_handle[0] == Core::IResource::INVALID); - ASSERT(_handle[1] == Core::IResource::INVALID); - ASSERT(_index != Core::IResource::INVALID); - ASSERT(_copy == Core::IResource::INVALID); - - // The original owner of replacing (_index) is responsible for cleaning it up + Close(); _index = Core::IResource::INVALID; } public: bool Open() { - // Create a pipe only once ASSERT(_index != Core::IResource::INVALID); - ASSERT(_handle[0] == Core::IResource::INVALID); - ASSERT(_handle[1] == Core::IResource::INVALID); - if ((_handle[0] == Core::IResource::INVALID) && (::pipe(_handle) != -1)) { + if ((_handle[0] == Core::IResource::INVALID) && (::pipe(_handle) == 0)) { _copy = ::dup(_index); - - ASSERT(_copy != -1); - - // A copy of some valid file descriptior represented by _index - - switch(_index) { - case STDERR_FILENO : do {} while(false); - case STDIN_FILENO : // no sync - break; - case STDOUT_FILENO : do {} while(false); - default : { - int result = ::fsync(_index); - ASSERT(result != 1); - } - } - - // Get flags associated with _handle[0] + ::fsync(_index); int flags = ::fcntl(_handle[0], F_GETFL); - - ASSERT(flags >= 0); - - // Set 'old' flags to _handle[0], with one extra flag - int result = ::fcntl(_handle[0], F_SETFL, (flags | O_NONBLOCK)); - - ASSERT(result != -1); - - ASSERT(_handle[1] != Core::IResource::INVALID); - ASSERT(_handle[1] != _index); - - // For invalid handle _index remains open - // Identical handles have no effect and returns _index, otherwise _index closed, and then _index becomes a copy of _handle[1] - result = ::dup2(_handle[1], _index); - - ASSERT(result != -1); - - result = ::close(_handle[1]); - - ASSERT(result != -1); - + ::fcntl(_handle[0], F_SETFL, (flags | O_NONBLOCK)); + ::dup2(_handle[1], _index); + ::close(_handle[1]); _handle[1] = Core::IResource::INVALID; + ResourceMonitor::Instance().Register(*this); } - - ResourceMonitor::Instance().Register(*this); - - ASSERT(_handle[0] != Core::IResource::INVALID); - ASSERT(_handle[1] == Core::IResource::INVALID); - ASSERT(_index != Core::IResource::INVALID); - ASSERT(_copy != Core::IResource::INVALID); - return (_handle[0] != Core::IResource::INVALID); } bool Close() { - ASSERT(_handle[0] != Core::IResource::INVALID); - ASSERT(_handle[1] == Core::IResource::INVALID); - ASSERT(_index != Core::IResource::INVALID); - ASSERT(_copy != Core::IResource::INVALID); - if (_handle[0] != Core::IResource::INVALID) { - switch(_handle[0]) { - case STDERR_FILENO : do {} while(false); - case STDIN_FILENO : // no sync - break; - case STDOUT_FILENO : do {} while(false); - default : { - int result = ::fsync(_index); - ASSERT(result != 1); - } - } - - int result = ::close(_handle[0]); - - ASSERT(result != -1); - - _handle[0] = Core::IResource::INVALID; - } - - if (_copy != Core::IResource::INVALID) { - ASSERT(_copy != _index); - int result = ::dup2(_copy, _index); + ::fsync(_handle[0]); - ASSERT(result != -1); - - result = ::close(_copy); - - ASSERT(result != -1); - - _copy = Core::IResource::INVALID; + if (::dup2(_copy, _index) != -1) { + ::close(_handle[0]); + ::close(_copy); + ResourceMonitor::Instance().Unregister(*this); + _handle[0] = Core::IResource::INVALID; + _copy = Core::IResource::INVALID; + Reader::Flush(); + } } - - ResourceMonitor::Instance().Unregister(*this); - - Reader::Flush(); - - ASSERT(_handle[0] == Core::IResource::INVALID); - return (_handle[0] == Core::IResource::INVALID); } Core::IResource::handle Origin() const { From 3aeb751b4d7dd87caad319d4250cfbbae1e0adf3 Mon Sep 17 00:00:00 2001 From: msieben <4319079+msieben@users.noreply.github.com> Date: Mon, 2 Sep 2024 07:38:48 +0000 Subject: [PATCH 35/35] [Tests/unit/core] : Enable 'test_message_unit' --- Tests/unit/core/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/Tests/unit/core/CMakeLists.txt b/Tests/unit/core/CMakeLists.txt index 2e665133f..213fc2e4c 100644 --- a/Tests/unit/core/CMakeLists.txt +++ b/Tests/unit/core/CMakeLists.txt @@ -80,12 +80,10 @@ add_executable(${TEST_RUNNER_NAME} test_workerpool.cpp test_xgetopt.cpp ) -#[[ target_sources(${TEST_RUNNER_NAME} PRIVATE test_message_unit.cpp) target_link_libraries(${TEST_RUNNER_NAME} ThunderMessaging ) -]] else() add_executable(${TEST_RUNNER_NAME} test_databuffer.cpp