Skip to content

Commit 86e3f33

Browse files
committed
Implementing get_qos_for_publishers/subscribers
- Implemented the functions defined in ros2#511 - rcl_get_qos_for_publishers - rcl_get_qos_for_subscribers - Wrote tests for the same Note: colcon build --packages-up-to rcl && colcon test --packages-select rcl && colcon test-result --verbose --test-result-base build/rcl runs successfully without any errors or failures. Signed-off-by: Jaison Titus <[email protected]>
1 parent 3813ade commit 86e3f33

File tree

3 files changed

+283
-27
lines changed

3 files changed

+283
-27
lines changed

rcl/include/rcl/graph.h

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -525,22 +525,22 @@ rcl_count_subscribers(
525525
size_t * count);
526526

527527
/// Returns a list of all publishers to a topic.
528-
/// Each element in the list will contain the publisher's name and its respective qos profile.
528+
/// Each element in the list will contain the node name, node namespace, topic type,
529+
/// gid and the qos profile of the publisher.
529530
/**
530531
* The `node` parameter must point to a valid node.
531532
*
532533
* The `topic_name` parameter must not be `NULL`.
533534
*
534-
* The `publishers` parameter must point to a valid struct of type rmw_participants_t.
535-
* The `count` field inside the struct must be set to 0
536-
* The `participants` field inside the struct must be set to null.
537-
* The `publishers` parameter is the output for this function and will be set.
535+
* The `no_mangle` parameter determines if the provided topic_name should be
536+
* expanded to its fully qualified name.
538537
*
539-
* The topic name is not automatically remapped by this function.
540-
* If there is a publisher created with topic name `foo` and remap rule `foo:=bar` then calling
541-
* this with `topic_name` set to `bar` will return a list with 1 publisher, and with `topic_name` set to `foo`
542-
* will return a list with 0 publishers.
543-
* /sa rcl_remap_topic_name()
538+
* It is the responsibility of the caller to ensure that `publishers_info` parameter points
539+
* to a valid struct of type rmw_topic_info_array_t. The `count` field inside the struct
540+
* must be set to 0 and the `info_array` field inside the struct must be set to null.
541+
*
542+
* The `allocator` will be used to allocate memory to the `info_array` member
543+
* inside of `publishers_info`.
544544
*
545545
* <hr>
546546
* Attribute | Adherence
@@ -552,8 +552,11 @@ rcl_count_subscribers(
552552
* <i>[1] implementation may need to protect the data structure with a lock</i>
553553
*
554554
* \param[in] node the handle to the node being used to query the ROS graph
555+
* \param[in] allocator allocator to be used when allocating space for
556+
* the array inside publishers_info
555557
* \param[in] topic_name the name of the topic in question
556-
* \param[out] publishers a struct representing a list of publishers with their qos profile.
558+
* \param[in] no_mangle if true, the topic_name will be expanded to its fully qualified name.
559+
* \param[out] publishers_info a struct representing a list of publisher information.
557560
* \return `RCL_RET_OK` if the query was successful, or
558561
* \return `RCL_RET_NODE_INVALID` if the node is invalid, or
559562
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
@@ -562,29 +565,32 @@ rcl_count_subscribers(
562565
RCL_PUBLIC
563566
RCL_WARN_UNUSED
564567
rcl_ret_t
565-
rcl_get_qos_for_publishers(
568+
rcl_get_publishers_info_by_topic(
566569
const rcl_node_t * node,
570+
rcutils_allocator_t * allocator,
567571
const char * topic_name,
568-
rmw_participants_t * publishers);
572+
bool no_mangle,
573+
rmw_topic_info_array_t * publishers_info);
574+
569575

570-
/// Returns a list of all subscribers to a topic.
571-
/// Each element in the list will contain the subscriber's name and its respective qos profile.
576+
/// Returns a list of all subscriptions to a topic.
577+
/// Each element in the list will contain the node name, node namespace, topic type,
578+
/// gid and the qos profile of the subscription.
572579
/**
573580
* The `node` parameter must point to a valid node.
574581
*
575582
* The `topic_name` parameter must not be `NULL`.
576583
*
577-
* The `subscriber` parameter must point to a valid struct of type rmw_participants_t.
578-
* The `count` field inside the struct must be set to 0
579-
* The `participants` field inside the struct must be set to null.
580-
* The `subscribers` parameter is the output for this function and will be set.
584+
* The `no_mangle` parameter determines if the provided topic_name should be
585+
* expanded to its fully qualified name.
581586
*
582-
* The topic name is not automatically remapped by this function.
583-
* If there is a subscriber created with topic name `foo` and remap rule `foo:=bar` then calling
584-
* this with `topic_name` set to `bar` will return a list with 1 subscriber , and with `topic_name` set to `foo`
585-
* will return a list with 0 subscribers.
586-
* /sa rcl_remap_topic_name()
587+
* It is the responsibility of the caller to ensure that `subscriptions_info` parameter points
588+
* to a valid struct of type rmw_topic_info_array_t. The `count` field inside the struct
589+
* must be set to 0 and the `info_array` field inside the struct must be set to null.
587590
*
591+
* The `allocator` will be used to allocate memory to the `info_array` member
592+
* inside of `subscriptions_info`.
593+
588594
* <hr>
589595
* Attribute | Adherence
590596
* ------------------ | -------------
@@ -595,8 +601,11 @@ rcl_get_qos_for_publishers(
595601
* <i>[1] implementation may need to protect the data structure with a lock</i>
596602
*
597603
* \param[in] node the handle to the node being used to query the ROS graph
604+
* \param[in] allocator allocator to be used when allocating space for
605+
* the array inside publishers_info
598606
* \param[in] topic_name the name of the topic in question
599-
* \param[out] subscribers a struct representing a list of subscribers with their qos profile.
607+
* \param[in] no_mangle if true, the topic_name will be expanded to its fully qualified name.
608+
* \param[out] subscriptions_info a struct representing a list of subscriptions information.
600609
* \return `RCL_RET_OK` if the query was successful, or
601610
* \return `RCL_RET_NODE_INVALID` if the node is invalid, or
602611
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
@@ -605,10 +614,12 @@ rcl_get_qos_for_publishers(
605614
RCL_PUBLIC
606615
RCL_WARN_UNUSED
607616
rcl_ret_t
608-
rcl_get_qos_for_subscribers(
617+
rcl_get_subscriptions_info_by_topic(
609618
const rcl_node_t * node,
619+
rcutils_allocator_t * allocator,
610620
const char * topic_name,
611-
rmw_participants_t * subscribers);
621+
bool no_mangle,
622+
rmw_topic_info_array_t * subscriptions_info);
612623

613624

614625
/// Check if a service server is available for the given service client.

rcl/src/rcl/graph.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,73 @@ rcl_count_subscribers(
375375
return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
376376
}
377377

378+
379+
typedef rmw_ret_t (* get_topic_info_func)(
380+
const rcl_node_t * node,
381+
rcutils_allocator_t * allocator,
382+
const char * topic_name,
383+
bool no_mangle,
384+
rmw_topic_info_array_t * info_array);
385+
386+
rcl_ret_t
387+
__rcl_get_info_by_topic(
388+
const rmw_node_t * node,
389+
rcutils_allocator_t * allocator,
390+
const char * topic_name,
391+
bool no_mangle,
392+
rmw_topic_info_array_t * info_array,
393+
get_topic_info_func get_topic_info)
394+
{
395+
if (!rcl_node_is_valid(node)) {
396+
RCL_SET_ERROR_MSG("Invalid node provided.");
397+
return RCL_RET_NODE_INVALID;
398+
}
399+
const rcl_node_options_t * node_options = rcl_node_get_options(node);
400+
if (!node_options) {
401+
RCL_SET_ERROR_MSG("Node options are invalid.");
402+
return RCL_RET_NODE_INVALID; // shouldn't happen, but error is already set if so
403+
}
404+
RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
405+
RCL_CHECK_ARGUMENT_FOR_NULL(topic_name, RCL_RET_INVALID_ARGUMENT);
406+
RCL_CHECK_ARGUMENT_FOR_NULL(info_array, RCL_RET_INVALID_ARGUMENT);
407+
if (info_array->info_array != NULL) {
408+
RCL_SET_ERROR_MSG("The variable participants inside rmw_participants_t should be set to null. "
409+
"It will be malloc'd where it gets populated.");
410+
return RCL_RET_INVALID_ARGUMENT;
411+
}
412+
rmw_ret_t rmw_ret = get_topic_info(
413+
rcl_node_get_rmw_handle(node),
414+
allocator,
415+
topic_name,
416+
no_mangle,
417+
info_array);
418+
return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
419+
}
420+
421+
rcl_ret_t
422+
rcl_get_publishers_info_by_topic(
423+
const rcl_node_t * node,
424+
rcutils_allocator_t * allocator,
425+
const char * topic_name,
426+
bool no_mangle,
427+
rmw_topic_info_array_t * publishers_info)
428+
{
429+
return __rcl_get_info_by_topic(node, allocator, topic_name, no_mangle, publishers_info,
430+
rmw_get_publishers_info_by_topic);
431+
}
432+
433+
rcl_ret_t
434+
rcl_get_subscriptions_info_by_topic(
435+
const rcl_node_t * node,
436+
rcutils_allocator_t * allocator,
437+
const char * topic_name,
438+
bool no_mangle,
439+
rmw_topic_info_array_t * subscriptions_info)
440+
{
441+
return __rcl_get_info_by_topic(node, allocator, topic_name, no_mangle, subscriptions_info,
442+
rmw_get_subscriptions_info_by_topic);
443+
}
444+
378445
rcl_ret_t
379446
rcl_service_server_is_available(
380447
const rcl_node_t * node,

rcl/test/rcl/test_graph.cpp

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ class CLASSNAME (TestGraphFixture, RMW_IMPLEMENTATION) : public ::testing::Test
6363
rcl_wait_set_t * wait_set_ptr;
6464
const char * test_graph_node_name = "test_graph_node";
6565

66+
rmw_topic_info_array_t * topic_info_array;
67+
const char * topic_name = "valid_topic_name";
68+
6669
void SetUp()
6770
{
6871
rcl_ret_t ret;
@@ -101,6 +104,12 @@ class CLASSNAME (TestGraphFixture, RMW_IMPLEMENTATION) : public ::testing::Test
101104
ret = rcl_wait_set_init(
102105
this->wait_set_ptr, 0, 1, 0, 0, 0, 0, this->context_ptr, rcl_get_default_allocator());
103106
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
107+
108+
rmw_topic_info_array_t valid_topic_info_array = {
109+
0, /*count*/
110+
nullptr /*info_array*/
111+
};
112+
this->topic_info_array = &valid_topic_info_array;
104113
}
105114

106115
void TearDown()
@@ -1321,3 +1330,172 @@ TEST_F(CLASSNAME(TestGraphFixture, RMW_IMPLEMENTATION), test_rcl_service_server_
13211330
wait_for_service_state_to_change(false, is_available);
13221331
ASSERT_FALSE(is_available);
13231332
}
1333+
1334+
1335+
/*
1336+
* This does not test content of the response.
1337+
* It only tests if the return code is the one expected.
1338+
*/
1339+
TEST_F(CLASSNAME(TestGraphFixture, RMW_IMPLEMENTATION),
1340+
test_rcl_get_publishers_info_by_topic_null_node)
1341+
{
1342+
rcl_allocator_t allocator = rcl_get_default_allocator();
1343+
auto ret = rcl_get_publishers_info_by_topic(nullptr,
1344+
&allocator, this->topic_name, false, this->topic_info_array);
1345+
EXPECT_EQ(RCL_RET_NODE_INVALID, ret);
1346+
}
1347+
1348+
/*
1349+
* This does not test content of the response.
1350+
* It only tests if the return code is the one expected.
1351+
*/
1352+
TEST_F(CLASSNAME(TestGraphFixture, RMW_IMPLEMENTATION),
1353+
test_rcl_get_subscriptions_info_by_topic_null_node)
1354+
{
1355+
rcl_allocator_t allocator = rcl_get_default_allocator();
1356+
auto ret = rcl_get_subscriptions_info_by_topic(nullptr,
1357+
&allocator, this->topic_name, false, this->topic_info_array);
1358+
EXPECT_EQ(RCL_RET_NODE_INVALID, ret);
1359+
}
1360+
1361+
/*
1362+
* This does not test content of the response.
1363+
* It only tests if the return code is the one expected.
1364+
*/
1365+
TEST_F(CLASSNAME(TestGraphFixture, RMW_IMPLEMENTATION),
1366+
test_rcl_get_publishers_info_by_topic_invalid_node)
1367+
{
1368+
// this->old_node_ptr is a pointer to an invalid node.
1369+
rcl_allocator_t allocator = rcl_get_default_allocator();
1370+
auto ret = rcl_get_publishers_info_by_topic(this->old_node_ptr,
1371+
&allocator, this->topic_name, false, this->topic_info_array);
1372+
EXPECT_EQ(RCL_RET_NODE_INVALID, ret);
1373+
}
1374+
1375+
/*
1376+
* This does not test content of the response.
1377+
* It only tests if the return code is the one expected.
1378+
*/
1379+
TEST_F(CLASSNAME(TestGraphFixture, RMW_IMPLEMENTATION),
1380+
test_rcl_get_subscriptions_info_by_topic_invalid_node)
1381+
{
1382+
// this->old_node_ptr is a pointer to an invalid node.
1383+
rcl_allocator_t allocator = rcl_get_default_allocator();
1384+
auto ret = rcl_get_subscriptions_info_by_topic(this->old_node_ptr,
1385+
&allocator, this->topic_name, false, this->topic_info_array);
1386+
EXPECT_EQ(RCL_RET_NODE_INVALID, ret);
1387+
}
1388+
1389+
/*
1390+
* This does not test content of the response.
1391+
* It only tests if the return code is the one expected.
1392+
*/
1393+
TEST_F(CLASSNAME(TestGraphFixture, RMW_IMPLEMENTATION),
1394+
test_rcl_get_publishers_info_by_topic_null_allocator)
1395+
{
1396+
auto ret = rcl_get_publishers_info_by_topic(this->node_ptr, nullptr, this->topic_name, false,
1397+
this->topic_info_array);
1398+
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
1399+
}
1400+
1401+
/*
1402+
* This does not test content of the response.
1403+
* It only tests if the return code is the one expected.
1404+
*/
1405+
TEST_F(CLASSNAME(TestGraphFixture, RMW_IMPLEMENTATION),
1406+
test_rcl_get_subscriptions_info_by_topic_null_allocator)
1407+
{
1408+
auto ret = rcl_get_subscriptions_info_by_topic(this->node_ptr, nullptr, this->topic_name, false,
1409+
this->topic_info_array);
1410+
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
1411+
}
1412+
1413+
/*
1414+
* This does not test content of the response.
1415+
* It only tests if the return code is the one expected.
1416+
*/
1417+
TEST_F(CLASSNAME(TestGraphFixture, RMW_IMPLEMENTATION),
1418+
test_rcl_get_publishers_info_by_topic_null_topic)
1419+
{
1420+
rcl_allocator_t allocator = rcl_get_default_allocator();
1421+
auto ret = rcl_get_publishers_info_by_topic(this->node_ptr,
1422+
&allocator, nullptr, false, this->topic_info_array);
1423+
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
1424+
}
1425+
1426+
/*
1427+
* This does not test content of the response.
1428+
* It only tests if the return code is the one expected.
1429+
*/
1430+
TEST_F(CLASSNAME(TestGraphFixture, RMW_IMPLEMENTATION),
1431+
test_rcl_get_subscriptions_info_by_topic_null_topic)
1432+
{
1433+
rcl_allocator_t allocator = rcl_get_default_allocator();
1434+
auto ret = rcl_get_subscriptions_info_by_topic(this->node_ptr,
1435+
&allocator, nullptr, false, this->topic_info_array);
1436+
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
1437+
}
1438+
1439+
/*
1440+
* This does not test content of the response.
1441+
* It only tests if the return code is the one expected.
1442+
*/
1443+
TEST_F(CLASSNAME(TestGraphFixture, RMW_IMPLEMENTATION),
1444+
test_rcl_get_publishers_info_by_topic_null_participants)
1445+
{
1446+
rcl_allocator_t allocator = rcl_get_default_allocator();
1447+
auto ret = rcl_get_publishers_info_by_topic(this->node_ptr,
1448+
&allocator, this->topic_name, false, nullptr);
1449+
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
1450+
}
1451+
1452+
/*
1453+
* This does not test content of the response.
1454+
* It only tests if the return code is the one expected.
1455+
*/
1456+
TEST_F(CLASSNAME(TestGraphFixture, RMW_IMPLEMENTATION),
1457+
test_rcl_get_subscriptions_info_by_topic_null_participants)
1458+
{
1459+
rcl_allocator_t allocator = rcl_get_default_allocator();
1460+
auto ret = rcl_get_subscriptions_info_by_topic(this->node_ptr,
1461+
&allocator, this->topic_name, false, nullptr);
1462+
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
1463+
}
1464+
1465+
/*
1466+
* This does not test content of the response.
1467+
* It only tests if the return code is the one expected.
1468+
*/
1469+
TEST_F(CLASSNAME(TestGraphFixture, RMW_IMPLEMENTATION),
1470+
test_rcl_get_publishers_info_by_topic_invalid_participants)
1471+
{
1472+
// this participant is invalid as the pointer "participants" inside is expected to be null.
1473+
this->topic_info_array->info_array =
1474+
reinterpret_cast<rmw_topic_info_t *>(malloc(sizeof(rmw_topic_info_t *)));
1475+
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
1476+
free(this->topic_info_array->info_array);
1477+
});
1478+
rcl_allocator_t allocator = rcl_get_default_allocator();
1479+
auto ret = rcl_get_publishers_info_by_topic(this->node_ptr,
1480+
&allocator, this->topic_name, false, this->topic_info_array);
1481+
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
1482+
}
1483+
1484+
/*
1485+
* This does not test content of the response.
1486+
* It only tests if the return code is the one expected.
1487+
*/
1488+
TEST_F(CLASSNAME(TestGraphFixture, RMW_IMPLEMENTATION),
1489+
test_rcl_get_subscriptions_info_by_topic_invalid_participants)
1490+
{
1491+
// this participant is invalid as the pointer "participants" inside is expected to be null.
1492+
this->topic_info_array->info_array =
1493+
reinterpret_cast<rmw_topic_info_t *>(malloc(sizeof(rmw_topic_info_t *)));
1494+
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
1495+
free(this->topic_info_array->info_array);
1496+
});
1497+
rcl_allocator_t allocator = rcl_get_default_allocator();
1498+
auto ret = rcl_get_subscriptions_info_by_topic(this->node_ptr,
1499+
&allocator, this->topic_name, false, this->topic_info_array);
1500+
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
1501+
}

0 commit comments

Comments
 (0)