diff --git a/include/fastdds/rtps/participant/RTPSParticipant.h b/include/fastdds/rtps/participant/RTPSParticipant.h index 1b3a19abd56..c94868f7584 100644 --- a/include/fastdds/rtps/participant/RTPSParticipant.h +++ b/include/fastdds/rtps/participant/RTPSParticipant.h @@ -54,6 +54,8 @@ namespace dds { namespace builtin { class TypeLookupManager; +struct PublicationBuiltinTopicData; +struct SubscriptionBuiltinTopicData; } // namespace builtin } // namespace dds @@ -306,6 +308,30 @@ class RTPS_DllAPI RTPSParticipant */ std::vector get_netmask_filter_info() const; + /** + * @brief Fills the provided fastdds::dds::builtin::PublicationBuiltinTopicData with the information of the + * writer identified by writer_guid. + * + * @param[out] data fastdds::dds::builtin::PublicationBuiltinTopicData to fill. + * @param[in] writer_guid GUID of the writer to get the information from. + * @return True if the writer was found and the data was filled. + */ + bool get_publication_info( + fastdds::dds::builtin::PublicationBuiltinTopicData& data, + const GUID_t& writer_guid) const; + + /** + * @brief Fills the provided fastdds::dds::builtin::SubscriptionBuiltinTopicData with the information of the + * reader identified by reader_guid. + * + * @param[out] data fastdds::dds::builtin::SubscriptionBuiltinTopicData to fill. + * @param[in] reader_guid GUID of the reader to get the information from. + * @return True if the reader was found and the data was filled. + */ + bool get_subscription_info( + fastdds::dds::builtin::SubscriptionBuiltinTopicData& data, + const GUID_t& reader_guid) const; + #if HAVE_SECURITY /** diff --git a/include/fastdds/rtps/reader/RTPSReader.h b/include/fastdds/rtps/reader/RTPSReader.h index 6db4528e617..124d7258d53 100644 --- a/include/fastdds/rtps/reader/RTPSReader.h +++ b/include/fastdds/rtps/reader/RTPSReader.h @@ -276,6 +276,15 @@ class RTPSReader data_filter_ = filter; } + /** + * @brief Fills the provided vector with the GUIDs of the matched writers. + * + * @param[out] guids Vector to be filled with the GUIDs of the matched writers. + * @return True if the operation was successful. + */ + RTPS_DllAPI bool matched_writers_guids( + std::vector& guids) const; + /*! * @brief Returns there is a clean state with all Writers. * It occurs when the Reader received all samples sent by Writers. In other words, diff --git a/include/fastdds/rtps/writer/RTPSWriter.h b/include/fastdds/rtps/writer/RTPSWriter.h index b4503bd18bf..d8d0c753a7d 100644 --- a/include/fastdds/rtps/writer/RTPSWriter.h +++ b/include/fastdds/rtps/writer/RTPSWriter.h @@ -317,6 +317,15 @@ class RTPSWriter return false; } + /** + * @brief Fills the provided vector with the GUIDs of the matched readers. + * + * @param[out] guids Vector to be filled with the GUIDs of the matched readers. + * @return True if the operation was successful. + */ + RTPS_DllAPI bool matched_readers_guids( + std::vector& guids) const; + /** * Tries to remove a change waiting a maximum of the provided microseconds. * @param max_blocking_time_point Maximum time to wait for. diff --git a/src/cpp/rtps/participant/RTPSParticipant.cpp b/src/cpp/rtps/participant/RTPSParticipant.cpp index f6a32273acb..ce4263aa2ef 100644 --- a/src/cpp/rtps/participant/RTPSParticipant.cpp +++ b/src/cpp/rtps/participant/RTPSParticipant.cpp @@ -201,6 +201,20 @@ std::vector RTPSParticipant::get_netm return mp_impl->get_netmask_filter_info(); } +bool RTPSParticipant::get_publication_info( + fastdds::dds::builtin::PublicationBuiltinTopicData&, + const GUID_t&) const +{ + return false; +} + +bool RTPSParticipant::get_subscription_info( + fastdds::dds::builtin::SubscriptionBuiltinTopicData&, + const GUID_t&) const +{ + return false; +} + #if HAVE_SECURITY bool RTPSParticipant::is_security_enabled_for_writer( diff --git a/src/cpp/rtps/reader/RTPSReader.cpp b/src/cpp/rtps/reader/RTPSReader.cpp index 297feee6ef9..17822930d3a 100644 --- a/src/cpp/rtps/reader/RTPSReader.cpp +++ b/src/cpp/rtps/reader/RTPSReader.cpp @@ -435,6 +435,12 @@ bool RTPSReader::is_sample_valid( return true; } +bool RTPSReader::matched_writers_guids( + std::vector&) const +{ + return false; +} + #ifdef FASTDDS_STATISTICS bool RTPSReader::add_statistics_listener( diff --git a/src/cpp/rtps/writer/RTPSWriter.cpp b/src/cpp/rtps/writer/RTPSWriter.cpp index ec7527bd75f..8ce1b9eb3e2 100644 --- a/src/cpp/rtps/writer/RTPSWriter.cpp +++ b/src/cpp/rtps/writer/RTPSWriter.cpp @@ -462,6 +462,12 @@ bool RTPSWriter::send_nts( locator_selector.locator_selector.end(), max_blocking_time_point); } +bool RTPSWriter::matched_readers_guids( + std::vector&) const +{ + return false; +} + #ifdef FASTDDS_STATISTICS bool RTPSWriter::add_statistics_listener( diff --git a/test/blackbox/api/dds-pim/PubSubParticipant.hpp b/test/blackbox/api/dds-pim/PubSubParticipant.hpp index bc4afb9800a..534bd71dd09 100644 --- a/test/blackbox/api/dds-pim/PubSubParticipant.hpp +++ b/test/blackbox/api/dds-pim/PubSubParticipant.hpp @@ -334,6 +334,12 @@ class PubSubParticipant return false; } + if (publisher_topicname_.empty()) + { + EPROSIMA_LOG_ERROR(PUBSUBPARTICIPANT, "Publisher topic name not set"); + return false; + } + eprosima::fastdds::dds::Topic* topic = dynamic_cast(participant_->lookup_topicdescription( publisher_topicname_)); @@ -371,6 +377,12 @@ class PubSubParticipant return false; } + if (subscriber_topicname_.empty()) + { + EPROSIMA_LOG_ERROR(PUBSUBPARTICIPANT, "Subscriber topic name not set"); + return false; + } + eprosima::fastdds::dds::Topic* topic = dynamic_cast(participant_->lookup_topicdescription( subscriber_topicname_)); diff --git a/test/blackbox/api/dds-pim/PubSubReader.hpp b/test/blackbox/api/dds-pim/PubSubReader.hpp index 1a277c56280..b4af750d732 100644 --- a/test/blackbox/api/dds-pim/PubSubReader.hpp +++ b/test/blackbox/api/dds-pim/PubSubReader.hpp @@ -1453,7 +1453,7 @@ class PubSubReader return *this; } - PubSubReader& userData( + PubSubReader& user_data( std::vector user_data) { participant_qos_.user_data() = user_data; diff --git a/test/blackbox/api/dds-pim/PubSubWriter.hpp b/test/blackbox/api/dds-pim/PubSubWriter.hpp index 672a9396991..3649cd3987c 100644 --- a/test/blackbox/api/dds-pim/PubSubWriter.hpp +++ b/test/blackbox/api/dds-pim/PubSubWriter.hpp @@ -1391,7 +1391,7 @@ class PubSubWriter return *this; } - PubSubWriter& userData( + PubSubWriter& user_data( std::vector user_data) { participant_qos_.user_data() = user_data; diff --git a/test/blackbox/common/BlackboxTests.cpp b/test/blackbox/common/BlackboxTests.cpp index 55eee5beb5a..b8f2b684370 100644 --- a/test/blackbox/common/BlackboxTests.cpp +++ b/test/blackbox/common/BlackboxTests.cpp @@ -16,9 +16,10 @@ #include +#include +#include #include #include -#include #include #include @@ -85,6 +86,36 @@ class BlackboxEnvironment : public ::testing::Environment }; +void entity_id_to_builtin_topic_key( + eprosima::fastdds::dds::builtin::BuiltinTopicKey_t& bt_key, + const eprosima::fastrtps::rtps::EntityId_t& entity_id) +{ + bt_key.value[0] = 0; + bt_key.value[1] = 0; + bt_key.value[2] = static_cast(entity_id.value[0]) << 24 + | static_cast(entity_id.value[1]) << 16 + | static_cast(entity_id.value[2]) << 8 + | static_cast(entity_id.value[3]); +} + +void guid_prefix_to_builtin_topic_key( + eprosima::fastdds::dds::builtin::BuiltinTopicKey_t& bt_key, + const eprosima::fastrtps::rtps::GuidPrefix_t& guid_prefix) +{ + bt_key.value[0] = static_cast(guid_prefix.value[0]) << 24 + | static_cast(guid_prefix.value[1]) << 16 + | static_cast(guid_prefix.value[2]) << 8 + | static_cast(guid_prefix.value[3]); + bt_key.value[1] = static_cast(guid_prefix.value[4]) << 24 + | static_cast(guid_prefix.value[5]) << 16 + | static_cast(guid_prefix.value[6]) << 8 + | static_cast(guid_prefix.value[7]); + bt_key.value[2] = static_cast(guid_prefix.value[8]) << 24 + | static_cast(guid_prefix.value[9]) << 16 + | static_cast(guid_prefix.value[10]) << 8 + | static_cast(guid_prefix.value[11]); +} + int main( int argc, char** argv) diff --git a/test/blackbox/common/BlackboxTests.hpp b/test/blackbox/common/BlackboxTests.hpp index 9665b329977..f193294d915 100644 --- a/test/blackbox/common/BlackboxTests.hpp +++ b/test/blackbox/common/BlackboxTests.hpp @@ -46,6 +46,18 @@ #include #include +namespace eprosima { +namespace fastdds { +namespace dds { +namespace builtin { + +struct BuiltinTopicKey_t; + +} // namespace builtin +} // namespace dds +} // namespace fastdds +} // namespace eprosima + #if HAVE_SECURITY extern void blackbox_security_init(); #endif // if HAVE_SECURITY @@ -202,4 +214,15 @@ void print_non_received_messages( /***** End auxiliary lambda function *****/ +/****** Auxiliary conversion helpers *******/ +void entity_id_to_builtin_topic_key( + eprosima::fastdds::dds::builtin::BuiltinTopicKey_t& bt_key, + const eprosima::fastrtps::rtps::EntityId_t& entity_id); + +void guid_prefix_to_builtin_topic_key( + eprosima::fastdds::dds::builtin::BuiltinTopicKey_t& bt_key, + const eprosima::fastrtps::rtps::GuidPrefix_t& guid_prefix); + +/****** End Auxiliary conversion helpers *******/ + #endif // __BLACKBOX_BLACKBOXTESTS_HPP__ diff --git a/test/blackbox/common/BlackboxTestsDiscovery.cpp b/test/blackbox/common/BlackboxTestsDiscovery.cpp index 6894fe523e5..40b1536f77d 100644 --- a/test/blackbox/common/BlackboxTestsDiscovery.cpp +++ b/test/blackbox/common/BlackboxTestsDiscovery.cpp @@ -934,7 +934,7 @@ TEST_P(Discovery, PubSubAsReliableHelloworldUserData) PubSubWriter writer(TEST_TOPIC_NAME); writer.history_depth(100). - userData({'a', 'b', 'c', 'd'}).init(); + user_data({'a', 'b', 'c', 'd'}).init(); ASSERT_TRUE(writer.isInitialized()); diff --git a/test/blackbox/common/BlackboxTestsPubSubBasic.cpp b/test/blackbox/common/BlackboxTestsPubSubBasic.cpp index 913991e1b53..79972bd89f7 100644 --- a/test/blackbox/common/BlackboxTestsPubSubBasic.cpp +++ b/test/blackbox/common/BlackboxTestsPubSubBasic.cpp @@ -385,7 +385,7 @@ TEST_P(PubSubBasic, ReceivedDynamicDataWithNoSizeLimit) writer.history_depth(100) .partition("A").partition("B").partition("C") - .userData({'a', 'b', 'c', 'd'}).init(); + .user_data({'a', 'b', 'c', 'd'}).init(); ASSERT_TRUE(writer.isInitialized()); @@ -418,7 +418,7 @@ TEST_P(PubSubBasic, ReceivedDynamicDataWithinSizeLimit) writer.history_depth(100) .partition("A").partition("B").partition("C") - .userData({'a', 'b', 'c', 'd'}).init(); + .user_data({'a', 'b', 'c', 'd'}).init(); ASSERT_TRUE(writer.isInitialized()); @@ -452,7 +452,7 @@ TEST_P(PubSubBasic, ReceivedUserDataExceedsSizeLimit) PubSubWriter writer(TEST_TOPIC_NAME); writer.history_depth(100) - .userData({'a', 'b', 'c', 'd', 'e', 'f'}).init(); + .user_data({'a', 'b', 'c', 'd', 'e', 'f'}).init(); ASSERT_TRUE(writer.isInitialized()); diff --git a/test/blackbox/common/BlackboxTestsSecurity.cpp b/test/blackbox/common/BlackboxTestsSecurity.cpp index 944a9d166cf..7de019ac43d 100644 --- a/test/blackbox/common/BlackboxTestsSecurity.cpp +++ b/test/blackbox/common/BlackboxTestsSecurity.cpp @@ -2706,7 +2706,7 @@ TEST_P(Security, BuiltinAuthenticationAndCryptoPlugin_user_data) pub_property_policy.properties().emplace_back("rtps.endpoint.payload_protection_kind", "ENCRYPT"); writer.history_depth(100). - userData({ 'a', 'b', 'c', 'd', 'e' }). + user_data({ 'a', 'b', 'c', 'd', 'e' }). property_policy(pub_part_property_policy). entity_property_policy(pub_property_policy).init(); diff --git a/test/blackbox/common/DDSBlackboxTestsDataReader.cpp b/test/blackbox/common/DDSBlackboxTestsDataReader.cpp index c45a2dd5db1..b6576d08021 100644 --- a/test/blackbox/common/DDSBlackboxTestsDataReader.cpp +++ b/test/blackbox/common/DDSBlackboxTestsDataReader.cpp @@ -535,6 +535,288 @@ TEST(DDSDataReader, datareader_qos_use_topic_qos) ASSERT_EQ(control_qos, test_qos); } +bool validate_publication_builtin_topic_data( + const eprosima::fastdds::dds::builtin::PublicationBuiltinTopicData& pubdata, + const eprosima::fastdds::dds::DataWriter& datawriter) +{ + bool ret = true; + + auto dw_qos = datawriter.get_qos(); + auto pub_qos = datawriter.get_publisher()->get_qos(); + + eprosima::fastdds::dds::builtin::BuiltinTopicKey_t dw_key, part_key; + + entity_id_to_builtin_topic_key(dw_key, datawriter.guid().entityId); + guid_prefix_to_builtin_topic_key(part_key, datawriter.get_publisher()->get_participant()->guid().guidPrefix); + + ret &= (0 == memcmp(pubdata.key.value, dw_key.value, sizeof(eprosima::fastdds::dds::builtin::BuiltinTopicKey_t))); + ret &= + (0 == + memcmp(pubdata.participant_key.value, part_key.value, + sizeof(eprosima::fastdds::dds::builtin::BuiltinTopicKey_t))); + ret &= (pubdata.topic_name == datawriter.get_topic()->get_name()); + ret &= (pubdata.type_name == datawriter.get_topic()->get_type_name()); + + // DataWriter Qos + ret &= (pubdata.durability == dw_qos.durability()); + ret &= (pubdata.durability_service == dw_qos.durability_service()); + ret &= (pubdata.deadline == dw_qos.deadline()); + ret &= (pubdata.latency_budget == dw_qos.latency_budget()); + ret &= (pubdata.liveliness == dw_qos.liveliness()); + ret &= (pubdata.reliability == dw_qos.reliability()); + ret &= (pubdata.lifespan == dw_qos.lifespan()); + ret &= ( + (pubdata.user_data.size() == dw_qos.user_data().size()) && + (0 == memcmp(pubdata.user_data.data(), dw_qos.user_data().data(), pubdata.user_data.size()))); + ret &= (pubdata.ownership == dw_qos.ownership()); + ret &= (pubdata.ownership_strength == dw_qos.ownership_strength()); + ret &= (pubdata.destination_order == dw_qos.destination_order()); + + // Publisher Qos + ret &= (pubdata.presentation == pub_qos.presentation()); + ret &= (pubdata.partition.getNames() == pub_qos.partition().getNames()); + // topic_data not implemented + // group_data too + + return ret; +} + +/** + * @test DDS-DR-API-GMPD-01 + * + * get_matched_publication_data() must return RETCODE_BAD_PARAMETER + * if the publication is not matched. + */ +TEST(DDSDataReader, datareader_get_matched_publication_data_bad_parameter) +{ + PubSubReader reader(TEST_TOPIC_NAME); + PubSubWriter writer_1(TEST_TOPIC_NAME); + PubSubWriter writer_2(TEST_TOPIC_NAME); + + eprosima::fastdds::dds::builtin::PublicationBuiltinTopicData pubdata; + + reader.reliability(RELIABLE_RELIABILITY_QOS) + .init(); + + writer_1.reliability(BEST_EFFORT_RELIABILITY_QOS) + .init(); + writer_2.ownership_strength(10) + .init(); + + ASSERT_TRUE(reader.isInitialized()); + ASSERT_TRUE(writer_1.isInitialized()); + ASSERT_TRUE(writer_2.isInitialized()); + + // Reader should not be matched with any writer + reader.wait_discovery(std::chrono::seconds(2), 2); + + ASSERT_TRUE(!reader.is_matched()); + + auto& native_reader = reader.get_native_reader(); + + InstanceHandle_t w1_handle = writer_1.get_native_writer().get_instance_handle(); + ReturnCode_t ret = native_reader.get_matched_publication_data(pubdata, w1_handle); + + ASSERT_EQ(ret, ReturnCode_t::RETCODE_BAD_PARAMETER); + + InstanceHandle_t w2_handle = writer_2.get_native_writer().get_instance_handle(); + ret = native_reader.get_matched_publication_data(pubdata, w2_handle); + + ASSERT_EQ(ret, ReturnCode_t::RETCODE_BAD_PARAMETER); +} + +/** + * @test DDS-DR-API-GMPD-02 + * + * The operation must succeed when the publication is matched and correctly + * retrieve the publication data. Parameterize the test for different transports. + */ +TEST_P(DDSDataReader, datareader_get_matched_publication_data_correctly_behaves) +{ + PubSubReader reader(TEST_TOPIC_NAME); + PubSubWriter writer_1(TEST_TOPIC_NAME); + PubSubWriter writer_2(TEST_TOPIC_NAME); + + eprosima::fastdds::dds::builtin::PublicationBuiltinTopicData w1_pubdata, w2_pubdata; + + reader.partition("*") + .init(); + + writer_1.partition("*") + .init(); + writer_2.user_data({'u', 's', 'e', 'r', 'd', 'a', 't', 'a'}) + .partition("*") + .reliability(BEST_EFFORT_RELIABILITY_QOS) + .init(); + + ASSERT_TRUE(reader.isInitialized()); + ASSERT_TRUE(writer_1.isInitialized()); + ASSERT_TRUE(writer_2.isInitialized()); + + // Reader must match with both writers + reader.wait_discovery(std::chrono::seconds::zero(), 2); + + ASSERT_EQ(reader.get_matched(), 2u); + + auto& native_reader = reader.get_native_reader(); + + InstanceHandle_t w1_handle = writer_1.get_native_writer().get_instance_handle(); + ReturnCode_t ret = native_reader.get_matched_publication_data(w1_pubdata, w1_handle); + + ASSERT_EQ(ret, ReturnCode_t::RETCODE_OK); + ASSERT_TRUE(validate_publication_builtin_topic_data(w1_pubdata, writer_1.get_native_writer())); + + InstanceHandle_t w2_handle = writer_2.get_native_writer().get_instance_handle(); + ret = native_reader.get_matched_publication_data(w2_pubdata, w2_handle); + + ASSERT_EQ(ret, ReturnCode_t::RETCODE_OK); + ASSERT_TRUE(validate_publication_builtin_topic_data(w2_pubdata, writer_2.get_native_writer())); +} + +/** + * @test DDS-DR-API-GMP-01 + * + * get_matched_publications() must return RETCODE_OK + * with an empty list if no DataWriters are matched. + */ +TEST(DDSDataReader, datareader_get_matched_publications_ok_empty_list) +{ + PubSubReader reader(TEST_TOPIC_NAME); + PubSubWriter writer_1(TEST_TOPIC_NAME); + PubSubWriter writer_2(TEST_TOPIC_NAME); + + std::vector pub_handles; + + reader.reliability(RELIABLE_RELIABILITY_QOS) + .init(); + + writer_1.reliability(BEST_EFFORT_RELIABILITY_QOS) + .init(); + + writer_2.ownership_strength(10) + .init(); + + ASSERT_TRUE(reader.isInitialized()); + ASSERT_TRUE(writer_1.isInitialized()); + ASSERT_TRUE(writer_2.isInitialized()); + + // Reader should not be matched with any writer + reader.wait_discovery(std::chrono::seconds(2), 2); + ASSERT_FALSE(reader.is_matched()); + + auto& native_reader = reader.get_native_reader(); + ReturnCode_t ret = native_reader.get_matched_publications(pub_handles); + + ASSERT_EQ(ret, ReturnCode_t::RETCODE_OK); + ASSERT_EQ(pub_handles.size(), 0u); +} + +/** + * @test DDS-DR-API-GMP-02 + * + * get_matched_publications() must provide the correct list of matched publication handles. + * Parameterize the test for different transports. + */ +TEST_P(DDSDataReader, datareader_get_matched_publications_correctly_behaves) +{ + const size_t num_writers = 5; + + PubSubReader reader(TEST_TOPIC_NAME); + std::vector>> writers; + std::vector expected_pub_handles; + std::vector pub_handles; + + writers.reserve(num_writers); + pub_handles.reserve(num_writers); + + reader.reliability(RELIABLE_RELIABILITY_QOS) + .init(); + + ASSERT_TRUE(reader.isInitialized()); + + for (size_t i = 0; i < num_writers; ++i) + { + writers.emplace_back(new PubSubWriter(TEST_TOPIC_NAME)); + writers.back()->init(); + ASSERT_TRUE(writers.back()->isInitialized()); + expected_pub_handles.emplace_back(writers.back()->get_native_writer().get_instance_handle()); + } + + // Wait for discovery + reader.wait_discovery(std::chrono::seconds::zero(), num_writers); + ASSERT_EQ(reader.get_matched(), num_writers); + + auto& native_reader = reader.get_native_reader(); + ReturnCode_t ret = native_reader.get_matched_publications(pub_handles); + + // Check that the list of matched publication handles is correct + ASSERT_EQ(ret, ReturnCode_t::RETCODE_OK); + ASSERT_EQ(pub_handles.size(), num_writers); + ASSERT_TRUE(std::is_permutation(pub_handles.begin(), pub_handles.end(), expected_pub_handles.begin())); + + // Remove two writers and check that the list of matched publication handles is updated + writers.pop_back(); + writers.pop_back(); + expected_pub_handles.pop_back(); + expected_pub_handles.pop_back(); + + // Wait for undiscovery + reader.wait_writer_undiscovery(static_cast(num_writers - 2)); + + pub_handles.clear(); + ret = native_reader.get_matched_publications(pub_handles); + ASSERT_EQ(ret, ReturnCode_t::RETCODE_OK); + ASSERT_EQ(pub_handles.size(), static_cast(num_writers - 2)); + ASSERT_TRUE(std::is_permutation(pub_handles.begin(), pub_handles.end(), expected_pub_handles.begin())); +} + +/** + * @test DDS-DR-API-GMP-03 + * + * The operation must provide the correct list of matched publication handles in multiple + * participants scenario. Parameterize the test for different transports. + */ +TEST_P(DDSDataReader, datareader_get_matched_publications_multiple_participants_correctly_behave) +{ + PubSubParticipant part_1(1, 1, 1, 1); + PubSubParticipant part_2(1, 1, 1, 1); + + part_1.pub_topic_name(TEST_TOPIC_NAME); + part_1.sub_topic_name(TEST_TOPIC_NAME + "_1"); + part_2.pub_topic_name(TEST_TOPIC_NAME + "_1"); + part_2.sub_topic_name(TEST_TOPIC_NAME); + + ASSERT_TRUE(part_1.init_participant()); + ASSERT_TRUE(part_1.init_publisher(0)); + ASSERT_TRUE(part_1.init_subscriber(0)); + + ASSERT_TRUE(part_2.init_participant()); + ASSERT_TRUE(part_2.init_subscriber(0)); + ASSERT_TRUE(part_2.init_publisher(0)); + + part_1.pub_wait_discovery(); + part_1.sub_wait_discovery(); + + part_2.pub_wait_discovery(); + part_2.sub_wait_discovery(); + + auto& reader_p1 = part_1.get_native_reader(0); + auto& reader_p2 = part_2.get_native_reader(0); + + std::vector pub_handles_p1; + std::vector pub_handles_p2; + + ReturnCode_t ret = reader_p1.get_matched_publications(pub_handles_p1); + ASSERT_EQ(ret, ReturnCode_t::RETCODE_OK); + ASSERT_EQ(pub_handles_p1.size(), 1u); + ASSERT_EQ(pub_handles_p1[0], part_2.get_native_writer(0).get_instance_handle()); + + ret = reader_p2.get_matched_publications(pub_handles_p2); + ASSERT_EQ(ret, ReturnCode_t::RETCODE_OK); + ASSERT_EQ(pub_handles_p2.size(), 1u); + ASSERT_EQ(pub_handles_p2[0], part_1.get_native_writer(0).get_instance_handle()); +} + #ifdef INSTANTIATE_TEST_SUITE_P #define GTEST_INSTANTIATE_TEST_MACRO(x, y, z, w) INSTANTIATE_TEST_SUITE_P(x, y, z, w) #else diff --git a/test/blackbox/common/DDSBlackboxTestsDataWriter.cpp b/test/blackbox/common/DDSBlackboxTestsDataWriter.cpp index 14444fe20fe..29ca1cf7de6 100644 --- a/test/blackbox/common/DDSBlackboxTestsDataWriter.cpp +++ b/test/blackbox/common/DDSBlackboxTestsDataWriter.cpp @@ -34,6 +34,7 @@ #include #include "BlackboxTests.hpp" +#include "PubSubParticipant.hpp" #include "PubSubReader.hpp" #include "PubSubWriter.hpp" @@ -533,6 +534,295 @@ TEST(DDSDataWriter, datawriter_qos_use_topic_qos) ASSERT_EQ(control_qos, test_qos); } +bool validate_subscription_builtin_topic_data( + const eprosima::fastdds::dds::builtin::SubscriptionBuiltinTopicData& subdata, + const eprosima::fastdds::dds::DataReader& datareader) +{ + bool ret = true; + + auto dr_qos = datareader.get_qos(); + auto sub_qos = datareader.get_subscriber()->get_qos(); + + eprosima::fastdds::dds::builtin::BuiltinTopicKey_t dr_key, part_key; + + entity_id_to_builtin_topic_key(dr_key, datareader.guid().entityId); + guid_prefix_to_builtin_topic_key(part_key, datareader.get_subscriber()->get_participant()->guid().guidPrefix); + + ret &= (0 == memcmp(subdata.key.value, dr_key.value, sizeof(eprosima::fastdds::dds::builtin::BuiltinTopicKey_t))); + ret &= + (0 == + memcmp(subdata.participant_key.value, part_key.value, + sizeof(eprosima::fastdds::dds::builtin::BuiltinTopicKey_t))); + ret &= (subdata.topic_name == datareader.get_topicdescription()->get_name()); + ret &= (subdata.type_name == datareader.get_topicdescription()->get_type_name()); + + // DataReader Qos + ret &= (subdata.durability == dr_qos.durability()); + ret &= (subdata.deadline == dr_qos.deadline()); + ret &= (subdata.latency_budget == dr_qos.latency_budget()); + ret &= (subdata.liveliness == dr_qos.liveliness()); + ret &= (subdata.reliability == dr_qos.reliability()); + ret &= (subdata.ownership == dr_qos.ownership()); + ret &= (subdata.destination_order == dr_qos.destination_order()); + ret &= ( + (subdata.user_data.size() == dr_qos.user_data().size()) && + (0 == memcmp(subdata.user_data.data(), dr_qos.user_data().data(), subdata.user_data.size()))); + // time based filter not implemented + + // Subscriber Qos + ret &= (subdata.presentation == sub_qos.presentation()); + ret &= (subdata.partition.getNames() == sub_qos.partition().getNames()); + // topic_data not implemented + // group_data too + + return ret; +} + +/** + * @test DDS-DW-API-GMSD-01 + * + * get_matched_subscription_data() must return RETCODE_BAD_PARAMETER + * if the subscription is not matched. + */ +TEST(DDSDataWriter, datawriter_get_matched_subscription_data_bad_parameter) +{ + using InstanceHandle_t = eprosima::fastrtps::rtps::InstanceHandle_t; + + PubSubWriter writer(TEST_TOPIC_NAME); + PubSubReader reader_1(TEST_TOPIC_NAME); + PubSubReader reader_2(TEST_TOPIC_NAME); + + eprosima::fastdds::dds::builtin::SubscriptionBuiltinTopicData subdata; + + writer.reliability(BEST_EFFORT_RELIABILITY_QOS) + .init(); + + reader_1.reliability(RELIABLE_RELIABILITY_QOS) + .init(); + reader_2.ownership_exclusive() + .init(); + + ASSERT_TRUE(writer.isInitialized()); + ASSERT_TRUE(reader_1.isInitialized()); + ASSERT_TRUE(reader_2.isInitialized()); + + // Writer should not be matched with any reader + writer.wait_discovery(2, std::chrono::seconds(1)); + + ASSERT_TRUE(!writer.is_matched()); + + auto& native_writer = writer.get_native_writer(); + + InstanceHandle_t r1_handle = reader_1.get_native_reader().get_instance_handle(); + ReturnCode_t ret = native_writer.get_matched_subscription_data(subdata, r1_handle); + + ASSERT_EQ(ret, ReturnCode_t::RETCODE_BAD_PARAMETER); + + InstanceHandle_t r2_handle = reader_2.get_native_reader().get_instance_handle(); + ret = native_writer.get_matched_subscription_data(subdata, r2_handle); + + ASSERT_EQ(ret, ReturnCode_t::RETCODE_BAD_PARAMETER); +} + +/** + * @test DDS-DW-API-GMSD-02 + * + * The operation must succeed when the subscription is matched and correctly + * retrieve the publication data. Parameterize the test for different transports. + */ +TEST_P(DDSDataWriter, datawriter_get_matched_subscription_data_correctly_behaves) +{ + using InstanceHandle_t = eprosima::fastrtps::rtps::InstanceHandle_t; + + PubSubWriter writer(TEST_TOPIC_NAME); + PubSubReader reader_1(TEST_TOPIC_NAME); + PubSubReader reader_2(TEST_TOPIC_NAME); + + eprosima::fastdds::dds::builtin::SubscriptionBuiltinTopicData r1_subdata, r2_subdata; + + writer.partition("*") + .init(); + + reader_1.partition("*") + .init(); + reader_2.user_data({'u', 's', 'e', 'r', 'd', 'a', 't', 'a'}) + .partition("*") + .reliability(RELIABLE_RELIABILITY_QOS) + .init(); + + ASSERT_TRUE(writer.isInitialized()); + ASSERT_TRUE(reader_1.isInitialized()); + ASSERT_TRUE(reader_2.isInitialized()); + + // Writer must match with both readers + writer.wait_discovery(2, std::chrono::seconds::zero()); + + ASSERT_EQ(writer.get_matched(), 2u); + + auto& native_writer = writer.get_native_writer(); + + InstanceHandle_t r1_handle = reader_1.get_native_reader().get_instance_handle(); + ReturnCode_t ret = native_writer.get_matched_subscription_data(r1_subdata, r1_handle); + + ASSERT_EQ(ret, ReturnCode_t::RETCODE_OK); + ASSERT_TRUE(validate_subscription_builtin_topic_data(r1_subdata, reader_1.get_native_reader())); + + InstanceHandle_t r2_handle = reader_2.get_native_reader().get_instance_handle(); + ret = native_writer.get_matched_subscription_data(r2_subdata, r2_handle); + + ASSERT_EQ(ret, ReturnCode_t::RETCODE_OK); + ASSERT_TRUE(validate_subscription_builtin_topic_data(r2_subdata, reader_2.get_native_reader())); +} + +/** + * @test DDS-DW-API-GMS-01 + * + * get_matched_subscriptions() must return RETCODE_OK + * with an empty list if no DataWriters are matched. + */ +TEST(DDSDataWriter, datawriter_get_matched_subscriptions_ok_empty_list) +{ + using InstanceHandle_t = eprosima::fastrtps::rtps::InstanceHandle_t; + + PubSubWriter writer(TEST_TOPIC_NAME); + PubSubReader reader_1(TEST_TOPIC_NAME); + PubSubReader reader_2(TEST_TOPIC_NAME); + + std::vector sub_handles; + + writer.reliability(BEST_EFFORT_RELIABILITY_QOS) + .init(); + + reader_1.reliability(RELIABLE_RELIABILITY_QOS) + .init(); + + reader_2.ownership_exclusive() + .init(); + + ASSERT_TRUE(writer.isInitialized()); + ASSERT_TRUE(reader_1.isInitialized()); + ASSERT_TRUE(reader_2.isInitialized()); + + // Writer should not be matched with any reader + writer.wait_discovery(2, std::chrono::seconds(2)); + ASSERT_FALSE(writer.is_matched()); + + auto& native_writer = writer.get_native_writer(); + ReturnCode_t ret = native_writer.get_matched_subscriptions(sub_handles); + + ASSERT_EQ(ret, ReturnCode_t::RETCODE_OK); + ASSERT_EQ(sub_handles.size(), 0u); +} + +/** + * @test DDS-DW-API-GMS-02 + * + * get_matched_subscriptions() must provide the correct list of matched subscription handles. + * Parameterize the test for different transports. + */ +TEST_P(DDSDataWriter, datawriter_get_matched_subscriptions_correctly_behaves) +{ + using InstanceHandle_t = eprosima::fastrtps::rtps::InstanceHandle_t; + + const size_t num_readers = 5; + + PubSubWriter writer(TEST_TOPIC_NAME); + std::vector>> readers; + std::vector expected_sub_handles; + std::vector sub_handles; + + readers.reserve(num_readers); + sub_handles.reserve(num_readers); + + writer.init(); + + ASSERT_TRUE(writer.isInitialized()); + + for (size_t i = 0; i < num_readers; ++i) + { + readers.emplace_back(new PubSubReader(TEST_TOPIC_NAME)); + readers.back()->init(); + ASSERT_TRUE(readers.back()->isInitialized()); + expected_sub_handles.emplace_back(readers.back()->get_native_reader().get_instance_handle()); + } + + // Wait for discovery + writer.wait_discovery(num_readers, std::chrono::seconds::zero()); + ASSERT_EQ(writer.get_matched(), num_readers); + + auto& native_writer = writer.get_native_writer(); + ReturnCode_t ret = native_writer.get_matched_subscriptions(sub_handles); + + // Check that the list of matched publication handles is correct + ASSERT_EQ(ret, ReturnCode_t::RETCODE_OK); + ASSERT_EQ(sub_handles.size(), num_readers); + ASSERT_TRUE(std::is_permutation(sub_handles.begin(), sub_handles.end(), expected_sub_handles.begin())); + + // Remove two readers and check that the list of matched publication handles is updated + readers.pop_back(); + readers.pop_back(); + expected_sub_handles.pop_back(); + expected_sub_handles.pop_back(); + + // Wait for undiscovery + writer.wait_reader_undiscovery(static_cast(num_readers - 2)); + + sub_handles.clear(); + ret = native_writer.get_matched_subscriptions(sub_handles); + ASSERT_EQ(ret, ReturnCode_t::RETCODE_OK); + ASSERT_EQ(sub_handles.size(), static_cast(num_readers - 2)); + ASSERT_TRUE(std::is_permutation(sub_handles.begin(), sub_handles.end(), expected_sub_handles.begin())); +} + +/** + * @test DDS-DW-API-GMS-03 + * + * The operation must provide the correct list of matched subscription handles in multiple + * participants scenario. Parameterize the test for different transports. + */ +TEST_P(DDSDataWriter, datawriter_get_matched_subscriptions_multiple_participants_correctly_behave) +{ + using InstanceHandle_t = eprosima::fastrtps::rtps::InstanceHandle_t; + + PubSubParticipant part_1(1, 1, 1, 1); + PubSubParticipant part_2(1, 1, 1, 1); + + part_1.pub_topic_name(TEST_TOPIC_NAME); + part_1.sub_topic_name(TEST_TOPIC_NAME + "_1"); + part_2.pub_topic_name(TEST_TOPIC_NAME + "_1"); + part_2.sub_topic_name(TEST_TOPIC_NAME); + + ASSERT_TRUE(part_1.init_participant()); + ASSERT_TRUE(part_1.init_publisher(0)); + ASSERT_TRUE(part_1.init_subscriber(0)); + + ASSERT_TRUE(part_2.init_participant()); + ASSERT_TRUE(part_2.init_subscriber(0)); + ASSERT_TRUE(part_2.init_publisher(0)); + + part_1.pub_wait_discovery(); + part_1.sub_wait_discovery(); + + part_2.pub_wait_discovery(); + part_2.sub_wait_discovery(); + + auto& writer_p1 = part_1.get_native_writer(0); + auto& writer_p2 = part_2.get_native_writer(0); + + std::vector sub_handles_p1; + std::vector sub_handles_p2; + + ReturnCode_t ret = writer_p1.get_matched_subscriptions(sub_handles_p1); + ASSERT_EQ(ret, ReturnCode_t::RETCODE_OK); + ASSERT_EQ(sub_handles_p1.size(), 1u); + ASSERT_EQ(sub_handles_p1[0], part_2.get_native_reader(0).get_instance_handle()); + + ret = writer_p2.get_matched_subscriptions(sub_handles_p2); + ASSERT_EQ(ret, ReturnCode_t::RETCODE_OK); + ASSERT_EQ(sub_handles_p2.size(), 1u); + ASSERT_EQ(sub_handles_p2[0], part_1.get_native_reader(0).get_instance_handle()); +} + #ifdef INSTANTIATE_TEST_SUITE_P #define GTEST_INSTANTIATE_TEST_MACRO(x, y, z, w) INSTANTIATE_TEST_SUITE_P(x, y, z, w) #else diff --git a/test/blackbox/common/DDSBlackboxTestsPersistence.cpp b/test/blackbox/common/DDSBlackboxTestsPersistence.cpp index ba702e05d3b..2cbdbacf442 100644 --- a/test/blackbox/common/DDSBlackboxTestsPersistence.cpp +++ b/test/blackbox/common/DDSBlackboxTestsPersistence.cpp @@ -404,8 +404,8 @@ TEST_P(PersistenceLargeData, PubSubAsReliablePubPersistentWithStaticDiscovery) .multicastLocatorList(WriterMulticastLocators) .setPublisherIDs(1, 2) .setManualTopicName(std::string("BlackBox_StaticDiscovery_") + TOPIC_RANDOM_NUMBER) - .userData({'V', 'G', 'W', 0x78, 0x73, 0x69, 0x74, 0x65, 0x72, 0x5f, 0x70, 0x65, 0x72, 0x73, 0x5f, 0x67, - 0x75, 0x69}) + .user_data({'V', 'G', 'W', 0x78, 0x73, 0x69, 0x74, 0x65, 0x72, 0x5f, 0x70, 0x65, 0x72, 0x73, 0x5f, 0x67, + 0x75, 0x69}) .init(); ASSERT_TRUE(writer.isInitialized()); diff --git a/test/blackbox/common/RTPSBlackboxTests.cpp b/test/blackbox/common/RTPSBlackboxTests.cpp index b8f5ce212a1..3ebdf137140 100644 --- a/test/blackbox/common/RTPSBlackboxTests.cpp +++ b/test/blackbox/common/RTPSBlackboxTests.cpp @@ -21,9 +21,10 @@ #include +#include +#include #include #include -#include #include #include @@ -83,6 +84,36 @@ class BlackboxEnvironment : public ::testing::Environment }; +void entity_id_to_builtin_topic_key( + eprosima::fastdds::dds::builtin::BuiltinTopicKey_t& bt_key, + const eprosima::fastrtps::rtps::EntityId_t& entity_id) +{ + bt_key.value[0] = 0; + bt_key.value[1] = 0; + bt_key.value[2] = static_cast(entity_id.value[0]) << 24 + | static_cast(entity_id.value[1]) << 16 + | static_cast(entity_id.value[2]) << 8 + | static_cast(entity_id.value[3]); +} + +void guid_prefix_to_builtin_topic_key( + eprosima::fastdds::dds::builtin::BuiltinTopicKey_t& bt_key, + const eprosima::fastrtps::rtps::GuidPrefix_t& guid_prefix) +{ + bt_key.value[0] = static_cast(guid_prefix.value[0]) << 24 + | static_cast(guid_prefix.value[1]) << 16 + | static_cast(guid_prefix.value[2]) << 8 + | static_cast(guid_prefix.value[3]); + bt_key.value[1] = static_cast(guid_prefix.value[4]) << 24 + | static_cast(guid_prefix.value[5]) << 16 + | static_cast(guid_prefix.value[6]) << 8 + | static_cast(guid_prefix.value[7]); + bt_key.value[2] = static_cast(guid_prefix.value[8]) << 24 + | static_cast(guid_prefix.value[9]) << 16 + | static_cast(guid_prefix.value[10]) << 8 + | static_cast(guid_prefix.value[11]); +} + int main( int argc, char** argv) diff --git a/test/blackbox/common/RTPSBlackboxTestsBasic.cpp b/test/blackbox/common/RTPSBlackboxTestsBasic.cpp index 409fdc3dff8..a67d991d7e4 100644 --- a/test/blackbox/common/RTPSBlackboxTestsBasic.cpp +++ b/test/blackbox/common/RTPSBlackboxTestsBasic.cpp @@ -21,6 +21,9 @@ #include +#include +#include +#include #include #include #include @@ -1276,6 +1279,172 @@ TEST(RTPS, max_output_message_size_writer) } +bool validate_publication_builtin_topic_data( + const eprosima::fastdds::dds::builtin::PublicationBuiltinTopicData& pubdata, + const RTPSWriter& writer, + const TopicAttributes& topic_atts, + const WriterQos& writer_qos, + const GUID_t& participant_guid) +{ + bool ret = true; + + eprosima::fastdds::dds::builtin::BuiltinTopicKey_t w_key, part_key; + + entity_id_to_builtin_topic_key(w_key, writer.getGuid().entityId); + guid_prefix_to_builtin_topic_key(part_key, participant_guid.guidPrefix); + + ret &= (0 == memcmp(pubdata.key.value, w_key.value, sizeof(eprosima::fastdds::dds::builtin::BuiltinTopicKey_t))); + ret &= + (0 == + memcmp(pubdata.participant_key.value, part_key.value, + sizeof(eprosima::fastdds::dds::builtin::BuiltinTopicKey_t))); + ret &= (pubdata.topic_name == topic_atts.topicName.to_string()); + ret &= (pubdata.type_name == topic_atts.topicDataType.to_string()); + + // Writer Qos + ret &= (pubdata.durability == writer_qos.m_durability); + ret &= (pubdata.durability_service == writer_qos.m_durabilityService); + ret &= (pubdata.deadline == writer_qos.m_deadline); + ret &= (pubdata.latency_budget == writer_qos.m_latencyBudget); + ret &= (pubdata.liveliness == writer_qos.m_liveliness); + ret &= (pubdata.reliability == writer_qos.m_reliability); + ret &= (pubdata.lifespan == writer_qos.m_lifespan); + ret &= ( + (pubdata.user_data.size() == writer_qos.m_userData.size()) && + (0 == memcmp(pubdata.user_data.data(), writer_qos.m_userData.data(), pubdata.user_data.size()))); + ret &= (pubdata.ownership == writer_qos.m_ownership); + ret &= (pubdata.ownership_strength == writer_qos.m_ownershipStrength); + ret &= (pubdata.destination_order == writer_qos.m_destinationOrder); + + // Publisher Qos + ret &= (pubdata.presentation == writer_qos.m_presentation); + ret &= (pubdata.partition.getNames() == writer_qos.m_partition.getNames()); + // ignore topic_data not implemented + // ignore group_data + + return ret; +} + +bool validate_subscription_builtin_topic_data( + const eprosima::fastdds::dds::builtin::SubscriptionBuiltinTopicData& subdata, + const RTPSReader& reader, + const TopicAttributes& topic_atts, + const ReaderQos& reader_qos, + const GUID_t& participant_guid) +{ + bool ret = true; + + eprosima::fastdds::dds::builtin::BuiltinTopicKey_t r_key, part_key; + + entity_id_to_builtin_topic_key(r_key, reader.getGuid().entityId); + guid_prefix_to_builtin_topic_key(part_key, participant_guid.guidPrefix); + + ret &= (0 == memcmp(subdata.key.value, r_key.value, sizeof(eprosima::fastdds::dds::builtin::BuiltinTopicKey_t))); + ret &= + (0 == + memcmp(subdata.participant_key.value, part_key.value, + sizeof(eprosima::fastdds::dds::builtin::BuiltinTopicKey_t))); + ret &= (subdata.topic_name == topic_atts.topicName.to_string()); + ret &= (subdata.type_name == topic_atts.topicDataType.to_string()); + + // RTPS Reader + ret &= (subdata.durability == reader_qos.m_durability); + ret &= (subdata.deadline == reader_qos.m_deadline); + ret &= (subdata.latency_budget == reader_qos.m_latencyBudget); + ret &= (subdata.liveliness == reader_qos.m_liveliness); + ret &= (subdata.reliability == reader_qos.m_reliability); + ret &= (subdata.ownership == reader_qos.m_ownership); + ret &= (subdata.destination_order == reader_qos.m_destinationOrder); + ret &= ( + (subdata.user_data.size() == reader_qos.m_userData.size()) && + (0 == memcmp(subdata.user_data.data(), reader_qos.m_userData.data(), subdata.user_data.size()))); + // time based filter not implemented + + // Subscriber Qos + ret &= (subdata.presentation == reader_qos.m_presentation); + ret &= (subdata.partition.getNames() == reader_qos.m_partition.getNames()); + // ignore topic_data not implemented + // ignore group_data + + return ret; +} + +/** + * @test RTPS-PART-API-GSI-GPI-01 + * + * get_subscription/publication_info() must return false if the entity is not found. + */ +TEST(RTPS, rtps_participant_get_pubsub_info_negative) +{ + RTPSWithRegistrationWriter writer(TEST_TOPIC_NAME); + RTPSWithRegistrationReader reader(TEST_TOPIC_NAME); + + writer.init(); + reader.init(); + + ASSERT_TRUE(writer.isInitialized()); + ASSERT_TRUE(reader.isInitialized()); + + eprosima::fastdds::dds::builtin::PublicationBuiltinTopicData pubdata; + eprosima::fastdds::dds::builtin::SubscriptionBuiltinTopicData subdata; + + // Get publication info from the reader participant and validate it + GUID_t unknown_writer_guid = writer.guid(); + unknown_writer_guid.entityId.value[3] = 0x44; + bool ret = reader.get_rtps_participant()->get_publication_info(pubdata, unknown_writer_guid); + ASSERT_FALSE(ret); + + GUID_t unknown_reader_guid = reader.guid(); + unknown_reader_guid.entityId.value[3] = 0x44; + // Get subscription info from the reader participant and validate it + ret = writer.get_rtps_participant()->get_subscription_info(subdata, unknown_reader_guid); + ASSERT_FALSE(ret); +} + +/** + * @test RTPS-PART-API-GSI-GPI-02 + * + * get_subscription/publication_info() must succeed when the guid is known and correctly retrieve the publication/subscription data. + * Parameterize the test for different transports (Transport, Datasharing and Intraprocess). + */ +TEST_P(RTPS, rtps_participant_get_pubsub_info) +{ + RTPSWithRegistrationWriter writer(TEST_TOPIC_NAME); + RTPSWithRegistrationReader reader(TEST_TOPIC_NAME); + + std::vector partitions{"*"}; + + writer.user_data({'u', 's', 'e', 'r', 'd', 'a', 't', 'a'}) + .partitions(partitions) + .init(); + reader.user_data({'u', 's', 'e', 'r', 'd', 'a', 't', 'a'}) + .partitions(partitions) + .init(); + + ASSERT_TRUE(writer.isInitialized()); + ASSERT_TRUE(reader.isInitialized()); + + writer.wait_discovery(); + reader.wait_discovery(); + + eprosima::fastdds::dds::builtin::PublicationBuiltinTopicData pubdata; + eprosima::fastdds::dds::builtin::SubscriptionBuiltinTopicData subdata; + + // Get publication info from the reader participant and validate it + bool ret = reader.get_rtps_participant()->get_publication_info(pubdata, writer.guid()); + ASSERT_TRUE(ret); + ASSERT_TRUE(validate_publication_builtin_topic_data(pubdata, writer.get_native_writer(), + writer.get_topic_attributes(), + writer.get_writerqos(), writer.get_rtps_participant()->getGuid())); + + // Get subscription info from the reader participant and validate it + ret = writer.get_rtps_participant()->get_subscription_info(subdata, reader.guid()); + ASSERT_TRUE(ret); + ASSERT_TRUE(validate_subscription_builtin_topic_data(subdata, reader.get_native_reader(), + reader.get_topic_attributes(), + reader.get_readerqos(), reader.get_rtps_participant()->getGuid())); +} + #ifdef INSTANTIATE_TEST_SUITE_P #define GTEST_INSTANTIATE_TEST_MACRO(x, y, z, w) INSTANTIATE_TEST_SUITE_P(x, y, z, w) #else diff --git a/test/blackbox/common/RTPSBlackboxTestsReader.cpp b/test/blackbox/common/RTPSBlackboxTestsReader.cpp new file mode 100644 index 00000000000..7129e3678a7 --- /dev/null +++ b/test/blackbox/common/RTPSBlackboxTestsReader.cpp @@ -0,0 +1,156 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 "BlackboxTests.hpp" + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "RTPSWithRegistrationReader.hpp" +#include "RTPSWithRegistrationWriter.hpp" + +using namespace eprosima::fastrtps; +using namespace eprosima::fastrtps::rtps; + +enum communication_type +{ + TRANSPORT, + INTRAPROCESS +}; + +class RTPSReaderTests : public testing::TestWithParam +{ +public: + + void SetUp() override + { + LibrarySettingsAttributes library_settings; + switch (GetParam()) + { + case INTRAPROCESS: + library_settings.intraprocess_delivery = IntraprocessDeliveryType::INTRAPROCESS_FULL; + xmlparser::XMLProfileManager::library_settings(library_settings); + break; + case TRANSPORT: + default: + break; + } + } + + void TearDown() override + { + LibrarySettingsAttributes library_settings; + switch (GetParam()) + { + case INTRAPROCESS: + library_settings.intraprocess_delivery = IntraprocessDeliveryType::INTRAPROCESS_OFF; + xmlparser::XMLProfileManager::library_settings(library_settings); + break; + case TRANSPORT: + default: + break; + } + } + +}; + +/** + * @test RTPS-READER-API-MWG-01 + * + * matched_writers_guids() must return true with empty list when the entitiy is not matched. + * matched_writers_guids() must return true with a correct list when the entitiy is matched. + */ +TEST_P(RTPSReaderTests, rtpsreader_matched_writers_guids) +{ + RTPSWithRegistrationReader reader(TEST_TOPIC_NAME); + RTPSWithRegistrationWriter writer(TEST_TOPIC_NAME); + + reader.reliability(eprosima::fastrtps::rtps::RELIABLE) + .init(); + + writer.reliability(eprosima::fastrtps::rtps::BEST_EFFORT) + .init(); + + ASSERT_TRUE(reader.isInitialized()); + ASSERT_TRUE(writer.isInitialized()); + + // Expect not to discover + reader.wait_discovery(std::chrono::seconds(1)); + ASSERT_FALSE(reader.get_matched()); + + std::vector matched_guids; + auto& native_rtps_reader = reader.get_native_reader(); + ASSERT_TRUE(native_rtps_reader.matched_writers_guids(matched_guids)); + ASSERT_TRUE(matched_guids.empty()); + + writer.destroy(); + reader.wait_undiscovery(); + + const size_t num_matched_writers = 3; + std::vector>> writers; + std::vector expected_matched_guids; + + writers.reserve(num_matched_writers); + expected_matched_guids.reserve(num_matched_writers); + + for (size_t i = 0; i < num_matched_writers; ++i) + { + writers.emplace_back(new RTPSWithRegistrationWriter(TEST_TOPIC_NAME)); + writers.back()->init(); + expected_matched_guids.emplace_back(writers.back()->guid()); + } + + reader.wait_discovery(num_matched_writers, std::chrono::seconds::zero()); + ASSERT_EQ(num_matched_writers, reader.get_matched()); + native_rtps_reader.matched_writers_guids(matched_guids); + ASSERT_EQ(expected_matched_guids.size(), matched_guids.size()); + ASSERT_TRUE(std::is_permutation(expected_matched_guids.begin(), expected_matched_guids.end(), + matched_guids.begin())); +} + +#ifdef INSTANTIATE_TEST_SUITE_P +#define GTEST_INSTANTIATE_TEST_MACRO(x, y, z, w) INSTANTIATE_TEST_SUITE_P(x, y, z, w) +#else +#define GTEST_INSTANTIATE_TEST_MACRO(x, y, z, w) INSTANTIATE_TEST_CASE_P(x, y, z, w) +#endif // ifdef INSTANTIATE_TEST_SUITE_P + +GTEST_INSTANTIATE_TEST_MACRO(RTPSReaderTests, + RTPSReaderTests, + testing::Values(TRANSPORT, INTRAPROCESS), + [](const testing::TestParamInfo& info) + { + switch (info.param) + { + case INTRAPROCESS: + return "Intraprocess"; + break; + case TRANSPORT: + default: + return "Transport"; + } + + }); diff --git a/test/blackbox/common/RTPSBlackboxTestsWriter.cpp b/test/blackbox/common/RTPSBlackboxTestsWriter.cpp new file mode 100644 index 00000000000..6ba28624e72 --- /dev/null +++ b/test/blackbox/common/RTPSBlackboxTestsWriter.cpp @@ -0,0 +1,156 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// 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 "BlackboxTests.hpp" + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "RTPSWithRegistrationReader.hpp" +#include "RTPSWithRegistrationWriter.hpp" + +using namespace eprosima::fastrtps; +using namespace eprosima::fastrtps::rtps; + +enum communication_type +{ + TRANSPORT, + INTRAPROCESS +}; + +class RTPSWriterTests : public testing::TestWithParam +{ +public: + + void SetUp() override + { + LibrarySettingsAttributes library_settings; + switch (GetParam()) + { + case INTRAPROCESS: + library_settings.intraprocess_delivery = IntraprocessDeliveryType::INTRAPROCESS_FULL; + xmlparser::XMLProfileManager::library_settings(library_settings); + break; + case TRANSPORT: + default: + break; + } + } + + void TearDown() override + { + LibrarySettingsAttributes library_settings; + switch (GetParam()) + { + case INTRAPROCESS: + library_settings.intraprocess_delivery = IntraprocessDeliveryType::INTRAPROCESS_OFF; + xmlparser::XMLProfileManager::library_settings(library_settings); + break; + case TRANSPORT: + default: + break; + } + } + +}; + +/** + * @test RTPS-WRITER-API-MRG-01 + * + * matched_readers_guids() must return true with empty list when the entitiy is not matched. + * matched_readers_guids() must return true with a correct list when the entitiy is matched. + */ +TEST_P(RTPSWriterTests, rtpswriter_matched_readers_guids) +{ + RTPSWithRegistrationWriter writer(TEST_TOPIC_NAME); + RTPSWithRegistrationReader reader(TEST_TOPIC_NAME); + + writer.reliability(eprosima::fastrtps::rtps::BEST_EFFORT) + .init(); + + reader.reliability(eprosima::fastrtps::rtps::RELIABLE) + .init(); + + ASSERT_TRUE(writer.isInitialized()); + ASSERT_TRUE(reader.isInitialized()); + + // Expect not to discover + writer.wait_discovery(std::chrono::seconds(1)); + ASSERT_FALSE(writer.get_matched()); + + std::vector matched_guids; + auto& native_rtps_writer = writer.get_native_writer(); + ASSERT_TRUE(native_rtps_writer.matched_readers_guids(matched_guids)); + ASSERT_TRUE(matched_guids.empty()); + + reader.destroy(); + writer.wait_undiscovery(); + + const size_t num_matched_readers = 3; + std::vector>> readers; + std::vector expected_matched_guids; + + readers.reserve(num_matched_readers); + expected_matched_guids.reserve(num_matched_readers); + + for (size_t i = 0; i < num_matched_readers; ++i) + { + readers.emplace_back(new RTPSWithRegistrationReader(TEST_TOPIC_NAME)); + readers.back()->init(); + expected_matched_guids.emplace_back(readers.back()->guid()); + } + + writer.wait_discovery(num_matched_readers, std::chrono::seconds::zero()); + ASSERT_EQ(num_matched_readers, writer.get_matched()); + native_rtps_writer.matched_readers_guids(matched_guids); + ASSERT_EQ(expected_matched_guids.size(), matched_guids.size()); + ASSERT_TRUE(std::is_permutation(expected_matched_guids.begin(), expected_matched_guids.end(), + matched_guids.begin())); +} + +#ifdef INSTANTIATE_TEST_SUITE_P +#define GTEST_INSTANTIATE_TEST_MACRO(x, y, z, w) INSTANTIATE_TEST_SUITE_P(x, y, z, w) +#else +#define GTEST_INSTANTIATE_TEST_MACRO(x, y, z, w) INSTANTIATE_TEST_CASE_P(x, y, z, w) +#endif // ifdef INSTANTIATE_TEST_SUITE_P + +GTEST_INSTANTIATE_TEST_MACRO(RTPSWriterTests, + RTPSWriterTests, + testing::Values(TRANSPORT, INTRAPROCESS), + [](const testing::TestParamInfo& info) + { + switch (info.param) + { + case INTRAPROCESS: + return "Intraprocess"; + break; + case TRANSPORT: + default: + return "Transport"; + } + + }); diff --git a/test/blackbox/common/RTPSWithRegistrationReader.hpp b/test/blackbox/common/RTPSWithRegistrationReader.hpp index d48300ca830..56c9130817f 100644 --- a/test/blackbox/common/RTPSWithRegistrationReader.hpp +++ b/test/blackbox/common/RTPSWithRegistrationReader.hpp @@ -551,6 +551,21 @@ class RTPSWithRegistrationReader return *reader_; } + const eprosima::fastrtps::ReaderQos& get_readerqos() const + { + return reader_qos_; + } + + const eprosima::fastrtps::TopicAttributes& get_topic_attributes() const + { + return topic_attr_; + } + + eprosima::fastrtps::rtps::RTPSParticipant* get_rtps_participant() + { + return participant_; + } + private: void receive_one( diff --git a/test/blackbox/common/RTPSWithRegistrationWriter.hpp b/test/blackbox/common/RTPSWithRegistrationWriter.hpp index 0b35f07cd9e..af66ff7cfdf 100644 --- a/test/blackbox/common/RTPSWithRegistrationWriter.hpp +++ b/test/blackbox/common/RTPSWithRegistrationWriter.hpp @@ -573,6 +573,26 @@ class RTPSWithRegistrationWriter return writer_->getGuid(); } + eprosima::fastrtps::rtps::RTPSWriter& get_native_writer() const + { + return *writer_; + } + + const eprosima::fastrtps::WriterQos& get_writerqos() const + { + return writer_qos_; + } + + const eprosima::fastrtps::TopicAttributes& get_topic_attributes() const + { + return topic_attr_; + } + + eprosima::fastrtps::rtps::RTPSParticipant* get_rtps_participant() + { + return participant_; + } + private: void on_reader_discovery( diff --git a/test/mock/rtps/RTPSParticipant/fastdds/rtps/participant/RTPSParticipant.h b/test/mock/rtps/RTPSParticipant/fastdds/rtps/participant/RTPSParticipant.h index 26326c84327..60fea577b93 100644 --- a/test/mock/rtps/RTPSParticipant/fastdds/rtps/participant/RTPSParticipant.h +++ b/test/mock/rtps/RTPSParticipant/fastdds/rtps/participant/RTPSParticipant.h @@ -49,6 +49,8 @@ namespace dds { namespace builtin { class TypeLookupManager; +struct PublicationBuiltinTopicData; +struct SubscriptionBuiltinTopicData; } // namespace builtin } // namespace dds @@ -225,6 +227,14 @@ class RTPS_DllAPI RTPSParticipant return {}; } + MOCK_METHOD(bool, get_publication_info, + (fastdds::dds::builtin::PublicationBuiltinTopicData&, + const GUID_t&), (const)); + + MOCK_METHOD(bool, get_subscription_info, + (fastdds::dds::builtin::SubscriptionBuiltinTopicData&, + const GUID_t&), (const)); + const RTPSParticipantAttributes& getRTPSParticipantAttributes() { return attributes_;