From f51dee1832c60c9243dafcdc311b5b3dcfe3bac9 Mon Sep 17 00:00:00 2001 From: Jacob Perron Date: Sun, 28 Feb 2021 12:43:15 -0800 Subject: [PATCH] Add function for checking QoS profile compatibility (#45) * Add function for checking QoS profile compatibility Given QoS profiles for a publisher and a subscription, this function will return `true` if the profiles are compatible. Compatible profiles implies that the subscription and publisher will be able to communicate. Connected to https://github.com/ros2/rmw/pull/299 Signed-off-by: Jacob Perron * Refactor signature of _write_to_buffer Signed-off-by: Jacob Perron * Set error message instead of setting reason Signed-off-by: Jacob Perron * Error is null reason and non-zero reason_size Signed-off-by: Jacob Perron * Do not set output parameter if an error occurs Signed-off-by: Jacob Perron * Add test for reason buffer too small Signed-off-by: Jacob Perron * Warn on unknown values instead of error Signed-off-by: Jacob Perron * Fixes * Use vsnprintf over snprintf (or undefined things can happen) * Handle NULL return value from `*to_str()` functions * Add more tests Signed-off-by: Jacob Perron * Guard against zero reason_size Add test case. Signed-off-by: Jacob Perron --- rmw_dds_common/CMakeLists.txt | 6 + rmw_dds_common/docs/FEATURES.md | 1 + rmw_dds_common/include/rmw_dds_common/qos.hpp | 61 ++ rmw_dds_common/src/qos.cpp | 377 +++++++++ rmw_dds_common/test/test_qos.cpp | 758 ++++++++++++++++++ 5 files changed, 1203 insertions(+) create mode 100644 rmw_dds_common/include/rmw_dds_common/qos.hpp create mode 100644 rmw_dds_common/src/qos.cpp create mode 100644 rmw_dds_common/test/test_qos.cpp diff --git a/rmw_dds_common/CMakeLists.txt b/rmw_dds_common/CMakeLists.txt index b21f275..51f92ce 100644 --- a/rmw_dds_common/CMakeLists.txt +++ b/rmw_dds_common/CMakeLists.txt @@ -33,6 +33,7 @@ rosidl_generate_interfaces( add_library(${PROJECT_NAME}_library SHARED src/gid_utils.cpp src/graph_cache.cpp + src/qos.cpp src/time_utils.cpp) set_target_properties(${PROJECT_NAME}_library @@ -93,6 +94,11 @@ if(BUILD_TESTING) target_link_libraries(test_gid_utils ${PROJECT_NAME}_library) endif() + ament_add_gmock(test_qos test/test_qos.cpp) + if(TARGET test_qos) + target_link_libraries(test_qos ${PROJECT_NAME}_library) + endif() + ament_add_gmock(test_time_utils test/test_time_utils.cpp) if(TARGET test_time_utils) target_link_libraries(test_time_utils ${PROJECT_NAME}_library) diff --git a/rmw_dds_common/docs/FEATURES.md b/rmw_dds_common/docs/FEATURES.md index a29114a..9dc2443 100644 --- a/rmw_dds_common/docs/FEATURES.md +++ b/rmw_dds_common/docs/FEATURES.md @@ -11,3 +11,4 @@ This package includes: - A generic [`Context`](rmw_dds_common/include/rmw_dds_common/context.hpp) type to withhold most state needed to implement [ROS nodes discovery](https://github.com/ros2/design/pull/250) - [Comparison utilities and some C++ operator overloads](rmw_dds_common/include/rmw_dds_common/gid_utils.hpp) for `rmw_gid_t` instances - [Conversion utilities](rmw_dds_common/include/rmw_dds_common/gid_utils.hpp) between `rmw_dds_common/msg/Gid` messages and `rmw_gid_t` instances + - A function for checking the compatibility of two QoS profiles, [`qos_profile_check_compatible`](rmw_dds_common/include/rmw_dds_common/qos.hpp) diff --git a/rmw_dds_common/include/rmw_dds_common/qos.hpp b/rmw_dds_common/include/rmw_dds_common/qos.hpp new file mode 100644 index 0000000..cb76d56 --- /dev/null +++ b/rmw_dds_common/include/rmw_dds_common/qos.hpp @@ -0,0 +1,61 @@ +// Copyright 2021 Open Source Robotics Foundation, Inc. +// +// 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. + +#ifndef RMW_DDS_COMMON__QOS_HPP_ +#define RMW_DDS_COMMON__QOS_HPP_ + +#include "rmw/qos_profiles.h" +#include "rmw/types.h" + +#include "rmw_dds_common/visibility_control.h" + +namespace rmw_dds_common +{ + +/// Check if two QoS profiles are compatible +/** + * Two QoS profiles are compatible if a publisher and subcription + * using the QoS policies can communicate with each other. + * + * This implements the rmw API \ref rmw_qos_profile_check_compatible(). + * See \ref rmw_qos_profile_check_compatible() for more information. + * + * \param[in] publisher_profile: The QoS profile used for a publisher. + * \param[in] subscription_profile: The QoS profile used for a subscription. + * \param[out] compatibility: `RMW_QOS_COMPATIBILITY_OK` if the QoS profiles are compatible, or + * `RMW_QOS_COMPATIBILITY_WARNING` if the QoS profiles might be compatible, or + * `RMW_QOS_COMPATIBILITY_ERROR` if the QoS profiles are not compatible. + * \param[out] reason: A detailed reason for a QoS incompatibility or potential incompatibility. + * Must be pre-allocated by the caller. + * This parameter is optional and may be set to `nullptr` if the reason information is not + * desired. + * \param[in] reason_size: Size of the string buffer `reason`, if one is provided. + * If `reason` is `nullptr`, then this parameter must be zero. + * \return `RMW_RET_OK` if the check was successful, or + * \return `RMW_RET_INVALID_ARGUMENT` if `compatiblity` is `nullptr`, or + * \return `RMW_RET_INVALID_ARGUMENT` if `reason` is `nullptr` and `reason_size` is not zero, or + * \return `RMW_RET_ERROR` if there is an unexpected error. + */ +RMW_DDS_COMMON_PUBLIC +rmw_ret_t +qos_profile_check_compatible( + const rmw_qos_profile_t publisher_qos, + const rmw_qos_profile_t subscription_qos, + rmw_qos_compatibility_type_t * compatibility, + char * reason, + size_t reason_size); + +} // namespace rmw_dds_common + +#endif // RMW_DDS_COMMON__QOS_HPP_ diff --git a/rmw_dds_common/src/qos.cpp b/rmw_dds_common/src/qos.cpp new file mode 100644 index 0000000..6a8cdeb --- /dev/null +++ b/rmw_dds_common/src/qos.cpp @@ -0,0 +1,377 @@ +// Copyright 2021 Open Source Robotics Foundation, Inc. +// +// 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 "rmw_dds_common/qos.hpp" + +#include +#include + +#include "rcutils/snprintf.h" +#include "rmw/error_handling.h" +#include "rmw/qos_profiles.h" +#include "rmw/qos_string_conversions.h" + +namespace rmw_dds_common +{ + +static bool +operator==(rmw_time_t t1, rmw_time_t t2) +{ + return t1.sec == t2.sec && t1.nsec == t2.nsec; +} + +static bool +operator!=(rmw_time_t t1, rmw_time_t t2) +{ + return !(t1 == t2); +} + +static bool +operator<(rmw_time_t t1, rmw_time_t t2) +{ + if (t1.sec < t2.sec) { + return true; + } else if (t1.sec == t2.sec && t1.nsec < t2.nsec) { + return true; + } + return false; +} + +// Returns RMW_RET_OK if successful or no buffer was provided +// Returns RMW_RET_ERROR if there as an error copying the message to the buffer +static rmw_ret_t +_append_to_buffer(char * buffer, size_t buffer_size, const char * format, ...) +{ + // Only write if a buffer is provided + if (!buffer || buffer_size == 0u) { + return RMW_RET_OK; + } + // Determine available space left in buffer + size_t offset = strnlen(buffer, buffer_size); + size_t write_size = buffer_size - offset; + std::va_list args; + va_start(args, format); + int snprintf_ret = rcutils_vsnprintf(buffer + offset, write_size, format, args); + va_end(args); + if (snprintf_ret < 0) { + RMW_SET_ERROR_MSG("failed to append to character buffer"); + return RMW_RET_ERROR; + } + return RMW_RET_OK; +} + +rmw_ret_t +qos_profile_check_compatible( + const rmw_qos_profile_t publisher_qos, + const rmw_qos_profile_t subscription_qos, + rmw_qos_compatibility_type_t * compatibility, + char * reason, + size_t reason_size) +{ + if (!compatibility) { + RMW_SET_ERROR_MSG("compatibility parameter is null"); + return RMW_RET_INVALID_ARGUMENT; + } + + if (!reason && reason_size != 0u) { + RMW_SET_ERROR_MSG("reason parameter is null, but reason_size parameter is not zero"); + return RMW_RET_INVALID_ARGUMENT; + } + + // Presume profiles are compatible until proven otherwise + *compatibility = RMW_QOS_COMPATIBILITY_OK; + + // Initialize reason buffer + if (reason && reason_size != 0u) { + reason[0] = '\0'; + } + + // Best effort publisher and reliable subscription + if (publisher_qos.reliability == RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT && + subscription_qos.reliability == RMW_QOS_POLICY_RELIABILITY_RELIABLE) + { + *compatibility = RMW_QOS_COMPATIBILITY_ERROR; + rmw_ret_t append_ret = _append_to_buffer( + reason, + reason_size, + "ERROR: Best effort publisher and reliable subscription;"); + if (RMW_RET_OK != append_ret) { + return append_ret; + } + } + + // Volatile publisher and transient local subscription + if (publisher_qos.durability == RMW_QOS_POLICY_DURABILITY_VOLATILE && + subscription_qos.durability == RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL) + { + *compatibility = RMW_QOS_COMPATIBILITY_ERROR; + rmw_ret_t append_ret = _append_to_buffer( + reason, + reason_size, + "ERROR: Volatile publisher and transient local subscription;"); + if (RMW_RET_OK != append_ret) { + return append_ret; + } + } + + const rmw_time_t & pub_deadline = publisher_qos.deadline; + const rmw_time_t & sub_deadline = subscription_qos.deadline; + const rmw_time_t deadline_default = RMW_QOS_DEADLINE_DEFAULT; + + // No deadline for publisher and deadline for subscription + if (pub_deadline == deadline_default && sub_deadline != deadline_default) { + *compatibility = RMW_QOS_COMPATIBILITY_ERROR; + rmw_ret_t ret = _append_to_buffer( + reason, + reason_size, + "ERROR: Subscription has a deadline, but publisher does not;"); + if (RMW_RET_OK != ret) { + return ret; + } + } + + // Subscription deadline is less than publisher deadline + if (pub_deadline != deadline_default && sub_deadline != deadline_default) { + if (sub_deadline < pub_deadline) { + *compatibility = RMW_QOS_COMPATIBILITY_ERROR; + rmw_ret_t append_ret = _append_to_buffer( + reason, + reason_size, + "ERROR: Subscription deadline is less than publisher deadline;"); + if (RMW_RET_OK != append_ret) { + return append_ret; + } + } + } + + // Automatic liveliness for publisher and manual by topic for subscription + if (publisher_qos.liveliness == RMW_QOS_POLICY_LIVELINESS_AUTOMATIC && + subscription_qos.liveliness == RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC) + { + *compatibility = RMW_QOS_COMPATIBILITY_ERROR; + rmw_ret_t append_ret = _append_to_buffer( + reason, + reason_size, + "ERROR: Publisher's liveliness is automatic and subscription's is manual by topic;"); + if (RMW_RET_OK != append_ret) { + return append_ret; + } + } + + const rmw_time_t & pub_lease = publisher_qos.liveliness_lease_duration; + const rmw_time_t & sub_lease = subscription_qos.liveliness_lease_duration; + const rmw_time_t lease_default = RMW_QOS_LIVELINESS_LEASE_DURATION_DEFAULT; + + // No lease duration for publisher and lease duration for subscription + if (pub_lease == lease_default && sub_lease != lease_default) { + *compatibility = RMW_QOS_COMPATIBILITY_ERROR; + rmw_ret_t append_ret = _append_to_buffer( + reason, + reason_size, + "ERROR: Subscription has a liveliness lease duration, but publisher does not;"); + if (RMW_RET_OK != append_ret) { + return append_ret; + } + } + + // Subscription lease duration is less than publisher lease duration + if (pub_lease != lease_default && sub_lease != lease_default) { + if (sub_lease < pub_lease) { + *compatibility = RMW_QOS_COMPATIBILITY_ERROR; + rmw_ret_t append_ret = _append_to_buffer( + reason, + reason_size, + "ERROR: Subscription liveliness lease duration is less than publisher;"); + if (RMW_RET_OK != append_ret) { + return append_ret; + } + } + } + + // Only check for warnings if there are no errors + if (RMW_QOS_COMPATIBILITY_OK == *compatibility) { + // We don't know the policy if the value is "system default" or "unknown" + const bool pub_reliability_unknown = + publisher_qos.reliability == RMW_QOS_POLICY_RELIABILITY_SYSTEM_DEFAULT || + publisher_qos.reliability == RMW_QOS_POLICY_RELIABILITY_UNKNOWN; + const bool sub_reliability_unknown = + subscription_qos.reliability == RMW_QOS_POLICY_RELIABILITY_SYSTEM_DEFAULT || + subscription_qos.reliability == RMW_QOS_POLICY_RELIABILITY_UNKNOWN; + const bool pub_durability_unknown = + publisher_qos.durability == RMW_QOS_POLICY_DURABILITY_SYSTEM_DEFAULT || + publisher_qos.durability == RMW_QOS_POLICY_DURABILITY_UNKNOWN; + const bool sub_durability_unknown = + subscription_qos.durability == RMW_QOS_POLICY_DURABILITY_SYSTEM_DEFAULT || + subscription_qos.durability == RMW_QOS_POLICY_DURABILITY_UNKNOWN; + const bool pub_liveliness_unknown = + publisher_qos.liveliness == RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT || + publisher_qos.liveliness == RMW_QOS_POLICY_LIVELINESS_UNKNOWN; + const bool sub_liveliness_unknown = + subscription_qos.liveliness == RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT || + subscription_qos.liveliness == RMW_QOS_POLICY_LIVELINESS_UNKNOWN; + + const char * pub_reliability_str = rmw_qos_reliability_policy_to_str(publisher_qos.reliability); + if (!pub_reliability_str) { + pub_reliability_str = "unknown"; + } + const char * sub_reliability_str = rmw_qos_reliability_policy_to_str( + subscription_qos.reliability); + if (!sub_reliability_str) { + sub_reliability_str = "unknown"; + } + const char * pub_durability_str = rmw_qos_durability_policy_to_str(publisher_qos.durability); + if (!pub_durability_str) { + pub_durability_str = "unknown"; + } + const char * sub_durability_str = rmw_qos_durability_policy_to_str(subscription_qos.durability); + if (!sub_durability_str) { + sub_durability_str = "unknown"; + } + const char * pub_liveliness_str = rmw_qos_liveliness_policy_to_str(publisher_qos.liveliness); + if (!pub_liveliness_str) { + pub_liveliness_str = "unknown"; + } + const char * sub_liveliness_str = rmw_qos_liveliness_policy_to_str(subscription_qos.liveliness); + if (!sub_liveliness_str) { + sub_liveliness_str = "unknown"; + } + + // Reliability warnings + if (pub_reliability_unknown && sub_reliability_unknown) { + // Reliability for publisher and subscription is unknown + *compatibility = RMW_QOS_COMPATIBILITY_WARNING; + rmw_ret_t append_ret = _append_to_buffer( + reason, + reason_size, + "WARNING: Publisher reliability is %s and subscription reliability is %s;", + pub_reliability_str, + sub_reliability_str); + if (RMW_RET_OK != append_ret) { + return append_ret; + } + } else if (pub_reliability_unknown && // NOLINT + subscription_qos.reliability == RMW_QOS_POLICY_RELIABILITY_RELIABLE) + { + // Reliability for publisher is unknown and subscription is reliable + *compatibility = RMW_QOS_COMPATIBILITY_WARNING; + rmw_ret_t append_ret = _append_to_buffer( + reason, + reason_size, + "WARNING: Reliable subscription, but publisher is %s;", + pub_reliability_str); + if (RMW_RET_OK != append_ret) { + return append_ret; + } + } else if (publisher_qos.reliability == RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT && // NOLINT + sub_reliability_unknown) + { + // Reliability for publisher is best effort and subscription is unknown + *compatibility = RMW_QOS_COMPATIBILITY_WARNING; + rmw_ret_t append_ret = _append_to_buffer( + reason, + reason_size, + "WARNING: Best effort publisher, but subscription is %s;", + sub_reliability_str); + if (RMW_RET_OK != append_ret) { + return append_ret; + } + } + + // Durability warnings + if (pub_durability_unknown && sub_durability_unknown) { + // Durability for publisher and subscription is unknown + *compatibility = RMW_QOS_COMPATIBILITY_WARNING; + rmw_ret_t append_ret = _append_to_buffer( + reason, + reason_size, + "WARNING: Publisher durabilty is %s and subscription durability is %s;", + pub_durability_str, + sub_durability_str); + if (RMW_RET_OK != append_ret) { + return append_ret; + } + } else if (pub_durability_unknown && // NOLINT + subscription_qos.durability == RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL) + { + // Durability for publisher is unknown and subscription is transient local + *compatibility = RMW_QOS_COMPATIBILITY_WARNING; + rmw_ret_t ret = _append_to_buffer( + reason, + reason_size, + "WARNING: Transient local subscription, but publisher is %s;", + pub_durability_str); + if (RMW_RET_OK != ret) { + return ret; + } + } else if (publisher_qos.durability == RMW_QOS_POLICY_DURABILITY_VOLATILE && // NOLINT + sub_durability_unknown) + { + // Durability for publisher is volatile and subscription is unknown + *compatibility = RMW_QOS_COMPATIBILITY_WARNING; + rmw_ret_t ret = _append_to_buffer( + reason, + reason_size, + "WARNING: Volatile publisher, but subscription is %s;", + sub_durability_str); + if (RMW_RET_OK != ret) { + return ret; + } + } + + // Liveliness warnings + if (pub_liveliness_unknown && sub_liveliness_unknown) { + // Liveliness for publisher and subscription is unknown + *compatibility = RMW_QOS_COMPATIBILITY_WARNING; + rmw_ret_t append_ret = _append_to_buffer( + reason, + reason_size, + "WARNING: Publisher liveliness is %s and subscription liveliness is %s;", + pub_liveliness_str, + sub_liveliness_str); + if (RMW_RET_OK != append_ret) { + return append_ret; + } + } else if (pub_liveliness_unknown && // NOLINT + subscription_qos.liveliness == RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC) + { + // Unknown liveliness for publisher and manual by topic for subscription + *compatibility = RMW_QOS_COMPATIBILITY_WARNING; + rmw_ret_t ret = _append_to_buffer( + reason, + reason_size, + "WARNING: Subscription's liveliness is manual by topic, but publisher's is %s;", + pub_liveliness_str); + if (RMW_RET_OK != ret) { + return ret; + } + } else if (publisher_qos.liveliness == RMW_QOS_POLICY_LIVELINESS_AUTOMATIC && // NOLINT + sub_liveliness_unknown) + { + // Automatic liveliness for publisher and unknown for subscription + *compatibility = RMW_QOS_COMPATIBILITY_WARNING; + rmw_ret_t ret = _append_to_buffer( + reason, + reason_size, + "WARNING: Publisher's liveliness is automatic, but subscription's is %s;", + sub_liveliness_str); + if (RMW_RET_OK != ret) { + return ret; + } + } + } + + return RMW_RET_OK; +} + +} // namespace rmw_dds_common diff --git a/rmw_dds_common/test/test_qos.cpp b/rmw_dds_common/test/test_qos.cpp new file mode 100644 index 0000000..1c926b2 --- /dev/null +++ b/rmw_dds_common/test/test_qos.cpp @@ -0,0 +1,758 @@ +// Copyright 2021 Open Source Robotics Foundation, Inc. +// +// 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 + +#include + +#include "rmw/types.h" + +#include "rmw_dds_common/qos.hpp" + +static rmw_qos_profile_t +get_qos_profile_fixture() +{ + return { + RMW_QOS_POLICY_HISTORY_KEEP_LAST, + 5, + RMW_QOS_POLICY_RELIABILITY_RELIABLE, + RMW_QOS_POLICY_DURABILITY_VOLATILE, + RMW_QOS_DEADLINE_DEFAULT, + RMW_QOS_LIFESPAN_DEFAULT, + RMW_QOS_POLICY_LIVELINESS_AUTOMATIC, + RMW_QOS_LIVELINESS_LEASE_DURATION_DEFAULT, + false + }; +} + +TEST(test_qos, test_qos_profile_check_compatible_reliability) +{ + // Reliable pub, reliable sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE; + sub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_OK); + EXPECT_EQ(0u, strnlen(reason, 1)); + } + + // Reliable pub, best effort sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE; + sub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_OK); + EXPECT_EQ(0u, strnlen(reason, 1)); + } + + // Best effort pub, best effort sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT; + sub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_OK); + EXPECT_EQ(0u, strnlen(reason, 1)); + } + + // Best effort pub, reliable sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT; + sub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_ERROR); + EXPECT_LT(0u, strnlen(reason, 1)); + } +} + +TEST(test_qos, test_qos_profile_check_compatible_durability) +{ + // Volatile pub, volatile sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.durability = RMW_QOS_POLICY_DURABILITY_VOLATILE; + sub_qos.durability = RMW_QOS_POLICY_DURABILITY_VOLATILE; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_OK); + EXPECT_EQ(0u, strnlen(reason, 1)); + } + // Volatile pub, transient local sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.durability = RMW_QOS_POLICY_DURABILITY_VOLATILE; + sub_qos.durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_ERROR); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Transient local pub, transient local sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL; + sub_qos.durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_OK); + EXPECT_EQ(0u, strnlen(reason, 1)); + } + // Transient local pub, volatile sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL; + sub_qos.durability = RMW_QOS_POLICY_DURABILITY_VOLATILE; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_OK); + EXPECT_EQ(0u, strnlen(reason, 1)); + } +} + +TEST(test_qos, test_qos_profile_check_compatible_deadline) +{ + // No deadline pub, no deadline sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.deadline = RMW_QOS_DEADLINE_DEFAULT; + sub_qos.deadline = RMW_QOS_DEADLINE_DEFAULT; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_OK); + EXPECT_EQ(0u, strnlen(reason, 1)); + } + + // No deadline pub, deadline sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.deadline = RMW_QOS_DEADLINE_DEFAULT; + sub_qos.deadline = {1, 0}; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_ERROR); + EXPECT_LT(0u, strnlen(reason, 1)); + } + + // Deadline pub > deadline sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.deadline = {1, 1}; + sub_qos.deadline = {1, 0}; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_ERROR); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Deadline pub == deadline sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.deadline = {1, 1}; + sub_qos.deadline = {1, 1}; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_OK); + EXPECT_EQ(0u, strnlen(reason, 1)); + } + // Deadline pub < deadline sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.deadline = {1, 1}; + sub_qos.deadline = {2, 0}; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_OK); + EXPECT_EQ(0u, strnlen(reason, 1)); + } +} + +TEST(test_qos, test_qos_profile_check_compatible_liveliness) +{ + // Automatic pub, automatic sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC; + sub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_OK); + EXPECT_EQ(0u, strnlen(reason, 1)); + } + // Automatic pub, manual sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC; + sub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_ERROR); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Manual pub, manual sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC; + sub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_OK); + EXPECT_EQ(0u, strnlen(reason, 1)); + } + // Manual pub, automatic sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC; + sub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_OK); + EXPECT_EQ(0u, strnlen(reason, 1)); + } +} + +TEST(test_qos, test_qos_profile_check_compatible_liveliness_lease_duration) +{ + // No duration pub, no duration sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.liveliness_lease_duration = RMW_QOS_LIVELINESS_LEASE_DURATION_DEFAULT; + sub_qos.liveliness_lease_duration = RMW_QOS_LIVELINESS_LEASE_DURATION_DEFAULT; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_OK); + EXPECT_EQ(0u, strnlen(reason, 1)); + } + // No duration pub, some duration sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.liveliness_lease_duration = RMW_QOS_LIVELINESS_LEASE_DURATION_DEFAULT; + sub_qos.liveliness_lease_duration = {1, 0}; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_ERROR); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Lease duration pub == lease duration sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.liveliness_lease_duration = {1, 0}; + sub_qos.liveliness_lease_duration = {1, 0}; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_OK); + EXPECT_EQ(0u, strnlen(reason, 1)); + } + // Lease duration pub > lease duration sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.liveliness_lease_duration = {1, 1}; + sub_qos.liveliness_lease_duration = {1, 0}; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_ERROR); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Lease duration pub < lease duration sub + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.liveliness_lease_duration = {1, 1}; + sub_qos.liveliness_lease_duration = {2, 1}; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_OK); + EXPECT_EQ(0u, strnlen(reason, 1)); + } +} + +TEST(test_qos, test_qos_profile_check_compatible_system_default) +{ + // Some policies set to "system default" should cause a warning + + // Pub best effort, sub system default + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT; + sub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_SYSTEM_DEFAULT; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Pub system default, sub reliable + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_SYSTEM_DEFAULT; + sub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Both reliability system default + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_SYSTEM_DEFAULT; + sub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_SYSTEM_DEFAULT; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Pub volatile, sub system default + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.durability = RMW_QOS_POLICY_DURABILITY_VOLATILE; + sub_qos.durability = RMW_QOS_POLICY_DURABILITY_SYSTEM_DEFAULT; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Pub system default, sub transient local + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.durability = RMW_QOS_POLICY_DURABILITY_SYSTEM_DEFAULT; + sub_qos.durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Both durability system default + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.durability = RMW_QOS_POLICY_DURABILITY_SYSTEM_DEFAULT; + sub_qos.durability = RMW_QOS_POLICY_DURABILITY_SYSTEM_DEFAULT; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Pub automatic, sub system default + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC; + sub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Pub system default, sub manual by topic + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT; + sub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Both liveliness system default + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT; + sub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } +} + +TEST(test_qos, test_qos_profile_check_compatible_unknown) +{ + // Some policies set to "unknown" should cause a warning + + // Pub best effort, sub unknown + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT; + sub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_UNKNOWN; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Pub unknown, sub reliable + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_UNKNOWN; + sub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Both reliability unknown + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_UNKNOWN; + sub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_UNKNOWN; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Pub volatile, sub unknown + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.durability = RMW_QOS_POLICY_DURABILITY_VOLATILE; + sub_qos.durability = RMW_QOS_POLICY_DURABILITY_UNKNOWN; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Pub unknown, sub transient local + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.durability = RMW_QOS_POLICY_DURABILITY_UNKNOWN; + sub_qos.durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Both durability unknown + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.durability = RMW_QOS_POLICY_DURABILITY_UNKNOWN; + sub_qos.durability = RMW_QOS_POLICY_DURABILITY_UNKNOWN; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Pub automatic, sub unknown + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC; + sub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_UNKNOWN; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Pub unknown, sub manual by topic + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_UNKNOWN; + sub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } + // Both liveliness unknown + { + rmw_qos_compatibility_type_t compatible; + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_UNKNOWN; + sub_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_UNKNOWN; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_WARNING); + EXPECT_LT(0u, strnlen(reason, 1)); + } +} + +TEST(test_qos, test_qos_profile_check_compatible_no_reason) +{ + // Compatible + { + rmw_qos_compatibility_type_t compatible; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, nullptr, 0u); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_OK); + } + // Incompatible + { + rmw_qos_compatibility_type_t compatible; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT; + sub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, nullptr, 0u); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_ERROR); + } +} + +TEST(test_qos, test_qos_profile_check_compatible_reason_buffer_too_small) +{ + // We expect a message larger than 10 characters + char reason[10]; + size_t reason_size = 10u; + rmw_qos_compatibility_type_t compatible; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT; + sub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_ERROR); + // Expect the first 10 characters including the terminating null character + EXPECT_STREQ(reason, "ERROR: Be"); +} + +TEST(test_qos, test_qos_profile_check_compatible_reason_buffer_size_zero) +{ + char reason[10] = "untouched"; + // With reason size zero, we don't expect any message to be written + size_t reason_size = 0u; + rmw_qos_compatibility_type_t compatible; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + pub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT; + sub_qos.reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE; + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_OK); + EXPECT_EQ(compatible, RMW_QOS_COMPATIBILITY_ERROR); + EXPECT_STREQ(reason, "untouched"); +} + +TEST(test_qos, test_qos_profile_check_compatible_invalid) +{ + // Null compatible parameter + { + const size_t reason_size = 2048u; + char reason[2048]; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, nullptr, reason, reason_size); + EXPECT_EQ(ret, RMW_RET_INVALID_ARGUMENT); + } + // Null reason, but non-zero reason_size + { + rmw_qos_compatibility_type_t compatible; + rmw_qos_profile_t pub_qos = get_qos_profile_fixture(); + rmw_qos_profile_t sub_qos = get_qos_profile_fixture(); + rmw_ret_t ret = rmw_dds_common::qos_profile_check_compatible( + pub_qos, sub_qos, &compatible, nullptr, 3u); + EXPECT_EQ(ret, RMW_RET_INVALID_ARGUMENT); + } +}