From 246de5700c82d64b95660878821a45c31305ad37 Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Fri, 3 Jan 2025 15:41:35 +0100 Subject: [PATCH] [#573] Test c++ deadline binding --- .../cxx/include/iox2/enum_translation.hpp | 8 ++ .../cxx/include/iox2/notifier_error.hpp | 7 ++ .../cxx/tests/src/service_event_tests.cpp | 99 +++++++++++++++++++ iceoryx2/tests/service_event_tests.rs | 30 ++++++ 4 files changed, 144 insertions(+) diff --git a/iceoryx2-ffi/cxx/include/iox2/enum_translation.hpp b/iceoryx2-ffi/cxx/include/iox2/enum_translation.hpp index 6f996356b..28a6a7b6f 100644 --- a/iceoryx2-ffi/cxx/include/iox2/enum_translation.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/enum_translation.hpp @@ -867,6 +867,10 @@ constexpr auto from(const int value) noexcept -> switch (error) { case iox2_notifier_notify_error_e_EVENT_ID_OUT_OF_BOUNDS: return iox2::NotifierNotifyError::EventIdOutOfBounds; + case iox2_notifier_notify_error_e_MISSED_DEADLINE: + return iox2::NotifierNotifyError::MissedDeadline; + case iox2_notifier_notify_error_e_UNABLE_TO_ACQUIRE_ELAPSED_TIME: + return iox2::NotifierNotifyError::UnableToAcquireElapsedTime; } IOX_UNREACHABLE(); @@ -879,6 +883,10 @@ from(const iox2::Notifi switch (value) { case iox2::NotifierNotifyError::EventIdOutOfBounds: return iox2_notifier_notify_error_e_EVENT_ID_OUT_OF_BOUNDS; + case iox2::NotifierNotifyError::MissedDeadline: + return iox2_notifier_notify_error_e_MISSED_DEADLINE; + case iox2::NotifierNotifyError::UnableToAcquireElapsedTime: + return iox2_notifier_notify_error_e_UNABLE_TO_ACQUIRE_ELAPSED_TIME; } IOX_UNREACHABLE(); diff --git a/iceoryx2-ffi/cxx/include/iox2/notifier_error.hpp b/iceoryx2-ffi/cxx/include/iox2/notifier_error.hpp index ae55afb6c..d3ed38e07 100644 --- a/iceoryx2-ffi/cxx/include/iox2/notifier_error.hpp +++ b/iceoryx2-ffi/cxx/include/iox2/notifier_error.hpp @@ -34,6 +34,13 @@ enum class NotifierNotifyError : uint8_t { /// is greater than the maximum supported [`EventId`] by the /// [`Service`] EventIdOutOfBounds, + /// The notification was delivered to all [`Listener`] ports + /// but the deadline contract, the maximum time span between two notifications, of the + /// [`Service`] was violated. + MissedDeadline, + /// The notification was delivered but the elapsed system time could not be acquired. + /// Therefore, it is unknown if the deadline was missed or not. + UnableToAcquireElapsedTime, }; } // namespace iox2 diff --git a/iceoryx2-ffi/cxx/tests/src/service_event_tests.cpp b/iceoryx2-ffi/cxx/tests/src/service_event_tests.cpp index 5d364e739..5bdb620ed 100644 --- a/iceoryx2-ffi/cxx/tests/src/service_event_tests.cpp +++ b/iceoryx2-ffi/cxx/tests/src/service_event_tests.cpp @@ -470,4 +470,103 @@ TYPED_TEST(ServiceEventTest, open_fails_when_attributes_are_incompatible) { ASSERT_THAT(service_open.error(), Eq(EventOpenError::IncompatibleAttributes)); } +TYPED_TEST(ServiceEventTest, deadline_can_be_set) { + constexpr iox::units::Duration DEADLINE = iox::units::Duration::fromMilliseconds(9281); + constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; + const auto service_name = iox2_testing::generate_service_name(); + Config config; + config.defaults().event().set_deadline(iox::nullopt); + auto node = NodeBuilder().config(config).create().expect(""); + + auto service_create = node.service_builder(service_name).event().deadline(DEADLINE).create().expect(""); + auto listener_create = service_create.listener_builder().create().expect(""); + auto notifier_create = service_create.notifier_builder().create().expect(""); + + auto service_open = node.service_builder(service_name).event().open().expect(""); + auto listener_open = service_open.listener_builder().create().expect(""); + auto notifier_open = service_open.notifier_builder().create().expect(""); + + ASSERT_THAT(service_create.static_config().deadline(), Eq(iox::optional(DEADLINE))); + ASSERT_THAT(service_open.static_config().deadline(), Eq(iox::optional(DEADLINE))); + ASSERT_THAT(listener_create.deadline(), Eq(iox::optional(DEADLINE))); + ASSERT_THAT(listener_open.deadline(), Eq(iox::optional(DEADLINE))); + ASSERT_THAT(notifier_create.deadline(), Eq(iox::optional(DEADLINE))); + ASSERT_THAT(notifier_open.deadline(), Eq(iox::optional(DEADLINE))); +} + +TYPED_TEST(ServiceEventTest, deadline_can_be_disabled) { + constexpr iox::units::Duration DEADLINE = iox::units::Duration::fromMilliseconds(9281); + constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; + const auto service_name = iox2_testing::generate_service_name(); + Config config; + config.defaults().event().set_deadline(iox::optional(DEADLINE)); + auto node = NodeBuilder().config(config).create().expect(""); + + auto service_create = node.service_builder(service_name).event().disable_deadline().create().expect(""); + auto listener_create = service_create.listener_builder().create().expect(""); + auto notifier_create = service_create.notifier_builder().create().expect(""); + + auto service_open = node.service_builder(service_name).event().open().expect(""); + auto listener_open = service_open.listener_builder().create().expect(""); + auto notifier_open = service_open.notifier_builder().create().expect(""); + + ASSERT_THAT(service_create.static_config().deadline(), Eq(iox::nullopt)); + ASSERT_THAT(service_open.static_config().deadline(), Eq(iox::nullopt)); + ASSERT_THAT(listener_create.deadline(), Eq(iox::nullopt)); + ASSERT_THAT(listener_open.deadline(), Eq(iox::nullopt)); + ASSERT_THAT(notifier_create.deadline(), Eq(iox::nullopt)); + ASSERT_THAT(notifier_open.deadline(), Eq(iox::nullopt)); +} + +TYPED_TEST(ServiceEventTest, notifier_is_informed_when_deadline_was_missed) { + constexpr iox::units::Duration DEADLINE = iox::units::Duration::fromNanoseconds(1); + constexpr uint64_t TIMEOUT = 10; + constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; + const auto service_name = iox2_testing::generate_service_name(); + auto node = NodeBuilder().create().expect(""); + + auto service_create = node.service_builder(service_name).event().deadline(DEADLINE).create().expect(""); + auto listener = service_create.listener_builder().create().expect(""); + auto notifier_create = service_create.notifier_builder().create().expect(""); + + auto service_open = node.service_builder(service_name).event().open().expect(""); + auto notifier_open = service_open.notifier_builder().create().expect(""); + + std::this_thread::sleep_for(std::chrono::milliseconds(TIMEOUT)); + auto result = notifier_create.notify(); + ASSERT_THAT(result.has_value(), Eq(false)); + ASSERT_THAT(result.error(), Eq(NotifierNotifyError::MissedDeadline)); + ASSERT_THAT(listener.try_wait_one().expect("").has_value(), Eq(true)); + + std::this_thread::sleep_for(std::chrono::milliseconds(TIMEOUT)); + result = notifier_open.notify(); + ASSERT_THAT(result.has_value(), Eq(false)); + ASSERT_THAT(result.error(), Eq(NotifierNotifyError::MissedDeadline)); + ASSERT_THAT(listener.try_wait_one().expect("").has_value(), Eq(true)); +} + +TYPED_TEST(ServiceEventTest, when_deadline_is_not_missed_notification_works) { + constexpr iox::units::Duration DEADLINE = iox::units::Duration::fromSeconds(3600); + constexpr uint64_t TIMEOUT = 10; + constexpr ServiceType SERVICE_TYPE = TestFixture::TYPE; + const auto service_name = iox2_testing::generate_service_name(); + auto node = NodeBuilder().create().expect(""); + + auto service_create = node.service_builder(service_name).event().deadline(DEADLINE).create().expect(""); + auto listener = service_create.listener_builder().create().expect(""); + auto notifier_create = service_create.notifier_builder().create().expect(""); + + auto service_open = node.service_builder(service_name).event().open().expect(""); + auto notifier_open = service_open.notifier_builder().create().expect(""); + + std::this_thread::sleep_for(std::chrono::milliseconds(TIMEOUT)); + auto result = notifier_create.notify(); + ASSERT_THAT(result.has_value(), Eq(true)); + ASSERT_THAT(listener.try_wait_one().expect("").has_value(), Eq(true)); + + std::this_thread::sleep_for(std::chrono::milliseconds(TIMEOUT)); + result = notifier_open.notify(); + ASSERT_THAT(result.has_value(), Eq(true)); + ASSERT_THAT(listener.try_wait_one().expect("").has_value(), Eq(true)); +} } // namespace diff --git a/iceoryx2/tests/service_event_tests.rs b/iceoryx2/tests/service_event_tests.rs index 73c3fb93a..1aa2d154e 100644 --- a/iceoryx2/tests/service_event_tests.rs +++ b/iceoryx2/tests/service_event_tests.rs @@ -1371,6 +1371,36 @@ mod service_event { assert_that!(listener.try_wait_one().unwrap(), is_some); } + #[test] + fn when_deadline_is_not_missed_notification_works() { + const DEADLINE: Duration = Duration::from_secs(3600); + const TIMEOUT: Duration = Duration::from_millis(10); + let service_name = generate_name(); + let config = generate_isolated_config(); + let node = NodeBuilder::new().config(&config).create::().unwrap(); + + let sut_create = node + .service_builder(&service_name) + .event() + .deadline(DEADLINE) + .create() + .unwrap(); + + let listener = sut_create.listener_builder().create().unwrap(); + let notifier_create = sut_create.notifier_builder().create().unwrap(); + + let sut_open = node.service_builder(&service_name).event().open().unwrap(); + let notifier_open = sut_open.notifier_builder().create().unwrap(); + + std::thread::sleep(TIMEOUT); + assert_that!(notifier_create.notify(), is_ok); + assert_that!(listener.try_wait_one().unwrap(), is_some); + + std::thread::sleep(TIMEOUT); + assert_that!(notifier_open.notify(), is_ok); + assert_that!(listener.try_wait_one().unwrap(), is_some); + } + #[instantiate_tests()] mod ipc {}